2 * \brief DOpE server module
4 * \author Norman Feske <nf2@inf.tu-dresden.de>
6 * This module is the main communication interface
7 * between DOpE clients and DOpE.
11 * Copyright (C) 2002-2004 Norman Feske <nf2@os.inf.tu-dresden.de>
12 * Technische Universitaet Dresden, Operating Systems Research Group
14 * This file is part of the DOpE package, which is distributed under
15 * the terms of the GNU General Public Licence 2. Please see the
16 * COPYING file for details.
24 /*** DOPE SPECIFIC ***/
32 #include "messenger.h"
33 #include "userstate.h"
34 #include "scheduler.h"
35 #include <l4/dope/dopedef.h>
38 #include <l4/re/namespace>
39 #include <l4/re/util/cap_alloc>
40 #include <l4/sys/factory>
41 #include <l4/sys/typeinfo_svr>
42 #include <l4/cxx/exceptions>
44 #include <l4/cxx/iostream>
45 #include <l4/cxx/l4iostream>
46 #include <l4/cxx/minmax>
48 #include <l4/re/protocols>
49 #include <l4/re/util/object_registry>
50 #include <l4/re/util/video/goos_svr>
51 #include <l4/re/util/event_svr>
52 #include <l4/re/util/event_buffer>
53 #include <l4/re/c/event.h>
54 #include <l4/re/video/goos>
56 #include <l4/sys/debugger.h>
57 #include <pthread-l4.h>
59 static struct userstate_services *userstate;
60 static struct thread_services *thread;
61 static struct appman_services *appman;
62 static struct script_services *script;
63 static struct scope_services *scope;
64 static struct screen_services *screen;
65 static struct scheduler_services *scheduler;
66 static struct messenger_services *msg;
68 extern "C" int init_server(struct dope_services *d);
71 static int get_val(const char *configstr, const char *var, unsigned long *val)
74 a = strstr(configstr, var);
77 *val = strtoul(a + strlen(var), NULL, 0);
81 static int get_string(const char *configstr, const char *var,
82 char **val, unsigned long *vallen)
85 a = strstr(configstr, var);
90 while (*a && !isspace(*a))
96 // ------------------------------------------------------------------------
97 static L4Re::Util::Object_registry *dope_registry;
99 // ------------------------------------------------------------------------
101 static L4::Cap<void> rcv_cap()
103 static L4::Cap<void> _rcv = L4Re::Util::cap_alloc.alloc<void>();
107 class Dope_base : public L4Re::Util::Event_svr<Dope_base>,
108 public L4::Server_object
112 L4Re::Util::Event_buffer evbuf;
114 int cmd(const char *c);
115 int cmd_ret(const char *c, char *result, unsigned long res_len);
118 bool register_appid(s32 ai, Dope_base *obj);
121 void event_cb(l4re_event_t *e, unsigned nr_events);
122 static Dope_base *get_obj(s32 ai);
123 static L4::Cap<void> rcv_cap() { return ::rcv_cap(); }
126 static void check_appid(s32 ai);
127 static Dope_base *appid_to_obj[MAX_APPS];
130 Dope_base *Dope_base::appid_to_obj[MAX_APPS];
132 void Dope_base::check_appid(s32 ai)
136 printf("Oops: %d >= MAX_APPS\n", ai);
141 bool Dope_base::register_appid(s32 ai, Dope_base *obj)
144 appid_to_obj[ai] = obj;
148 Dope_base *Dope_base::get_obj(s32 ai)
151 return appid_to_obj[ai];
154 extern "C" void dope_event_inject(s32 appid, l4re_event_t *e,
157 Dope_base::get_obj(appid)->event_cb(e, nr_events);
160 int Dope_base::cmd(const char *c)
162 INFO(printf("Server(exec_cmd): cmd %s execution requested by app_id=%u\n", c, (u32)app_id);)
163 appman->lock(app_id);
164 int ret = script->exec_command(app_id, (char *)c, NULL, 0);
165 appman->unlock(app_id);
167 printf("DOpE(exec_cmd): Error - command \"%s\" returned %d\n", c, ret);
171 int Dope_base::cmd_ret(const char *c, char *result, unsigned long res_len)
173 INFO(printf("Server(exec_req): cmd %s execution requested by app_id=%u\n",
175 appman->lock(app_id);
177 int ret = script->exec_command(app_id, (char *)c, result, res_len);
178 appman->unlock(app_id);
179 INFO(printf("Server(exec_req): send result msg: %s\n", result));
181 if (ret < 0) printf("DOpE(exec_req): Error - command \"%s\" returned %d\n", c, ret);
186 Dope_base::create_event()
190 L4Re::Util::Auto_cap<L4Re::Dataspace>::Cap b
191 = L4Re::Util::cap_alloc.alloc<L4Re::Dataspace>();
195 if ((r = L4Re::Env::env()->mem_alloc()->alloc(L4_PAGESIZE, b.get())) < 0)
198 if ((r = evbuf.attach(b.get(), L4Re::Env::env()->rm())) < 0)
201 memset(evbuf.buf(), 0, b.get()->size());
208 void Dope_base::event_cb(l4re_event_t *e, unsigned nr_events)
211 printf("emmit event (client=%p): event (t=%d c=%d v=%d stream=%lx)\n",
212 this, e->type, e->code, e->value, e->stream_id);
214 for (unsigned i = 0; i < nr_events; ++i)
215 evbuf.put(*reinterpret_cast<L4Re::Event_buffer::Event const*>(&e[i]));
220 // ------------------------------------------------------------------------
222 class Dope_app : public Dope_base
225 explicit Dope_app(const char *configstr);
226 int dispatch(l4_umword_t obj, L4::Ipc_iostream &ios);
227 int dispatch_dope_app(l4_umword_t, L4::Ipc_iostream &ios);
229 int client_cmd(L4::Ipc_iostream &ios);
230 int client_cmd_req(L4::Ipc_iostream &ios);
231 int client_vscreen_get_fb(L4::Ipc_iostream &ios);
232 int client_get_keystate(L4::Ipc_iostream &ios);
235 Dope_app::Dope_app(const char *configstr)
237 dope_registry->register_obj(this);
242 const char *appname = "App";
244 if (get_string(configstr, "name=", &s, &val))
246 strncpy(buf, s, val);
251 if (int r = create_event())
252 throw (L4::Runtime_error(r));
254 app_id = appman->reg_app(appname);
255 register_appid(app_id, this);
257 SCOPE *rootscope = scope->create();
258 appman->set_rootscope(app_id, rootscope);
259 INFO(printf("Server(init_app): application init request. appname=%s\n", appname));
262 int Dope_app::client_cmd(L4::Ipc_iostream &ios)
267 len = sizeof(buf_in);
268 ios >> L4::ipc_buf_cp_in(buf_in, len);
275 int Dope_app::client_cmd_req(L4::Ipc_iostream &ios)
281 len = sizeof(buf_in);
282 ios >> L4::ipc_buf_cp_in(buf_in, len);
285 cmd_ret(buf_in, buf_out, sizeof(buf_out));
287 len = strlen(buf_out);
288 if (len >= sizeof(buf_out))
290 len = sizeof(buf_out) - 1;
291 buf_out[sizeof(buf_out) - 1] = 0;
294 ios << L4::ipc_buf_cp_out(buf_out, len);
299 int Dope_app::client_vscreen_get_fb(L4::Ipc_iostream &ios)
305 len = sizeof(buf_in);
306 ios >> L4::ipc_buf_cp_in(buf_in, len);
309 snprintf(buf, sizeof(buf), "%s.map()", buf_in);
310 cmd_ret(buf, buf_in, sizeof(buf_in));
311 l4_cap_idx_t x = strtoul(&buf_in[3], NULL, 0);
312 L4::Cap<L4Re::Dataspace> ds = L4::Cap<L4Re::Dataspace>(x);
317 int Dope_app::client_get_keystate(L4::Ipc_iostream &ios)
320 ios >> x; // get keycode
321 x = userstate->get_keystate(x);
322 ios << x; // send state
326 int Dope_app::dispatch_dope_app(l4_umword_t, L4::Ipc_iostream &ios)
333 case Dope::Dope_app_::Cmd:
334 return client_cmd(ios);
335 case Dope::Dope_app_::Cmd_req:
336 return client_cmd_req(ios);
337 case Dope::Dope_app_::Vscreen_get_fb:
338 return client_vscreen_get_fb(ios);
339 case Dope::Dope_app_::Get_keystate:
340 return client_get_keystate(ios);
346 int Dope_app::dispatch(l4_umword_t obj, L4::Ipc_iostream &ios)
353 case Dope::Protocol::App:
354 return dispatch_dope_app(obj, ios);
355 case L4Re::Protocol::Event:
357 return L4Re::Util::Event_svr<Dope_base>::dispatch(obj, ios);
359 return -L4_EBADPROTO;
364 // ------------------------------------------------------------------------
366 class Dope_fb : public L4Re::Util::Video::Goos_svr,
370 explicit Dope_fb(const char *configstr);
371 int dispatch(l4_umword_t obj, L4::Ipc_iostream &ios);
373 virtual int refresh(int x, int y, int w, int h);
376 Dope_fb::Dope_fb(const char *configstr)
379 unsigned xpos = 20, ypos = 20, w, h;
381 dope_registry->register_obj(this);
383 _screen_info.width = 300;
384 _screen_info.height = 200;
386 if (sscanf(configstr, "%dx%d", &w, &h) == 2)
388 _screen_info.width = w;
389 _screen_info.height = h;
392 if (char *a = strstr(configstr, "pos="))
393 sscanf(a + 4, "%d,%d", &xpos, &ypos);
395 L4Re::Video::Pixel_info pixinfo(16, 5, 11, 6, 5, 5, 0);
396 pixinfo.bytes_per_pixel(2);
398 _screen_info.flags = L4Re::Video::Goos::F_pointer;
399 _screen_info.num_static_views = 1;
400 _screen_info.num_static_buffers = 1;
401 _screen_info.pixel_info = pixinfo;
404 _view_info.bytes_per_line = _screen_info.width * 2;
405 _view_info.buffer_offset = 0;
407 const char *appname = "fb";
408 //const char *listener = "listener";
412 if (get_string(configstr, "name=", &s, &val))
414 strncpy(buf, s, val);
419 app_id = appman->reg_app(appname);
420 register_appid(app_id, this);
422 SCOPE *rootscope = scope->create();
423 //THREAD *listener_thread = thread->alloc_thread();
424 appman->set_rootscope(app_id, rootscope);
426 INFO(printf("Server(init_fb): fb init request. appname=%s\n", appname));
428 //thread->ident2thread(listener, listener_thread);
429 //appman->reg_list_thread(app_id, listener_thread);
430 //appman->reg_listener(app_id, (void *)&listener_thread->tid);
432 //appman->reg_app_thread(app_id, (THREAD *)&client_thread);
434 if (int r = create_event())
435 throw (L4::Runtime_error(r));
437 cmd("x=new Window()");
438 cmd("y=new VScreen()");
439 snprintf(buf, sizeof(buf), "y.setmode(%ld,%ld,\"RGB16\")",
440 _screen_info.width, _screen_info.height);
441 buf[sizeof(buf)-1] = 0;
444 snprintf(buf, sizeof(buf), "x.set(-x %d -y %d -content y -workw %ld -workh %ld)",
446 _screen_info.width, _screen_info.height);
447 buf[sizeof(buf)-1] = 0;
450 snprintf(buf, sizeof(buf), "y.bind(\"press\", 1)");
451 buf[sizeof(buf)-1] = 0;
454 snprintf(buf, sizeof(buf), "y.bind(\"release\", 1)");
455 buf[sizeof(buf)-1] = 0;
458 snprintf(buf, sizeof(buf), "y.bind(\"motion\", 1)");
459 buf[sizeof(buf)-1] = 0;
464 cmd_ret("y.map()", buf, sizeof(buf));
466 printf("y.map() = %s\n", buf);
468 l4_cap_idx_t x = strtoul(&buf[3], NULL, 0);
469 _fb_ds = L4::Cap<L4Re::Dataspace>(x);
471 // printf("fb_ds = %lx\n", _fb_ds.cap());
472 // printf("evbuf2 = %p\n", evbuf.buf());
475 int Dope_fb::refresh(int x, int y, int w, int h)
478 // Hmm: y is a VSCREEN, so we could use y->vscr->refresh(y, ...)
479 snprintf(buf, sizeof(buf), "y.refresh(-x %d -y %d -w %d -h %d)", x, y, w, h);
480 buf[sizeof(buf) - 1] = 0;
485 int Dope_fb::dispatch(l4_umword_t obj, L4::Ipc_iostream &ios)
492 case L4Re::Protocol::Goos:
493 return L4Re::Util::Video::Goos_svr::dispatch(obj, ios);
494 case L4Re::Protocol::Event:
496 return L4Re::Util::Event_svr<Dope_base>::dispatch(obj, ios);
498 return -L4_EBADPROTO;
502 // ------------------------------------------------------------------------
504 class Controller : public L4::Server_object
507 int dispatch(l4_umword_t obj, L4::Ipc_iostream &ios);
511 Controller::dispatch(l4_umword_t, L4::Ipc_iostream &ios)
518 case L4::Meta::Protocol:
519 return L4::Util::handle_meta_request<L4::Factory>(ios);
520 case L4::Factory::Protocol:
523 return -L4_EBADPROTO;
526 L4::Factory::Proto op;
529 if (!arg.is_of<char const*>())
532 unsigned long size = 100;
534 strncpy(s, arg.value<char const*>(), cxx::min<int>(size, arg.length()));
542 printf("Invalid object type requested\n");
545 case L4Re::Video::Goos::Protocol:
547 Dope_fb *x = new Dope_fb(s);
551 case 0: // dope iface
553 Dope_app *x = new Dope_app(s);
559 catch (L4::Runtime_error const &e)
565 struct My_loop_hooks :
566 public L4::Ipc_svr::Ignore_errors,
567 public L4::Ipc_svr::Default_timeout,
568 public L4::Ipc_svr::Compound_reply
570 void setup_wait(L4::Ipc_istream &istr, L4::Ipc_svr::Reply_mode)
573 istr << L4::Small_buf(rcv_cap().cap(), L4_RCV_ITEM_LOCAL_ID);
574 l4_utcb_br_u(istr.utcb())->bdr = 0;
578 /*** DOpE SERVER THREAD ***/
579 static void *server_thread(void *)
581 static Controller ctrl;
583 l4_debugger_set_object_name(pthread_getl4cap(pthread_self()), "dope-srv");
585 dope_registry = new L4Re::Util::Object_registry
586 (L4::Cap<L4::Thread>(pthread_getl4cap(pthread_self())),
587 L4Re::Env::env()->factory());
592 static L4::Server<My_loop_hooks> dope_server(l4_utcb());
594 if (!dope_registry->register_obj(&ctrl, "dope").is_valid())
596 printf("Service registration failed.\n");
600 INFO(printf("Server(server_thread): entering server loop\n"));
601 dope_server.loop(dope_registry);
607 /******************************************************
608 *** FUNCTIONS THAT ARE CALLED BY THE SERVER THREAD ***
609 ******************************************************/
611 long dope_manager_init_app_component(void *,
612 const char* ,//appname,
613 const char* ,//listener,
616 printf("%s %d\n", __func__, __LINE__);
618 s32 app_id = appman->reg_app((char *)appname);
619 SCOPE *rootscope = scope->create();
620 THREAD *listener_thread = thread->alloc_thread();
621 appman->set_rootscope(app_id, rootscope);
623 INFO(printf("Server(init_app): application init request. appname=%s, listener=%s (new app_id=%x)\n", appname, listener, (int)app_id));
625 thread->ident2thread(listener, listener_thread);
626 appman->reg_list_thread(app_id, listener_thread);
627 appman->reg_listener(app_id, (void *)&listener_thread->tid);
634 void dope_manager_deinit_app_component(void *,
638 printf("%s %d\n", __func__, __LINE__);
640 struct thread client_thread = { *_dice_corba_obj };
642 /* check if the app_id belongs to the client */
643 if (!thread->thread_equal(&client_thread, appman->get_listener(app_id))) {
644 printf("Server(deinit_app): Error: permission denied\n");
648 INFO(printf("Server(deinit_app): application (id=%u) deinit requested\n", (u32)app_id);)
649 scheduler->release_app(app_id);
650 userstate->release_app(app_id);
651 screen->forget_children(app_id);
652 appman->unreg_app(app_id);
657 long dope_manager_exec_cmd_component(void *,
663 struct thread client_thread = { *_dice_corba_obj };
666 /* check if the app_id belongs to the client */
667 if (!thread->thread_equal(&client_thread, appman->get_listener(app_id))) {
668 printf("Server(exec_cmd): Error: permission denied\n");
669 return DOPE_ERR_PERM;
672 appman->reg_app_thread(app_id, (THREAD *)&client_thread);
673 INFO(printf("Server(exec_cmd): cmd %s execution requested by app_id=%u\n", cmd, (u32)app_id);)
674 // printf("Server(exec_cmd): cmd %s execution requested by app_id=%u\n", cmd, (u32)app_id);
675 appman->lock(app_id);
676 ret = script->exec_command(app_id, (char *)cmd, NULL, 0);
677 appman->unlock(app_id);
678 if (ret < 0) printf("DOpE(exec_cmd): Error - command \"%s\" returned %d\n", cmd, ret);
685 long dope_manager_exec_req_component(void *,
688 char /*result*/[256],
693 struct thread client_thread = { *_dice_corba_obj };
696 /* check if the app_id belongs to the client */
697 if (!thread->thread_equal(&client_thread, appman->get_listener(app_id))) {
698 printf("Server(exec_req): Error: permission denied\n");
699 return DOPE_ERR_PERM;
702 appman->reg_app_thread(app_id, (THREAD *)&client_thread);
704 INFO(printf("Server(exec_req): cmd %s execution requested by app_id=%u\n", cmd, (u32)app_id);)
705 appman->lock(app_id);
707 ret = script->exec_command(app_id, (char *)cmd, &result[0], *res_len);
708 appman->unlock(app_id);
709 INFO(printf("Server(exec_req): send result msg: %s\n", result));
711 if (ret < 0) printf("DOpE(exec_req): Error - command \"%s\" returned %d\n", cmd, ret);
719 long dope_manager_get_keystate_component(void *,
723 return userstate->get_keystate(keycode);
727 char dope_manager_get_ascii_component(void *,
731 return userstate->get_ascii(keycode);
735 /*************************
736 *** SERVICE FUNCTIONS ***
737 *************************/
739 /*** START SERVING ***/
740 static void start(void)
742 INFO(printf("Server(start): creating server thread\n");)
743 thread->start_thread(NULL, &server_thread, NULL);
747 /****************************************
748 *** SERVICE STRUCTURE OF THIS MODULE ***
749 ****************************************/
751 static struct server_services services = {
756 /**************************
757 *** MODULE ENTRY POINT ***
758 **************************/
760 extern "C" int init_server(struct dope_services *d)
762 thread = (thread_services *)d->get_module("Thread 1.0");
763 appman = (appman_services *)d->get_module("ApplicationManager 1.0");
764 script = (script_services *)d->get_module("Script 1.0");
765 msg = (messenger_services *)d->get_module("Messenger 1.0");
766 userstate = (userstate_services *)d->get_module("UserState 1.0");
767 scope = (scope_services *)d->get_module("Scope 1.0");
768 screen = (screen_services *)d->get_module("Screen 1.0");
769 scheduler = (scheduler_services *)d->get_module("Scheduler 1.0");
771 d->register_module("Server 1.0", &services);