aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
-rw-r--r--LICENCES6
-rw-r--r--lib/LSL.lua7
-rwxr-xr-xsrc/GuiLua/build.lua1
-rw-r--r--src/GuiLua/test_c.c1
-rw-r--r--src/LuaSL/LuaSL.h31
-rw-r--r--src/LuaSL/LuaSL_LSL_tree.h10
-rw-r--r--src/LuaSL/LuaSL_compile.c73
-rw-r--r--src/LuaSL/LuaSL_main.c248
-rw-r--r--src/LuaSL/LuaSL_threads.c511
-rw-r--r--src/LuaSL/LuaSL_threads.h54
-rwxr-xr-xsrc/LuaSL/build.lua2
-rwxr-xr-xsrc/extantz/build.lua2
-rw-r--r--src/extantz/extantz.c2
-rw-r--r--src/libraries/LumbrJack.c7
-rw-r--r--src/libraries/Runnr.c593
-rw-r--r--src/libraries/Runnr.h70
-rw-r--r--src/libraries/SledjHamr.c2
-rwxr-xr-xsrc/love/build.lua1
-rw-r--r--src/love/love.c20
19 files changed, 781 insertions, 860 deletions
diff --git a/LICENCES b/LICENCES
index 6ca5ff2..ec9d456 100644
--- a/LICENCES
+++ b/LICENCES
@@ -469,10 +469,12 @@ http://creativecommons.org/licenses/publicdomain
469=============================================================================== 469===============================================================================
470 470
471-------------------------------------------------------------------------------- 471--------------------------------------------------------------------------------
472[Note, luaproc is no longer included, but it's source is still in the git history.]
472 473
473Note that luaproc has been extensively rewritten by me, but large parts 474Note that luaproc had been extensively rewritten by me, but large parts
474of it still exist in the original form, and the rewritten bits tended to 475of it still exist in the original form, and the rewritten bits tended to
475stick with the original design. 476stick with the original design. And now, the entire thing was rewritten
477from scratch as part of Runnr.c
476 478
477Luaproc is covered by this copyright notice and license - 479Luaproc is covered by this copyright notice and license -
478 480
diff --git a/lib/LSL.lua b/lib/LSL.lua
index 6306045..a95ead3 100644
--- a/lib/LSL.lua
+++ b/lib/LSL.lua
@@ -199,7 +199,7 @@ function args2string(doType, ...)
199end 199end
200 200
201function mt.callAndReturn(name, ...) 201function mt.callAndReturn(name, ...)
202 luaproc.sendback(name .. "(" .. args2string(true, ...) .. ")") 202 Runnr.send(nil, name .. "(" .. args2string(true, ...) .. ")")
203end 203end
204 204
205function mt.callAndWait(name, ...) 205function mt.callAndWait(name, ...)
@@ -952,8 +952,9 @@ function waitAndProcess(returnWanted)
952 952
953 if returnWanted then Type = "result" end 953 if returnWanted then Type = "result" end
954 while running do 954 while running do
955 local message = luaproc.receive(SID) 955 local message = Runnr.receive()
956 if message then 956 if message then
957--print('GOT MESSAGE for script ' .. scriptName .. ' - "' .. message .. '"')
957 -- TODO - should we be discarding return values while paused? I don't think so, so we need to process those, 958 -- TODO - should we be discarding return values while paused? I don't think so, so we need to process those,
958 if paused then 959 if paused then
959 if "start()" == message then paused = false end 960 if "start()" == message then paused = false end
@@ -977,7 +978,7 @@ function waitAndProcess(returnWanted)
977 end 978 end
978 -- Otherwise, just run it and keep looping. 979 -- Otherwise, just run it and keep looping.
979 -- TODO - Not sure why I had this here. "sid" is not set anywhere, and SID would just send it to ourselves. 980 -- TODO - Not sure why I had this here. "sid" is not set anywhere, and SID would just send it to ourselves.
980-- status, errorMsg = luaproc.send(sid, result1) 981-- status, errorMsg = Runnr.send(nil, result1)
981-- if not status then 982-- if not status then
982-- msg("Error sending results from " .. Type .. ": " .. message .. " ERROR MESSAGE: " .. errorMsg) 983-- msg("Error sending results from " .. Type .. ": " .. message .. " ERROR MESSAGE: " .. errorMsg)
983-- end 984-- end
diff --git a/src/GuiLua/build.lua b/src/GuiLua/build.lua
index 8b4a1c8..08446f0 100755
--- a/src/GuiLua/build.lua
+++ b/src/GuiLua/build.lua
@@ -18,7 +18,6 @@ LDFLAGS = '-L ' .. dir .. ' ' .. LDFLAGS
18removeFiles(dir, {'test_c.so', 'GuiLua.o', lib_d .. '/libGuiLua.so', '../../skang'}) 18removeFiles(dir, {'test_c.so', 'GuiLua.o', lib_d .. '/libGuiLua.so', '../../skang'})
19 19
20runCommand('C modules', dir, 'gcc ' .. CFLAGS .. ' -fPIC -shared -o test_c.so test_c.c') 20runCommand('C modules', dir, 'gcc ' .. CFLAGS .. ' -fPIC -shared -o test_c.so test_c.c')
21
22runCommand('C libraries', dir, 'gcc ' .. CFLAGS .. ' -fPIC -c GuiLua.c') 21runCommand('C libraries', dir, 'gcc ' .. CFLAGS .. ' -fPIC -c GuiLua.c')
23runCommand(nil, dir, 'gcc ' .. CFLAGS .. ' -shared -Wl,-soname,libGuiLua.so -o ' .. lib_d .. '/libGuiLua.so GuiLua.o') 22runCommand(nil, dir, 'gcc ' .. CFLAGS .. ' -shared -Wl,-soname,libGuiLua.so -o ' .. lib_d .. '/libGuiLua.so GuiLua.o')
24runCommand('C apps', dir, 'gcc ' .. CFLAGS .. ' -Wl,-export-dynamic -o ../../skang skang.c ' .. LDFLAGS .. ' -lGuiLua -lwinFang ' .. libs) 23runCommand('C apps', dir, 'gcc ' .. CFLAGS .. ' -Wl,-export-dynamic -o ../../skang skang.c ' .. LDFLAGS .. ' -lGuiLua -lwinFang ' .. libs)
diff --git a/src/GuiLua/test_c.c b/src/GuiLua/test_c.c
index ed680b0..f964d65 100644
--- a/src/GuiLua/test_c.c
+++ b/src/GuiLua/test_c.c
@@ -10,6 +10,7 @@ http://lua-users.org/lists/lua-l/2008-01/msg00671.html
10*/ 10*/
11 11
12 12
13#include "LumbrJack.h"
13#include "Runnr.h" 14#include "Runnr.h"
14#include "GuiLua.h" 15#include "GuiLua.h"
15 16
diff --git a/src/LuaSL/LuaSL.h b/src/LuaSL/LuaSL.h
index 299477b..cfee0aa 100644
--- a/src/LuaSL/LuaSL.h
+++ b/src/LuaSL/LuaSL.h
@@ -16,46 +16,19 @@
16#include <lualib.h> 16#include <lualib.h>
17#include <lauxlib.h> 17#include <lauxlib.h>
18 18
19typedef struct _script script; // Define this here, so LuaSL_threads.h can use it.
20typedef struct _gameGlobals gameGlobals; // Define this here, so LuaSL_threads.h can use it. 19typedef struct _gameGlobals gameGlobals; // Define this here, so LuaSL_threads.h can use it.
21 20
22#include "LuaSL_threads.h"
23#include "LumbrJack.h" 21#include "LumbrJack.h"
22#include "Runnr.h"
24 23
25 24
26struct _gameGlobals 25struct _gameGlobals
27{ 26{
28 Ecore_Con_Server *server; 27 Ecore_Con_Server *server;
29 Eina_Hash *scripts, *names; 28 Eina_Hash *names;
30 const char *address; 29 const char *address;
31 int port; 30 int port;
32}; 31};
33 32
34struct _script
35{
36 Eina_Clist node;
37 gameGlobals *game;
38 char SID[PATH_MAX];
39 char fileName[PATH_MAX];
40 char *name;
41 lua_State *L;
42 struct timeval startTime;
43 float timerTime;
44 int status;
45 int args;
46 Eina_Clist messages;
47 Ecore_Con_Client *client;
48 Ecore_Timer *timer;
49};
50
51typedef struct
52{
53 Eina_Clist node;
54 script *script;
55 const char message[PATH_MAX];
56} scriptMessage;
57
58
59void scriptSendBack(void * data);
60 33
61#include "LuaSL_LSL_tree.h" 34#include "LuaSL_LSL_tree.h"
diff --git a/src/LuaSL/LuaSL_LSL_tree.h b/src/LuaSL/LuaSL_LSL_tree.h
index 1021be8..fca31db 100644
--- a/src/LuaSL/LuaSL_LSL_tree.h
+++ b/src/LuaSL/LuaSL_LSL_tree.h
@@ -55,14 +55,6 @@ typedef enum
55 55
56typedef void (*outputToken) (FILE *file, outputMode mode, LSL_Leaf *content); 56typedef void (*outputToken) (FILE *file, outputMode mode, LSL_Leaf *content);
57 57
58//#ifndef FALSE
59//typedef enum
60//{
61// FALSE = 0,
62// TRUE = 1
63//} boolean;
64//#endif
65
66typedef enum 58typedef enum
67{ 59{
68 LSL_NONE = 0, 60 LSL_NONE = 0,
@@ -409,7 +401,7 @@ typedef struct
409 401
410 402
411boolean compilerSetup(gameGlobals *ourGlobals); 403boolean compilerSetup(gameGlobals *ourGlobals);
412boolean compileLSL(gameGlobals *ourGlobals, Ecore_Con_Client *client, char *SID, char *script, boolean doConstants); 404boolean compileLSL(LuaCompiler *lCompiler, gameGlobals *ourGlobals, Ecore_Con_Client *client, char *SID, char *script, boolean doConstants);
413void burnLeaf(void *data); 405void burnLeaf(void *data);
414 406
415LSL_Leaf *addBlock(LuaSL_compiler *compiler, LSL_Leaf *left, LSL_Leaf *lval, LSL_Leaf *right); 407LSL_Leaf *addBlock(LuaSL_compiler *compiler, LSL_Leaf *left, LSL_Leaf *lval, LSL_Leaf *right);
diff --git a/src/LuaSL/LuaSL_compile.c b/src/LuaSL/LuaSL_compile.c
index afe7ec0..61fce8f 100644
--- a/src/LuaSL/LuaSL_compile.c
+++ b/src/LuaSL/LuaSL_compile.c
@@ -2170,6 +2170,14 @@ static void outputStringToken(FILE *file, outputMode mode, LSL_Leaf *content)
2170 fprintf(file, "%s", content->value.stringValue); // The quotes are part of the string value already. 2170 fprintf(file, "%s", content->value.stringValue); // The quotes are part of the string value already.
2171} 2171}
2172 2172
2173static void _compileCb(LuaCompiler *compiler)
2174{
2175 free(compiler->luaName);
2176 free(compiler->SID);
2177 free(compiler->file);
2178 free(compiler);
2179}
2180
2173boolean compilerSetup(gameGlobals *ourGlobals) 2181boolean compilerSetup(gameGlobals *ourGlobals)
2174{ 2182{
2175 int i; 2183 int i;
@@ -2184,6 +2192,7 @@ boolean compilerSetup(gameGlobals *ourGlobals)
2184 if (tokens) 2192 if (tokens)
2185 { 2193 {
2186 char buf[PATH_MAX]; 2194 char buf[PATH_MAX];
2195 LuaCompiler *compiler = calloc(1, sizeof(LuaCompiler));
2187 2196
2188 // Sort the token table. 2197 // Sort the token table.
2189 for (i = 0; LSL_Tokens[i].toKen != NULL; i++) 2198 for (i = 0; LSL_Tokens[i].toKen != NULL; i++)
@@ -2197,7 +2206,12 @@ boolean compilerSetup(gameGlobals *ourGlobals)
2197 snprintf(buf, sizeof(buf), "lua -e 'require(\"LSL\").gimmeLSL()' > %s/constants.lsl", prefix_lib_get()); 2206 snprintf(buf, sizeof(buf), "lua -e 'require(\"LSL\").gimmeLSL()' > %s/constants.lsl", prefix_lib_get());
2198 system(buf); 2207 system(buf);
2199 snprintf(buf, sizeof(buf), "%s/constants.lsl", prefix_lib_get()); 2208 snprintf(buf, sizeof(buf), "%s/constants.lsl", prefix_lib_get());
2200 compileLSL(ourGlobals, NULL, "FAKE_SID", buf, TRUE); 2209 compiler->file = strdup(buf);
2210 compiler->SID = strdup("FAKE_SID");
2211 compiler->data = ourGlobals;
2212 compiler->cb = _compileCb;
2213 if (!compileLSL(compiler, ourGlobals, NULL, "FAKE_SID", buf, TRUE))
2214 _compileCb(compiler);
2201 2215
2202 return TRUE; 2216 return TRUE;
2203 } 2217 }
@@ -2207,17 +2221,7 @@ boolean compilerSetup(gameGlobals *ourGlobals)
2207 return FALSE; 2221 return FALSE;
2208} 2222}
2209 2223
2210static int luaWriter(lua_State *L, const void* p, size_t sz, void* ud) 2224boolean compileLSL(LuaCompiler *lCompiler, gameGlobals *ourGlobals, Ecore_Con_Client *client, char *SID, char *script, boolean doConstants)
2211{
2212 FILE *out = ud;
2213 int result = 0;
2214
2215 if (sz != fwrite(p, 1, sz, out))
2216 result = -1;
2217 return result;
2218}
2219
2220boolean compileLSL(gameGlobals *ourGlobals, Ecore_Con_Client *client, char *SID, char *script, boolean doConstants)
2221{ 2225{
2222 boolean result = FALSE; 2226 boolean result = FALSE;
2223 LuaSL_compiler compiler; 2227 LuaSL_compiler compiler;
@@ -2348,8 +2352,6 @@ boolean compileLSL(gameGlobals *ourGlobals, Ecore_Con_Client *client, char *SID,
2348 // Generate the Lua source code. 2352 // Generate the Lua source code.
2349 if (out) 2353 if (out)
2350 { 2354 {
2351 lua_State *L;
2352 int err;
2353 char *ext; 2355 char *ext;
2354 2356
2355 fprintf(out, "--// Generated code goes here.\n\n"); 2357 fprintf(out, "--// Generated code goes here.\n\n");
@@ -2366,49 +2368,14 @@ boolean compileLSL(gameGlobals *ourGlobals, Ecore_Con_Client *client, char *SID,
2366 fclose(out); 2368 fclose(out);
2367 2369
2368 // Compile the Lua source code. 2370 // Compile the Lua source code.
2369 if ((L = luaL_newstate())) 2371 lCompiler->luaName = strdup(luaName);
2370 { 2372 lCompiler->bugCount = compiler.script.bugCount;
2371 luaL_openlibs(L); 2373 compileScript(lCompiler);
2372 // This ends up pushing a function onto the stack. The function is the compiled code. 2374 result = TRUE;
2373 err = luaL_loadfile(L, luaName);
2374 if (err)
2375 {
2376 compiler.script.bugCount++;
2377 if (LUA_ERRSYNTAX == err)
2378 PE("Lua syntax error in %s: %s", luaName, lua_tostring(L, -1));
2379 else if (LUA_ERRFILE == err)
2380 PE("Lua compile file error in %s: %s", luaName, lua_tostring(L, -1));
2381 else if (LUA_ERRMEM == err)
2382 PE("Lua compile memory allocation error in %s: %s", luaName, lua_tostring(L, -1));
2383 }
2384 else
2385 {
2386 // Write the compiled code to a file.
2387 strcat(luaName, ".out");
2388 out = fopen(luaName, "w");
2389 if (out)
2390 {
2391 err = lua_dump(L, luaWriter, out);
2392 if (err)
2393 {
2394 compiler.script.bugCount++;
2395 PE("Lua compile file error writing to %s", luaName);
2396 }
2397 fclose(out);
2398 }
2399 else
2400 PC("Unable to open file %s for writing!", luaName);
2401 }
2402 }
2403 else
2404 PE("Can't create a new Lua state!");
2405 } 2375 }
2406 else 2376 else
2407 PC("Unable to open file %s for writing!", luaName); 2377 PC("Unable to open file %s for writing!", luaName);
2408 } 2378 }
2409
2410 if (0 == compiler.script.bugCount)
2411 result = TRUE;
2412 } 2379 }
2413 2380
2414 if (NULL != compiler.file) 2381 if (NULL != compiler.file)
diff --git a/src/LuaSL/LuaSL_main.c b/src/LuaSL/LuaSL_main.c
index 2c40348..e60278f 100644
--- a/src/LuaSL/LuaSL_main.c
+++ b/src/LuaSL/LuaSL_main.c
@@ -1,31 +1,27 @@
1 1
2#include "LuaSL.h" 2#include "LuaSL.h"
3#include "Runnr.h"
4#include "SledjHamr.h" 3#include "SledjHamr.h"
5 4
6 5
7int logDom = -1; // Our logging domain. 6int logDom = -1; // Our logging domain.
8static int CPUs = 4;
9static Eina_Strbuf *clientStream; 7static Eina_Strbuf *clientStream;
10 8
11 9
12static Eina_Bool _sleep_timer_cb(void *data) 10static Eina_Bool _sleep_timer_cb(void *data)
13{ 11{
14 script *script = data; 12 script *script = data;
15 gameGlobals *ourGlobals = script->game;
16 13
17// PD("Waking up %s", script->name); 14// PD("Waking up %s", script->name);
18 sendToChannel(ourGlobals, script->SID, "return 0.0"); 15 send2script(script->SID, "return 0.0");
19 return ECORE_CALLBACK_CANCEL; 16 return ECORE_CALLBACK_CANCEL;
20} 17}
21 18
22static Eina_Bool _timer_timer_cb(void *data) 19static Eina_Bool _timer_timer_cb(void *data)
23{ 20{
24 script *script = data; 21 script *script = data;
25 gameGlobals *ourGlobals = script->game;
26 22
27 PD("Timer for %s", script->name); 23// PD("Timer for %s", script->name);
28 sendToChannel(ourGlobals, script->SID, "events.timer()"); 24 send2script(script->SID, "events.timer()");
29 return ECORE_CALLBACK_RENEW; 25 return ECORE_CALLBACK_RENEW;
30} 26}
31 27
@@ -44,88 +40,63 @@ static script *findThem(gameGlobals *ourGlobals, const char *base, const char *t
44 return eina_hash_find(ourGlobals->names, name); 40 return eina_hash_find(ourGlobals->names, name);
45} 41}
46 42
47static void resetScript(script *victim) 43void send2server(script *me, const char *message)
48{ 44{
49 gameGlobals *ourGlobals = victim->game; 45 gameGlobals *ourGlobals = me->data;
50 script *me;
51 char buf[PATH_MAX];
52
53// PD("RESETTING %s", victim->name);
54 sendToChannel(ourGlobals, victim->SID, "quit()");
55
56 eina_hash_del(ourGlobals->scripts, victim->SID, NULL);
57 eina_hash_del(ourGlobals->names, victim->fileName, NULL);
58
59 // The old one will eventually die, create a new one.
60 me = calloc(1, sizeof(script));
61 gettimeofday(&me->startTime, NULL);
62 strncpy(me->SID, victim->SID, sizeof(me->SID));
63 strncpy(me->fileName, victim->fileName, sizeof(me->fileName));
64 me->name = &me->fileName[strlen(prefix_data_get())];
65 me->game = ourGlobals;
66 me->client = victim->client;
67 eina_hash_add(ourGlobals->scripts, me->SID, me);
68 eina_hash_add(ourGlobals->names, me->fileName, me);
69 sprintf(buf, "%s.lua.out", me->fileName);
70 newProc(buf, TRUE, me);
71}
72
73void scriptSendBack(void * data)
74{
75 scriptMessage *message = data;
76 gameGlobals *ourGlobals = message->script->game;
77 46
78 if (!message->script) 47//printf("GOT MESSAGE from script %s - '%s'\n", me->name, message);
79 {
80 PE("scriptSendBack script is NULL");
81 return;
82 }
83 48
84 if (0 == strncmp(message->message, "llSleep(", 8)) 49 if (0 == strncmp(message, "llSleep(", 8))
85 ecore_timer_add(atof(&(message->message)[8]), _sleep_timer_cb, message->script); 50 ecore_timer_add(atof(&(message)[8]), _sleep_timer_cb, me);
86 else if (0 == strncmp(message->message, "llResetTime(", 12)) 51 else if (0 == strncmp(message, "llResetTime(", 12))
87 { 52 {
88 gettimeofday(&message->script->startTime, NULL); 53 takeScript(me);
54 gettimeofday(&me->startTime, NULL);
55 releaseScript(me);
89 } 56 }
90 else if (0 == strncmp(message->message, "llGetTime(", 10)) 57 else if (0 == strncmp(message, "llGetTime(", 10))
91 { 58 {
92 struct timeval now; 59 struct timeval now;
93 float time = timeDiff(&now, &message->script->startTime); 60 float time = timeDiff(&now, &me->startTime);
94 char result[128]; 61 char result[128];
95 62
96 snprintf(result, sizeof(result), "return %f", time); 63 snprintf(result, sizeof(result), "return %f", time);
97 sendToChannel(ourGlobals, message->script->SID, result); 64 send2script(me->SID, result);
98 } 65 }
99 else if (0 == strncmp(message->message, "llGetAndResetTime(", 18)) 66 else if (0 == strncmp(message, "llGetAndResetTime(", 18))
100 { 67 {
101 struct timeval now; 68 struct timeval now;
102 float time = timeDiff(&now, &message->script->startTime); 69 float time = timeDiff(&now, &me->startTime);
103 char result[128]; 70 char result[128];
104 71
72 takeScript(me);
105 // Reset it before doing anything else once the result is known. 73 // Reset it before doing anything else once the result is known.
106 gettimeofday(&message->script->startTime, NULL); 74 gettimeofday(&me->startTime, NULL);
75 releaseScript(me);
107 snprintf(result, sizeof(result), "return %f", time); 76 snprintf(result, sizeof(result), "return %f", time);
108 sendToChannel(ourGlobals, message->script->SID, result); 77 send2script(me->SID, result);
109 } 78 }
110 else if (0 == strncmp(message->message, "llSetTimerEvent(", 16)) 79 else if (0 == strncmp(message, "llSetTimerEvent(", 16))
111 { 80 {
112 message->script->timerTime = atof(&(message->message)[16]); 81 takeScript(me);
113 if (0.0 == message->script->timerTime) 82 me->timerTime = atof(&(message)[16]);
83 if (0.0 == me->timerTime)
114 { 84 {
115 if (message->script->timer) 85 if (me->timer)
116 ecore_timer_del(message->script->timer); 86 ecore_timer_del(me->timer);
117 message->script->timer = NULL; 87 me->timer = NULL;
118 } 88 }
119 else 89 else
120 message->script->timer = ecore_timer_add(message->script->timerTime, _timer_timer_cb, message->script); 90 me->timer = ecore_timer_add(me->timerTime, _timer_timer_cb, me);
91 releaseScript(me);
121 } 92 }
122 else if (0 == strncmp(message->message, "llSetScriptState(", 17)) 93 else if (0 == strncmp(message, "llSetScriptState(", 17))
123 { 94 {
124 script *them; 95 script *them;
125 96
126 if ((them = findThem(ourGlobals, message->script->fileName, &(message->message[18])))) 97 if ((them = findThem(ourGlobals, me->fileName, &(message[18]))))
127 { 98 {
128 char *temp = rindex(&(message->message[18]), ','); 99 char *temp = rindex(&(message[18]), ',');
129 100
130 if (temp) 101 if (temp)
131 { 102 {
@@ -133,9 +104,9 @@ void scriptSendBack(void * data)
133 while (isspace(*temp)) 104 while (isspace(*temp))
134 temp++; 105 temp++;
135 if ('1' == *temp) 106 if ('1' == *temp)
136 sendToChannel(ourGlobals, them->SID, "start()"); 107 send2script(them->SID, "start()");
137 else 108 else
138 sendToChannel(ourGlobals, them->SID, "stop()"); 109 send2script(them->SID, "stop()");
139// PD("Stopped %s", them->name); 110// PD("Stopped %s", them->name);
140 } 111 }
141 else 112 else
@@ -143,25 +114,34 @@ void scriptSendBack(void * data)
143 } 114 }
144 else 115 else
145 { 116 {
146 char *temp = rindex(&(message->message[18]), '"'); 117 char *temp = rindex(&(message[18]), '"');
147 118
148 if (temp) 119 if (temp)
149 *temp = '\0'; 120 *temp = '\0';
150 PE("Can't stop script, can't find %s", &(message->message[18])); 121 PE("Can't stop script, can't find %s", &(message[18]));
151 } 122 }
152 } 123 }
153 else if (0 == strncmp(message->message, "llResetOtherScript(", 19)) 124 else if (0 == strncmp(message, "llResetOtherScript(", 19))
154 { 125 {
155 script *them; 126 script *them;
156 127
157 if ((them = findThem(ourGlobals, message->script->fileName, &(message->message[20])))) 128 if ((them = findThem(ourGlobals, me->fileName, &(message[20]))))
129 {
130 PD("RESETTING OTHER %s", them->name);
158 resetScript(them); 131 resetScript(them);
132 }
133 }
134 else if (0 == strncmp(message, "llResetScript(", 14))
135 {
136 PD("RESETTING %s", me->name);
137 resetScript(me);
159 } 138 }
160 else if (0 == strncmp(message->message, "llResetScript(", 14))
161 resetScript(message->script);
162 else 139 else
163 sendBack(message->script->client, message->script->SID, message->message); 140 {
164 free(message); 141 takeScript(me);
142 sendBack(me->client, me->SID, message);
143 releaseScript(me);
144 }
165} 145}
166 146
167static Eina_Bool _add(void *data, int type __UNUSED__, Ecore_Con_Event_Client_Add *ev) 147static Eina_Bool _add(void *data, int type __UNUSED__, Ecore_Con_Event_Client_Add *ev)
@@ -170,6 +150,25 @@ static Eina_Bool _add(void *data, int type __UNUSED__, Ecore_Con_Event_Client_Ad
170 return ECORE_CALLBACK_RENEW; 150 return ECORE_CALLBACK_RENEW;
171} 151}
172 152
153static void _compileCb(LuaCompiler *compiler)
154{
155 if (0 == compiler->bugCount)
156 {
157 gameGlobals *ourGlobals = compiler->data;
158 script *me = scriptAdd(compiler->file, compiler->SID, send2server, ourGlobals);
159
160 me->client = compiler->client;
161 eina_hash_add(ourGlobals->names, me->fileName, me);
162 sendBack(compiler->client, compiler->SID, "compiled(true)");
163 }
164 else
165 sendBack(compiler->client, compiler->SID, "compiled(false)");
166 free(compiler->luaName);
167 free(compiler->SID);
168 free(compiler->file);
169 free(compiler);
170}
171
173static Eina_Bool _data(void *data, int type __UNUSED__, Ecore_Con_Event_Client_Data *ev) 172static Eina_Bool _data(void *data, int type __UNUSED__, Ecore_Con_Event_Client_Data *ev)
174{ 173{
175 gameGlobals *ourGlobals = data; 174 gameGlobals *ourGlobals = data;
@@ -197,6 +196,7 @@ static Eina_Bool _data(void *data, int type __UNUSED__, Ecore_Con_Event_Client_D
197 char *temp; 196 char *temp;
198 char *file; 197 char *file;
199 char *name; 198 char *name;
199 LuaCompiler *compiler = calloc(1, sizeof(LuaCompiler));
200 200
201 strcpy(buf, &command[8]); 201 strcpy(buf, &command[8]);
202 temp = buf; 202 temp = buf;
@@ -207,34 +207,27 @@ static Eina_Bool _data(void *data, int type __UNUSED__, Ecore_Con_Event_Client_D
207 207
208 name = &file[strlen(prefix_data_get())]; 208 name = &file[strlen(prefix_data_get())];
209 PD("Compiling %s, %s.", SID, name); 209 PD("Compiling %s, %s.", SID, name);
210 if (compileLSL(ourGlobals, ev->client, SID, file, FALSE)) 210 compiler->file = strdup(file);
211 compiler->SID = strdup(SID);
212 compiler->client = ev->client;
213 compiler->data = ourGlobals;
214 compiler->cb = _compileCb;
215 if (!compileLSL(compiler, ourGlobals, ev->client, SID, file, FALSE))
211 { 216 {
212 script *me = calloc(1, sizeof(script)); 217 compiler->bugCount++;
213 218 PE("Compile of %s failed in a mysterious way.", file);
214 gettimeofday(&me->startTime, NULL); 219 _compileCb(compiler);
215 strncpy(me->SID, SID, sizeof(me->SID));
216 strncpy(me->fileName, file, sizeof(me->fileName));
217 me->name = &me->fileName[strlen(prefix_data_get())];
218 me->game = ourGlobals;
219 me->client = ev->client;
220 eina_hash_add(ourGlobals->scripts, me->SID, me);
221 eina_hash_add(ourGlobals->names, me->fileName, me);
222 sendBack(ev->client, SID, "compiled(true)");
223 } 220 }
224 else
225 sendBack(ev->client, SID, "compiled(false)");
226 } 221 }
227 else if (0 == strcmp(command, "run()")) 222 else if (0 == strcmp(command, "run()"))
228 { 223 {
229 script *me; 224 script *me;
230 char buf[PATH_MAX];
231 225
232 me = eina_hash_find(ourGlobals->scripts, SID); 226 me = getScript(SID);
233 if (me) 227 if (me)
234 { 228 {
235 sprintf(buf, "%s.lua.out", me->fileName); 229 runScript(me);
236 gettimeofday(&me->startTime, NULL); 230 releaseScript(me);
237 newProc(buf, TRUE, me);
238 } 231 }
239 } 232 }
240 else if (0 == strcmp(command, "exit()")) 233 else if (0 == strcmp(command, "exit()"))
@@ -243,13 +236,7 @@ static Eina_Bool _data(void *data, int type __UNUSED__, Ecore_Con_Event_Client_D
243 ecore_main_loop_quit(); 236 ecore_main_loop_quit();
244 } 237 }
245 else 238 else
246 { 239 send2script(SID, command);
247 const char *status = NULL;
248
249 status = sendToChannel(ourGlobals, SID, command);
250 if (status)
251 PE("Error sending command %s to script %s : %s", command, SID, status);
252 }
253 } 240 }
254 241
255 // Get the next blob to check it. 242 // Get the next blob to check it.
@@ -272,6 +259,12 @@ static Eina_Bool _del(void *data, int type __UNUSED__, Ecore_Con_Event_Client_De
272 return ECORE_CALLBACK_RENEW; 259 return ECORE_CALLBACK_RENEW;
273} 260}
274 261
262//static Eina_Bool _statusTimer(void *data)
263//{
264// printScriptsStatus();
265// return ECORE_CALLBACK_RENEW;
266//}
267
275int main(int argc, char **argv) 268int main(int argc, char **argv)
276{ 269{
277 gameGlobals ourGlobals; 270 gameGlobals ourGlobals;
@@ -284,7 +277,6 @@ int main(int argc, char **argv)
284 if (eina_init()) 277 if (eina_init())
285 { 278 {
286 logDom = HamrTime(argv[0], main, logDom); 279 logDom = HamrTime(argv[0], main, logDom);
287 ourGlobals.scripts = eina_hash_string_superfast_new(NULL);
288 ourGlobals.names = eina_hash_string_superfast_new(NULL); 280 ourGlobals.names = eina_hash_string_superfast_new(NULL);
289 if (ecore_init()) 281 if (ecore_init())
290 { 282 {
@@ -292,7 +284,7 @@ int main(int argc, char **argv)
292 { 284 {
293 if ((ourGlobals.server = ecore_con_server_add(ECORE_CON_REMOTE_TCP, ourGlobals.address, ourGlobals.port, &ourGlobals))) 285 if ((ourGlobals.server = ecore_con_server_add(ECORE_CON_REMOTE_TCP, ourGlobals.address, ourGlobals.port, &ourGlobals)))
294 { 286 {
295 int i; 287// int i;
296 Eina_Iterator *scripts; 288 Eina_Iterator *scripts;
297 script *me; 289 script *me;
298 290
@@ -307,29 +299,20 @@ int main(int argc, char **argv)
307 299
308 result = 0; 300 result = 0;
309 compilerSetup(&ourGlobals); 301 compilerSetup(&ourGlobals);
310 luaprocInit(); 302
311 for (i = 0; i < CPUs; i++) 303// ecore_timer_add(3.0, _statusTimer, &ourGlobals);
312 { 304
313 if ( sched_create_worker( ) != LUAPROC_SCHED_OK )
314 PE("Error creating luaproc worker thread.");
315 }
316 ecore_main_loop_begin(); 305 ecore_main_loop_begin();
317 PD("Fell out of the main loop."); 306 PD("Fell out of the main loop.");
318 307
319 scripts = eina_hash_iterator_data_new(ourGlobals.scripts); 308 scripts = eina_hash_iterator_data_new(ourGlobals.names);
320 while(eina_iterator_next(scripts, (void **) &me)) 309 while(eina_iterator_next(scripts, (void **) &me))
321 { 310 {
322 const char *status = NULL; 311 if (me->SID[0])
323 312 send2script(me->SID, "quit()");
324 status = sendToChannel(&ourGlobals, me->SID, "quit()");
325 if (status)
326 PE("Error sending command quit() to script %s : %s", me->SID, status);
327 } 313 }
328 314
329 PD("Finished quitting scripts."); 315 PD("Finished quitting scripts.");
330 // TODO - This is what hangs the system, should change from raw pthreads to ecore threads.
331 // Or perhaps just run the main loop for a bit longer so all the scripts can quit?
332 sched_join_workerthreads();
333 } 316 }
334 else 317 else
335 PC("Failed to add server!"); 318 PC("Failed to add server!");
@@ -424,33 +407,6 @@ _elua_custom_panic(lua_State *L) // Stack usage [-0, +0, m]
424 return 0; 407 return 0;
425} 408}
426 409
427static void
428_edje_lua2_error_full(const char *file, const char *fnc, int line,
429 lua_State *L, int err_code) // Stack usage [-0, +0, m]
430{
431 const char *err_type;
432
433 switch (err_code)
434 {
435 case LUA_ERRRUN:
436 err_type = "runtime";
437 break;
438 case LUA_ERRSYNTAX:
439 err_type = "syntax";
440 break;
441 case LUA_ERRMEM:
442 err_type = "memory allocation";
443 break;
444 case LUA_ERRERR:
445 err_type = "error handler";
446 break;
447 default:
448 err_type = "unknown";
449 break;
450 }
451 printf("Lua %s error: %s\n", err_type, lua_tostring(L, -1)); // Stack usage [-0, +0, m]
452}
453
454static int errFunc(lua_State *L) 410static int errFunc(lua_State *L)
455{ 411{
456 int i = 0; 412 int i = 0;
@@ -510,7 +466,8 @@ void runLuaFile(gameGlobals *ourGlobals, const char *filename)
510 * Watchdog thread. 466 * Watchdog thread.
511 * 467 *
512 * 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. 468 * 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.
513 * The hard part is forcing Lua states to yield cleanly, without slowing performance too much. 469 * The hard part is forcing Lua states to yield cleanly, without slowing performance too much. On the other hand, it might be valid to just
470 * kill CPU hogs and tell the user.
514 * 471 *
515 * Identifying scripts. - OpenSim/Region/ScriptEngine/Interfaces/IScriptInstance.cs 472 * Identifying scripts. - OpenSim/Region/ScriptEngine/Interfaces/IScriptInstance.cs
516 * 473 *
@@ -650,7 +607,8 @@ void runLuaFile(gameGlobals *ourGlobals, const char *filename)
650 * Oops, names can have directory slashes in them. lol 607 * Oops, names can have directory slashes in them. lol
651 * On the other hand, sim objects CAN have the same name. 608 * On the other hand, sim objects CAN have the same name.
652 * 609 *
653 * 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. 610 * So we got sim directories, with an objects directory inside it, with object directories inside that. The object directories have object files in them.
611 * This is all like the test setup that is here.
654 * We need metadata. Sim metadata, object metadata, and object contents metadata. That can be done with a "foo.omg" file at each level. 612 * We need metadata. Sim metadata, object metadata, and object contents metadata. That can be done with a "foo.omg" file at each level.
655 * sim/index.omg - the list of object name.UUIDs, their X,Y,Z location, size, and rotation. 613 * sim/index.omg - the list of object name.UUIDs, their X,Y,Z location, size, and rotation.
656 * sim/objects/objectName_UUID/index.omg - the list of contents names, item UUIDs, asset UUIDs, and types. 614 * sim/objects/objectName_UUID/index.omg - the list of contents names, item UUIDs, asset UUIDs, and types.
@@ -763,7 +721,7 @@ void runLuaFile(gameGlobals *ourGlobals, const char *filename)
763 * 721 *
764 * Serialise the script state, send it somewhere. 722 * Serialise the script state, send it somewhere.
765 * 723 *
766 * 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. 724 * Lua can generally serialise itself 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.
767 * 725 *
768 * Email, HTTP, XML-RPC? 726 * Email, HTTP, XML-RPC?
769 * 727 *
diff --git a/src/LuaSL/LuaSL_threads.c b/src/LuaSL/LuaSL_threads.c
deleted file mode 100644
index 4746808..0000000
--- a/src/LuaSL/LuaSL_threads.c
+++ /dev/null
@@ -1,511 +0,0 @@
1/* This code is heavily based on luaproc.
2 *
3 * The luaproc copyright notice and license is -
4
5 ***************************************************
6
7Copyright 2008 Alexandre Skyrme, Noemi Rodriguez, Roberto Ierusalimschy
8
9Permission is hereby granted, free of charge, to any person obtaining a copy
10of this software and associated documentation files (the "Software"), to deal
11in the Software without restriction, including without limitation the rights
12to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13copies of the Software, and to permit persons to whom the Software is
14furnished to do so, subject to the following conditions:
15
16The above copyright notice and this permission notice shall be included in
17all copies or substantial portions of the Software.
18
19THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25THE SOFTWARE.
26
27 ****************************************************
28 *
29 * Additions and changes Copyright 2012 by David Seikel, using the above license.
30 */
31
32
33/* This is a redesign of luaproc. The design goals and notes -
34 *
35 * In general use EFL where it is useful.
36 * Probably one fixed unique message channel per object, which each script in the object shares.
37 * But might be better to handle that C side anyway.
38 * Better integration with LuaSL.
39 * Use ecore threads instead of raw pthreads.
40 * Ecore threads pretty much wraps pthreads on posix, but has Windows support to.
41 * Merge in the edje Lua code, and keep an eye on that, coz we might want to actually add this to edje Lua in the future.
42 * Use my coding standards, or EFL ones. Pffft.
43 *
44 */
45
46#include "LuaSL.h"
47
48
49/* ready process queue insertion status */
50#define LUAPROC_SCHED_QUEUE_PROC_OK 0
51//#define LUAPROC_SCHED_QUEUE_PROC_ERR -1
52
53/* process is idle */
54#define LUAPROC_STAT_IDLE 0
55/* process is ready to run */
56#define LUAPROC_STAT_READY 1
57/* process is blocked on send */
58#define LUAPROC_STAT_BLOCKED_SEND 2
59/* process is blocked on receive */
60#define LUAPROC_STAT_BLOCKED_RECV 3
61
62
63typedef struct
64{
65 Eina_Clist node;
66 lua_State *L;
67} recycled;
68
69/*********
70* globals
71*********/
72
73/* ready process list */
74Eina_Clist lpready;
75
76/* ready process queue access mutex */
77pthread_mutex_t mutex_queue_access = PTHREAD_MUTEX_INITIALIZER;
78
79/* wake worker up conditional variable */
80pthread_cond_t cond_wakeup_worker = PTHREAD_COND_INITIALIZER;
81
82/* active luaproc count access mutex */
83pthread_mutex_t mutex_lp_count = PTHREAD_MUTEX_INITIALIZER;
84
85/* no active luaproc conditional variable */
86pthread_cond_t cond_no_active_lp = PTHREAD_COND_INITIALIZER;
87
88/* number of active luaprocs */
89int lpcount = 0;
90
91/* no more lua processes flag */
92int no_more_processes = FALSE;
93
94/* channel operations mutex */
95pthread_mutex_t mutex_channel = PTHREAD_MUTEX_INITIALIZER;
96
97/* recycle list mutex */
98pthread_mutex_t mutex_recycle_list = PTHREAD_MUTEX_INITIALIZER;
99
100/* recycled lua process list */
101Eina_Clist recyclelp;
102
103
104/******************************
105* library functions prototypes
106******************************/
107/* send a message to a lua process */
108static int luaproc_send( lua_State *L );
109/* receive a message from a lua process */
110static int luaproc_receive( lua_State *L );
111/* send a message back to the main loop */
112static int luaproc_send_back( lua_State *L );
113
114/* luaproc function registration array - main (parent) functions */
115static const struct luaL_reg luaproc_funcs_parent[] = {
116 { "sendback", luaproc_send_back },
117 { NULL, NULL }
118};
119
120/* luaproc function registration array - newproc (child) functions */
121static const struct luaL_reg luaproc_funcs_child[] = {
122 { "send", luaproc_send },
123 { "receive", luaproc_receive },
124 { "sendback", luaproc_send_back },
125 { NULL, NULL }
126};
127
128
129/* increase active lua process count */
130static void sched_lpcount_inc(void)
131{
132 pthread_mutex_lock(&mutex_lp_count);
133 lpcount++;
134 pthread_mutex_unlock(&mutex_lp_count);
135}
136
137/* decrease active lua process count */
138static void sched_lpcount_dec(void)
139{
140 pthread_mutex_lock(&mutex_lp_count);
141 lpcount--;
142 /* if count reaches zero, signal there are no more active processes */
143 if (lpcount == 0)
144 pthread_cond_signal(&cond_no_active_lp);
145 pthread_mutex_unlock(&mutex_lp_count);
146}
147
148/* worker thread main function */
149static void *workermain( void *args ) {
150
151 script *lp;
152 int procstat;
153
154 /* detach thread so resources are freed as soon as thread exits (no further joining) */
155 pthread_detach( pthread_self( ));
156
157 /* main worker loop */
158 while ( 1 ) {
159
160 /* get exclusive access to the ready process queue */
161 pthread_mutex_lock( &mutex_queue_access );
162
163 /* wait until instructed to wake up (because there's work to do or because its time to finish) */
164 while (( eina_clist_count( &lpready ) == 0 ) && ( no_more_processes == FALSE )) {
165 pthread_cond_wait( &cond_wakeup_worker, &mutex_queue_access );
166 }
167
168 /* pop the first node from the ready process queue */
169 if ((lp = (script *) eina_clist_head(&lpready)))
170 eina_clist_remove(&(lp->node));
171 else {
172 /* free access to the process ready queue */
173 pthread_mutex_unlock( &mutex_queue_access );
174 /* finished thread */
175 pthread_exit( NULL );
176 }
177
178 /* free access to the process ready queue */
179 pthread_mutex_unlock( &mutex_queue_access );
180
181 /* execute the lua code specified in the lua process struct */
182 procstat = lua_resume(lp->L, lp->args);
183 /* reset the process argument count */
184 lp->args = 0;
185
186 /* check if process finished its whole execution, then recycle it */
187 if (procstat == 0)
188 {
189// recycled *trash = malloc(sizeof(recycled));
190
191 // TODO - Trash stuff trashes memory, fix it.
192 // Later, it's an optimization we don't need right now.
193/*
194 if (trash)
195 {
196 trash->L = lp->L;
197 pthread_mutex_lock(&mutex_recycle_list);
198 eina_clist_add_tail(&recyclelp, &(trash->node));
199 pthread_mutex_unlock(&mutex_recycle_list);
200 }
201*/
202 sched_lpcount_dec();
203 lua_close(lp->L);
204 if (lp->timer)
205 ecore_timer_del(lp->timer);
206// free(lp);
207 }
208
209 /* check if process yielded */
210 else if ( procstat == LUA_YIELD ) {
211
212 /* if so, further check if yield originated from an unmatched send/recv operation */
213 if (lp->status == LUAPROC_STAT_BLOCKED_SEND)
214 {
215 }
216 else if (lp->status == LUAPROC_STAT_BLOCKED_RECV)
217 {
218 }
219 /* or if yield resulted from an explicit call to coroutine.yield in the lua code being executed */
220 else
221 {
222 /* get exclusive access to the ready process queue */
223 pthread_mutex_lock( &mutex_queue_access );
224 /* re-insert the job at the end of the ready process queue */
225 eina_clist_add_tail(&lpready, &(lp->node));
226 /* free access to the process ready queue */
227 pthread_mutex_unlock( &mutex_queue_access );
228 }
229 }
230 /* check if there was any execution error (LUA_ERRRUN, LUA_ERRSYNTAX, LUA_ERRMEM or LUA_ERRERR) */
231 else
232 {
233 /* print error message */
234 fprintf( stderr, "close lua_State (error: %s)\n", luaL_checkstring(lp->L, -1 ));
235 /* close lua state */
236 lua_close(lp->L);
237 /* decrease active lua process count */
238 sched_lpcount_dec();
239 }
240 }
241}
242
243/* move process to ready queue (ie, schedule process) */
244static int sched_queue_proc( script *lp ) {
245
246 /* get exclusive access to the ready process queue */
247 pthread_mutex_lock( &mutex_queue_access );
248
249 /* add process to ready queue */
250 eina_clist_add_tail(&lpready, &(lp->node));
251
252 lp->status = LUAPROC_STAT_READY;
253
254 /* wake worker up */
255 pthread_cond_signal( &cond_wakeup_worker );
256 /* free access to the process ready queue */
257 pthread_mutex_unlock( &mutex_queue_access );
258
259 return LUAPROC_SCHED_QUEUE_PROC_OK;
260}
261
262/* synchronize worker threads */
263void sched_join_workerthreads( void ) {
264
265 pthread_mutex_lock( &mutex_lp_count );
266
267 /* wait until there is no more active lua processes */
268 while( lpcount != 0 ) {
269 pthread_cond_wait( &cond_no_active_lp, &mutex_lp_count );
270 }
271 /* get exclusive access to the ready process queue */
272 pthread_mutex_lock( &mutex_queue_access );
273 /* set the no more active lua processes flag to true */
274 no_more_processes = TRUE;
275 /* wake ALL workers up */
276 pthread_cond_broadcast( &cond_wakeup_worker );
277 /* free access to the process ready queue */
278 pthread_mutex_unlock( &mutex_queue_access );
279
280// We don't need this, as we only get here during shutdown. Linking this to EFL results in a hang otherwise anyway.
281 /* wait for (join) worker threads */
282// pthread_exit( NULL );
283
284 pthread_mutex_unlock( &mutex_lp_count );
285
286}
287
288/* create a new worker pthread */
289int sched_create_worker(void)
290{
291 pthread_t worker;
292
293 /* create a new pthread */
294 if (pthread_create( &worker, NULL, workermain, NULL ) != 0)
295 return LUAPROC_SCHED_PTHREAD_ERROR;
296 return LUAPROC_SCHED_OK;
297}
298
299void newProc(const char *code, int file, script *lp)
300{
301 int ret;
302// recycled *trash;
303
304 // Try to recycle a Lua state, otherwise create one from scratch.
305#if 0 // TODO - something about this causes a crash.
306 pthread_mutex_lock(&mutex_recycle_list);
307 /* pop list head */
308 if ((trash = (recycled *) eina_clist_head(&recyclelp)))
309 {
310 printf(" Reusing Lua trash.\n");
311 eina_clist_remove(&(trash->node));
312 lp->L = trash->L;
313 free(trash);
314 }
315 pthread_mutex_unlock(&mutex_recycle_list);
316#endif
317
318 if (NULL == lp->L)
319 {
320 lp->L = luaL_newstate();
321
322 luaL_openlibs(lp->L);
323 luaL_register(lp->L, "luaproc", luaproc_funcs_child);
324 }
325
326 /* store the script struct in its own Lua state */
327 lua_pushlightuserdata(lp->L, lp);
328 lua_setfield(lp->L, LUA_REGISTRYINDEX, "_SELF");
329
330 lp->status = LUAPROC_STAT_IDLE;
331 lp->args = 0;
332 eina_clist_element_init(&(lp->node));
333 eina_clist_init(&(lp->messages));
334
335 /* load process' code */
336 if (file)
337 ret = luaL_loadfile(lp->L, code);
338 else
339 ret = luaL_loadstring(lp->L, code);
340
341 /* in case of errors, destroy Lua process */
342 if (ret != 0)
343 {
344 lua_close(lp->L);
345 lp->L = NULL;
346 }
347
348 if (lp->L)
349 {
350 sched_lpcount_inc();
351
352 /* schedule luaproc */
353 if (sched_queue_proc(lp) != LUAPROC_SCHED_QUEUE_PROC_OK)
354 {
355 printf( "[luaproc] error queueing Lua process\n" );
356 sched_lpcount_dec();
357 lua_close(lp->L);
358 }
359 }
360}
361
362/* return the lua process associated with a given lua state */
363static script *luaproc_getself(lua_State *L)
364{
365 script *lp;
366
367 lua_getfield(L, LUA_REGISTRYINDEX, "_SELF");
368 lp = (script *) lua_touserdata(L, -1);
369 lua_pop(L, 1);
370 return lp;
371}
372
373/* send a message to the client process */
374static int luaproc_send_back(lua_State *L)
375{
376 script *self = luaproc_getself(L);
377 const char *message = luaL_checkstring(L, 1);
378
379 if (self)
380 {
381 scriptMessage *sm = calloc(1, sizeof(scriptMessage));
382
383 if (sm)
384 {
385 eina_clist_element_init(&(sm->node));
386 sm->script = self;
387 strcpy((char *) sm->message, message);
388 ecore_main_loop_thread_safe_call_async(scriptSendBack, sm);
389 }
390 }
391
392 return 0;
393}
394
395/* error messages for the sendToChannel function */
396const char *sendToChannelErrors[] =
397{
398 "non-existent channel",
399 "error scheduling process"
400};
401
402/* send a message to a lua process */
403const char *sendToChannel(gameGlobals *ourGlobals, const char *SID, const char *message)
404{
405 const char *result = NULL;
406 script *dstlp;
407
408 if (!message)
409 {
410 PE("sendToChannel NULL message to %s", SID);
411 return NULL;
412 }
413// PD("sendToChannel message to %s -> %s", SID, message);
414
415 /* get exclusive access to operate on channels */
416 pthread_mutex_lock(&mutex_channel);
417
418 // Add the message to the queue.
419 if ((dstlp = eina_hash_find(ourGlobals->scripts, SID)))
420 {
421 scriptMessage *sm = NULL;
422
423 if ((sm = malloc(sizeof(scriptMessage))))
424 {
425 sm->script = dstlp;
426 strcpy((char *) sm->message, message);
427 eina_clist_add_tail(&(dstlp->messages), &(sm->node));
428 }
429
430 /* if it's already waiting, send the next message to it and (queue) wake it */
431 if (dstlp->status == LUAPROC_STAT_BLOCKED_RECV)
432 {
433 scriptMessage *msg = (scriptMessage *) eina_clist_head(&(dstlp->messages));
434
435 // See if there's a message on the queue. Note, this may not be the same as the incoming message, if there was already a queue.
436 if (msg)
437 {
438 eina_clist_remove(&(msg->node));
439 message = msg->message;
440 }
441 /* push the message onto the receivers stack */
442 lua_pushstring(dstlp->L, message);
443 dstlp->args = lua_gettop(dstlp->L) - 1;
444 if (msg)
445 free(msg);
446
447 if (sched_queue_proc(dstlp) != LUAPROC_SCHED_QUEUE_PROC_OK)
448 {
449 sched_lpcount_dec();
450 lua_close(dstlp->L);
451 result = sendToChannelErrors[1];
452 }
453 }
454 }
455
456 pthread_mutex_unlock(&mutex_channel);
457
458 return result;
459}
460
461/* send a message to a lua process */
462static int luaproc_send(lua_State *L)
463{
464 script *self = luaproc_getself(L);
465 const char *result = sendToChannel(self->game, luaL_checkstring(L, 1), luaL_checkstring(L, 2));
466
467 if (result)
468 {
469 lua_pushnil(L);
470 lua_pushstring(L, result);
471 return 2;
472 }
473
474 lua_pushboolean(L, TRUE);
475 return 1;
476}
477
478/* receive a message from a lua process */
479static int luaproc_receive(lua_State *L)
480{
481 script *self;
482 const char *chname = luaL_checkstring(L, 1);
483 scriptMessage *msg;
484
485 // First check if there are queued messages, and grab one.
486 self = luaproc_getself(L);
487 if ((msg = (scriptMessage *) eina_clist_head(&(self->messages))))
488 {
489 eina_clist_remove(&(msg->node));
490 lua_pushstring(L, msg->message);
491 free(msg);
492 return lua_gettop(L) - 1;
493 }
494
495 /* if trying an asynchronous receive, return an error */
496 if ( lua_toboolean( L, 2 ))
497 {
498 lua_pushnil(L);
499 lua_pushfstring(L, "no senders waiting on channel %s", chname);
500 return 2;
501 }
502 /* otherwise (synchronous receive) simply block process */
503 self->status = LUAPROC_STAT_BLOCKED_RECV;
504 return lua_yield(L, lua_gettop(L));
505}
506
507void luaprocInit(void)
508{
509 eina_clist_init(&recyclelp);
510 eina_clist_init(&lpready);
511}
diff --git a/src/LuaSL/LuaSL_threads.h b/src/LuaSL/LuaSL_threads.h
deleted file mode 100644
index 9a11b5c..0000000
--- a/src/LuaSL/LuaSL_threads.h
+++ /dev/null
@@ -1,54 +0,0 @@
1/* This code is heavily based on luaproc.
2 *
3 * The luaproc copyright notice and license is -
4
5 ***************************************************
6
7Copyright 2008 Alexandre Skyrme, Noemi Rodriguez, Roberto Ierusalimschy
8
9Permission is hereby granted, free of charge, to any person obtaining a copy
10of this software and associated documentation files (the "Software"), to deal
11in the Software without restriction, including without limitation the rights
12to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13copies of the Software, and to permit persons to whom the Software is
14furnished to do so, subject to the following conditions:
15
16The above copyright notice and this permission notice shall be included in
17all copies or substantial portions of the Software.
18
19THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25THE SOFTWARE.
26
27 ****************************************************
28 *
29 * Additions and changes Copyright 2012 by David Seikel, using the above license.
30 */
31
32#ifndef __LUASL_THREADS_H__
33#define __LUASL_THREADS_H__
34
35/* scheduler function return constants */
36#define LUAPROC_SCHED_OK 0
37#define LUAPROC_SCHED_SOCKET_ERROR -1
38#define LUAPROC_SCHED_SETSOCKOPT_ERROR -2
39#define LUAPROC_SCHED_BIND_ERROR -3
40#define LUAPROC_SCHED_LISTEN_ERROR -4
41#define LUAPROC_SCHED_FORK_ERROR -5
42#define LUAPROC_SCHED_PTHREAD_ERROR -6
43#define LUAPROC_SCHED_INIT_ERROR -7
44
45
46void luaprocInit(void);
47int sched_create_worker(void);
48void newProc(const char *code, int file, script *lp);
49const char *sendToChannel(gameGlobals *ourGlobals, const char *SID, const char *message);
50
51/* join all worker threads and exit */
52void sched_join_workerthreads(void);
53
54#endif
diff --git a/src/LuaSL/build.lua b/src/LuaSL/build.lua
index de16c2b..0878e3d 100755
--- a/src/LuaSL/build.lua
+++ b/src/LuaSL/build.lua
@@ -19,4 +19,4 @@ removeFiles(dir, {'../../LuaSL', '*.o', '*.output', '*.backup', 'LuaSL_lexer.h',
19-- Run lemon first, flex depends on it to define the symbol values. 19-- Run lemon first, flex depends on it to define the symbol values.
20runCommand('lemon', dir, '../../libraries/lemon/lemon -s -T../../libraries/lemon/lempar.c LuaSL_lemon_yaccer.y') 20runCommand('lemon', dir, '../../libraries/lemon/lemon -s -T../../libraries/lemon/lempar.c LuaSL_lemon_yaccer.y')
21runCommand('flex', dir, 'flex -C --outfile=LuaSL_lexer.c --header-file=LuaSL_lexer.h LuaSL_lexer.l') 21runCommand('flex', dir, 'flex -C --outfile=LuaSL_lexer.c --header-file=LuaSL_lexer.h LuaSL_lexer.l')
22compileFiles('../../LuaSL', dir, {'LuaSL_main', 'LuaSL_compile', 'LuaSL_threads', 'LuaSL_lexer', 'LuaSL_lemon_yaccer'}, '') 22compileFiles('../../LuaSL', dir, {'LuaSL_main', 'LuaSL_compile', 'LuaSL_lexer', 'LuaSL_lemon_yaccer'}, '')
diff --git a/src/extantz/build.lua b/src/extantz/build.lua
index 1591e8a..99362d1 100755
--- a/src/extantz/build.lua
+++ b/src/extantz/build.lua
@@ -15,7 +15,7 @@ end
15 15
16CFLAGS = CFLAGS .. ' -I../../libraries/irrlicht-1.8.1/include -I/usr/X11R6/include -I../GuiLua' 16CFLAGS = CFLAGS .. ' -I../../libraries/irrlicht-1.8.1/include -I/usr/X11R6/include -I../GuiLua'
17LDFLAGS = LDFLAGS .. ' -L../../libraries/irrlicht-1.8.1/lib/Linux' 17LDFLAGS = LDFLAGS .. ' -L../../libraries/irrlicht-1.8.1/lib/Linux'
18libs = libs .. ' -lIrrlicht -lGL -lbz2 -lGuiLua -lwinFang -lRunnr' 18libs = libs .. ' -lIrrlicht -lephysics -lGL -lbz2 -lGuiLua -lwinFang -lRunnr'
19 19
20removeFiles(dir, {'crappisspuke.o', 'CDemo.o', 'extantzCamera.o', 'gears.o', 'ephysics_demo.o', 'Evas_3D_demo.o', '../../media/extantz.edj'}) 20removeFiles(dir, {'crappisspuke.o', 'CDemo.o', 'extantzCamera.o', 'gears.o', 'ephysics_demo.o', 'Evas_3D_demo.o', '../../media/extantz.edj'})
21removeFiles(dir, {'../../extantz', 'camera.o', 'files.o', 'scenri.o', 'woMan.o'}) 21removeFiles(dir, {'../../extantz', 'camera.o', 'files.o', 'scenri.o', 'woMan.o'})
diff --git a/src/extantz/extantz.c b/src/extantz/extantz.c
index a27118b..2ccb97c 100644
--- a/src/extantz/extantz.c
+++ b/src/extantz/extantz.c
@@ -669,7 +669,7 @@ EAPI_MAIN int elm_main(int argc, char **argv)
669 ourGlobals.LSLGuiMess = GuiLuaLoad("LSLGuiMess", ourGlobals.mainWindow, ourGlobals.world); 669 ourGlobals.LSLGuiMess = GuiLuaLoad("LSLGuiMess", ourGlobals.mainWindow, ourGlobals.world);
670 ourGlobals.files = filesAdd(&ourGlobals, (char *) prefix_data_get(), EINA_TRUE, EINA_FALSE); 670 ourGlobals.files = filesAdd(&ourGlobals, (char *) prefix_data_get(), EINA_TRUE, EINA_FALSE);
671 671
672 // Try to connect to the love server we started before. 672 // Try to connect to a local love server.
673 serverStream = eina_strbuf_new(); 673 serverStream = eina_strbuf_new();
674 reachOut("127.0.0.1", 8211 + 1, &ourGlobals, (Ecore_Event_Handler_Cb) _add, (Ecore_Event_Handler_Cb) _data, (Ecore_Event_Handler_Cb) _del); 674 reachOut("127.0.0.1", 8211 + 1, &ourGlobals, (Ecore_Event_Handler_Cb) _add, (Ecore_Event_Handler_Cb) _data, (Ecore_Event_Handler_Cb) _del);
675 675
diff --git a/src/libraries/LumbrJack.c b/src/libraries/LumbrJack.c
index 56d4c50..27ca524 100644
--- a/src/libraries/LumbrJack.c
+++ b/src/libraries/LumbrJack.c
@@ -15,7 +15,7 @@ int HamrTime(char *argv0, void *main, int logDom)
15{ 15{
16 Eina_Array *path; 16 Eina_Array *path;
17 char *env, name[PATH_MAX], cwd[PATH_MAX], temp[PATH_MAX * 2]; 17 char *env, name[PATH_MAX], cwd[PATH_MAX], temp[PATH_MAX * 2];
18 int i, len = strlen(argv0); 18 int i, len;
19 19
20 if (!eina_init()) 20 if (!eina_init())
21 { 21 {
@@ -30,6 +30,7 @@ int HamrTime(char *argv0, void *main, int logDom)
30 logDom = loggingStartup(name, logDom); 30 logDom = loggingStartup(name, logDom);
31 eina_array_free(path); 31 eina_array_free(path);
32 32
33 len = strlen(name);
33 temp[len] = 0; 34 temp[len] = 0;
34 cwd[len] = 0; 35 cwd[len] = 0;
35 for (i = 0; i < len; i++) 36 for (i = 0; i < len; i++)
@@ -39,9 +40,7 @@ int HamrTime(char *argv0, void *main, int logDom)
39 } 40 }
40 41
41 if (!(prefix = eina_prefix_new(argv0, main, temp, cwd, "checkme.txt", PACKAGE_BIN_DIR, PACKAGE_LIB_DIR, PACKAGE_DATA_DIR, PACKAGE_LOCALE_DIR))) 42 if (!(prefix = eina_prefix_new(argv0, main, temp, cwd, "checkme.txt", PACKAGE_BIN_DIR, PACKAGE_LIB_DIR, PACKAGE_DATA_DIR, PACKAGE_LOCALE_DIR)))
42 {
43 PC("Can't find application prefix!"); 43 PC("Can't find application prefix!");
44 }
45 44
46 PD("%s is installed in %s", name, eina_prefix_get(prefix)); 45 PD("%s is installed in %s", name, eina_prefix_get(prefix));
47 PD("The binaries are in %s", eina_prefix_bin_get(prefix)); 46 PD("The binaries are in %s", eina_prefix_bin_get(prefix));
@@ -67,7 +66,7 @@ const char *prefix_get() {return eina_prefix_get(prefix);}
67const char *prefix_bin_get() {return eina_prefix_bin_get(prefix);} 66const char *prefix_bin_get() {return eina_prefix_bin_get(prefix);}
68const char *prefix_data_get() {return eina_prefix_data_get(prefix);} 67const char *prefix_data_get() {return eina_prefix_data_get(prefix);}
69const char *prefix_lib_get() {return eina_prefix_lib_get(prefix);} 68const char *prefix_lib_get() {return eina_prefix_lib_get(prefix);}
70const char *prefix_locale_get() {return eina_prefix_locale_get(prefix);} 69const char *prefix_locale_get() {return eina_prefix_locale_get(prefix);}
71 70
72void pantsOff(int logDom) 71void pantsOff(int logDom)
73{ 72{
diff --git a/src/libraries/Runnr.c b/src/libraries/Runnr.c
index 72bc523..c905ce9 100644
--- a/src/libraries/Runnr.c
+++ b/src/libraries/Runnr.c
@@ -1,62 +1,139 @@
1/* Runnr - a library that deals with running Lua scripts. 1/* Runnr - a library that deals with running Lua scripts.
2
3*/ 2*/
4 3
5 4
5#include "LumbrJack.h"
6#include "Runnr.h" 6#include "Runnr.h"
7 7
8 8
9static Ecore_Idle_Enterer *enterer;
10static Eina_Clist scripts;
11
12static int _send(lua_State *L);
13static int _receive(lua_State *L);
14static void _cancel(void *data, Ecore_Thread *thread);
15
16
17static const struct luaL_reg runnrFunctions[] =
18{
19 { "send", _send },
20 { "receive", _receive },
21 { NULL, NULL }
22};
23
24
9void dumpStack(lua_State *L, int i) 25void dumpStack(lua_State *L, int i)
10{ 26{
11 int type = lua_type(L, i); 27 int type = lua_type(L, i);
28 const char *t = lua_typename(L, type);
12 29
30 printf("Stack %d is %s", i, t);
13 switch (type) 31 switch (type)
14 { 32 {
15 case LUA_TNONE : printf("Stack %d is empty\n", i); break; 33 case LUA_TNONE : break;
16 case LUA_TNIL : printf("Stack %d is a nil\n", i); break; 34 case LUA_TNIL : break;
17 case LUA_TBOOLEAN : printf("Stack %d is a boolean - %d\n", i, lua_toboolean(L, i)); break; 35 case LUA_TBOOLEAN : printf(" - %d", lua_toboolean(L, i)); break;
18 case LUA_TNUMBER : printf("Stack %d is a number\n - %f", i, lua_tonumber(L, i)); break; 36 case LUA_TNUMBER : printf(" - %f", lua_tonumber(L, i)); break;
19 case LUA_TSTRING : printf("Stack %d is a string - %s\n", i, lua_tostring(L, i)); break; 37 case LUA_TSTRING : printf(" - %s", lua_tostring(L, i)); break;
20 case LUA_TFUNCTION : printf("Stack %d is a function\n", i); break; 38 case LUA_TFUNCTION : break;
21 case LUA_TTHREAD : printf("Stack %d is a thread\n", i); break; 39 case LUA_TTHREAD : break;
22 case LUA_TTABLE : 40 case LUA_TTABLE :
23 { 41 {
24 int j; 42 int j;
25 43
26 printf("Stack %d is a table", i);
27 lua_getfield(L, i, "_NAME"); 44 lua_getfield(L, i, "_NAME");
28 j = lua_gettop(L); 45 j = lua_gettop(L);
29 if (lua_isstring(L, j)) 46 if (lua_isstring(L, j))
30 printf(" - %s", lua_tostring(L, j)); 47 printf(" - %s", lua_tostring(L, j));
31 lua_pop(L, 1); 48 lua_pop(L, 1);
32 printf("\n");
33 break; 49 break;
34 } 50 }
35 case LUA_TUSERDATA : printf("Stack %d is a userdata\n", i); break; 51 case LUA_TUSERDATA : break;
36 case LUA_TLIGHTUSERDATA : printf("Stack %d is a light userdata\n", i); break; 52 case LUA_TLIGHTUSERDATA : break;
37 default : printf("Stack %d is unknown\n", i); break; 53 default : printf("- unknown!"); break;
38 } 54 }
55 printf("\n");
39} 56}
40 57
41static int traceBack(lua_State *L) 58static int traceBack(lua_State *L)
42{ 59{
43 const char *msg = ""; 60 lua_Debug ar;
44 int top = lua_gettop(L); 61 int i, top = lua_gettop(L), b = 1;
45// int i;
46 62
47// printf("Stack is %d deep\n", top); 63// printf("Stack is %d deep\n", top);
48// for (i = 1; i <= top; i++) 64// for (i = 1; i <= top; i++)
49// dumpStack(L, i); 65// dumpStack(L, i);
50 66
51 if (top) 67 if (top)
52 msg = lua_tostring(L, 1); 68 printf("Lua error - %s\n", lua_tostring(L, 1));
53 lua_getglobal(L, "debug"); 69
54 push_lua(L, "@ ( )", lua_gettop(L), "traceback", 1); 70 i = 0;
55 lua_pushstring(L, "\n"); 71 while (lua_getstack(L, i++, &ar))
56 lua_pushstring(L, msg); 72 {
57 lua_concat(L, 3); 73 if (lua_getinfo(L, "nSlu", &ar))
58 74 {
59 return 1; 75 if (NULL == ar.name)
76 ar.name = "DUNNO";
77 printf(" Lua backtrace %d - %s %s %s @ %s : %d\n", i, ar.what, ar.namewhat, ar.name, ar.short_src, ar.currentline);
78 b = 0;
79 }
80 else
81 printf(" Failed to get trace line!\n");
82 }
83
84 if (b)
85 printf(" NO BACKTRACE!\n");
86
87 return 0;
88}
89
90static void printLuaError(int err, char *string, lua_State *L)
91{
92 const char *err_type;
93
94 switch (err)
95 {
96 case LUA_ERRRUN: err_type = "runtime"; break;
97 case LUA_ERRSYNTAX: err_type = "syntax"; break;
98 case LUA_ERRMEM: err_type = "memory allocation"; break;
99 case LUA_ERRERR: err_type = "error handler"; break;
100 default: err_type = "unknown"; break;
101 }
102 printf("Error running - %s, \n %s - %s\n", string, err_type, lua_tostring(L, -1));
103}
104
105static int panics = 0;
106static int _panic(lua_State *L) // Stack usage [-0, +0, m]
107{
108 // If we somehow manage to have multiple panics, it's likely due to being out
109 // of memory in the following lua_tostring() call.
110 panics++;
111 if (panics)
112 printf("Lua PANICS!!!!!");
113 else
114 printf("Lua PANIC!!!!!: %s", lua_tostring(L, -1)); // Stack usage [-0, +0, m]
115 // The docs say that this will cause an exit(EXIT_FAILURE) if we return,
116 // and that we we should long jump some where to avoid that. This is only
117 // called for things not called from a protected environment. We always
118 // use pcalls though, except for the library load calls. If we can't load
119 // the standard libraries, then perhaps a crash is the right thing.
120 //
121 // The above is not true when we deal with the threaded stuff, that uses lua_resume().
122 return 0;
123}
124
125void printScriptsStatus()
126{
127 int active, pending_total, pending_feedback, pending_short, available;
128
129 active = ecore_thread_active_get();
130 pending_total = ecore_thread_pending_total_get();
131 pending_feedback = ecore_thread_pending_feedback_get();
132 pending_short = ecore_thread_pending_get();
133 available = ecore_thread_available_get();
134
135 printf("Scripts - active %d available %d pending short jobs %d pending feedback jobs %d pending total %d\n",
136 active, available, pending_short, pending_feedback, pending_total);
60} 137}
61 138
62void doLuaString(lua_State *L, char *string, char *module) 139void doLuaString(lua_State *L, char *string, char *module)
@@ -87,23 +164,452 @@ void doLuaString(lua_State *L, char *string, char *module)
87 } 164 }
88 } 165 }
89 166
167//printf("doLuaString(%s)\n", string);
90 if ((err = lua_pcall(L, 0, LUA_MULTRET, _T))) 168 if ((err = lua_pcall(L, 0, LUA_MULTRET, _T)))
169 printLuaError(err, string, L);
170 }
171}
172
173static void _stopScript(script *s)
174{
175 scriptMessage *sm0, *sm1;
176
177//printf("^^^^^^^^^^^^^^^^^^^_stop(, %s)\n", s->name);
178 if (s->L) lua_close(s->L); s->L = NULL;
179 if (s->timer) ecore_timer_del(s->timer); s->timer = NULL;
180 EINA_CLIST_FOR_EACH_ENTRY_SAFE(sm0, sm1, &(s->messages), scriptMessage, node)
181 {
182 eina_clist_remove(&(sm0->node));
183 free(sm0);
184 }
185 s->status = RUNNR_NOT_STARTED;
186}
187
188static void _workerFunction(void *data, Ecore_Thread *thread)
189{
190 script *s = data;
191 scriptMessage *msg = NULL;
192 const char *message = NULL;
193
194 takeScript(s);
195// if (RUNNR_FINISHED == s->status)
196// {
197// releaseScript(s);
198// return;
199// }
200
201 // The documentation is not clear on which thread is which inside and out,
202 // but states that at least for some they are different.
203 // So store the internal one as well.
204#if THREADIT
205 s->me = thread;
206#endif
207
208 if (RUNNR_RESET == s->status)
209 _stopScript(s);
210
211 if (RUNNR_READY == s->status)
212 {
213//printf("_workerFunction() READY %s\n", s->name);
214 if ((msg = (scriptMessage *) eina_clist_head(&(s->messages))))
91 { 215 {
92 const char *err_type; 216 eina_clist_remove(&(msg->node));
217 message = msg->message;
218 if (s->L)
219 s->status = RUNNR_RUNNING;
220 else
221 s->status = RUNNR_NOT_STARTED;
222 }
223 }
224
225 if (RUNNR_NOT_STARTED == s->status)
226 {
227 int err;
93 228
94 switch (err) 229//printf("_workerFunction() STARTING %s\n", s->name);
230 s->status = RUNNR_RUNNING;
231 s->L = luaL_newstate(); // Sets a standard allocator and panic function.
232
233 lua_atpanic(s->L, _panic);
234 // TODO - Set our allocator here.
235 luaL_openlibs(s->L);
236 luaL_register(s->L, "Runnr", runnrFunctions);
237
238 // Store the script struct in its own Lua state,
239 lua_pushlightuserdata(s->L, s);
240 lua_setfield(s->L, LUA_REGISTRYINDEX, "_SELF");
241
242 err = luaL_loadfile(s->L, s->binName);
243 if (err != 0)
244 s->status = RUNNR_FINISHED;
245 gettimeofday(&s->startTime, NULL);
246 }
247
248 releaseScript(s);
249
250 if (RUNNR_RUNNING == s->status)
251 {
252 int stat;
253
254//printf("_workerFunction() RUNNING %s %s\n", s->name, message);
255 // Resume running the script.
256 // lua_resume() needs a Lua thread, and the initial Lua state is a thread.
257 // Other Lua threads have their own state, but share the environment with the initial state.
258 // In theory lua_resume() is a pcall.
259 if (message)
260 lua_pushstring(s->L, message);
261 stat = lua_resume(s->L, (message) ? 1 : 0);
262 free(msg);
263
264 takeScript(s);
265 // If the script finished.
266 if (stat == 0)
267 s->status = RUNNR_FINISHED;
268 else if (stat != LUA_YIELD)
269 {
270 printf("lua_resume error at %s\n", s->name);
271 printLuaError(stat, s->name, s->L);
272 s->status = RUNNR_FINISHED;
273 }
274 else
275 {
276 if (eina_clist_count(&s->messages) == 0)
277 s->status = RUNNR_WAIT;
278 else
279 s->status = RUNNR_READY;
280 }
281 releaseScript(s);
282 }
283
284 takeScript(s);
285 // Start again from the top when Ecore_Thread has a spare thread ready, unless the script finished.
286 if (RUNNR_FINISHED == s->status)
287 {
288//printf("_workerFunction() FINISHED %s\n", s->name);
289#if THREADIT
290 ecore_thread_cancel(thread);
291#else
292 _cancel(s, NULL);
293#endif
294 }
295 else if (RUNNR_WAIT == s->status)
296 {
297;//printf("_workerFunction() WAIT %s\n", s->name);
298 }
299#if THREADIT
300 else if (RUNNR_READY == s->status)
301 ecore_thread_reschedule(thread);
302#endif
303 releaseScript(s);
304}
305
306static void _notify(void *data, Ecore_Thread *thread, void *message)
307{
308 script *s = data;
309
310 if (s->send2server) s->send2server(s, message);
311 free(message);
312}
313
314static void _cancel(void *data, Ecore_Thread *thread)
315{
316 script *s = data;
317
318 takeScript(s);
319 _stopScript(s);
320 s->status = RUNNR_FINISHED;
321 eina_clist_remove(&(s->node));
322 if (s->SID[0]) ecore_thread_global_data_del(s->SID); s->SID[0] = 0;
323//printf("^^^^^^^^^^^^^^^^^^^_del(, %s)\n", s->name);
324 // TODO - Perhaps have our own deletion callback to pass back?
325 releaseScript(s);
326#if THREADIT
327 eina_lock_free(&s->mutex);
328#endif
329 free(s);
330}
331
332#if THREADIT
333static void _end(void *data, Ecore_Thread *thread)
334{
335}
336#endif
337
338static Eina_Bool _enterer(void *data)
339{
340 script *s, *s1;
341
342 EINA_CLIST_FOR_EACH_ENTRY_SAFE(s, s1, &(scripts), script, node)
343 {
344 takeScript(s);
345 if ((RUNNR_WAIT == s->status) && (eina_clist_count(&s->messages)))
346 {
347 s->status = RUNNR_READY;
348#if THREADIT
349 ecore_thread_feedback_run(_workerFunction, _notify, _end, _cancel, s, EINA_FALSE);
350#else
351 _workerFunction(s, NULL);
352#endif
353 }
354 if ((RUNNR_RESET == s->status) || (RUNNR_READY == s->status) || (RUNNR_RUNNING == s->status) || (RUNNR_NOT_STARTED == s->status))
355 {
356#if THREADIT
357 ecore_thread_feedback_run(_workerFunction, _notify, _end, _cancel, s, EINA_FALSE);
358#else
359 _workerFunction(s, NULL);
360#endif
361 }
362 releaseScript(s);
363 }
364
365 return ECORE_CALLBACK_RENEW;
366}
367
368script *scriptAdd(char *file, char *SID, RunnrServerCb send2server, void *data)
369{
370 script *result;
371
372 if (!enterer)
373 {
374 eina_clist_init(&(scripts));
375 enterer = ecore_idler_add(_enterer, NULL);
376 }
377
378 result = calloc(1, sizeof(script));
379 gettimeofday(&result->startTime, NULL);
380 strcpy(result->SID, SID);
381 result->status = RUNNR_NOT_STARTED;
382 result->data = data;
383 result->send2server = send2server;
384
385 strncpy(result->fileName, file, sizeof(result->fileName));
386 result->name = &result->fileName[strlen(prefix_data_get())];
387 sprintf(result->binName, "%s.lua.out", result->fileName);
388
389#if THREADIT
390 eina_lock_new(&result->mutex);
391#endif
392 eina_clist_init(&(result->messages));
393 ecore_thread_global_data_add(result->SID, result, NULL, EINA_FALSE);
394
395 eina_clist_add_tail(&(scripts), &(result->node));
396
397 return result;
398}
399
400static int luaWriter(lua_State *L, const void* p, size_t sz, void* ud)
401{
402 FILE *out = ud;
403 int result = 0;
404
405 if (sz != fwrite(p, 1, sz, out))
406 result = -1;
407 return result;
408}
409
410// TODO - This didn't help the compile time much, perhaps move the rest of the compiling stage into this thread as a callback?
411static void _compileNotify(void *data, Ecore_Thread *thread, void *message)
412{
413 LuaCompiler *compiler = data;
414
415 if (compiler->cb) compiler->cb(compiler);
416}
417
418static void _compileThread(void *data, Ecore_Thread *thread)
419{
420 LuaCompiler *compiler = data;
421 char name[PATH_MAX];
422 lua_State *L;
423 FILE *out;
424 int err;
425
426 strcpy(name, compiler->luaName);
427 if ((L = luaL_newstate()))
428 {
429 luaL_openlibs(L);
430 // This ends up pushing a function onto the stack. The function is the compiled code.
431 err = luaL_loadfile(L, name);
432 if (err)
433 {
434 compiler->bugCount++;
435 if (LUA_ERRSYNTAX == err)
436 printf("Lua syntax error in %s: %s\n", name, lua_tostring(L, -1));
437 else if (LUA_ERRFILE == err)
438 printf("Lua compile file error in %s: %s\n", name, lua_tostring(L, -1));
439 else if (LUA_ERRMEM == err)
440 printf("Lua compile memory allocation error in %s: %s\n", name, lua_tostring(L, -1));
441 }
442 else
443 {
444 // Write the compiled code to a file.
445 strcat(name, ".out");
446 out = fopen(name, "w");
447 if (out)
448 {
449 err = lua_dump(L, luaWriter, out);
450 if (err)
451 {
452 compiler->bugCount++;
453 printf("Lua compile file error writing to %s\n", name);
454 }
455 fclose(out);
456 }
457 else
458 {
459 compiler->bugCount++;
460 printf("CRITICAL! Unable to open file %s for writing!\n", name);
461 }
462 }
463 }
464 else
465 {
466 compiler->bugCount++;
467 printf("Can't create a new Lua state!\n");
468 }
469
470 ecore_thread_feedback(thread, compiler);
471}
472
473void compileScript(LuaCompiler *compiler)
474{
475 ecore_thread_feedback_run(_compileThread, _compileNotify, NULL, NULL, compiler, EINA_FALSE);
476}
477
478// Assumes the scripts mutex is taken already.
479void runScript(script *s)
480{
481#if THREADIT
482 if ((RUNNR_NOT_STARTED == s->status) || (RUNNR_FINISHED == s->status))
483#endif
484 {
485#if THREADIT
486 ecore_thread_feedback_run(_workerFunction, _notify, _end, _cancel, s, EINA_FALSE);
487#elsif
488 _workerFunction(s, NULL);
489#endif
490 }
491}
492
493void resetScript(script *s)
494{
495 takeScript(s);
496 s->status = RUNNR_RESET;
497 releaseScript(s);
498}
499
500script *getScript(char *SID)
501{
502 script *result = ecore_thread_global_data_find(SID);
503
504 if (result)
505 {
506 takeScript(result);
507 if (RUNNR_FINISHED == result->status)
508 {
509 releaseScript(result);
510 result = NULL;
511 }
512 }
513 return result;
514}
515
516void takeScript(script *s)
517{
518#if THREADIT
519 Eina_Lock_Result result = eina_lock_take(&s->mutex);
520 if (EINA_LOCK_DEADLOCK == result) printf("Script %s IS DEADLOCKED!\n", s->name);
521 if (EINA_LOCK_FAIL == result) printf("Script %s LOCK FAILED!\n", s->name);
522#endif
523}
524
525void releaseScript(script *s)
526{
527#if THREADIT
528 eina_lock_release(&s->mutex);
529#endif
530}
531
532void send2script(const char *SID, const char *message)
533{
534 if (SID)
535 {
536 script *s = ecore_thread_global_data_find(SID);
537
538 if (s)
539 {
540 takeScript(s);
541 if (RUNNR_FINISHED != s->status)
95 { 542 {
96 case LUA_ERRRUN: err_type = "runtime"; break; 543 scriptMessage *sm = NULL;
97 case LUA_ERRSYNTAX: err_type = "syntax"; break; 544
98 case LUA_ERRMEM: err_type = "memory allocation"; break; 545 if ((sm = malloc(sizeof(scriptMessage))))
99 case LUA_ERRERR: err_type = "error handler"; break; 546 {
100 default: err_type = "unknown"; break; 547 runnrStatus stat;
548
549 sm->s = s;
550 strcpy((char *) sm->message, message);
551 eina_clist_add_tail(&(s->messages), &(sm->node));
552
553 stat = s->status;
554 s->status = RUNNR_READY;
555 if (RUNNR_WAIT == stat)
556#if THREADIT
557 ecore_thread_feedback_run(_workerFunction, _notify, _end, _cancel, s, EINA_FALSE);
558#else
559 _workerFunction(s, NULL);
560#endif
561 }
101 } 562 }
102 printf("Error running - %s, \n%s - %s", string, err_type, lua_tostring(L, -1)); 563 releaseScript(s);
103 } 564 }
104 } 565 }
105} 566}
106 567
568static script *_getSelf(lua_State *L)
569{
570 script *s;
571
572 lua_getfield(L, LUA_REGISTRYINDEX, "_SELF");
573 s = (script *) lua_touserdata(L, -1);
574 lua_pop(L, 1);
575
576 return s;
577}
578
579static int _send(lua_State *L)
580{
581 script *self = _getSelf(L);
582 const char *SID = NULL, *message = luaL_checkstring(L, 2);
583
584 if (lua_isstring(L, 1))
585 SID = lua_tostring(L, 1);
586
587 if (SID)
588 send2script(SID, message);
589 else
590 {
591 takeScript(self);
592#if THREADIT
593 ecore_thread_feedback(self->me, strdup(message));
594#else
595 _notify(self, NULL, strdup(message));
596#endif
597 releaseScript(self);
598 }
599
600 return 0;
601}
602
603static int _receive(lua_State *L)
604{
605 script *self = _getSelf(L);
606
607 takeScript(self);
608 self->status = RUNNR_WAIT;
609 releaseScript(self);
610 return lua_yield(L, 0);
611}
612
107 613
108// These are what the various symbols are for each type - 614// These are what the various symbols are for each type -
109// int % 615// int %
@@ -282,10 +788,24 @@ int push_lua(lua_State *L, char *params, ...) // Stack usage [-0, +n, em]
282 va_list vl; 788 va_list vl;
283 char *f = strdup(params); 789 char *f = strdup(params);
284 char *p = f; 790 char *p = f;
285 int n = 0, table = 0, i = -1; 791 int n = 0, table = 0, i = -1, needTrace = 0, _T;
286 792
287 if (!f) return -1; 793 if (!f) return -1;
288 794
795 // Scan ahead looking for ), so we know to put the traceBack function on the stack first.
796 while (*p)
797 {
798 p++;
799 if ('0' == *p)
800 {
801 lua_pushcfunction(L, traceBack);
802 _T = lua_gettop(L);
803 needTrace = 1;
804 break;
805 }
806 }
807 p = f;
808
289 va_start(vl, params); 809 va_start(vl, params);
290 810
291 while (*p) 811 while (*p)
@@ -364,7 +884,10 @@ int push_lua(lua_State *L, char *params, ...) // Stack usage [-0, +n, em]
364 } 884 }
365 case ')': 885 case ')':
366 { 886 {
367 lua_call(L, n - 1, va_arg(vl, int)); 887 int err;
888
889 if ((err = lua_pcall(L, n - 1, va_arg(vl, int), _T)))
890 printLuaError(err, params, L);
368 n = 0; 891 n = 0;
369 set = EINA_FALSE; 892 set = EINA_FALSE;
370 break; 893 break;
@@ -401,6 +924,8 @@ int push_lua(lua_State *L, char *params, ...) // Stack usage [-0, +n, em]
401 } 924 }
402 925
403 va_end(vl); 926 va_end(vl);
927 if (needTrace)
928 lua_remove(L, _T);
404 free(f); 929 free(f);
405 return n; 930 return n;
406} 931}
diff --git a/src/libraries/Runnr.h b/src/libraries/Runnr.h
index 0e0fc73..ba5c17e 100644
--- a/src/libraries/Runnr.h
+++ b/src/libraries/Runnr.h
@@ -4,12 +4,82 @@
4#include <ctype.h> 4#include <ctype.h>
5 5
6#include <Eina.h> 6#include <Eina.h>
7#include <Ecore.h>
8#include <Ecore_Con.h>
7 9
8#include <lua.h> 10#include <lua.h>
9#include <luajit.h> 11#include <luajit.h>
10#include <lualib.h> 12#include <lualib.h>
11#include <lauxlib.h> 13#include <lauxlib.h>
12 14
15// Stick with Plan C for now.
16#define THREADIT 0
17
18typedef enum
19{
20 RUNNR_COMPILING,
21 RUNNR_NOT_STARTED,
22 RUNNR_RUNNING,
23 RUNNR_WAIT,
24 RUNNR_READY,
25 RUNNR_RESET,
26 RUNNR_FINISHED
27} runnrStatus;
28
29typedef struct _LuaCompile LuaCompile;
30typedef void (* compileCb)(LuaCompile *compiler);
31
32typedef struct _LuaCompile
33{
34 char *file, *SID, *luaName;
35 int bugCount;
36 void *data;
37 Ecore_Con_Client *client;
38 compileCb cb;
39} LuaCompiler;
40
41typedef struct _script script;
42typedef void (* RunnrServerCb)(script *me, const char *message);
43
44typedef struct _script
45{
46 Eina_Clist node;
47#if THREADIT
48 Eina_Lock mutex;
49 Ecore_Thread *me;
50#endif
51 void *data;
52 char SID[PATH_MAX];
53 char *name;
54 char fileName[PATH_MAX];
55 char binName[PATH_MAX];
56 lua_State *L;
57 struct timeval startTime;
58 float timerTime;
59 runnrStatus status;
60 RunnrServerCb send2server;
61 Eina_Clist messages;
62 Ecore_Con_Client *client;
63 Ecore_Timer *timer;
64} script;
65
66typedef struct
67{
68 Eina_Clist node;
69 script *s;
70 const char message[PATH_MAX];
71} scriptMessage;
72
73
74script *scriptAdd(char *file, char *SID, RunnrServerCb send2server, void *data);
75void compileScript(LuaCompiler *compiler);
76void runScript(script *me);
77void resetScript(script *me);
78script *getScript(char *SID);
79void takeScript(script *me);
80void releaseScript(script *me);
81void send2script(const char *SID, const char *message);
82void printScriptsStatus();
13 83
14void dumpStack(lua_State *L, int i); 84void dumpStack(lua_State *L, int i);
15void doLuaString(lua_State *L, char *string, char *module); 85void doLuaString(lua_State *L, char *string, char *module);
diff --git a/src/libraries/SledjHamr.c b/src/libraries/SledjHamr.c
index 5f26fde..5e1d387 100644
--- a/src/libraries/SledjHamr.c
+++ b/src/libraries/SledjHamr.c
@@ -1,3 +1,5 @@
1// This might become nails, since at the moment it's only got comms stuff in it.
2
1#include <unistd.h> 3#include <unistd.h>
2#include "SledjHamr.h" 4#include "SledjHamr.h"
3 5
diff --git a/src/love/build.lua b/src/love/build.lua
index 5ecca31..8fd9a29 100755
--- a/src/love/build.lua
+++ b/src/love/build.lua
@@ -17,5 +17,4 @@ end
17removeFiles(dir, {'../../love', '*.o', '../../media/love.edj'}) 17removeFiles(dir, {'../../love', '*.o', '../../media/love.edj'})
18 18
19runCommand('edje_cc', dir, 'edje_cc ' .. EDJE_FLAGS .. ' love.edc ../../media/love.edj') 19runCommand('edje_cc', dir, 'edje_cc ' .. EDJE_FLAGS .. ' love.edc ../../media/love.edj')
20
21compileFiles('../../love', dir, {'love'}, '') 20compileFiles('../../love', dir, {'love'}, '')
diff --git a/src/love/love.c b/src/love/love.c
index 1f885bc..d194f11 100644
--- a/src/love/love.c
+++ b/src/love/love.c
@@ -44,7 +44,7 @@ typedef struct _gameGlobals
44 boolean ui; // Wether we actually start up the UI. 44 boolean ui; // Wether we actually start up the UI.
45} gameGlobals; 45} gameGlobals;
46 46
47typedef struct _script 47typedef struct _Lscript
48{ 48{
49 char SID[PATH_MAX]; 49 char SID[PATH_MAX];
50 char fileName[PATH_MAX]; 50 char fileName[PATH_MAX];
@@ -52,11 +52,10 @@ typedef struct _script
52 float compileTime; 52 float compileTime;
53 int bugs, warnings; 53 int bugs, warnings;
54 boolean running; 54 boolean running;
55} script; 55} LoveScript;
56 56
57 57
58int logDom = -1; // Our logging domain. 58int logDom = -1; // Our logging domain.
59//static int CPUs = 4;
60static Eina_Strbuf *LuaSLStream; 59static Eina_Strbuf *LuaSLStream;
61static Eina_Strbuf *clientStream; 60static Eina_Strbuf *clientStream;
62static int scriptCount = 0; 61static int scriptCount = 0;
@@ -145,7 +144,7 @@ static void dirList_compile(const char *name, const char *path, void *data)
145 // TODO - We are leaking these, coz we don't know when scripts get deleted in the script server. 144 // TODO - We are leaking these, coz we don't know when scripts get deleted in the script server.
146 // On the other hand, the main use for this is a temporary hack that sends events to all scripts. 145 // On the other hand, the main use for this is a temporary hack that sends events to all scripts.
147 // So that part will get a rewrite when we make it real later anyway. 146 // So that part will get a rewrite when we make it real later anyway.
148 script *me = calloc(1, sizeof(script)); 147 LoveScript *me = calloc(1, sizeof(LoveScript));
149 148
150 scriptCount++; 149 scriptCount++;
151 gettimeofday(&me->startTime, NULL); 150 gettimeofday(&me->startTime, NULL);
@@ -213,7 +212,7 @@ static Eina_Bool _dataLuaSL(void *data, int type, Ecore_Con_Event_Server_Data *e
213 ext = index(SID, '.'); 212 ext = index(SID, '.');
214 if (ext) 213 if (ext)
215 { 214 {
216 script *me; 215 LoveScript *me;
217 216
218 ext[0] = '\0'; 217 ext[0] = '\0';
219 command = ext + 1; 218 command = ext + 1;
@@ -383,7 +382,7 @@ static Eina_Bool _dataLuaSL(void *data, int type, Ecore_Con_Event_Server_Data *e
383 else if (0 == strncmp(command, "llMessageLinked(", 16)) 382 else if (0 == strncmp(command, "llMessageLinked(", 16))
384 { 383 {
385 Eina_Iterator *scripts; 384 Eina_Iterator *scripts;
386 script *me; 385 LoveScript *me;
387 386
388 // TODO - For now, just send it to everyone. 387 // TODO - For now, just send it to everyone.
389 scripts = eina_hash_iterator_data_new(ourGlobals->scripts); 388 scripts = eina_hash_iterator_data_new(ourGlobals->scripts);
@@ -419,7 +418,7 @@ static Eina_Bool _dataLuaSL(void *data, int type, Ecore_Con_Event_Server_Data *e
419 if (-1 != fd) 418 if (-1 != fd)
420 { 419 {
421 Eina_Iterator *scripts; 420 Eina_Iterator *scripts;
422 script *me; 421 LoveScript *me;
423 long len; 422 long len;
424 423
425 temp = NULL; 424 temp = NULL;
@@ -542,7 +541,7 @@ static Eina_Bool _dataClient(void *data, int type, Ecore_Con_Event_Client_Data *
542 if (0 == strncmp(command, "events.touch_start(", 19)) 541 if (0 == strncmp(command, "events.touch_start(", 19))
543 { 542 {
544 Eina_Iterator *scripts; 543 Eina_Iterator *scripts;
545 script *me; 544 LoveScript *me;
546 545
547 // TODO - For now, just send it to everyone. 546 // TODO - For now, just send it to everyone.
548 scripts = eina_hash_iterator_data_new(ourGlobals->scripts); 547 scripts = eina_hash_iterator_data_new(ourGlobals->scripts);
@@ -557,7 +556,7 @@ static Eina_Bool _dataClient(void *data, int type, Ecore_Con_Event_Client_Data *
557 else if (0 == strncmp(command, "events.listen(", 14)) 556 else if (0 == strncmp(command, "events.listen(", 14))
558 { 557 {
559 Eina_Iterator *scripts; 558 Eina_Iterator *scripts;
560 script *me; 559 LoveScript *me;
561 560
562 // TODO - For now, just send it to everyone. 561 // TODO - For now, just send it to everyone.
563 scripts = eina_hash_iterator_data_new(ourGlobals->scripts); 562 scripts = eina_hash_iterator_data_new(ourGlobals->scripts);
@@ -586,7 +585,7 @@ static Eina_Bool _delClient(void *data, int type, Ecore_Con_Event_Client_Del *ev
586 { 585 {
587 Eina_List const *clients; 586 Eina_List const *clients;
588 587
589 // This is only really for testing, normally it just runs 24/7, or until told to. 588 // This is only really for testing, normally it just runs 24/7, or until told not to.
590 clients = ecore_con_server_clients_get(ourGlobals->server); 589 clients = ecore_con_server_clients_get(ourGlobals->server);
591 if (0 == eina_list_count(clients)) 590 if (0 == eina_list_count(clients))
592 { 591 {
@@ -606,7 +605,6 @@ static Eina_Bool _delClient(void *data, int type, Ecore_Con_Event_Client_Del *ev
606 605
607int main(int argc, char **argv) 606int main(int argc, char **argv)
608{ 607{
609 /* put here any init specific to this app like parsing args etc. */
610 gameGlobals ourGlobals; 608 gameGlobals ourGlobals;
611 char *programName = argv[0]; 609 char *programName = argv[0];
612 boolean badArgs = FALSE; 610 boolean badArgs = FALSE;