]> rtime.felk.cvut.cz Git - l4.git/blob - l4/pkg/ned/server/src/lua_exec.cc
update
[l4.git] / l4 / pkg / ned / server / src / lua_exec.cc
1 /*
2  * (c) 2010 Adam Lackorzynski <adam@os.inf.tu-dresden.de>,
3  *          Alexander Warg <warg@os.inf.tu-dresden.de>
4  *     economic rights: Technische Universität Dresden (Germany)
5  *
6  * This file is part of TUD:OS and distributed under the terms of the
7  * GNU General Public License 2.
8  * Please see the COPYING-GPL-2 file for details.
9  */
10 #include "app_task.h"
11 #include "app_model.h"
12 #include "debug.h"
13
14 #include <l4/cxx/auto_ptr>
15 #include <l4/cxx/ref_ptr>
16 #include <l4/libloader/elf>
17 #include <l4/util/bitops.h>
18
19 #include <lua.h>
20 #include <lauxlib.h>
21 #include <lualib.h>
22
23 #include <pthread-l4.h>
24 #include "lua.h"
25 #include "lua_cap.h"
26 #include "server.h"
27
28 using L4Re::chksys;
29
30 inline void *operator new (size_t, void *p) throw() { return p; }
31 namespace Lua { namespace {
32
33 class Observer : public Ned::Server_object
34 {
35 public:
36   int dispatch(l4_umword_t obj, L4::Ipc_iostream &ios);
37 };
38
39 static Observer *observer;
40
41 int
42 Observer::dispatch(l4_umword_t, L4::Ipc_iostream &ios)
43 {
44   l4_cap_idx_t thread = L4::Ipc::read<l4_cap_idx_t>(ios);
45   App_task *t = (App_task*)L4::Ipc::read<l4_addr_t>(ios);
46
47   if (t->state() == App_task::Zombie)
48     return 0;
49
50   t->observer(thread);
51   return -L4_ENOREPLY;
52 }
53
54 class Am : public Rmt_app_model
55 {
56 private:
57   lua_State *_lua;
58   int _argc;
59   int _env_idx;
60   int _cfg_idx;
61   int _arg_idx;
62
63   L4::Cap<L4::Factory> _rm_fab;
64
65   l4_umword_t _cfg_integer(char const *f, l4_umword_t def = 0)
66   {
67     l4_umword_t r = def;
68     lua_getfield(_lua, _cfg_idx, f);
69     if (lua_isnumber(_lua, -1))
70       r = lua_tointeger(_lua, -1);
71
72     lua_pop(_lua, 1);
73     return r;
74   }
75
76   void _cfg_cap(char const *f, l4_fpage_t *r)
77   {
78     lua_getfield(_lua, _cfg_idx, f);
79     while (lua_isfunction(_lua, -1))
80       {
81         lua_pushvalue(_lua, _cfg_idx);
82         lua_call(_lua, 1, 1);
83       }
84
85     if (!lua_isnil(_lua, -1))
86       {
87         Cap *c = Lua::check_cap(_lua, -1);
88         *r = c->cap<void>().fpage(c->rights());
89       }
90     lua_pop(_lua, 1);
91   }
92
93 public:
94
95   explicit Am(lua_State *l)
96   : Rmt_app_model(), _lua(l), _argc(lua_gettop(l)), _env_idx(0), _cfg_idx(1),
97     _arg_idx(2)
98   {
99     if (_argc > 2 && lua_type(_lua, _argc) == LUA_TTABLE)
100       _env_idx = _argc;
101
102     if (_env_idx)
103       --_argc;
104   }
105
106   l4_cap_idx_t push_initial_caps(l4_cap_idx_t start)
107   {
108     lua_getfield(_lua, _cfg_idx, "caps");
109     int tab = lua_gettop(_lua);
110
111     if (lua_isnil(_lua, tab))
112       {
113         lua_pop(_lua, 1);
114         return start;
115       }
116
117     lua_pushnil(_lua);
118     while (lua_next(_lua, tab))
119       {
120         char const *r = luaL_checkstring(_lua, -2);
121         while (lua_isfunction(_lua, -1))
122           {
123             lua_pushvalue(_lua, tab);
124             lua_call(_lua, 1, 1);
125           }
126
127         if (!lua_isnil(_lua, -1) && lua_touserdata(_lua, -1))
128           {
129             Lua::check_cap(_lua, -1);
130             _stack.push(l4re_env_cap_entry_t(r, start));
131             start += L4_CAP_OFFSET;
132           }
133         lua_pop(_lua, 1);
134       }
135     lua_pop(_lua, 1);
136     return start;
137   }
138
139   void map_initial_caps(L4::Cap<L4::Task> task, l4_cap_idx_t start)
140   {
141     lua_getfield(_lua, _cfg_idx, "caps");
142     int tab = lua_gettop(_lua);
143
144     if (lua_isnil(_lua, tab))
145       {
146         lua_pop(_lua, 1);
147         return;
148       }
149
150     lua_pushnil(_lua);
151     while (lua_next(_lua, tab))
152       {
153         luaL_checkstring(_lua, -2);
154         while (lua_isfunction(_lua, -1))
155           {
156             lua_pushvalue(_lua, tab);
157             lua_call(_lua, 1, 1);
158           }
159
160         if (!lua_isnil(_lua, -1) && lua_touserdata(_lua, -1))
161           {
162             Cap *c = Lua::check_cap(_lua, -1);
163             chksys(task->map(L4Re::This_task, c->cap<void>().fpage(c->rights()), L4::Cap<void>(start).snd_base() | c->ext_rights()));
164             start += L4_CAP_OFFSET;
165           }
166         lua_pop(_lua, 1);
167       }
168     lua_pop(_lua, 1);
169   }
170
171   void parse_cfg()
172   {
173     prog_info()->mem_alloc = L4Re::Env::env()->mem_alloc().fpage();
174     prog_info()->log = L4Re::Env::env()->log().fpage();
175     prog_info()->factory = L4Re::Env::env()->factory().fpage();
176     prog_info()->scheduler = L4Re::Env::env()->scheduler().fpage();
177     //  parser.scheduler_cap.set_fpage(&am.prog_info()->scheduler);
178
179     prog_info()->ldr_flags = 0;
180     prog_info()->l4re_dbg = 0;
181
182     if (!_cfg_idx)
183       return;
184
185     prog_info()->ldr_flags = _cfg_integer("ldr_flags", prog_info()->ldr_flags);
186     prog_info()->l4re_dbg = _cfg_integer("l4re_dbg", prog_info()->l4re_dbg);
187
188     _cfg_cap("log", &prog_info()->log);
189     _cfg_cap("mem", &prog_info()->mem_alloc);
190     _cfg_cap("factory", &prog_info()->factory);
191     _cfg_cap("scheduler", &prog_info()->scheduler);
192
193     l4_fpage_t fab = prog_info()->mem_alloc;
194     _cfg_cap("rm_fab", &fab);
195     _rm_fab = L4::Cap<L4::Factory>(fab.raw);
196   }
197
198   void set_task(App_task *t) { _task = t; }
199
200   void push_argv_strings()
201   {
202     argv.a0 = 0;
203     for (int i = _arg_idx; i <= _argc; ++i)
204       {
205         if (lua_isnil(_lua, i))
206           continue;
207
208         size_t l;
209         char const *r = luaL_checklstring(_lua, i, &l);
210         argv.al = _stack.push_str(r, l);
211         if (argv.a0 == 0)
212           argv.a0 = argv.al;
213       }
214   }
215
216   void push_env_strings()
217   {
218     if (!_env_idx)
219       return;
220
221     lua_pushnil(_lua);
222     bool _f = true;
223     while (lua_next(_lua, _env_idx))
224       {
225         size_t kl;
226         char const *k = luaL_checklstring(_lua, -2, &kl);
227         size_t vl;
228         char const *v = luaL_checklstring(_lua, -1, &vl);
229
230         _stack.push_str(v, vl);
231         _stack.push('=');
232         envp.al = _stack.push_object(k, kl);
233         if (_f)
234           {
235             envp.a0 = envp.al;
236             _f = false;
237           }
238         lua_pop(_lua, 1);
239       }
240   }
241 };
242
243
244 static char const *const APP_TASK_TYPE = "L4_NED_APP_TASK";
245 typedef cxx::Ref_ptr<App_task> App_ptr;
246
247 static
248 App_ptr &check_at(lua_State *l, int i)
249 {
250   App_ptr *t = (App_ptr*)luaL_checkudata(l, i, APP_TASK_TYPE);
251   return *t;
252 }
253
254 static int __task_state(lua_State *l)
255 {
256   App_ptr t = check_at(l, 1);
257
258   if (!t)
259     {
260       lua_pushnil(l);
261       return 1;
262     }
263
264   switch (t->state())
265     {
266     case App_task::Initializing:
267       lua_pushstring(l, "initializing");
268       break;
269
270     case App_task::Running:
271       lua_pushstring(l, "running");
272       break;
273
274     case App_task::Zombie:
275       lua_pushstring(l, "zombie");
276       break;
277
278     default:
279       lua_pushstring(l, "nan");
280       break;
281     }
282
283   return 1;
284 }
285
286 static int __task_exit_code(lua_State *l)
287 {
288   App_ptr t = check_at(l, 1);
289   if (!t)
290     lua_pushnil(l);
291   else
292     lua_pushinteger(l, t->exit_code());
293
294   return 1;
295 }
296
297 static int __task_wait(lua_State *l)
298 {
299   App_ptr &t = check_at(l, 1);
300
301   if (!t)
302     {
303       lua_pushnil(l);
304       return 1;
305     }
306
307   if (Ned::server->registry()->reap_list()->remove(t.get()))
308     {
309       lua_pushinteger(l, t->exit_code());
310       t = 0; // zap task
311       return 1;
312     }
313
314   L4::Ipc::Iostream s(l4_utcb());
315   s << pthread_getl4cap(pthread_self()) << l4_addr_t(t.get());
316   s.call(observer->obj_cap().cap());
317
318   if (Ned::server->registry()->reap_list()->remove(t.get()))
319     lua_pushinteger(l, t->exit_code());
320   else
321     lua_pushnil(l);
322
323   t = 0; // zap task
324   return 1;
325 }
326
327 static int __task_kill(lua_State *l)
328 {
329   App_ptr &t = check_at(l, 1);
330
331   if (!t)
332     {
333       lua_pushnil(l);
334       return 1;
335     }
336
337   if (t->state() == App_task::Zombie)
338     {
339       lua_pushinteger(l, t->exit_code());
340       t = 0; // zap task
341       return 1;
342     }
343
344   t->terminate();
345   t = 0; // kill task
346   lua_pushstring(l, "killed");
347
348   return 1;
349 }
350
351 static int __task_gc(lua_State *l)
352 {
353   App_ptr &t = check_at(l, 1);
354   t = 0; // drop reference to task
355   return 0;
356 }
357
358 static int __task_eq(lua_State *l)
359 {
360   App_ptr const &t1 = check_at(l, 1);
361   App_ptr const &t2 = check_at(l, 2);
362   lua_pushboolean(l, t1 == t2);
363   return 1;
364 }
365
366 static int __task_lt(lua_State *l)
367 {
368   App_ptr const &t1 = check_at(l, 1);
369   App_ptr const &t2 = check_at(l, 2);
370   lua_pushboolean(l, t1 < t2);
371   return 1;
372 }
373
374 static int __task_le(lua_State *l)
375 {
376   App_ptr const &t1 = check_at(l, 1);
377   App_ptr const &t2 = check_at(l, 2);
378   lua_pushboolean(l, t1 <= t2);
379   return 1;
380 }
381
382 static const luaL_Reg _task_ops[] = {
383     { "state", __task_state },
384     { "exit_code", __task_exit_code },
385     { "wait", __task_wait },
386     { "kill", __task_kill },
387     { NULL, NULL }
388 };
389
390
391 static int wait_any(lua_State *l)
392 {
393   using Ned::Server_object;
394   while (Server_object *t = Ned::server->registry()->reap_list()->remove(0))
395     {
396       App_ptr ap(dynamic_cast<App_task*>(t));
397       if (!ap)
398         continue;
399
400       App_ptr *at = new (lua_newuserdata(l, sizeof(App_ptr))) App_ptr();
401       *at = ap;
402
403       // remove the reap_list reference
404       ap->remove_ref();
405
406       luaL_newmetatable(l, APP_TASK_TYPE);
407       lua_setmetatable(l, -2);
408       return 1;
409     }
410
411   return 0;
412   // block
413 }
414
415 //void do_some_exc_tests();
416
417 static int exec(lua_State *l)
418 {
419   try {
420
421   Am am(l);
422   am.parse_cfg();
423   L4::Cap<L4Re::Mem_alloc> mem_alloc(am.prog_info()->mem_alloc.raw);
424
425   typedef cxx::Ref_ptr<App_task> App_ptr;
426
427   App_ptr app_task(new App_task(Ned::server->registry(), L4::cap_dynamic_cast<L4::Factory>(mem_alloc)));
428
429   if (!app_task)
430     {
431       Err().printf("could not allocate task control block\n");
432       return 0;
433     }
434
435
436   am.set_task(app_task.get());
437
438   typedef Ldr::Elf_loader<Am, Dbg> Loader;
439
440   Dbg ldr(Dbg::Loader, "ldr");
441   Loader _l;
442   _l.launch(&am, "rom/l4re", ldr);
443
444   app_task->running();
445
446   App_ptr *at = new (lua_newuserdata(l, sizeof(App_ptr))) App_ptr();
447   *at = app_task;
448
449   luaL_newmetatable(l, APP_TASK_TYPE);
450   lua_setmetatable(l, -2);
451
452   return 1;
453   } catch (...) {
454     printf("LUA ============================== EXEC FAILED\n");
455     luaL_error(l, "could not create process");
456   }
457
458   return 0;
459 }
460 #if 0
461 void do_some_exc_tests()
462 {
463   char _ta[333];
464   char const *const cont = "Das ist ein lustiger test";
465
466   for (unsigned i = 0; i < strlen(cont); ++i)
467     _ta[i] = cont[i];
468
469   volatile int *x = (int*)0x500;
470 //printf("Test Exc\n");
471   int y = *x;
472 }
473 #endif
474
475
476 static const luaL_Reg _task_meta_ops[] = {
477     { "__gc", __task_gc },
478     { "__eq", __task_eq },
479     { "__lt", __task_lt },
480     { "__le", __task_le },
481     { NULL, NULL }
482 };
483
484 class Lib_exec : public Lib
485 {
486 public:
487   Lib_exec() : Lib(P_env) {}
488   void init(lua_State *l)
489   {
490     static const luaL_Reg _ops[] =
491     {
492       { "exec", exec },
493       { "wait_any", wait_any },
494       { NULL, NULL }
495     };
496     luaL_register(l, "L4", _ops);
497
498     if (luaL_newmetatable(l, APP_TASK_TYPE))
499       {
500         lua_newtable(l);
501         luaL_register(l, NULL, _task_ops);
502         lua_setfield(l, -2, "__index");
503         luaL_register(l, NULL, _task_meta_ops);
504       }
505     lua_pop(l, 2);
506
507     observer = new Observer();
508     Ned::server->registry()->register_obj(observer);
509   }
510 };
511
512 static Lib_exec __lib;
513
514 }}
515