diff options
-rw-r--r-- | LuaSL/src/LSL.lua | 12 | ||||
-rw-r--r-- | LuaSL/src/LuaSL.h | 1 | ||||
-rw-r--r-- | LuaSL/src/LuaSL_main.c | 10 | ||||
-rw-r--r-- | LuaSL/src/LuaSL_test.c | 12 | ||||
-rw-r--r-- | LuaSL/src/LuaSL_threads.c | 451 | ||||
-rw-r--r-- | LuaSL/src/LuaSL_threads.h | 9 |
6 files changed, 108 insertions, 387 deletions
diff --git a/LuaSL/src/LSL.lua b/LuaSL/src/LSL.lua index 3810abc..662c880 100644 --- a/LuaSL/src/LSL.lua +++ b/LuaSL/src/LSL.lua | |||
@@ -82,6 +82,7 @@ end | |||
82 | 82 | ||
83 | events = {} | 83 | events = {} |
84 | 84 | ||
85 | function start() paused = false end | ||
85 | function stop() paused = true end | 86 | function stop() paused = true end |
86 | function quit() running = false end | 87 | function quit() running = false end |
87 | 88 | ||
@@ -761,26 +762,18 @@ function LSL.stateChange(x) | |||
761 | end; | 762 | end; |
762 | 763 | ||
763 | function LSL.mainLoop(sid, name, x) | 764 | function LSL.mainLoop(sid, name, x) |
764 | local status, errorMsg = luaproc.newchannel(sid) | 765 | local status, errorMsg |
765 | local result | 766 | local result |
766 | 767 | ||
767 | SID = sid | 768 | SID = sid |
768 | scriptName = name | 769 | scriptName = name |
769 | |||
770 | LSL.EOF = "\n\n\n" -- Fix this up now. | 770 | LSL.EOF = "\n\n\n" -- Fix this up now. |
771 | 771 | ||
772 | if not status then | ||
773 | msg("Can't open the luaproc channel " .. sid .. " ERROR MESSAGE: " .. errorMsg) | ||
774 | return | ||
775 | end | ||
776 | |||
777 | LSL.stateChange(x); | 772 | LSL.stateChange(x); |
778 | waitAndProcess(false) | 773 | waitAndProcess(false) |
779 | msg("Script quitting.") | 774 | msg("Script quitting.") |
780 | end | 775 | end |
781 | 776 | ||
782 | -- Need a FIFO queue of incoming events. Which will be in the C main thread, coz that's listening on the socket for us. | ||
783 | -- The ecore_con stuff ends up being a FIFO queue of the commands coming from OpenSim. So no worries. | ||
784 | function waitAndProcess(returnWanted) | 777 | function waitAndProcess(returnWanted) |
785 | local Type = "event" | 778 | local Type = "event" |
786 | 779 | ||
@@ -798,6 +791,7 @@ function waitAndProcess(returnWanted) | |||
798 | else | 791 | else |
799 | -- Set the functions environment to ours, for the protection of the script, coz loadstring sets it to the global environment instead. | 792 | -- Set the functions environment to ours, for the protection of the script, coz loadstring sets it to the global environment instead. |
800 | -- TODO - On the other hand, we will need the global environment when we call event handlers. So we should probably stash it around here somewhere. | 793 | -- TODO - On the other hand, we will need the global environment when we call event handlers. So we should probably stash it around here somewhere. |
794 | -- Meh, seems to be working fine as it is. | ||
801 | setfenv(result, getfenv(1)) | 795 | setfenv(result, getfenv(1)) |
802 | status, result = pcall(result) | 796 | status, result = pcall(result) |
803 | if not status then | 797 | if not status then |
diff --git a/LuaSL/src/LuaSL.h b/LuaSL/src/LuaSL.h index 057788b..086d1b7 100644 --- a/LuaSL/src/LuaSL.h +++ b/LuaSL/src/LuaSL.h | |||
@@ -84,7 +84,6 @@ struct _script | |||
84 | boolean running; | 84 | boolean running; |
85 | int status; | 85 | int status; |
86 | int args; | 86 | int args; |
87 | channel chan; | ||
88 | Eina_Clist messages; | 87 | Eina_Clist messages; |
89 | Ecore_Con_Client *client; | 88 | Ecore_Con_Client *client; |
90 | Ecore_Timer *timer; | 89 | Ecore_Timer *timer; |
diff --git a/LuaSL/src/LuaSL_main.c b/LuaSL/src/LuaSL_main.c index c03a827..f15ae4a 100644 --- a/LuaSL/src/LuaSL_main.c +++ b/LuaSL/src/LuaSL_main.c | |||
@@ -12,7 +12,7 @@ static Eina_Bool _sleep_timer_cb(void *data) | |||
12 | gameGlobals *game = script->game; | 12 | gameGlobals *game = script->game; |
13 | 13 | ||
14 | PD("Waking up %s", script->SID); | 14 | PD("Waking up %s", script->SID); |
15 | sendToChannel(game, script->SID, "return 0.0", NULL, NULL); | 15 | sendToChannel(game, script->SID, "return 0.0"); |
16 | return ECORE_CALLBACK_CANCEL; | 16 | return ECORE_CALLBACK_CANCEL; |
17 | } | 17 | } |
18 | 18 | ||
@@ -22,7 +22,7 @@ static Eina_Bool _timer_timer_cb(void *data) | |||
22 | gameGlobals *game = script->game; | 22 | gameGlobals *game = script->game; |
23 | 23 | ||
24 | PD("Timer for %s", script->SID); | 24 | PD("Timer for %s", script->SID); |
25 | sendToChannel(game, script->SID, "events.timer()", NULL, NULL); | 25 | sendToChannel(game, script->SID, "events.timer()"); |
26 | return ECORE_CALLBACK_RENEW; | 26 | return ECORE_CALLBACK_RENEW; |
27 | } | 27 | } |
28 | 28 | ||
@@ -82,9 +82,9 @@ void scriptSendBack(void * data) | |||
82 | while (isspace(*temp)) | 82 | while (isspace(*temp)) |
83 | temp++; | 83 | temp++; |
84 | if ('1' == *temp) | 84 | if ('1' == *temp) |
85 | sendToChannel(game, them->SID, "start()", NULL, NULL); | 85 | sendToChannel(game, them->SID, "start()"); |
86 | else | 86 | else |
87 | sendToChannel(game, them->SID, "stop()", NULL, NULL); | 87 | sendToChannel(game, them->SID, "stop()"); |
88 | PD("Stopped %s", them->fileName); | 88 | PD("Stopped %s", them->fileName); |
89 | } | 89 | } |
90 | else | 90 | else |
@@ -191,7 +191,7 @@ static Eina_Bool _data(void *data, int type __UNUSED__, Ecore_Con_Event_Client_D | |||
191 | { | 191 | { |
192 | const char *status = NULL; | 192 | const char *status = NULL; |
193 | 193 | ||
194 | status = sendToChannel(game, SID, command, NULL, NULL); | 194 | status = sendToChannel(game, SID, command); |
195 | if (status) | 195 | if (status) |
196 | PE("Error sending command %s to script %s : %s", command, SID, status); | 196 | PE("Error sending command %s to script %s : %s", command, SID, status); |
197 | } | 197 | } |
diff --git a/LuaSL/src/LuaSL_test.c b/LuaSL/src/LuaSL_test.c index ec76a32..463ae3b 100644 --- a/LuaSL/src/LuaSL_test.c +++ b/LuaSL/src/LuaSL_test.c | |||
@@ -112,19 +112,17 @@ static Eina_Bool _timer_cb(void *data) | |||
112 | { | 112 | { |
113 | case 5 : | 113 | case 5 : |
114 | { | 114 | { |
115 | // TODO - do it as one line, coz sendToChannel() locks up if I do them one at a time too quickly. | 115 | sendForth(game, me->SID, "events.detectedKeys({\"%s\"})", ownerKey); |
116 | sendForth(game, me->SID, "events.detectedKeys({\"%s\"}); events.detectedNames({\"%s\"}); events.touch_start(1)", ownerKey, ownerName); | 116 | sendForth(game, me->SID, "events.detectedNames({\"%s\"})", ownerName); |
117 | // sendForth(game, me->SID, "events.detectedKeys({\"%s\"})", ownerKey); | 117 | sendForth(game, me->SID, "events.touch_start(1)"); |
118 | // sendForth(game, me->SID, "events.detectedNames({\"%s\"})", ownerName); | ||
119 | // sendForth(game, me->SID, "events.touch_start(1)"); | ||
120 | break; | 118 | break; |
121 | } | 119 | } |
122 | case 9+3 : | 120 | case 9 : |
123 | { | 121 | { |
124 | sendForth(game, me->SID, "quit()"); | 122 | sendForth(game, me->SID, "quit()"); |
125 | break; | 123 | break; |
126 | } | 124 | } |
127 | case 11+3 : | 125 | case 11 : |
128 | { | 126 | { |
129 | exit = TRUE; | 127 | exit = TRUE; |
130 | break; | 128 | break; |
diff --git a/LuaSL/src/LuaSL_threads.c b/LuaSL/src/LuaSL_threads.c index 4a7397e..aec5ed6 100644 --- a/LuaSL/src/LuaSL_threads.c +++ b/LuaSL/src/LuaSL_threads.c | |||
@@ -33,10 +33,6 @@ THE SOFTWARE. | |||
33 | /* This is a redesign of luaproc. The design goals and notes - | 33 | /* This is a redesign of luaproc. The design goals and notes - |
34 | * | 34 | * |
35 | * In general use EFL where it is useful. | 35 | * In general use EFL where it is useful. |
36 | * One fixed unique message channel per script. | ||
37 | * No need for channel.c / .h, we are not using that sort of arbitrary channels. | ||
38 | * FIFO queue on message channels, seems the C socket queue is not enough. | ||
39 | * On the other hand, could just peel messages of the socket queue, then shove them on the scripts queue. | ||
40 | * Probably one fixed unique message channel per object, which each script in the object shares. | 36 | * Probably one fixed unique message channel per object, which each script in the object shares. |
41 | * But might be better to handle that C side anyway. | 37 | * But might be better to handle that C side anyway. |
42 | * Better integration with LuaSL. | 38 | * Better integration with LuaSL. |
@@ -50,16 +46,9 @@ THE SOFTWARE. | |||
50 | #include "LuaSL.h" | 46 | #include "LuaSL.h" |
51 | 47 | ||
52 | 48 | ||
53 | #define CHANNEL_MAX_NAME_LENGTH 255 | ||
54 | |||
55 | #define CHANNEL_DESTROYED 0 | ||
56 | |||
57 | /* ready process queue insertion status */ | 49 | /* ready process queue insertion status */ |
58 | #define LUAPROC_SCHED_QUEUE_PROC_OK 0 | 50 | #define LUAPROC_SCHED_QUEUE_PROC_OK 0 |
59 | #define LUAPROC_SCHED_QUEUE_PROC_ERR -1 | 51 | //#define LUAPROC_SCHED_QUEUE_PROC_ERR -1 |
60 | |||
61 | /* scheduler default number of worker threads */ | ||
62 | #define LUAPROC_SCHED_DEFAULT_WORKER_THREADS 1 | ||
63 | 52 | ||
64 | /* process is idle */ | 53 | /* process is idle */ |
65 | #define LUAPROC_STAT_IDLE 0 | 54 | #define LUAPROC_STAT_IDLE 0 |
@@ -71,14 +60,6 @@ THE SOFTWARE. | |||
71 | #define LUAPROC_STAT_BLOCKED_RECV 3 | 60 | #define LUAPROC_STAT_BLOCKED_RECV 3 |
72 | 61 | ||
73 | 62 | ||
74 | /* message channel */ | ||
75 | struct stchannel { | ||
76 | Eina_Clist send; | ||
77 | Eina_Clist recv; | ||
78 | pthread_mutex_t *mutex; | ||
79 | pthread_cond_t *in_use; | ||
80 | }; | ||
81 | |||
82 | typedef struct | 63 | typedef struct |
83 | { | 64 | { |
84 | Eina_Clist node; | 65 | Eina_Clist node; |
@@ -89,12 +70,6 @@ typedef struct | |||
89 | * globals | 70 | * globals |
90 | *********/ | 71 | *********/ |
91 | 72 | ||
92 | /* global channel lua_State mutex */ | ||
93 | pthread_mutex_t mutex_channel_lstate = PTHREAD_MUTEX_INITIALIZER; | ||
94 | |||
95 | /* global where channels will be stored */ | ||
96 | Eina_Hash *channels; | ||
97 | |||
98 | /* ready process list */ | 73 | /* ready process list */ |
99 | Eina_Clist lpready; | 74 | Eina_Clist lpready; |
100 | 75 | ||
@@ -133,8 +108,6 @@ Eina_Clist recyclelp; | |||
133 | static int luaproc_send( lua_State *L ); | 108 | static int luaproc_send( lua_State *L ); |
134 | /* receive a message from a lua process */ | 109 | /* receive a message from a lua process */ |
135 | static int luaproc_receive( lua_State *L ); | 110 | static int luaproc_receive( lua_State *L ); |
136 | /* create a new channel */ | ||
137 | static int luaproc_create_channel( lua_State *L ); | ||
138 | /* send a message back to the main loop */ | 111 | /* send a message back to the main loop */ |
139 | static int luaproc_send_back( lua_State *L ); | 112 | static int luaproc_send_back( lua_State *L ); |
140 | 113 | ||
@@ -148,59 +121,11 @@ static const struct luaL_reg luaproc_funcs_parent[] = { | |||
148 | static const struct luaL_reg luaproc_funcs_child[] = { | 121 | static const struct luaL_reg luaproc_funcs_child[] = { |
149 | { "send", luaproc_send }, | 122 | { "send", luaproc_send }, |
150 | { "receive", luaproc_receive }, | 123 | { "receive", luaproc_receive }, |
151 | { "newchannel", luaproc_create_channel }, | ||
152 | { "sendback", luaproc_send_back }, | 124 | { "sendback", luaproc_send_back }, |
153 | { NULL, NULL } | 125 | { NULL, NULL } |
154 | }; | 126 | }; |
155 | 127 | ||
156 | 128 | ||
157 | /* queue a lua process sending a message without a matching receiver */ | ||
158 | static void luaproc_queue_sender(script *lp) | ||
159 | { | ||
160 | eina_clist_add_tail(&(lp->chan->send), &(lp->node)); | ||
161 | } | ||
162 | |||
163 | /* dequeue a lua process sending a message with a receiver match */ | ||
164 | static script *luaproc_dequeue_sender(channel chan) | ||
165 | { | ||
166 | script *lp; | ||
167 | |||
168 | if ((lp = (script *) eina_clist_head(&(chan->send)))) | ||
169 | eina_clist_remove(&(lp->node)); | ||
170 | |||
171 | return lp; | ||
172 | } | ||
173 | |||
174 | /* queue a luc process receiving a message without a matching sender */ | ||
175 | static void luaproc_queue_receiver(script *lp) | ||
176 | { | ||
177 | eina_clist_add_tail(&(lp->chan->recv), &(lp->node)); | ||
178 | } | ||
179 | |||
180 | /* dequeue a lua process receiving a message with a sender match */ | ||
181 | static script *luaproc_dequeue_receiver(channel chan) | ||
182 | { | ||
183 | script *lp; | ||
184 | |||
185 | if ((lp = (script *) eina_clist_head(&(chan->recv)))) | ||
186 | eina_clist_remove(&(lp->node)); | ||
187 | |||
188 | return lp; | ||
189 | } | ||
190 | |||
191 | /* unlock access to a channel */ | ||
192 | static void luaproc_unlock_channel(channel chan) | ||
193 | { | ||
194 | /* get exclusive access to operate on channels */ | ||
195 | pthread_mutex_lock(&mutex_channel); | ||
196 | /* unlock channel access */ | ||
197 | pthread_mutex_unlock(chan->mutex); | ||
198 | /* signal channel not in use */ | ||
199 | pthread_cond_signal(chan->in_use); | ||
200 | /* free access to operate on channels */ | ||
201 | pthread_mutex_unlock(&mutex_channel); | ||
202 | } | ||
203 | |||
204 | /* increase active lua process count */ | 129 | /* increase active lua process count */ |
205 | static void sched_lpcount_inc(void) | 130 | static void sched_lpcount_inc(void) |
206 | { | 131 | { |
@@ -255,7 +180,6 @@ static void *workermain( void *args ) { | |||
255 | 180 | ||
256 | /* execute the lua code specified in the lua process struct */ | 181 | /* execute the lua code specified in the lua process struct */ |
257 | procstat = lua_resume(lp->L, lp->args); | 182 | procstat = lua_resume(lp->L, lp->args); |
258 | |||
259 | /* reset the process argument count */ | 183 | /* reset the process argument count */ |
260 | lp->args = 0; | 184 | lp->args = 0; |
261 | 185 | ||
@@ -273,8 +197,8 @@ static void *workermain( void *args ) { | |||
273 | sched_lpcount_dec(); | 197 | sched_lpcount_dec(); |
274 | } | 198 | } |
275 | lua_close(lp->L); | 199 | lua_close(lp->L); |
276 | // if (lp->timer) | 200 | if (lp->timer) |
277 | // ecore_timer_del(lp->timer); | 201 | ecore_timer_del(lp->timer); |
278 | free(lp); | 202 | free(lp); |
279 | } | 203 | } |
280 | 204 | ||
@@ -282,22 +206,15 @@ static void *workermain( void *args ) { | |||
282 | else if ( procstat == LUA_YIELD ) { | 206 | else if ( procstat == LUA_YIELD ) { |
283 | 207 | ||
284 | /* if so, further check if yield originated from an unmatched send/recv operation */ | 208 | /* if so, further check if yield originated from an unmatched send/recv operation */ |
285 | if ( lp->status == LUAPROC_STAT_BLOCKED_SEND ) { | 209 | if (lp->status == LUAPROC_STAT_BLOCKED_SEND) |
286 | /* queue blocked lua process on corresponding channel */ | 210 | { |
287 | luaproc_queue_sender( lp ); | ||
288 | /* unlock channel access */ | ||
289 | luaproc_unlock_channel(lp->chan); | ||
290 | } | 211 | } |
291 | 212 | else if (lp->status == LUAPROC_STAT_BLOCKED_RECV) | |
292 | else if ( lp->status == LUAPROC_STAT_BLOCKED_RECV ) { | 213 | { |
293 | /* queue blocked lua process on corresponding channel */ | ||
294 | luaproc_queue_receiver( lp ); | ||
295 | /* unlock channel access */ | ||
296 | luaproc_unlock_channel(lp->chan); | ||
297 | } | 214 | } |
298 | |||
299 | /* or if yield resulted from an explicit call to coroutine.yield in the lua code being executed */ | 215 | /* or if yield resulted from an explicit call to coroutine.yield in the lua code being executed */ |
300 | else { | 216 | else |
217 | { | ||
301 | /* get exclusive access to the ready process queue */ | 218 | /* get exclusive access to the ready process queue */ |
302 | pthread_mutex_lock( &mutex_queue_access ); | 219 | pthread_mutex_lock( &mutex_queue_access ); |
303 | /* re-insert the job at the end of the ready process queue */ | 220 | /* re-insert the job at the end of the ready process queue */ |
@@ -306,9 +223,9 @@ static void *workermain( void *args ) { | |||
306 | pthread_mutex_unlock( &mutex_queue_access ); | 223 | pthread_mutex_unlock( &mutex_queue_access ); |
307 | } | 224 | } |
308 | } | 225 | } |
309 | |||
310 | /* check if there was any execution error (LUA_ERRRUN, LUA_ERRSYNTAX, LUA_ERRMEM or LUA_ERRERR) */ | 226 | /* check if there was any execution error (LUA_ERRRUN, LUA_ERRSYNTAX, LUA_ERRMEM or LUA_ERRERR) */ |
311 | else { | 227 | else |
228 | { | ||
312 | /* print error message */ | 229 | /* print error message */ |
313 | fprintf( stderr, "close lua_State (error: %s)\n", luaL_checkstring(lp->L, -1 )); | 230 | fprintf( stderr, "close lua_State (error: %s)\n", luaL_checkstring(lp->L, -1 )); |
314 | /* close lua state */ | 231 | /* close lua state */ |
@@ -365,20 +282,16 @@ void sched_join_workerthreads( void ) { | |||
365 | } | 282 | } |
366 | 283 | ||
367 | /* create a new worker pthread */ | 284 | /* create a new worker pthread */ |
368 | int sched_create_worker( void ) { | 285 | int sched_create_worker(void) |
369 | 286 | { | |
370 | pthread_t worker; | 287 | pthread_t worker; |
371 | |||
372 | /* create a new pthread */ | ||
373 | if ( pthread_create( &worker, NULL, workermain, NULL ) != 0 ) { | ||
374 | return LUAPROC_SCHED_PTHREAD_ERROR; | ||
375 | } | ||
376 | 288 | ||
377 | return LUAPROC_SCHED_OK; | 289 | /* create a new pthread */ |
290 | if (pthread_create( &worker, NULL, workermain, NULL ) != 0) | ||
291 | return LUAPROC_SCHED_PTHREAD_ERROR; | ||
292 | return LUAPROC_SCHED_OK; | ||
378 | } | 293 | } |
379 | 294 | ||
380 | |||
381 | |||
382 | void newProc(const char *code, int file, script *lp) | 295 | void newProc(const char *code, int file, script *lp) |
383 | { | 296 | { |
384 | int ret; | 297 | int ret; |
@@ -408,7 +321,6 @@ void newProc(const char *code, int file, script *lp) | |||
408 | 321 | ||
409 | lp->status = LUAPROC_STAT_IDLE; | 322 | lp->status = LUAPROC_STAT_IDLE; |
410 | lp->args = 0; | 323 | lp->args = 0; |
411 | lp->chan = NULL; | ||
412 | eina_clist_element_init(&(lp->node)); | 324 | eina_clist_element_init(&(lp->node)); |
413 | eina_clist_init(&(lp->messages)); | 325 | eina_clist_init(&(lp->messages)); |
414 | 326 | ||
@@ -439,18 +351,6 @@ void newProc(const char *code, int file, script *lp) | |||
439 | } | 351 | } |
440 | } | 352 | } |
441 | 353 | ||
442 | /* moves values between lua states' stacks */ | ||
443 | static void luaproc_movevalues( lua_State *Lfrom, lua_State *Lto ) { | ||
444 | |||
445 | int i; | ||
446 | int n = lua_gettop( Lfrom ); | ||
447 | |||
448 | /* move values between lua states' stacks */ | ||
449 | for ( i = 2; i <= n; i++ ) { | ||
450 | lua_pushstring( Lto, lua_tostring( Lfrom, i )); | ||
451 | } | ||
452 | } | ||
453 | |||
454 | /* return the lua process associated with a given lua state */ | 354 | /* return the lua process associated with a given lua state */ |
455 | static script *luaproc_getself(lua_State *L) | 355 | static script *luaproc_getself(lua_State *L) |
456 | { | 356 | { |
@@ -462,70 +362,26 @@ static script *luaproc_getself(lua_State *L) | |||
462 | return lp; | 362 | return lp; |
463 | } | 363 | } |
464 | 364 | ||
465 | /* create a new channel */ | 365 | /* send a message to the client process */ |
466 | static int luaproc_create_channel(lua_State *L) | 366 | static int luaproc_send_back(lua_State *L) |
467 | { | 367 | { |
468 | const char *name = luaL_checkstring(L, 1); | 368 | script *self = luaproc_getself(L); |
469 | channel chan; | 369 | const char *message = luaL_checkstring(L, 1); |
470 | 370 | ||
471 | /* get exclusive access to operate on channels */ | 371 | if (self) |
472 | pthread_mutex_lock(&mutex_channel); | ||
473 | |||
474 | /* check if channel exists */ | ||
475 | if (eina_hash_find(channels, name) != NULL) | ||
476 | { | 372 | { |
477 | /* free access to operate on channels */ | 373 | scriptMessage *sm = calloc(1, sizeof(scriptMessage)); |
478 | pthread_mutex_unlock(&mutex_channel); | ||
479 | /* return an error to lua */ | ||
480 | lua_pushnil(L); | ||
481 | lua_pushstring(L, "channel already exists"); | ||
482 | return 2; | ||
483 | } | ||
484 | |||
485 | /* get exclusive access to the channel table */ | ||
486 | pthread_mutex_lock(&mutex_channel_lstate); | ||
487 | |||
488 | /* create a new channel */ | ||
489 | chan = (channel) calloc(1, sizeof(struct stchannel)); | ||
490 | eina_clist_init(&(chan->send)); | ||
491 | eina_clist_init(&(chan->recv)); | ||
492 | chan->mutex = (pthread_mutex_t *) malloc(sizeof(pthread_mutex_t)); | ||
493 | pthread_mutex_init( chan->mutex, NULL ); | ||
494 | chan->in_use = (pthread_cond_t *) malloc(sizeof(pthread_cond_t)); | ||
495 | pthread_cond_init(chan->in_use, NULL); | ||
496 | eina_hash_add(channels, name, chan); | ||
497 | |||
498 | /* let others access the channel table */ | ||
499 | pthread_mutex_unlock(&mutex_channel_lstate); | ||
500 | |||
501 | /* free access to operate on channels */ | ||
502 | pthread_mutex_unlock(&mutex_channel); | ||
503 | |||
504 | lua_pushboolean(L, TRUE); | ||
505 | return 1; | ||
506 | } | ||
507 | 374 | ||
508 | /* send a message to the client process */ | 375 | if (sm) |
509 | static int luaproc_send_back( lua_State *L ) { | ||
510 | |||
511 | script *self; | ||
512 | const char *message = luaL_checkstring( L, 1 ); | ||
513 | |||
514 | self = luaproc_getself(L); | ||
515 | if (self) | ||
516 | { | 376 | { |
517 | scriptMessage *sm = calloc(1, sizeof(scriptMessage)); | 377 | eina_clist_element_init(&(sm->node)); |
518 | 378 | sm->script = self; | |
519 | if (sm) | 379 | strcpy((char *) sm->message, message); |
520 | { | 380 | ecore_main_loop_thread_safe_call_async(scriptSendBack, sm); |
521 | eina_clist_element_init(&(sm->node)); | ||
522 | sm->script = self; | ||
523 | strcpy((char *) sm->message, message); | ||
524 | ecore_main_loop_thread_safe_call_async(scriptSendBack, sm); | ||
525 | } | ||
526 | } | 381 | } |
382 | } | ||
527 | 383 | ||
528 | return 0; | 384 | return 0; |
529 | } | 385 | } |
530 | 386 | ||
531 | /* error messages for the sendToChannel function */ | 387 | /* error messages for the sendToChannel function */ |
@@ -536,224 +392,105 @@ const char *sendToChannelErrors[] = | |||
536 | }; | 392 | }; |
537 | 393 | ||
538 | /* send a message to a lua process */ | 394 | /* send a message to a lua process */ |
539 | const char *sendToChannel(gameGlobals *game, const char *chname, const char *message, script **dst, channel *chn) | 395 | const char *sendToChannel(gameGlobals *game, const char *SID, const char *message) |
540 | { | 396 | { |
541 | const char *result = NULL; | 397 | const char *result = NULL; |
542 | channel chan; | ||
543 | script *dstlp; | 398 | script *dstlp; |
544 | scriptMessage *sm = NULL; | ||
545 | 399 | ||
546 | /* get exclusive access to operate on channels */ | 400 | /* get exclusive access to operate on channels */ |
547 | pthread_mutex_lock(&mutex_channel); | 401 | pthread_mutex_lock(&mutex_channel); |
548 | 402 | ||
549 | // Add the message to the queue. | 403 | // Add the message to the queue. |
550 | if ((dstlp = eina_hash_find(game->scripts, chname))) | 404 | if ((dstlp = eina_hash_find(game->scripts, SID))) |
551 | { | 405 | { |
406 | scriptMessage *sm = NULL; | ||
407 | |||
552 | if ((sm = malloc(sizeof(scriptMessage)))) | 408 | if ((sm = malloc(sizeof(scriptMessage)))) |
553 | { | 409 | { |
554 | sm->script = dstlp; | 410 | sm->script = dstlp; |
555 | strcpy((char *) sm->message, message); | 411 | strcpy((char *) sm->message, message); |
556 | eina_clist_add_tail(&(sm->script->messages), &(sm->node)); | 412 | eina_clist_add_tail(&(dstlp->messages), &(sm->node)); |
557 | } | 413 | } |
558 | } | ||
559 | |||
560 | /* wait until channel is not in use */ | ||
561 | while( ((chan = eina_hash_find(channels, chname)) != NULL) && (pthread_mutex_trylock(chan->mutex) != 0 )) | ||
562 | { | ||
563 | pthread_cond_wait(chan->in_use, &mutex_channel); | ||
564 | } | ||
565 | |||
566 | /* free access to operate on channels */ | ||
567 | pthread_mutex_unlock(&mutex_channel); | ||
568 | |||
569 | /* if channel is not found, return an error */ | ||
570 | if (chan == NULL) | ||
571 | return sendToChannelErrors[0]; | ||
572 | |||
573 | /* try to find a matching receiver */ | ||
574 | dstlp = luaproc_dequeue_receiver(chan); | ||
575 | |||
576 | /* if a match is found, send the message to it and (queue) wake it */ | ||
577 | if (dstlp != NULL) | ||
578 | { | ||
579 | scriptMessage *msg = (scriptMessage *) eina_clist_head(&(dstlp->messages)); | ||
580 | 414 | ||
581 | // 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. | 415 | /* if it's already waiting, send the next message to it and (queue) wake it */ |
582 | if (msg) | 416 | if (dstlp->status == LUAPROC_STAT_BLOCKED_RECV) |
583 | { | 417 | { |
584 | eina_clist_remove(&(msg->node)); | 418 | scriptMessage *msg = (scriptMessage *) eina_clist_head(&(dstlp->messages)); |
585 | message = msg->message; | ||
586 | } | ||
587 | /* push the message onto the receivers stack */ | ||
588 | lua_pushstring(dstlp->L, message); | ||
589 | dstlp->args = lua_gettop(dstlp->L) - 1; | ||
590 | if (msg) | ||
591 | free(msg); | ||
592 | |||
593 | if (sched_queue_proc(dstlp) != LUAPROC_SCHED_QUEUE_PROC_OK) | ||
594 | { | ||
595 | /* unlock channel access */ | ||
596 | luaproc_unlock_channel(chan); | ||
597 | 419 | ||
598 | /* decrease active luaproc count */ | 420 | // 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. |
599 | sched_lpcount_dec(); | 421 | if (msg) |
422 | { | ||
423 | eina_clist_remove(&(msg->node)); | ||
424 | message = msg->message; | ||
425 | } | ||
426 | /* push the message onto the receivers stack */ | ||
427 | lua_pushstring(dstlp->L, message); | ||
428 | dstlp->args = lua_gettop(dstlp->L) - 1; | ||
429 | if (msg) | ||
430 | free(msg); | ||
600 | 431 | ||
601 | /* close lua_State */ | 432 | if (sched_queue_proc(dstlp) != LUAPROC_SCHED_QUEUE_PROC_OK) |
602 | lua_close(dstlp->L); | 433 | { |
603 | return sendToChannelErrors[1]; | 434 | sched_lpcount_dec(); |
435 | lua_close(dstlp->L); | ||
436 | result = sendToChannelErrors[1]; | ||
437 | } | ||
604 | } | 438 | } |
605 | |||
606 | /* unlock channel access */ | ||
607 | luaproc_unlock_channel(chan); | ||
608 | } | 439 | } |
609 | else if (dst) | ||
610 | *dst = dstlp; | ||
611 | 440 | ||
612 | if (chn) | 441 | pthread_mutex_unlock(&mutex_channel); |
613 | chn = &chan; | 442 | |
614 | return result; | 443 | return result; |
615 | } | 444 | } |
616 | 445 | ||
617 | /* send a message to a lua process */ | 446 | /* send a message to a lua process */ |
618 | static int luaproc_send( lua_State *L ) { | 447 | static int luaproc_send(lua_State *L) |
619 | 448 | { | |
620 | channel chan; | 449 | script *self = luaproc_getself(L); |
621 | script *dstlp, *self = luaproc_getself(L); | 450 | const char *result = sendToChannel(self->game, luaL_checkstring(L, 1), luaL_checkstring(L, 2)); |
622 | const char *chname = luaL_checkstring( L, 1 ); | ||
623 | const char *message = luaL_checkstring( L, 2 ); | ||
624 | const char *result = sendToChannel(self->game, chname, message, &dstlp, &chan); | ||
625 | |||
626 | if (result) { | ||
627 | lua_pushnil( L ); | ||
628 | lua_pushstring( L, result ); | ||
629 | return 2; | ||
630 | } | ||
631 | |||
632 | if ( dstlp == NULL ) { | ||
633 | |||
634 | if ( self != NULL ) { | ||
635 | self->status = LUAPROC_STAT_BLOCKED_SEND; | ||
636 | self->chan = chan; | ||
637 | } | ||
638 | 451 | ||
639 | /* just yield the lua process, channel unlocking will be done by the scheduler */ | 452 | if (result) |
640 | return lua_yield( L, lua_gettop( L )); | 453 | { |
641 | } | 454 | lua_pushnil(L); |
455 | lua_pushstring(L, result); | ||
456 | return 2; | ||
457 | } | ||
642 | 458 | ||
643 | lua_pushboolean( L, TRUE ); | 459 | lua_pushboolean(L, TRUE); |
644 | return 1; | 460 | return 1; |
645 | } | 461 | } |
646 | 462 | ||
647 | /* receive a message from a lua process */ | 463 | /* receive a message from a lua process */ |
648 | static int luaproc_receive( lua_State *L ) { | 464 | static int luaproc_receive(lua_State *L) |
649 | 465 | { | |
650 | channel chan; | 466 | script *self; |
651 | script *srclp, *self; | 467 | const char *chname = luaL_checkstring(L, 1); |
652 | const char *chname = luaL_checkstring( L, 1 ); | 468 | scriptMessage *msg; |
653 | scriptMessage *msg; | ||
654 | |||
655 | // First check if there are queued messages, and grab one. | ||
656 | self = luaproc_getself(L); | ||
657 | if ((msg = (scriptMessage *) eina_clist_head(&(self->messages)))) | ||
658 | { | ||
659 | eina_clist_remove(&(msg->node)); | ||
660 | lua_pushstring(L, msg->message); | ||
661 | free(msg); | ||
662 | return lua_gettop(L) - 1; | ||
663 | } | ||
664 | |||
665 | /* get exclusive access to operate on channels */ | ||
666 | pthread_mutex_lock( &mutex_channel ); | ||
667 | |||
668 | /* wait until channel is not in use */ | ||
669 | while((( chan = eina_hash_find(channels, chname)) != NULL ) && ( pthread_mutex_trylock(chan->mutex) != 0 )) { | ||
670 | pthread_cond_wait(chan->in_use, &mutex_channel ); | ||
671 | } | ||
672 | |||
673 | /* free access to operate on channels */ | ||
674 | pthread_mutex_unlock( &mutex_channel ); | ||
675 | |||
676 | /* if channel is not found, free access to operate on channels and return an error to Lua */ | ||
677 | if ( chan == NULL ) { | ||
678 | lua_pushnil( L ); | ||
679 | lua_pushstring( L, "non-existent channel" ); | ||
680 | return 2; | ||
681 | } | ||
682 | |||
683 | /* try to find a matching sender */ | ||
684 | srclp = luaproc_dequeue_sender( chan ); | ||
685 | |||
686 | /* if a match is found, get values from it and (queue) wake it */ | ||
687 | if ( srclp != NULL ) { | ||
688 | |||
689 | /* move values between Lua states' stacks */ | ||
690 | luaproc_movevalues( srclp->L, L ); | ||
691 | |||
692 | /* return to sender indicanting message was sent */ | ||
693 | lua_pushboolean( srclp->L, TRUE ); | ||
694 | srclp->args = 1; | ||
695 | |||
696 | if ( sched_queue_proc( srclp ) != LUAPROC_SCHED_QUEUE_PROC_OK ) { | ||
697 | |||
698 | /* unlock channel access */ | ||
699 | luaproc_unlock_channel( chan ); | ||
700 | |||
701 | /* decrease active luaproc count */ | ||
702 | sched_lpcount_dec(); | ||
703 | |||
704 | /* close lua_State */ | ||
705 | lua_close( srclp->L ); | ||
706 | lua_pushnil( L ); | ||
707 | lua_pushstring( L, "error scheduling process" ); | ||
708 | return 2; | ||
709 | } | ||
710 | |||
711 | /* unlock channel access */ | ||
712 | luaproc_unlock_channel( chan ); | ||
713 | |||
714 | return lua_gettop( L ) - 1; | ||
715 | } | ||
716 | |||
717 | /* otherwise queue (block) the receiving process (sync) or return immediatly (async) */ | ||
718 | else { | ||
719 | |||
720 | /* if trying an asynchronous receive, unlock channel access and return an error */ | ||
721 | if ( lua_toboolean( L, 2 )) { | ||
722 | /* unlock channel access */ | ||
723 | luaproc_unlock_channel( chan ); | ||
724 | /* return an error */ | ||
725 | lua_pushnil( L ); | ||
726 | lua_pushfstring( L, "no senders waiting on channel %s", chname ); | ||
727 | return 2; | ||
728 | } | ||
729 | |||
730 | /* otherwise (synchronous receive) simply block process */ | ||
731 | else { | ||
732 | 469 | ||
733 | if ( self != NULL ) { | 470 | // First check if there are queued messages, and grab one. |
734 | self->status = LUAPROC_STAT_BLOCKED_RECV; | 471 | self = luaproc_getself(L); |
735 | self->chan = chan; | 472 | if ((msg = (scriptMessage *) eina_clist_head(&(self->messages)))) |
736 | } | 473 | { |
474 | eina_clist_remove(&(msg->node)); | ||
475 | lua_pushstring(L, msg->message); | ||
476 | free(msg); | ||
477 | return lua_gettop(L) - 1; | ||
478 | } | ||
737 | 479 | ||
738 | /* just yield the lua process, channel unlocking will be done by the scheduler */ | 480 | /* if trying an asynchronous receive, return an error */ |
739 | return lua_yield( L, lua_gettop( L )); | 481 | if ( lua_toboolean( L, 2 )) |
740 | } | 482 | { |
741 | } | 483 | lua_pushnil(L); |
484 | lua_pushfstring(L, "no senders waiting on channel %s", chname); | ||
485 | return 2; | ||
486 | } | ||
487 | /* otherwise (synchronous receive) simply block process */ | ||
488 | self->status = LUAPROC_STAT_BLOCKED_RECV; | ||
489 | return lua_yield(L, lua_gettop(L)); | ||
742 | } | 490 | } |
743 | 491 | ||
744 | void luaprocInit(void) | 492 | void luaprocInit(void) |
745 | { | 493 | { |
746 | eina_clist_init(&recyclelp); | 494 | eina_clist_init(&recyclelp); |
747 | |||
748 | int tid; | ||
749 | pthread_t worker; | ||
750 | |||
751 | eina_clist_init(&lpready); | 495 | eina_clist_init(&lpready); |
752 | channels = eina_hash_string_superfast_new(NULL); | ||
753 | |||
754 | /* create initial worker threads */ | ||
755 | for (tid = 0; tid < LUAPROC_SCHED_DEFAULT_WORKER_THREADS; tid++) | ||
756 | { | ||
757 | pthread_create( &worker, NULL, workermain, NULL); | ||
758 | } | ||
759 | } | 496 | } |
diff --git a/LuaSL/src/LuaSL_threads.h b/LuaSL/src/LuaSL_threads.h index b7f6449..78c6639 100644 --- a/LuaSL/src/LuaSL_threads.h +++ b/LuaSL/src/LuaSL_threads.h | |||
@@ -43,17 +43,10 @@ THE SOFTWARE. | |||
43 | #define LUAPROC_SCHED_INIT_ERROR -7 | 43 | #define LUAPROC_SCHED_INIT_ERROR -7 |
44 | 44 | ||
45 | 45 | ||
46 | /* message channel pointer type */ | ||
47 | typedef struct stchannel *channel; | ||
48 | |||
49 | |||
50 | void luaprocInit(void); | 46 | void luaprocInit(void); |
51 | |||
52 | /* create a new worker pthread */ | ||
53 | int sched_create_worker(void); | 47 | int sched_create_worker(void); |
54 | |||
55 | void newProc(const char *code, int file, script *lp); | 48 | void newProc(const char *code, int file, script *lp); |
56 | const char *sendToChannel(gameGlobals *game, const char *chname, const char *message, script **dst, channel *chn); | 49 | const char *sendToChannel(gameGlobals *game, const char *SID, const char *message); |
57 | 50 | ||
58 | /* join all worker threads and exit */ | 51 | /* join all worker threads and exit */ |
59 | void sched_join_workerthreads(void); | 52 | void sched_join_workerthreads(void); |