mirror of
https://github.com/genodelabs/genode.git
synced 2025-06-21 00:23:16 +00:00
Move server API concept to base framework
This commit introduces the new `Component` interface in the form of the headers base/component.h and base/entrypoint.h. The os/server.h API has become merely a compatibilty wrapper and will eventually be removed. The same holds true for os/signal_rpc_dispatcher.h. The mechanism has moved to base/signal.h and is now called 'Signal_handler'. Since the patch shuffles headers around, please do a 'make clean' in the build directory. Issue #1832
This commit is contained in:
committed by
Christian Helmuth
parent
4ac7127f89
commit
051e84c4b4
@ -6,19 +6,18 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2006-2015 Genode Labs GmbH
|
||||
* Copyright (C) 2006-2016 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU General Public License version 2.
|
||||
*/
|
||||
|
||||
/* Linux */
|
||||
/* Linux includes */
|
||||
#include <SDL/SDL.h>
|
||||
|
||||
/* Genode */
|
||||
/* Genode includes */
|
||||
#include <util/misc_math.h>
|
||||
#include <base/env.h>
|
||||
#include <base/sleep.h>
|
||||
#include <base/component.h>
|
||||
#include <base/rpc_server.h>
|
||||
#include <framebuffer_session/framebuffer_session.h>
|
||||
#include <cap_session/connection.h>
|
||||
@ -27,45 +26,23 @@
|
||||
#include <timer_session/connection.h>
|
||||
|
||||
/* local includes */
|
||||
#include <input.h>
|
||||
#include "input.h"
|
||||
|
||||
|
||||
/**
|
||||
* Read integer value from config attribute
|
||||
*/
|
||||
void config_arg(const char *attr, long *value)
|
||||
{
|
||||
try { Genode::config()->xml_node().attribute(attr).value(value); }
|
||||
catch (...) { }
|
||||
}
|
||||
using Genode::Attached_ram_dataspace;
|
||||
|
||||
|
||||
/*
|
||||
* Variables for the libSDL output window
|
||||
*/
|
||||
static SDL_Surface *screen;
|
||||
static long scr_width = 1024, scr_height = 768;
|
||||
static Framebuffer::Mode::Format scr_format = Framebuffer::Mode::RGB565;
|
||||
|
||||
/*
|
||||
* Dataspace capability and local address of virtual frame buffer
|
||||
* that is shared with the client.
|
||||
*/
|
||||
static Genode::Dataspace_capability fb_ds_cap;
|
||||
static void *fb_ds_addr;
|
||||
|
||||
|
||||
/***********************************************
|
||||
** Implementation of the framebuffer service **
|
||||
***********************************************/
|
||||
|
||||
namespace Framebuffer { class Session_component; }
|
||||
|
||||
class Framebuffer::Session_component : public Genode::Rpc_object<Session>
|
||||
{
|
||||
private:
|
||||
|
||||
Mode _mode;
|
||||
SDL_Surface *_screen { nullptr };
|
||||
|
||||
Mode _mode;
|
||||
Genode::Dataspace_capability _fb_ds_cap;
|
||||
void *_fb_ds_addr;
|
||||
|
||||
Timer::Connection _timer;
|
||||
|
||||
@ -74,9 +51,15 @@ class Framebuffer::Session_component : public Genode::Rpc_object<Session>
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
Session_component() : _mode(scr_width, scr_height, Mode::RGB565) { }
|
||||
Session_component(Framebuffer::Mode mode,
|
||||
Genode::Dataspace_capability fb_ds_cap, void *fb_ds_addr)
|
||||
:
|
||||
_mode(mode), _fb_ds_cap(fb_ds_cap), _fb_ds_addr(fb_ds_addr)
|
||||
{ }
|
||||
|
||||
Genode::Dataspace_capability dataspace() override { return fb_ds_cap; }
|
||||
void screen(SDL_Surface *screen) { _screen = screen; }
|
||||
|
||||
Genode::Dataspace_capability dataspace() override { return _fb_ds_cap; }
|
||||
|
||||
Mode mode() const override { return _mode; }
|
||||
|
||||
@ -93,105 +76,144 @@ class Framebuffer::Session_component : public Genode::Rpc_object<Session>
|
||||
/* clip refresh area to screen boundaries */
|
||||
int x1 = Genode::max(x, 0);
|
||||
int y1 = Genode::max(y, 0);
|
||||
int x2 = Genode::min(x + w - 1, scr_width - 1);
|
||||
int y2 = Genode::min(y + h - 1, scr_height - 1);
|
||||
int x2 = Genode::min(x + w - 1, _mode.width() - 1);
|
||||
int y2 = Genode::min(y + h - 1, _mode.height() - 1);
|
||||
|
||||
if (x1 <= x2 && y1 <= y2) {
|
||||
|
||||
/* copy pixels from shared dataspace to sdl surface */
|
||||
const int start_offset = _mode.bytes_per_pixel()*(y1*scr_width + x1);
|
||||
const int start_offset = _mode.bytes_per_pixel()*(y1*_mode.width() + x1);
|
||||
const int line_len = _mode.bytes_per_pixel()*(x2 - x1 + 1);
|
||||
const int pitch = _mode.bytes_per_pixel()*scr_width;
|
||||
const int pitch = _mode.bytes_per_pixel()*_mode.width();
|
||||
|
||||
char *src = (char *)fb_ds_addr + start_offset;
|
||||
char *dst = (char *)screen->pixels + start_offset;
|
||||
char *src = (char *)_fb_ds_addr + start_offset;
|
||||
char *dst = (char *)_screen->pixels + start_offset;
|
||||
|
||||
for (int i = y1; i <= y2; i++, src += pitch, dst += pitch)
|
||||
Genode::memcpy(dst, src, line_len);
|
||||
|
||||
/* flush pixels in sdl window */
|
||||
SDL_UpdateRect(screen, x1, y1, x2 - x1 + 1, y2 - y1 + 1);
|
||||
SDL_UpdateRect(_screen, x1, y1, x2 - x1 + 1, y2 - y1 + 1);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Main program
|
||||
*/
|
||||
int main()
|
||||
{
|
||||
using namespace Genode;
|
||||
using namespace Framebuffer;
|
||||
namespace Input {
|
||||
|
||||
config_arg("width", &scr_width);
|
||||
config_arg("height", &scr_height);
|
||||
|
||||
/*
|
||||
* Initialize libSDL window
|
||||
*/
|
||||
if (SDL_Init(SDL_INIT_VIDEO) < 0)
|
||||
struct Handler_rpc : Handler
|
||||
{
|
||||
PERR("SDL_Init failed (%s)", SDL_GetError());
|
||||
return -1;
|
||||
}
|
||||
GENODE_RPC(Rpc_event, void, event, Input::Event);
|
||||
GENODE_RPC_INTERFACE(Rpc_event);
|
||||
};
|
||||
|
||||
/*
|
||||
* We're testing only X11.
|
||||
*/
|
||||
static char driver[16] = { 0 };
|
||||
SDL_VideoDriverName(driver, sizeof(driver));
|
||||
if (::strcmp(driver, "x11") != 0) {
|
||||
PERR("fb_sdl works on X11 only. Your SDL backend is \"%s\".", driver);
|
||||
return -2;
|
||||
}
|
||||
struct Handler_client : Handler
|
||||
{
|
||||
Genode::Capability<Handler_rpc> cap;
|
||||
|
||||
Genode::size_t bpp = Framebuffer::Mode::bytes_per_pixel(scr_format);
|
||||
screen = SDL_SetVideoMode(scr_width, scr_height, bpp*8, SDL_SWSURFACE);
|
||||
if (!screen) {
|
||||
PERR("SDL_SetVideoMode failed (%s)", SDL_GetError());
|
||||
return -3;
|
||||
}
|
||||
Handler_client(Genode::Capability<Handler_rpc> cap) : cap(cap) { }
|
||||
|
||||
SDL_ShowCursor(0);
|
||||
void event(Input::Event ev) override
|
||||
{
|
||||
cap.call<Handler_rpc::Rpc_event>(ev);
|
||||
}
|
||||
};
|
||||
|
||||
Genode::printf("creating virtual framebuffer for mode %ldx%ld@%zd\n",
|
||||
scr_width, scr_height, bpp*8);
|
||||
struct Handler_component : Genode::Rpc_object<Handler_rpc, Handler_component>
|
||||
{
|
||||
Session_component &session;
|
||||
|
||||
/*
|
||||
* Create dataspace representing the virtual frame buffer
|
||||
*/
|
||||
try {
|
||||
static Attached_ram_dataspace fb_ds(env()->ram_session(), scr_width*scr_height*bpp);
|
||||
fb_ds_cap = fb_ds.cap();
|
||||
fb_ds_addr = fb_ds.local_addr<void>();
|
||||
} catch (...) {
|
||||
PERR("Could not allocate dataspace for virtual frame buffer");
|
||||
return -4;
|
||||
}
|
||||
Handler_component(Session_component &session) : session(session) { }
|
||||
|
||||
/*
|
||||
* Initialize server entry point
|
||||
*/
|
||||
enum { STACK_SIZE = 16*1024 };
|
||||
static Cap_connection cap;
|
||||
static Rpc_entrypoint ep(&cap, STACK_SIZE, "fb_ep");
|
||||
|
||||
static Input::Session_component input_session;
|
||||
static Input::Root_component input_root(ep, input_session);
|
||||
|
||||
static Framebuffer::Session_component fb_session;
|
||||
static Static_root<Framebuffer::Session> fb_root(ep.manage(&fb_session));
|
||||
|
||||
/*
|
||||
* Now, the root interfaces are ready to accept requests.
|
||||
* This is the right time to tell mummy about our services.
|
||||
*/
|
||||
env()->parent()->announce(ep.manage(&fb_root));
|
||||
env()->parent()->announce(ep.manage(&input_root));
|
||||
|
||||
for (;;)
|
||||
input_session.submit(wait_for_event());
|
||||
|
||||
return 0;
|
||||
void event(Input::Event e) override { session.submit(e); }
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Read integer value from config attribute
|
||||
*/
|
||||
template<typename T>
|
||||
static T config_arg(char const *attr, T const &default_value)
|
||||
{
|
||||
long value = default_value;
|
||||
|
||||
try { Genode::config()->xml_node().attribute(attr).value(&value); }
|
||||
catch (...) { }
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
struct Main
|
||||
{
|
||||
/* fatal exceptions */
|
||||
struct Sdl_init_failed { };
|
||||
struct Sdl_videodriver_not_supported { };
|
||||
struct Sdl_setvideomode_failed { };
|
||||
|
||||
Genode::Environment &env;
|
||||
|
||||
int fb_width { config_arg("width", 1024) };
|
||||
int fb_height { config_arg("height", 768) };
|
||||
|
||||
Framebuffer::Mode fb_mode { fb_width, fb_height, Framebuffer::Mode::RGB565 };
|
||||
|
||||
Attached_ram_dataspace fb_ds { &env.ram(),
|
||||
fb_mode.width()*fb_mode.height()*fb_mode.bytes_per_pixel() };
|
||||
|
||||
Framebuffer::Session_component fb_session { fb_mode, fb_ds.cap(), fb_ds.local_addr<void>() };
|
||||
|
||||
Genode::Static_root<Framebuffer::Session> fb_root { env.ep().manage(fb_session) };
|
||||
|
||||
Input::Session_component input_session;
|
||||
Input::Root_component input_root { env.ep().rpc_ep(), input_session };
|
||||
|
||||
Input::Handler_component input_handler_component { input_session };
|
||||
Input::Handler_client input_handler_client { env.ep().manage(input_handler_component) };
|
||||
|
||||
Main(Genode::Environment &env) : env(env)
|
||||
{
|
||||
/*
|
||||
* Initialize libSDL window
|
||||
*/
|
||||
if (SDL_Init(SDL_INIT_VIDEO) < 0)
|
||||
{
|
||||
PERR("SDL_Init failed (%s)", SDL_GetError());
|
||||
throw Sdl_init_failed();
|
||||
}
|
||||
|
||||
/*
|
||||
* We're testing only X11.
|
||||
*/
|
||||
char driver[16] = { 0 };
|
||||
SDL_VideoDriverName(driver, sizeof(driver));
|
||||
if (::strcmp(driver, "x11") != 0) {
|
||||
PERR("fb_sdl works on X11 only. Your SDL backend is \"%s\".", driver);
|
||||
throw Sdl_videodriver_not_supported();
|
||||
}
|
||||
|
||||
SDL_Surface *screen = SDL_SetVideoMode(fb_mode.width(), fb_mode.height(),
|
||||
fb_mode.bytes_per_pixel()*8, SDL_SWSURFACE);
|
||||
if (!screen) {
|
||||
PERR("SDL_SetVideoMode failed (%s)", SDL_GetError());
|
||||
throw Sdl_setvideomode_failed();
|
||||
}
|
||||
fb_session.screen(screen);
|
||||
|
||||
SDL_ShowCursor(0);
|
||||
|
||||
Genode::printf("creating virtual framebuffer for mode %dx%d@%zd\n",
|
||||
fb_mode.width(), fb_mode.height(), fb_mode.bytes_per_pixel()*8);
|
||||
|
||||
env.parent().announce(env.ep().manage(fb_root));
|
||||
env.parent().announce(env.ep().manage(input_root));
|
||||
|
||||
init_input_backend(input_handler_client);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
Genode::size_t Component::stack_size() { return 4*1024*sizeof(long); }
|
||||
char const * Component::name() { return "fb_sdl"; }
|
||||
void Component::construct(Genode::Environment &env) { static Main inst(env); }
|
||||
|
@ -6,21 +6,23 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2006-2015 Genode Labs GmbH
|
||||
* Copyright (C) 2006-2016 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU General Public License version 2.
|
||||
*/
|
||||
|
||||
/* Linux */
|
||||
/* Linux includes */
|
||||
#include <SDL/SDL.h>
|
||||
|
||||
/* Genode */
|
||||
#include <input/keycodes.h>
|
||||
/* Genode includes */
|
||||
#include <base/printf.h>
|
||||
#include <base/thread.h>
|
||||
#include <input/keycodes.h>
|
||||
|
||||
/* local includes */
|
||||
#include "input.h"
|
||||
|
||||
/* local */
|
||||
#include <input.h>
|
||||
|
||||
/**
|
||||
* Convert SDL keycode to Genode keycode
|
||||
@ -210,14 +212,38 @@ static Input::Event wait_for_sdl_event()
|
||||
return Event(type, keycode, mx, my, mx - ox, my - oy);
|
||||
}
|
||||
|
||||
Input::Event wait_for_event()
|
||||
{
|
||||
Input::Event e;
|
||||
|
||||
/* prevent flooding of client with invalid events */
|
||||
do {
|
||||
e = wait_for_sdl_event();
|
||||
} while (e.type() == Input::Event::INVALID);
|
||||
|
||||
return e;
|
||||
namespace Input {
|
||||
enum { STACK_SIZE = 4096*sizeof(long) };
|
||||
struct Backend;
|
||||
}
|
||||
|
||||
struct Input::Backend : Genode::Thread<STACK_SIZE>
|
||||
{
|
||||
Handler &handler;
|
||||
|
||||
Backend(Input::Handler &handler)
|
||||
:
|
||||
Genode::Thread<STACK_SIZE>("input_backend"),
|
||||
handler(handler)
|
||||
{
|
||||
start();
|
||||
}
|
||||
|
||||
void entry()
|
||||
{
|
||||
while (true) {
|
||||
Input::Event e;
|
||||
|
||||
/* prevent flooding of client with invalid events */
|
||||
do {
|
||||
e = wait_for_sdl_event();
|
||||
} while (e.type() == Input::Event::INVALID);
|
||||
|
||||
handler.event(e);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
void init_input_backend(Input::Handler &h) { static Input::Backend inst(h); }
|
||||
|
@ -1,11 +1,12 @@
|
||||
/*
|
||||
* \brief SDL input support
|
||||
* \author Norman Feske
|
||||
* \author Christian Helmuth
|
||||
* \date 2006-08-16
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2006-2013 Genode Labs GmbH
|
||||
* Copyright (C) 2006-2016 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU General Public License version 2.
|
||||
@ -14,11 +15,16 @@
|
||||
#ifndef _DRIVERS__FRAMEBUFFER__SPEC__SDL__INPUT_H_
|
||||
#define _DRIVERS__FRAMEBUFFER__SPEC__SDL__INPUT_H_
|
||||
|
||||
/* Genode include */
|
||||
#include <input/event.h>
|
||||
|
||||
/**
|
||||
* Wait for an event, Zzz...zz..
|
||||
*/
|
||||
Input::Event wait_for_event();
|
||||
namespace Input { struct Handler; }
|
||||
|
||||
struct Input::Handler
|
||||
{
|
||||
virtual void event(Input::Event) = 0;
|
||||
};
|
||||
|
||||
void init_input_backend(Input::Handler &);
|
||||
|
||||
#endif /* _DRIVERS__FRAMEBUFFER__SPEC__SDL__INPUT_H_ */
|
||||
|
@ -11,131 +11,34 @@
|
||||
* under the terms of the GNU General Public License version 2.
|
||||
*/
|
||||
|
||||
#include <base/component.h>
|
||||
#include <os/server.h>
|
||||
#include <cap_session/connection.h>
|
||||
|
||||
using namespace Server;
|
||||
|
||||
|
||||
static Cap_session &global_cap_session()
|
||||
Genode::size_t Component::stack_size()
|
||||
{
|
||||
static Cap_connection inst;
|
||||
return inst;
|
||||
return Server::stack_size();
|
||||
}
|
||||
|
||||
|
||||
static Rpc_entrypoint &global_rpc_ep()
|
||||
char const *Component::name()
|
||||
{
|
||||
static Rpc_entrypoint inst(&global_cap_session(),
|
||||
stack_size(),
|
||||
name());
|
||||
return inst;
|
||||
return Server::name();
|
||||
}
|
||||
|
||||
|
||||
static Entrypoint &global_ep()
|
||||
static Genode::Environment *_env;
|
||||
|
||||
|
||||
void Component::construct(Genode::Environment &env)
|
||||
{
|
||||
static Server::Entrypoint inst;
|
||||
return inst;
|
||||
_env = &env;
|
||||
Server::construct(env.ep());
|
||||
}
|
||||
|
||||
|
||||
static Genode::Signal_receiver &global_sig_rec()
|
||||
{
|
||||
static Genode::Signal_receiver inst;
|
||||
return inst;
|
||||
}
|
||||
|
||||
|
||||
static void dispatch(Signal &sig)
|
||||
{
|
||||
Signal_dispatcher_base *dispatcher = 0;
|
||||
dispatcher = dynamic_cast<Signal_dispatcher_base *>(sig.context());
|
||||
|
||||
if (!dispatcher)
|
||||
return;
|
||||
|
||||
dispatcher->dispatch(sig.num());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Dispatch a signal at entry point
|
||||
*/
|
||||
void Server::wait_and_dispatch_one_signal()
|
||||
{
|
||||
Signal sig = global_sig_rec().wait_for_signal();
|
||||
dispatch(sig);
|
||||
}
|
||||
|
||||
|
||||
Signal_context_capability Entrypoint::manage(Signal_dispatcher_base &dispatcher)
|
||||
{
|
||||
return global_sig_rec().manage(&dispatcher);
|
||||
}
|
||||
|
||||
|
||||
void Server::Entrypoint::dissolve(Signal_dispatcher_base &dispatcher)
|
||||
{
|
||||
global_sig_rec().dissolve(&dispatcher);
|
||||
}
|
||||
|
||||
|
||||
Server::Entrypoint::Entrypoint() : _rpc_ep(global_rpc_ep()) { }
|
||||
|
||||
|
||||
namespace Server {
|
||||
struct Constructor;
|
||||
struct Constructor_component;
|
||||
}
|
||||
|
||||
|
||||
struct Server::Constructor
|
||||
{
|
||||
GENODE_RPC(Rpc_construct, void, construct);
|
||||
GENODE_RPC(Rpc_signal, void, signal);
|
||||
GENODE_RPC_INTERFACE(Rpc_construct, Rpc_signal);
|
||||
};
|
||||
|
||||
|
||||
struct Server::Constructor_component : Rpc_object<Server::Constructor,
|
||||
Server::Constructor_component>
|
||||
{
|
||||
void construct() { Server::construct(global_ep()); }
|
||||
|
||||
void signal()
|
||||
{
|
||||
try {
|
||||
Signal sig = global_sig_rec().pending_signal();
|
||||
::dispatch(sig);
|
||||
} catch (Signal_receiver::Signal_not_pending) { }
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
static Server::Constructor_component constructor;
|
||||
|
||||
static Server::Entrypoint ep;
|
||||
|
||||
/* call Server::construct in the context of the entrypoint */
|
||||
Capability<Server::Constructor> constructor_cap = ep.manage(constructor);
|
||||
|
||||
constructor_cap.call<Server::Constructor::Rpc_construct>();
|
||||
|
||||
/* process incoming signals */
|
||||
for (;;) {
|
||||
|
||||
global_sig_rec().block_for_signal();
|
||||
|
||||
/*
|
||||
* It might happen that we try to forward a signal to the entrypoint,
|
||||
* while the context of that signal is already destroyed. In that case
|
||||
* we will get an ipc error exception as result, which has to be caught.
|
||||
*/
|
||||
try {
|
||||
constructor_cap.call<Server::Constructor::Rpc_signal>();
|
||||
} catch(Genode::Ipc_error) { }
|
||||
}
|
||||
if (_env)
|
||||
_env->ep().wait_and_dispatch_one_signal();
|
||||
}
|
||||
|
Reference in New Issue
Block a user