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;
381 dope_registry->register_obj(this);
383 _screen_info.width = 300;
384 _screen_info.height = 200;
387 if (get_val(configstr, "w=", &val))
388 _screen_info.width = val;
389 if (get_val(configstr, "h=", &val))
390 _screen_info.height = val;
392 if (get_val(configstr, "x=", &val))
394 if (get_val(configstr, "y=", &val))
397 L4Re::Video::Pixel_info pixinfo(16, 5, 11, 6, 5, 5, 0);
398 pixinfo.bytes_per_pixel(2);
400 _screen_info.flags = L4Re::Video::Goos::F_pointer;
401 _screen_info.num_static_views = 1;
402 _screen_info.num_static_buffers = 1;
403 _screen_info.pixel_info = pixinfo;
406 _view_info.bytes_per_line = _screen_info.width * 2;
407 _view_info.buffer_offset = 0;
409 const char *appname = "fb";
410 //const char *listener = "listener";
414 if (get_string(configstr, "name=", &s, &val))
416 strncpy(buf, s, val);
421 app_id = appman->reg_app(appname);
422 register_appid(app_id, this);
424 SCOPE *rootscope = scope->create();
425 //THREAD *listener_thread = thread->alloc_thread();
426 appman->set_rootscope(app_id, rootscope);
428 INFO(printf("Server(init_fb): fb init request. appname=%s\n", appname));
430 //thread->ident2thread(listener, listener_thread);
431 //appman->reg_list_thread(app_id, listener_thread);
432 //appman->reg_listener(app_id, (void *)&listener_thread->tid);
434 //appman->reg_app_thread(app_id, (THREAD *)&client_thread);
436 if (int r = create_event())
437 throw (L4::Runtime_error(r));
439 cmd("x=new Window()");
440 cmd("y=new VScreen()");
441 snprintf(buf, sizeof(buf), "y.setmode(%ld,%ld,\"RGB16\")",
442 _screen_info.width, _screen_info.height);
443 buf[sizeof(buf)-1] = 0;
446 snprintf(buf, sizeof(buf), "x.set(-x %d -y %d -content y -workw %ld -workh %ld)",
448 _screen_info.width, _screen_info.height);
449 buf[sizeof(buf)-1] = 0;
452 snprintf(buf, sizeof(buf), "y.bind(\"press\", 1)");
453 buf[sizeof(buf)-1] = 0;
456 snprintf(buf, sizeof(buf), "y.bind(\"release\", 1)");
457 buf[sizeof(buf)-1] = 0;
460 snprintf(buf, sizeof(buf), "y.bind(\"motion\", 1)");
461 buf[sizeof(buf)-1] = 0;
466 cmd_ret("y.map()", buf, sizeof(buf));
468 printf("y.map() = %s\n", buf);
470 l4_cap_idx_t x = strtoul(&buf[3], NULL, 0);
471 _fb_ds = L4::Cap<L4Re::Dataspace>(x);
473 // printf("fb_ds = %lx\n", _fb_ds.cap());
474 // printf("evbuf2 = %p\n", evbuf.buf());
477 int Dope_fb::refresh(int x, int y, int w, int h)
480 // Hmm: y is a VSCREEN, so we could use y->vscr->refresh(y, ...)
481 snprintf(buf, sizeof(buf), "y.refresh(-x %d -y %d -w %d -h %d)", x, y, w, h);
482 buf[sizeof(buf) - 1] = 0;
487 int Dope_fb::dispatch(l4_umword_t obj, L4::Ipc_iostream &ios)
494 case L4Re::Protocol::Goos:
495 return L4Re::Util::Video::Goos_svr::dispatch(obj, ios);
496 case L4Re::Protocol::Event:
498 return L4Re::Util::Event_svr<Dope_base>::dispatch(obj, ios);
500 return -L4_EBADPROTO;
504 // ------------------------------------------------------------------------
506 class Controller : public L4::Server_object
509 int dispatch(l4_umword_t obj, L4::Ipc_iostream &ios);
513 Controller::dispatch(l4_umword_t, L4::Ipc_iostream &ios)
520 case L4::Meta::Protocol:
521 return L4::Util::handle_meta_request<L4::Factory>(ios);
522 case L4::Factory::Protocol:
525 return -L4_EBADPROTO;
528 L4::Factory::Proto op;
531 if (!arg.is_of<char const*>())
534 unsigned long size = 100;
536 strncpy(s, arg.value<char const*>(), cxx::min<int>(size, arg.length()));
544 printf("Invalid object type requested\n");
547 case L4Re::Video::Goos::Protocol:
549 Dope_fb *x = new Dope_fb(s);
553 case 0: // dope iface
555 Dope_app *x = new Dope_app(s);
561 catch (L4::Runtime_error const &e)
567 struct My_loop_hooks :
568 public L4::Ipc_svr::Ignore_errors,
569 public L4::Ipc_svr::Default_timeout,
570 public L4::Ipc_svr::Compound_reply
572 void setup_wait(L4::Ipc_istream &istr, L4::Ipc_svr::Reply_mode)
575 istr << L4::Small_buf(rcv_cap().cap(), L4_RCV_ITEM_LOCAL_ID);
576 l4_utcb_br_u(istr.utcb())->bdr = 0;
580 /*** DOpE SERVER THREAD ***/
581 static void *server_thread(void *)
583 static Controller ctrl;
585 l4_debugger_set_object_name(pthread_getl4cap(pthread_self()), "dope-srv");
587 dope_registry = new L4Re::Util::Object_registry
588 (L4::Cap<L4::Thread>(pthread_getl4cap(pthread_self())),
589 L4Re::Env::env()->factory());
594 static L4::Server<My_loop_hooks> dope_server(l4_utcb());
596 if (!dope_registry->register_obj(&ctrl, "dope").is_valid())
598 printf("Service registration failed.\n");
602 INFO(printf("Server(server_thread): entering server loop\n"));
603 dope_server.loop(dope_registry);
609 /******************************************************
610 *** FUNCTIONS THAT ARE CALLED BY THE SERVER THREAD ***
611 ******************************************************/
613 long dope_manager_init_app_component(void *,
614 const char* ,//appname,
615 const char* ,//listener,
618 printf("%s %d\n", __func__, __LINE__);
620 s32 app_id = appman->reg_app((char *)appname);
621 SCOPE *rootscope = scope->create();
622 THREAD *listener_thread = thread->alloc_thread();
623 appman->set_rootscope(app_id, rootscope);
625 INFO(printf("Server(init_app): application init request. appname=%s, listener=%s (new app_id=%x)\n", appname, listener, (int)app_id));
627 thread->ident2thread(listener, listener_thread);
628 appman->reg_list_thread(app_id, listener_thread);
629 appman->reg_listener(app_id, (void *)&listener_thread->tid);
636 void dope_manager_deinit_app_component(void *,
640 printf("%s %d\n", __func__, __LINE__);
642 struct thread client_thread = { *_dice_corba_obj };
644 /* check if the app_id belongs to the client */
645 if (!thread->thread_equal(&client_thread, appman->get_listener(app_id))) {
646 printf("Server(deinit_app): Error: permission denied\n");
650 INFO(printf("Server(deinit_app): application (id=%u) deinit requested\n", (u32)app_id);)
651 scheduler->release_app(app_id);
652 userstate->release_app(app_id);
653 screen->forget_children(app_id);
654 appman->unreg_app(app_id);
659 long dope_manager_exec_cmd_component(void *,
665 struct thread client_thread = { *_dice_corba_obj };
668 /* check if the app_id belongs to the client */
669 if (!thread->thread_equal(&client_thread, appman->get_listener(app_id))) {
670 printf("Server(exec_cmd): Error: permission denied\n");
671 return DOPE_ERR_PERM;
674 appman->reg_app_thread(app_id, (THREAD *)&client_thread);
675 INFO(printf("Server(exec_cmd): cmd %s execution requested by app_id=%u\n", cmd, (u32)app_id);)
676 // printf("Server(exec_cmd): cmd %s execution requested by app_id=%u\n", cmd, (u32)app_id);
677 appman->lock(app_id);
678 ret = script->exec_command(app_id, (char *)cmd, NULL, 0);
679 appman->unlock(app_id);
680 if (ret < 0) printf("DOpE(exec_cmd): Error - command \"%s\" returned %d\n", cmd, ret);
687 long dope_manager_exec_req_component(void *,
690 char /*result*/[256],
695 struct thread client_thread = { *_dice_corba_obj };
698 /* check if the app_id belongs to the client */
699 if (!thread->thread_equal(&client_thread, appman->get_listener(app_id))) {
700 printf("Server(exec_req): Error: permission denied\n");
701 return DOPE_ERR_PERM;
704 appman->reg_app_thread(app_id, (THREAD *)&client_thread);
706 INFO(printf("Server(exec_req): cmd %s execution requested by app_id=%u\n", cmd, (u32)app_id);)
707 appman->lock(app_id);
709 ret = script->exec_command(app_id, (char *)cmd, &result[0], *res_len);
710 appman->unlock(app_id);
711 INFO(printf("Server(exec_req): send result msg: %s\n", result));
713 if (ret < 0) printf("DOpE(exec_req): Error - command \"%s\" returned %d\n", cmd, ret);
721 long dope_manager_get_keystate_component(void *,
725 return userstate->get_keystate(keycode);
729 char dope_manager_get_ascii_component(void *,
733 return userstate->get_ascii(keycode);
737 /*************************
738 *** SERVICE FUNCTIONS ***
739 *************************/
741 /*** START SERVING ***/
742 static void start(void)
744 INFO(printf("Server(start): creating server thread\n");)
745 thread->start_thread(NULL, &server_thread, NULL);
749 /****************************************
750 *** SERVICE STRUCTURE OF THIS MODULE ***
751 ****************************************/
753 static struct server_services services = {
758 /**************************
759 *** MODULE ENTRY POINT ***
760 **************************/
762 extern "C" int init_server(struct dope_services *d)
764 thread = (thread_services *)d->get_module("Thread 1.0");
765 appman = (appman_services *)d->get_module("ApplicationManager 1.0");
766 script = (script_services *)d->get_module("Script 1.0");
767 msg = (messenger_services *)d->get_module("Messenger 1.0");
768 userstate = (userstate_services *)d->get_module("UserState 1.0");
769 scope = (scope_services *)d->get_module("Scope 1.0");
770 screen = (screen_services *)d->get_module("Screen 1.0");
771 scheduler = (scheduler_services *)d->get_module("Scheduler 1.0");
773 d->register_module("Server 1.0", &services);