aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
authorDavid Walter Seikel2012-02-11 21:02:53 +1000
committerDavid Walter Seikel2012-02-11 21:02:53 +1000
commitfc3599b3a72b10feb86632dff6d7821a9af140f8 (patch)
treefcb56cb9536b0a6ceeb6c75ced60c00b416df7bb
parentUpdated .gitignore (diff)
downloadSledjHamr-fc3599b3a72b10feb86632dff6d7821a9af140f8.zip
SledjHamr-fc3599b3a72b10feb86632dff6d7821a9af140f8.tar.gz
SledjHamr-fc3599b3a72b10feb86632dff6d7821a9af140f8.tar.bz2
SledjHamr-fc3599b3a72b10feb86632dff6d7821a9af140f8.tar.xz
LuaSL_main is pretty small now, LuaSL_runner is mostly comment. Merge them.
-rwxr-xr-xLuaSL/build.sh2
-rw-r--r--LuaSL/src/LuaSL.h4
-rw-r--r--LuaSL/src/LuaSL_main.c322
-rw-r--r--LuaSL/src/LuaSL_runner.c323
4 files changed, 319 insertions, 332 deletions
diff --git a/LuaSL/build.sh b/LuaSL/build.sh
index 7242205..dcd243d 100755
--- a/LuaSL/build.sh
+++ b/LuaSL/build.sh
@@ -63,7 +63,7 @@ command="edje_cc $EDJE_FLAGS LuaSL.edc ../LuaSL.edj"
63echo $command 63echo $command
64$command 64$command
65 65
66names="LuaSL_main LuaSL_compile LuaSL_runner LuaSL_utilities LuaSL_lexer LuaSL_lemon_yaccer" 66names="LuaSL_main LuaSL_compile LuaSL_utilities LuaSL_lexer LuaSL_lemon_yaccer"
67objects="../../libraries/luaproc/channel.o ../../libraries/luaproc/list.o ../../libraries/luaproc/luaproc.o ../../libraries/luaproc/sched.o " 67objects="../../libraries/luaproc/channel.o ../../libraries/luaproc/list.o ../../libraries/luaproc/luaproc.o ../../libraries/luaproc/sched.o "
68for i in $names 68for i in $names
69do 69do
diff --git a/LuaSL/src/LuaSL.h b/LuaSL/src/LuaSL.h
index 3b8c761..a3bf3cb 100644
--- a/LuaSL/src/LuaSL.h
+++ b/LuaSL/src/LuaSL.h
@@ -64,10 +64,6 @@ typedef struct
64boolean compilerSetup(gameGlobals *game); 64boolean compilerSetup(gameGlobals *game);
65boolean compileLSL(gameGlobals *game, char *script, boolean doConstants); 65boolean compileLSL(gameGlobals *game, char *script, boolean doConstants);
66 66
67void runnerSetup(gameGlobals *game);
68void runLuaFile(gameGlobals *game, const char *filename);
69void runnerTearDown(gameGlobals *game);
70
71void loggingStartup(gameGlobals *game); 67void loggingStartup(gameGlobals *game);
72char *getDateTime(struct tm **nowOut, char *dateOut, time_t *tiemOut); 68char *getDateTime(struct tm **nowOut, char *dateOut, time_t *tiemOut);
73float timeDiff(struct timeval *now, struct timeval *then); 69float timeDiff(struct timeval *now, struct timeval *then);
diff --git a/LuaSL/src/LuaSL_main.c b/LuaSL/src/LuaSL_main.c
index 621aad2..0efc65e 100644
--- a/LuaSL/src/LuaSL_main.c
+++ b/LuaSL/src/LuaSL_main.c
@@ -2,7 +2,8 @@
2#include "LuaSL.h" 2#include "LuaSL.h"
3 3
4 4
5Eina_Strbuf *clientStream; 5static int CPUs = 4;
6static Eina_Strbuf *clientStream;
6 7
7 8
8Eina_Bool _add(void *data, int type __UNUSED__, Ecore_Con_Event_Client_Add *ev) 9Eina_Bool _add(void *data, int type __UNUSED__, Ecore_Con_Event_Client_Add *ev)
@@ -54,7 +55,7 @@ Eina_Bool _data(void *data, int type __UNUSED__, Ecore_Con_Event_Client_Data *ev
54 } 55 }
55 else if (0 == strcmp(command, "start()")) 56 else if (0 == strcmp(command, "start()"))
56 { 57 {
57 runLuaFile(game, SID); 58 newProc(SID, TRUE);
58 } 59 }
59 else if (0 == strcmp(command, "exit()")) 60 else if (0 == strcmp(command, "exit()"))
60 { 61 {
@@ -105,11 +106,20 @@ int main(int argc, char **argv)
105 106
106 if (edje_init()) 107 if (edje_init())
107 { 108 {
109 int i;
110
108 result = 0; 111 result = 0;
109 compilerSetup(&game); 112 compilerSetup(&game);
110 runnerSetup(&game); 113 luaprocInit();
114 for (i = 0; i < CPUs; i++)
115 {
116 if ( sched_create_worker( ) != LUAPROC_SCHED_OK )
117 PEm("Error creating luaproc worker thread.");
118 }
111 ecore_main_loop_begin(); 119 ecore_main_loop_begin();
112 runnerTearDown(&game); 120
121 // TODO - this is what hangs the system, should change from raw pthreads to ecare threads.
122 sched_join_workerthreads();
113 edje_shutdown(); 123 edje_shutdown();
114 } 124 }
115 else 125 else
@@ -127,3 +137,307 @@ int main(int argc, char **argv)
127 137
128 return result; 138 return result;
129} 139}
140
141
142/* Stuff to be merged in later.
143
144#ifdef _WIN32
145# define FMT_SIZE_T "%Iu"
146#else
147# define FMT_SIZE_T "%zu"
148#endif
149
150#define MAX_LUA_MEM (64 * 1024)) // LSL Mono is 64KB, edje Lua is 4MB. (4 * (1024 * 1024))
151
152#define _edje_lua2_error(L, err_code) _edje_lua2_error_full(__FILE__, __FUNCTION__, __LINE__, L, err_code)
153
154
155typedef struct _Edje_Lua_Alloc Edje_Lua_Alloc;
156
157struct _Edje_Lua_Alloc
158{
159 size_t max, cur;
160};
161
162static void *
163_elua_alloc(void *ud, void *ptr, size_t osize, size_t nsize)
164{
165 Edje_Lua_Alloc *ela = ud;
166 void *ptr2 = NULL;
167
168 if (ela)
169 {
170 ela->cur += nsize - osize;
171 if (ela->cur > ela->max)
172 {
173 printf("Lua memory limit of " FMT_SIZE_T " bytes reached (" FMT_SIZE_T " allocated)", ela->max, ela->cur);
174 }
175 else if (nsize == 0)
176 {
177 free(ptr);
178 }
179 else
180 {
181 ptr2 = realloc(ptr, nsize);
182 if (NULL == ptr2)
183 printf("Lua cannot re-allocate " FMT_SIZE_T " bytes", nsize);
184 }
185 }
186 else
187 printf("Lua cannoct allocate memory, no Edje_Lua_Alloc");
188
189 return ptr2;
190}
191
192static int panics = 0;
193static int
194_elua_custom_panic(lua_State *L) // Stack usage [-0, +0, m]
195{
196 // If we somehow manage to have multiple panics, it's likely due to being out
197 // of memory in the following lua_tostring() call.
198 panics++;
199 if (panics)
200 {
201 printf("Lua PANICS!!!!!");
202 }
203 else
204 {
205 printf("Lua PANIC!!!!!: %s", lua_tostring(L, -1)); // Stack usage [-0, +0, m]
206 }
207 // The docs say that this will cause an exit(EXIT_FAILURE) if we return,
208 // and that we we should long jump some where to avoid that. This is only
209 // called for things not called from a protected environment. We always
210 // use pcalls though, except for the library load calls. If we can't load
211 // the standard libraries, then perhaps a crash is the right thing.
212 return 0;
213}
214
215static void
216_edje_lua2_error_full(const char *file, const char *fnc, int line,
217 lua_State *L, int err_code) // Stack usage [-0, +0, m]
218{
219 const char *err_type;
220
221 switch (err_code)
222 {
223 case LUA_ERRRUN:
224 err_type = "runtime";
225 break;
226 case LUA_ERRSYNTAX:
227 err_type = "syntax";
228 break;
229 case LUA_ERRMEM:
230 err_type = "memory allocation";
231 break;
232 case LUA_ERRERR:
233 err_type = "error handler";
234 break;
235 default:
236 err_type = "unknown";
237 break;
238 }
239 printf("Lua %s error: %s\n", err_type, lua_tostring(L, -1)); // Stack usage [-0, +0, m]
240}
241
242static int errFunc(lua_State *L)
243{
244 int i = 0;
245 lua_Debug ar;
246
247 while (lua_getstack(L, i++, &ar))
248 {
249 if (lua_getinfo(L, "nSlu", &ar))
250 {
251 if (NULL == ar.name)
252 ar.name = "DUNNO";
253 printf("Lua error in the %s %s %s @ line %d in %s\n%s!", ar.what, ar.namewhat, ar.name, ar.currentline, ar.short_src, ar.source);
254 }
255 }
256 return 0;
257}
258
259void runLuaFile(gameGlobals *game, const char *filename)
260{
261 PD("Starting %s", filename);
262 newProc(filename, TRUE);
263
264// TODO, should set up our panic and errfunc as below. Plus the other TODO stuff.
265
266
267// TODO - hack up LuaJIT so that we can limit memory per state.
268// lua_setallocf(L, _elua_alloc, &ela); // LuaJIT uses a heavily hacked up dlmalloc. Seems that standard realloc is not so thread safe?
269 lua_atpanic(L, _elua_custom_panic);
270// TODO - Sandbox out what this opens. See lib_init.c from LuaJIT.
271// Just noticed this in the LuaJIT docs - "To change or extend the list of standard libraries to load, copy src/lib_init.c to your project and modify it accordingly. Make sure the jit library is loaded or the JIT compiler will not be activated."
272 luaL_openlibs(L);
273
274 lua_pushcfunction(L, errFunc);
275 ...
276 if ((err = lua_pcall(L, 0, 0, -2)))
277 _edje_lua2_error(L, err);
278}
279*/
280
281
282
283
284/* What we need to do, and how we might do it.
285 *
286 * Get configuration info.
287 *
288 * Some of the configuration info we need is tucked away in OpenSim .ini files. So we have to read that.
289 * Eet is probably not so useful here, as we would have to write a UI tool, and there's no UI otherwise.
290 *
291 * Multi task!
292 *
293 * Luaproc starts up X worker threads. Each one takes the next ready Lua state and runs it until it blocks waiting for a channel message, or yields.
294 * The current mainloop waits for events and commands from the message channel, executes them, then goes back to waiting.
295 * So that is fine in general, so long as the LSL event handlers actually return in a reasonable time.
296 * We need to be able to yield at suitable places, or be able to force a yield. Both without slowing things down too much.
297 *
298 * Watchdog thread.
299 *
300 * It's easy enough to have a watchdog thread wake up every now and then to check if any given Lua state has been hogging it's CPU for too long.
301 * The hard part is forcing Lua states to yield cleanly, without slowing performance too much.
302 *
303 * Identifying scripts. - OpenSim/Region/ScriptEngine/Interfaces/IScriptInstance.cs
304 *
305 * We need to be able to identify scripts so that messages can get to the right ones. Also the objects they are in.
306 * And do it all in a way that OpenSim is happy with.
307 * Copies of the same script in the same prim would have the same asset UUID, but different name, though they would run independently.
308 * Copies of the same script in different prims could have the same asset UUID AND the same name.
309 * OpenSim seems to be using a UUID to identify single scripts, and a uint to identify single prims, when sending events for either case.
310 * The UUID is from the script item in the prims inventory.
311 * There is also an asset UUID (the one printed out on the console at script startup time) that points to the source code in the prim.
312 * Which will be identical to the asset UUID for the multiple copies of the same script.
313 *
314 * Object inventory "cache".
315 *
316 * This code currently pretends that there is a local file based sim object store available.
317 * I think it would be a good idea to abuse the OpenSim cache system to produce that file based object store.
318 * It will help with the "damn OpenSim's asset database has to be a bottomless pit" monster design flaw.
319 * Prim contents must all be unique names anyway, and there are SOME constraints on contents names, so probably don't have to do much to convert an item name to a legal file name.
320 * Oops, names can have directory slashes in them. lol
321 * On the other hand, sim objects CAN have the same name.
322 *
323 * So we got sim directories, with an objects directory inside it, with object directories inside that. The object directories have object files in them. This is all like the test setup that is here.
324 * We need metadata. Sim metadata, object metadata, and object contents metadata. That can be done with a "foo.omg" file at each level.
325 * sim/index.omg - the list of object name.UUIDs, their X,Y,Z location, size, and rotation.
326 * sim/objects/objectName_UUID/index.omg - the list of contents names, item UUIDs, asset UUIDs, and types.
327 * sim/objects/objectName/subObjectName - the list of ITS contents names, item UUIDs, asset UUIDs, and types.
328 *
329 * Script start, stop, reset. - OpenSim/Region/ScriptEngine/Interfaces/IScriptEngine.cs
330 *
331 * Scripts and users have to be able to start, stop, and reset scripts.
332 * Users have to be able to see the start / stopped status of scripts from the viewer.
333 * Which means if the script does it, we have to tell OpenSim.
334 * Naturally, if OpenSim does it, it has to tell us.
335 * Should be able to do both by passing textual Lua function calls between OpenSim and LuaSL.
336 *
337 * Event handling, llDetect*() functions.
338 *
339 * OpenSim will generate events at random times and send us relevant information for llDetect*() functions and the handler calls.
340 * These should come through the scripts main loop eventually.
341 *
342 * Send messages from / to OpenSim and ROBUST.
343 *
344 * ROBUST uses HTTP for the communications, and some sort of XML, probably XML-RPC.
345 * OpenSim has some sort of generic mechanism for talking to script engines in C#. I want to turn that into a socket based, pass textual Lua function calls, type system.
346 * That assumes C# has some sort of semi decent introspection or reflection system.
347 * After a minimum of research, I have come to the conclusion that C# has suitable introspection, and will go ahead with my plans, leaving that problem to the C# coders.
348 * Looks like OpenSim is already using a bit of C# introspection for ll*() functions anyway.
349 * The scripts main loop can already deal with incoming commands as a string with a Lua function call in it.
350 *
351 * Send messages from / to Lua or C, and wait or not wait.
352 *
353 * Luaproc channels are distinct from Lua states, but some Lua state has to create them before they can be used.
354 * On the other hand, looks like broadcasting messages is not really catered for, it's first come first served.
355 * luaproc.send() can send multiple messages to a single channel. It blocks if no one is listening.
356 * This was done to simplify things for the luaproc programmers, who suggest creating more Lua states to deal with asynchronous message sending.
357 * luaprog.receive() gets a channel message. It can block waiting, or not block.
358 * I already hacked up C code to send and not block. I might have broken the luaproc.send() ability to send multiple messages.
359 * Before I hacked it up, actual message sending was done by copying the contents of the sending Lua states stack to the receiver states stack.
360 * This is the simple method for the luaproc programmers, as both states are in the context of a luaproc call, so both stacks are available.
361 * My hacked up version either takes one message from the sender, or is passed one from C. The C call just returns if there is no one waiting on that channel.
362 * luaproc.send() calls that C function after taking a single message from the stack, and block waits as usual if the C call cannot deliver.
363 * Don't think there is C to receive messages, luaproc seems to be lacking entirely in C side API.
364 * NOTE - Sending from C means that the message goes nowhere if no one is waiting for it.
365 * SOOOO, we may need to queue messages to.
366 * Just chuck them in a FIFO per channel, and destroy the FIFO when the channel get's destroyed.
367 * Edje messages might have to be used instead, or some hybrid.
368 *
369 * Main loop is waiting on messages, and that's the main driver. Luaproc is fine with that. Good for events.
370 * End of event handler -
371 * just wait for the next event.
372 * Stop a script from LSL -
373 * gotta find it's SID from it's name, and the prim UUID
374 * send the message
375 * wait for it to get the message - BUT we don't really want to wait.
376 * Stop a script from OpenSim -
377 * we should have it's SID from OpenSim, just send the message from C, no need to wait.
378 * Start a script -
379 * if it's stopped, it's already waiting for the message.
380 * if it's not stopped, then we don't care. BUT then we might be waiting for it to get the message if starting it from LSL.
381 * Reset a script -
382 * probably should be done from C anyway, and can reuse the libraries like luaproc likes to do.
383 * ask C to reset it.
384 * LSL calls a function we have to hand to OpenSim -
385 * send the message to C, wait.
386 * C eventually sends a message back.
387 * Sleep -
388 * tell C it's waiting for the wake up message.
389 * wait for the wake up message.
390 *
391 * C needs -
392 * Lua call for stop script.
393 * get the SID from the name, and the prim UUID.
394 * send the stop message to the SID.
395 * send something to OpenSim so it knows.
396 * return to Lua.
397 * Lua call for start script.
398 * get the SID from the name, and the prim UUID.
399 * send the start message to the SID.
400 * send something to OpenSim so it knows.
401 * return to Lua.
402 * Lua call for reset other script.
403 * get the SID from the name, and the prim UUID.
404 * figure out which Lua state it is.
405 * fall through to "reset this script", only with the script set to the found one.
406 * Lua call for reset this script.
407 * get luaproc to close this Lua state
408 * reload the script file
409 * start it again, reusing the previous Lua state, or which ever one luaproc wants to use.
410 * Lua call for sending a function to OpenSim.
411 * Lua first strings up the function call and args, with SID.
412 * C packs it off to opensim.
413 * C puts Lua state on the "waiting for message" queue if a return value is needed.
414 * OpenSim sends back the return value, business as usual.
415 * Lua call for sleep.
416 * setup an ecore timer callback
417 * put the Lua state into "waiting for message" queue.
418 * ecore timer callback sends the wake up message.
419 *
420 * Time and timers, plus deal with time dilation.
421 *
422 * Various LSL functions deal with time, that's no problem.
423 * Some might deal with time dilation, which means dealing with that info through OpenSim.
424 * There is a timer event, which should be done through ecore timers and whatever message system we end up with.
425 * Finally, a sleep call, which can be done with ecore timer and messages to.
426 *
427 * Deal directly with MySQL and SQLite databases.
428 *
429 * The script engine can run on the same computer as the sim server, that's how OpenSim does stuff. So we can directly access the database the sim server has, which gives us access to sim object metadata.
430 * Changing that metadata might require us to inform OpenSim about the changes. It's entirely possible that different changes do or do not need that.
431 * Esskyuehl may be suitable, though it's still in the prototype stage.
432 *
433 * Serialise the script state, send it somewhere.
434 *
435 * Lua can generally serialise itself as as a string of code to be executed at the destination. There might be some C side state that needs to be take care of as well. We shall see.
436 *
437 * Email, HTTP, XML-RPC?
438 *
439 * LSL has functions for using these as communications methods. We should implement them ourselves eventually, but use the existing OpenSim methods for now.
440 * Note that doing it ourselves may cause issues with OpenSim doing it for some other script engine.
441 * Azy might be suitable, but it's also in prototype.
442 *
443*/
diff --git a/LuaSL/src/LuaSL_runner.c b/LuaSL/src/LuaSL_runner.c
deleted file mode 100644
index f7f7a05..0000000
--- a/LuaSL/src/LuaSL_runner.c
+++ /dev/null
@@ -1,323 +0,0 @@
1
2#include "LuaSL.h"
3
4
5#ifdef _WIN32
6# define FMT_SIZE_T "%Iu"
7#else
8# define FMT_SIZE_T "%zu"
9#endif
10
11#define MAX_LUA_MEM (4 * (1024 * 1024))
12
13#define _edje_lua2_error(L, err_code) _edje_lua2_error_full(__FILE__, __FUNCTION__, __LINE__, L, err_code)
14
15/*
16typedef struct _Edje_Lua_Alloc Edje_Lua_Alloc;
17
18struct _Edje_Lua_Alloc
19{
20 size_t max, cur;
21};
22
23static void *
24_elua_alloc(void *ud, void *ptr, size_t osize, size_t nsize)
25{
26 Edje_Lua_Alloc *ela = ud;
27 void *ptr2 = NULL;
28
29 if (ela)
30 {
31 ela->cur += nsize - osize;
32 if (ela->cur > ela->max)
33 {
34 printf("Lua memory limit of " FMT_SIZE_T " bytes reached (" FMT_SIZE_T " allocated)", ela->max, ela->cur);
35 }
36 else if (nsize == 0)
37 {
38 free(ptr);
39 }
40 else
41 {
42 ptr2 = realloc(ptr, nsize);
43 if (NULL == ptr2)
44 printf("Lua cannot re-allocate " FMT_SIZE_T " bytes", nsize);
45 }
46 }
47 else
48 printf("Lua cannoct allocate memory, no Edje_Lua_Alloc");
49
50 return ptr2;
51}
52
53static int panics = 0;
54static int
55_elua_custom_panic(lua_State *L) // Stack usage [-0, +0, m]
56{
57 // If we somehow manage to have multiple panics, it's likely due to being out
58 // of memory in the following lua_tostring() call.
59 panics++;
60 if (panics)
61 {
62 printf("Lua PANICS!!!!!");
63 }
64 else
65 {
66 printf("Lua PANIC!!!!!: %s", lua_tostring(L, -1)); // Stack usage [-0, +0, m]
67 }
68 // The docs say that this will cause an exit(EXIT_FAILURE) if we return,
69 // and that we we should long jump some where to avoid that. This is only
70 // called for things not called from a protected environment. We always
71 // use pcalls though, except for the library load calls. If we can't load
72 // the standard libraries, then perhaps a crash is the right thing.
73 return 0;
74}
75
76static void
77_edje_lua2_error_full(const char *file, const char *fnc, int line,
78 lua_State *L, int err_code) // Stack usage [-0, +0, m]
79{
80 const char *err_type;
81
82 switch (err_code)
83 {
84 case LUA_ERRRUN:
85 err_type = "runtime";
86 break;
87 case LUA_ERRSYNTAX:
88 err_type = "syntax";
89 break;
90 case LUA_ERRMEM:
91 err_type = "memory allocation";
92 break;
93 case LUA_ERRERR:
94 err_type = "error handler";
95 break;
96 default:
97 err_type = "unknown";
98 break;
99 }
100 printf("Lua %s error: %s\n", err_type, lua_tostring(L, -1)); // Stack usage [-0, +0, m]
101}
102
103static int errFunc(lua_State *L)
104{
105 int i = 0;
106 lua_Debug ar;
107
108 while (lua_getstack(L, i++, &ar))
109 {
110 if (lua_getinfo(L, "nSlu", &ar))
111 {
112 if (NULL == ar.name)
113 ar.name = "DUNNO";
114 printf("Lua error in the %s %s %s @ line %d in %s\n%s!", ar.what, ar.namewhat, ar.name, ar.currentline, ar.short_src, ar.source);
115 }
116 }
117 return 0;
118}
119*/
120
121void runnerSetup(gameGlobals *game)
122{
123 luaprocInit();
124
125 if ( sched_create_worker( ) != LUAPROC_SCHED_OK )
126 PE("Error creating luaproc worker thread.");
127 if ( sched_create_worker( ) != LUAPROC_SCHED_OK )
128 PE("Error creating luaproc worker thread.");
129 if ( sched_create_worker( ) != LUAPROC_SCHED_OK )
130 PE("Error creating luaproc worker thread.");
131 if ( sched_create_worker( ) != LUAPROC_SCHED_OK )
132 PE("Error creating luaproc worker thread.");
133}
134
135void runLuaFile(gameGlobals *game, const char *filename)
136{
137// PD("Starting %s", filename);
138 newProc(filename, TRUE);
139
140// TODO, should set up our panic and errfunc as below. Plus the other TODO stuff.
141
142/*
143// TODO - hack up LuaJIT so that we can limit memory per state.
144// lua_setallocf(L, _elua_alloc, &ela); // LuaJIT uses a heavily hacked up dlmalloc. Seems that standard realloc is not so thread safe?
145 lua_atpanic(L, _elua_custom_panic);
146// TODO - Sandbox out what this opens. See lib_init.c from LuaJIT.
147// Just noticed this in the LuaJIT docs - "To change or extend the list of standard libraries to load, copy src/lib_init.c to your project and modify it accordingly. Make sure the jit library is loaded or the JIT compiler will not be activated."
148 luaL_openlibs(L);
149
150 lua_pushcfunction(L, errFunc);
151 ...
152 if ((err = lua_pcall(L, 0, 0, -2)))
153 _edje_lua2_error(L, err);
154*/
155}
156
157void runnerTearDown(gameGlobals *game)
158{
159// TODO - this is what hangs the system.
160 sched_join_workerthreads();
161}
162
163
164/* What we need to do, and how we might do it.
165 *
166 * Get configuration info.
167 *
168 * Some of the configuration info we need is tucked away in OpenSim .ini files. So we have to read that.
169 * Eet is probably not so useful here, as we would have to write a UI tool, and there's no UI otherwise.
170 *
171 * Multi task!
172 *
173 * Luaproc starts up X worker threads. Each one takes the next ready Lua state and runs it until it blocks waiting for a channel message, or yields.
174 * The current mainloop waits for events and commands from the message channel, executes them, then goes back to waiting.
175 * So that is fine in general, so long as the LSL event handlers actually return in a reasonable time.
176 * We need to be able to yield at suitable places, or be able to force a yield. Both without slowing things down too much.
177 *
178 * Watchdog thread.
179 *
180 * It's easy enough to have a watchdog thread wake up every now and then to check if any given Lua state has been hogging it's CPU for too long.
181 * The hard part is forcing Lua states to yield cleanly, without slowing performance too much.
182 *
183 * Identifying scripts. - OpenSim/Region/ScriptEngine/Interfaces/IScriptInstance.cs
184 *
185 * We need to be able to identify scripts so that messages can get to the right ones. Also the objects they are in.
186 * And do it all in a way that OpenSim is happy with.
187 * Copies of the same script in the same prim would have the same asset UUID, but different name, though they would run independently.
188 * Copies of the same script in different prims could have the same asset UUID AND the same name.
189 * OpenSim seems to be using a UUID to identify single scripts, and a uint to identify single prims, when sending events for either case.
190 * The UUID is from the script item in the prims inventory.
191 * There is also an asset UUID (the one printed out on the console at script startup time) that points to the source code in the prim.
192 * Which will be identical to the asset UUID for the multiple copies of the same script.
193 *
194 * Object inventory "cache".
195 *
196 * This code currently pretends that there is a local file based sim object store available.
197 * I think it would be a good idea to abuse the OpenSim cache system to produce that file based object store.
198 * It will help with the "damn OpenSim's asset database has to be a bottomless pit" monster design flaw.
199 * Prim contents must all be unique names anyway, and there are SOME constraints on contents names, so probably don't have to do much to convert an item name to a legal file name.
200 * Oops, names can have directory slashes in them. lol
201 * On the other hand, sim objects CAN have the same name.
202 *
203 * So we got sim directories, with an objects directory inside it, with object directories inside that. The object directories have object files in them. This is all like the test setup that is here.
204 * We need metadata. Sim metadata, object metadata, and object contents metadata. That can be done with a "foo.omg" file at each level.
205 * sim/index.omg - the list of object name.UUIDs, their X,Y,Z location, size, and rotation.
206 * sim/objects/objectName_UUID/index.omg - the list of contents names, item UUIDs, asset UUIDs, and types.
207 * sim/objects/objectName/subObjectName - the list of ITS contents names, item UUIDs, asset UUIDs, and types.
208 *
209 * Script start, stop, reset. - OpenSim/Region/ScriptEngine/Interfaces/IScriptEngine.cs
210 *
211 * Scripts and users have to be able to start, stop, and reset scripts.
212 * Users have to be able to see the start / stopped status of scripts from the viewer.
213 * Which means if the script does it, we have to tell OpenSim.
214 * Naturally, if OpenSim does it, it has to tell us.
215 * Should be able to do both by passing textual Lua function calls between OpenSim and LuaSL.
216 *
217 * Event handling, llDetect*() functions.
218 *
219 * OpenSim will generate events at random times and send us relevant information for llDetect*() functions and the handler calls.
220 * These should come through the scripts main loop eventually.
221 *
222 * Send messages from / to OpenSim and ROBUST.
223 *
224 * ROBUST uses HTTP for the communications, and some sort of XML, probably XML-RPC.
225 * OpenSim has some sort of generic mechanism for talking to script engines in C#. I want to turn that into a socket based, pass textual Lua function calls, type system.
226 * That assumes C# has some sort of semi decent introspection or reflection system.
227 * After a minimum of research, I have come to the conclusion that C# has suitable introspection, and will go ahead with my plans, leaving that problem to the C# coders.
228 * Looks like OpenSim is already using a bit of C# introspection for ll*() functions anyway.
229 * The scripts main loop can already deal with incoming commands as a string with a Lua function call in it.
230 *
231 * Send messages from / to Lua or C, and wait or not wait.
232 *
233 * Luaproc channels are distinct from Lua states, but some Lua state has to create them before they can be used.
234 * On the other hand, looks like broadcasting messages is not really catered for, it's first come first served.
235 * luaproc.send() can send multiple messages to a single channel. It blocks if no one is listening.
236 * This was done to simplify things for the luaproc programmers, who suggest creating more Lua states to deal with asynchronous message sending.
237 * luaprog.receive() gets a channel message. It can block waiting, or not block.
238 * I already hacked up C code to send and not block. I might have broken the luaproc.send() ability to send multiple messages.
239 * Before I hacked it up, actual message sending was done by copying the contents of the sending Lua states stack to the receiver states stack.
240 * This is the simple method for the luaproc programmers, as both states are in the context of a luaproc call, so both stacks are available.
241 * My hacked up version either takes one message from the sender, or is passed one from C. The C call just returns if there is no one waiting on that channel.
242 * luaproc.send() calls that C function after taking a single message from the stack, and block waits as usual if the C call cannot deliver.
243 * Don't think there is C to receive messages, luaproc seems to be lacking entirely in C side API.
244 * NOTE - Sending from C means that the message goes nowhere if no one is waiting for it.
245 * SOOOO, we may need to queue messages to.
246 * Just chuck them in a FIFO per channel, and destroy the FIFO when the channel get's destroyed.
247 * Edje messages might have to be used instead, or some hybrid.
248 *
249 * Main loop is waiting on messages, and that's the main driver. Luaproc is fine with that. Good for events.
250 * End of event handler -
251 * just wait for the next event.
252 * Stop a script from LSL -
253 * gotta find it's SID from it's name, and the prim UUID
254 * send the message
255 * wait for it to get the message - BUT we don't really want to wait.
256 * Stop a script from OpenSim -
257 * we should have it's SID from OpenSim, just send the message from C, no need to wait.
258 * Start a script -
259 * if it's stopped, it's already waiting for the message.
260 * if it's not stopped, then we don't care. BUT then we might be waiting for it to get the message if starting it from LSL.
261 * Reset a script -
262 * probably should be done from C anyway, and can reuse the libraries like luaproc likes to do.
263 * ask C to reset it.
264 * LSL calls a function we have to hand to OpenSim -
265 * send the message to C, wait.
266 * C eventually sends a message back.
267 * Sleep -
268 * tell C it's waiting for the wake up message.
269 * wait for the wake up message.
270 *
271 * C needs -
272 * Lua call for stop script.
273 * get the SID from the name, and the prim UUID.
274 * send the stop message to the SID.
275 * send something to OpenSim so it knows.
276 * return to Lua.
277 * Lua call for start script.
278 * get the SID from the name, and the prim UUID.
279 * send the start message to the SID.
280 * send something to OpenSim so it knows.
281 * return to Lua.
282 * Lua call for reset other script.
283 * get the SID from the name, and the prim UUID.
284 * figure out which Lua state it is.
285 * fall through to "reset this script", only with the script set to the found one.
286 * Lua call for reset this script.
287 * get luaproc to close this Lua state
288 * reload the script file
289 * start it again, reusing the previous Lua state, or which ever one luaproc wants to use.
290 * Lua call for sending a function to OpenSim.
291 * Lua first strings up the function call and args, with SID.
292 * C packs it off to opensim.
293 * C puts Lua state on the "waiting for message" queue if a return value is needed.
294 * OpenSim sends back the return value, business as usual.
295 * Lua call for sleep.
296 * setup an ecore timer callback
297 * put the Lua state into "waiting for message" queue.
298 * ecore timer callback sends the wake up message.
299 *
300 * Time and timers, plus deal with time dilation.
301 *
302 * Various LSL functions deal with time, that's no problem.
303 * Some might deal with time dilation, which means dealing with that info through OpenSim.
304 * There is a timer event, which should be done through ecore timers and whatever message system we end up with.
305 * Finally, a sleep call, which can be done with ecore timer and messages to.
306 *
307 * Deal directly with MySQL and SQLite databases.
308 *
309 * The script engine can run on the same computer as the sim server, that's how OpenSim does stuff. So we can directly access the database the sim server has, which gives us access to sim object metadata.
310 * Changing that metadata might require us to inform OpenSim about the changes. It's entirely possible that different changes do or do not need that.
311 * Esskyuehl may be suitable, though it's still in the prototype stage.
312 *
313 * Serialise the script state, send it somewhere.
314 *
315 * Lua can generally serialise itself as as a string of code to be executed at the destination. There might be some C side state that needs to be take care of as well. We shall see.
316 *
317 * Email, HTTP, XML-RPC?
318 *
319 * LSL has functions for using these as communications methods. We should implement them ourselves eventually, but use the existing OpenSim methods for now.
320 * Note that doing it ourselves may cause issues with OpenSim doing it for some other script engine.
321 * Azy might be suitable, but it's also in prototype.
322 *
323*/