diff options
author | David Walter Seikel | 2012-02-25 00:09:31 +1000 |
---|---|---|
committer | David Walter Seikel | 2012-02-25 00:09:31 +1000 |
commit | eff5b6e0fc5d7106a1a38967c3bbcbf73fdd6e44 (patch) | |
tree | ea1acf1bbd9fdd1f9905a7327183f0fe2bd87468 | |
parent | Time to fork luaproc and turn it into an EFL based thing, with tighter integr... (diff) | |
download | SledjHamr-eff5b6e0fc5d7106a1a38967c3bbcbf73fdd6e44.zip SledjHamr-eff5b6e0fc5d7106a1a38967c3bbcbf73fdd6e44.tar.gz SledjHamr-eff5b6e0fc5d7106a1a38967c3bbcbf73fdd6e44.tar.bz2 SledjHamr-eff5b6e0fc5d7106a1a38967c3bbcbf73fdd6e44.tar.xz |
Moved luaproc into LuaSL, merged it all into it's own file, and replaced the luaproc list with Eina_Clist.
From this point on, luaproc is officialy forked.
-rwxr-xr-x | LuaSL/build.sh | 2 | ||||
-rw-r--r-- | LuaSL/src/LuaSL.h | 1 | ||||
-rw-r--r-- | LuaSL/src/LuaSL_LSL_tree.h | 5 | ||||
-rw-r--r-- | LuaSL/src/LuaSL_threads.c | 1229 | ||||
-rw-r--r-- | LuaSL/src/LuaSL_threads.h (renamed from libraries/luaproc/luaproc.h) | 115 | ||||
-rwxr-xr-x | build.sh | 6 | ||||
-rw-r--r-- | libraries/README | 2 | ||||
-rw-r--r-- | libraries/luaproc/COPYRIGHT | 32 | ||||
-rw-r--r-- | libraries/luaproc/Lua_multithreading_ry08-05.pdf | bin | 135164 -> 0 bytes | |||
-rw-r--r-- | libraries/luaproc/Makefile | 65 | ||||
-rw-r--r-- | libraries/luaproc/README | 97 | ||||
-rw-r--r-- | libraries/luaproc/channel.c | 151 | ||||
-rw-r--r-- | libraries/luaproc/channel.h | 67 | ||||
-rw-r--r-- | libraries/luaproc/list.c | 241 | ||||
-rw-r--r-- | libraries/luaproc/list.h | 76 | ||||
-rw-r--r-- | libraries/luaproc/luaproc.c | 931 | ||||
-rw-r--r-- | libraries/luaproc/luaproc.lua | 34 | ||||
-rw-r--r-- | libraries/luaproc/sched.c | 356 | ||||
-rw-r--r-- | libraries/luaproc/sched.h | 78 | ||||
-rw-r--r-- | libraries/luaproc/test.lua | 39 |
20 files changed, 1334 insertions, 2193 deletions
diff --git a/LuaSL/build.sh b/LuaSL/build.sh index 39d3a55..447c04a 100755 --- a/LuaSL/build.sh +++ b/LuaSL/build.sh | |||
@@ -64,7 +64,7 @@ echo $command | |||
64 | $command | 64 | $command |
65 | 65 | ||
66 | names="LuaSL_main LuaSL_compile LuaSL_threads LuaSL_utilities LuaSL_lexer LuaSL_lemon_yaccer" | 66 | names="LuaSL_main LuaSL_compile LuaSL_threads LuaSL_utilities LuaSL_lexer LuaSL_lemon_yaccer" |
67 | objects="../../libraries/luaproc/channel.o ../../libraries/luaproc/list.o ../../libraries/luaproc/luaproc.o ../../libraries/luaproc/sched.o " | 67 | objects="" |
68 | for i in $names | 68 | for i in $names |
69 | do | 69 | do |
70 | command="gcc $CFLAGS -c -o $i.o $i.c" | 70 | command="gcc $CFLAGS -c -o $i.o $i.c" |
diff --git a/LuaSL/src/LuaSL.h b/LuaSL/src/LuaSL.h index f03b885..d27f501 100644 --- a/LuaSL/src/LuaSL.h +++ b/LuaSL/src/LuaSL.h | |||
@@ -1,4 +1,3 @@ | |||
1 | //#include <Elementary.h> | ||
2 | #ifdef HAVE_CONFIG_H | 1 | #ifdef HAVE_CONFIG_H |
3 | #include "config.h" | 2 | #include "config.h" |
4 | #else | 3 | #else |
diff --git a/LuaSL/src/LuaSL_LSL_tree.h b/LuaSL/src/LuaSL_LSL_tree.h index cbc34b3..eb58e79 100644 --- a/LuaSL/src/LuaSL_LSL_tree.h +++ b/LuaSL/src/LuaSL_LSL_tree.h | |||
@@ -13,9 +13,6 @@ | |||
13 | 13 | ||
14 | #include "assert.h" | 14 | #include "assert.h" |
15 | #include <unistd.h> | 15 | #include <unistd.h> |
16 | #include <sys/types.h> | ||
17 | #include <sys/stat.h> | ||
18 | #include <fcntl.h> | ||
19 | #include <stdlib.h> | 16 | #include <stdlib.h> |
20 | #include <stdio.h> | 17 | #include <stdio.h> |
21 | #include <limits.h> // For PATH_MAX. | 18 | #include <limits.h> // For PATH_MAX. |
@@ -25,7 +22,7 @@ | |||
25 | #include <lualib.h> | 22 | #include <lualib.h> |
26 | #include <lauxlib.h> | 23 | #include <lauxlib.h> |
27 | 24 | ||
28 | #include <luaproc/sched.h> | 25 | #include "LuaSL_threads.h" |
29 | 26 | ||
30 | #include "LuaSL_lemon_yaccer.h" | 27 | #include "LuaSL_lemon_yaccer.h" |
31 | 28 | ||
diff --git a/LuaSL/src/LuaSL_threads.c b/LuaSL/src/LuaSL_threads.c index eb809b3..a15b506 100644 --- a/LuaSL/src/LuaSL_threads.c +++ b/LuaSL/src/LuaSL_threads.c | |||
@@ -32,19 +32,1238 @@ THE SOFTWARE. | |||
32 | 32 | ||
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 | * Use eina lists instead of the rolled your own lists. | ||
36 | * Looks like a FIFO double linked list. | ||
37 | * Use ecore threads instead of raw pthreads. | 35 | * Use ecore threads instead of raw pthreads. |
38 | * Ecore threads pretty much wraps pthreads on posix, but has Windows support to. | 36 | * Ecore threads pretty much wraps pthreads on posix, but has Windows support to. |
39 | * In general use EFL where it is useful. | 37 | * In general use EFL where it is useful. |
40 | * One fixed unique message channel per script. | 38 | * One fixed unique message channel per script. |
41 | * Probably one fixed unique message channel per object, which each script in the object shares. | 39 | * Probably one fixed unique message channel per object, which each script in the object shares. |
42 | * But might be better to handle that C side anyway. | 40 | * But might be better to handle that C side anyway. |
43 | * FIFO queue on message channels, seems the C socket queue is not enough. | 41 | * No need for channel.c / .h, we are not using that sort of arbitrary channels. |
44 | * On the other hand, could just peel messages the socket queue, then shove them on the scripts queue. | 42 | * FIFO queue on message channels, seems the C socket queue is not enough. |
43 | * On the other hand, could just peel messages of the socket queue, then shove them on the scripts queue. | ||
45 | * Better integration with LuaSL. | 44 | * Better integration with LuaSL. |
46 | * Merge the luaproc structure with the script structure. | 45 | * Merge the luaproc structure with the script structure. |
47 | * 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. | 46 | * 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. |
47 | * Get rid of luaproc.lua, should not need it. | ||
48 | * Use my coding standards, or EFL ones. Pffft. | 48 | * Use my coding standards, or EFL ones. Pffft. |
49 | * | 49 | * |
50 | */ | 50 | */ |
51 | |||
52 | #include "LuaSL.h" | ||
53 | |||
54 | #include <netdb.h> | ||
55 | #include <pthread.h> | ||
56 | #include <string.h> | ||
57 | #include <arpa/inet.h> | ||
58 | #include <sys/select.h> | ||
59 | #include <sys/socket.h> | ||
60 | |||
61 | |||
62 | /********* | ||
63 | * globals | ||
64 | *********/ | ||
65 | |||
66 | /* global channel lua_State mutex */ | ||
67 | pthread_mutex_t mutex_channel_lstate = PTHREAD_MUTEX_INITIALIZER; | ||
68 | |||
69 | /* global lua_State where channel hash table will be stored */ | ||
70 | lua_State *chanls = NULL; | ||
71 | |||
72 | /* message channel */ | ||
73 | struct stchannel { | ||
74 | Eina_Clist send; | ||
75 | Eina_Clist recv; | ||
76 | pthread_mutex_t *mutex; | ||
77 | pthread_cond_t *in_use; | ||
78 | }; | ||
79 | |||
80 | |||
81 | |||
82 | /* ready process list */ | ||
83 | Eina_Clist lpready; | ||
84 | |||
85 | /* ready process queue access mutex */ | ||
86 | pthread_mutex_t mutex_queue_access = PTHREAD_MUTEX_INITIALIZER; | ||
87 | |||
88 | /* wake worker up conditional variable */ | ||
89 | pthread_cond_t cond_wakeup_worker = PTHREAD_COND_INITIALIZER; | ||
90 | |||
91 | /* active luaproc count access mutex */ | ||
92 | pthread_mutex_t mutex_lp_count = PTHREAD_MUTEX_INITIALIZER; | ||
93 | |||
94 | /* no active luaproc conditional variable */ | ||
95 | pthread_cond_t cond_no_active_lp = PTHREAD_COND_INITIALIZER; | ||
96 | |||
97 | /* number of active luaprocs */ | ||
98 | int lpcount = 0; | ||
99 | |||
100 | /* no more lua processes flag */ | ||
101 | int no_more_processes = FALSE; | ||
102 | |||
103 | |||
104 | |||
105 | /* channel operations mutex */ | ||
106 | pthread_mutex_t mutex_channel = PTHREAD_MUTEX_INITIALIZER; | ||
107 | |||
108 | /* recycle list mutex */ | ||
109 | pthread_mutex_t mutex_recycle_list = PTHREAD_MUTEX_INITIALIZER; | ||
110 | |||
111 | /* recycled lua process list */ | ||
112 | Eina_Clist recyclelp; | ||
113 | |||
114 | /* maximum lua processes to recycle */ | ||
115 | int recyclemax = 0; | ||
116 | |||
117 | /* lua process */ | ||
118 | struct stluaproc { | ||
119 | Eina_Clist node; | ||
120 | lua_State *lstate; | ||
121 | int stat; | ||
122 | int args; | ||
123 | channel chan; | ||
124 | int destroyworker; | ||
125 | void *data; | ||
126 | Ecore_Cb callback; | ||
127 | }; | ||
128 | |||
129 | |||
130 | |||
131 | /****************************** | ||
132 | * library functions prototypes | ||
133 | ******************************/ | ||
134 | /* create a new lua process */ | ||
135 | static int luaproc_create_newproc( lua_State *L ); | ||
136 | /* send a message to a lua process */ | ||
137 | static int luaproc_send( lua_State *L ); | ||
138 | /* receive a message from a lua process */ | ||
139 | static int luaproc_receive( lua_State *L ); | ||
140 | /* create a new channel */ | ||
141 | static int luaproc_create_channel( lua_State *L ); | ||
142 | /* destroy a channel */ | ||
143 | static int luaproc_destroy_channel( lua_State *L ); | ||
144 | /* wait until all luaprocs have finished and exit */ | ||
145 | static int luaproc_exit( lua_State *L ); | ||
146 | /* create a new worker */ | ||
147 | static int luaproc_create_worker( lua_State *L ); | ||
148 | /* destroy a worker */ | ||
149 | static int luaproc_destroy_worker( lua_State *L ); | ||
150 | /* set amount of lua processes that should be recycled (ie, reused) */ | ||
151 | static int luaproc_recycle_set( lua_State *L ); | ||
152 | /* send a message back to the main loop */ | ||
153 | static int luaproc_send_back( lua_State *L ); | ||
154 | |||
155 | /* luaproc function registration array - main (parent) functions */ | ||
156 | static const struct luaL_reg luaproc_funcs_parent[] = { | ||
157 | { "newproc", luaproc_create_newproc }, | ||
158 | { "exit", luaproc_exit }, | ||
159 | { "createworker", luaproc_create_worker }, | ||
160 | { "destroyworker", luaproc_destroy_worker }, | ||
161 | { "recycle", luaproc_recycle_set }, | ||
162 | { "sendback", luaproc_send_back }, | ||
163 | { NULL, NULL } | ||
164 | }; | ||
165 | |||
166 | /* luaproc function registration array - newproc (child) functions */ | ||
167 | static const struct luaL_reg luaproc_funcs_child[] = { | ||
168 | { "newproc", luaproc_create_newproc }, | ||
169 | { "send", luaproc_send }, | ||
170 | { "receive", luaproc_receive }, | ||
171 | { "newchannel", luaproc_create_channel }, | ||
172 | { "delchannel", luaproc_destroy_channel }, | ||
173 | { "createworker", luaproc_create_worker }, | ||
174 | { "destroyworker", luaproc_destroy_worker }, | ||
175 | { "recycle", luaproc_recycle_set }, | ||
176 | { "sendback", luaproc_send_back }, | ||
177 | { NULL, NULL } | ||
178 | }; | ||
179 | |||
180 | |||
181 | |||
182 | |||
183 | /* initialize channel table */ | ||
184 | void channel_init( void ) { | ||
185 | chanls = luaL_newstate(); | ||
186 | lua_newtable( chanls ); | ||
187 | lua_setglobal( chanls, "channeltb" ); | ||
188 | } | ||
189 | |||
190 | /* create new channel */ | ||
191 | channel channel_create( const char *cname ) { | ||
192 | |||
193 | channel chan; | ||
194 | |||
195 | /* get exclusive access to the channel table */ | ||
196 | pthread_mutex_lock( &mutex_channel_lstate ); | ||
197 | |||
198 | /* create a new channel */ | ||
199 | lua_getglobal( chanls, "channeltb"); | ||
200 | lua_pushstring( chanls, cname ); | ||
201 | chan = (channel )lua_newuserdata( chanls, sizeof( struct stchannel )); | ||
202 | eina_clist_init(&(chan->send)); | ||
203 | eina_clist_init(&(chan->recv)); | ||
204 | chan->mutex = (pthread_mutex_t *)malloc( sizeof( pthread_mutex_t )); | ||
205 | pthread_mutex_init( chan->mutex, NULL ); | ||
206 | chan->in_use = (pthread_cond_t *)malloc( sizeof( pthread_cond_t )); | ||
207 | pthread_cond_init( chan->in_use, NULL ); | ||
208 | lua_settable( chanls, -3 ); | ||
209 | lua_pop( chanls, 1 ); | ||
210 | |||
211 | /* let others access the channel table */ | ||
212 | pthread_mutex_unlock( &mutex_channel_lstate ); | ||
213 | |||
214 | return chan; | ||
215 | } | ||
216 | |||
217 | /* destroy a channel */ | ||
218 | int channel_destroy( channel chan, const char *chname ) { | ||
219 | |||
220 | /* get exclusive access to the channel table */ | ||
221 | pthread_mutex_lock( &mutex_channel_lstate ); | ||
222 | |||
223 | lua_getglobal( chanls, "channeltb"); | ||
224 | lua_pushstring( chanls, chname ); | ||
225 | lua_pushnil( chanls ); | ||
226 | lua_settable( chanls, -3 ); | ||
227 | lua_pop( chanls, 1 ); | ||
228 | |||
229 | /* let others access the channel table */ | ||
230 | pthread_mutex_unlock( &mutex_channel_lstate ); | ||
231 | |||
232 | return CHANNEL_DESTROYED; | ||
233 | } | ||
234 | |||
235 | /* search for and return a channel with a given name */ | ||
236 | channel channel_search( const char *cname ) { | ||
237 | |||
238 | channel chan; | ||
239 | |||
240 | /* get exclusive access to the channel table */ | ||
241 | pthread_mutex_lock( &mutex_channel_lstate ); | ||
242 | |||
243 | /* search for channel */ | ||
244 | lua_getglobal( chanls, "channeltb"); | ||
245 | lua_getfield( chanls, -1, cname ); | ||
246 | if (( lua_type( chanls, -1 )) == LUA_TUSERDATA ) { | ||
247 | chan = (channel )lua_touserdata( chanls, -1 ); | ||
248 | } else { | ||
249 | chan = NULL; | ||
250 | } | ||
251 | lua_pop( chanls, 2 ); | ||
252 | |||
253 | /* let others access channel table */ | ||
254 | pthread_mutex_unlock( &mutex_channel_lstate ); | ||
255 | |||
256 | return chan; | ||
257 | } | ||
258 | |||
259 | /* return a channel's send queue */ | ||
260 | Eina_Clist *channel_get_sendq( channel chan ) { | ||
261 | return &chan->send; | ||
262 | } | ||
263 | |||
264 | /* return a channel's receive queue */ | ||
265 | Eina_Clist *channel_get_recvq( channel chan ) { | ||
266 | return &chan->recv; | ||
267 | } | ||
268 | |||
269 | /* return a channel's mutex */ | ||
270 | pthread_mutex_t *channel_get_mutex( channel chan ) { | ||
271 | return chan->mutex; | ||
272 | } | ||
273 | |||
274 | /* return a channel's conditional variable */ | ||
275 | pthread_cond_t *channel_get_cond( channel chan ) { | ||
276 | return chan->in_use; | ||
277 | } | ||
278 | |||
279 | |||
280 | |||
281 | |||
282 | /* worker thread main function */ | ||
283 | void *workermain( void *args ) { | ||
284 | |||
285 | luaproc lp; | ||
286 | int procstat; | ||
287 | int destroyworker; | ||
288 | |||
289 | /* detach thread so resources are freed as soon as thread exits (no further joining) */ | ||
290 | pthread_detach( pthread_self( )); | ||
291 | |||
292 | /* main worker loop */ | ||
293 | while ( 1 ) { | ||
294 | |||
295 | /* get exclusive access to the ready process queue */ | ||
296 | pthread_mutex_lock( &mutex_queue_access ); | ||
297 | |||
298 | /* wait until instructed to wake up (because there's work to do or because its time to finish) */ | ||
299 | while (( eina_clist_count( &lpready ) == 0 ) && ( no_more_processes == FALSE )) { | ||
300 | pthread_cond_wait( &cond_wakeup_worker, &mutex_queue_access ); | ||
301 | } | ||
302 | |||
303 | /* pop the first node from the ready process queue */ | ||
304 | if ((lp = (luaproc) eina_clist_head(&lpready))) | ||
305 | eina_clist_remove(&(lp->node)); | ||
306 | else { | ||
307 | /* free access to the process ready queue */ | ||
308 | pthread_mutex_unlock( &mutex_queue_access ); | ||
309 | /* finished thread */ | ||
310 | pthread_exit( NULL ); | ||
311 | } | ||
312 | |||
313 | /* free access to the process ready queue */ | ||
314 | pthread_mutex_unlock( &mutex_queue_access ); | ||
315 | |||
316 | /* execute the lua code specified in the lua process struct */ | ||
317 | procstat = lua_resume( luaproc_get_state( lp ), luaproc_get_args( lp )); | ||
318 | |||
319 | /* reset the process argument count */ | ||
320 | luaproc_set_args( lp, 0 ); | ||
321 | |||
322 | /* check if process finished its whole execution */ | ||
323 | if ( procstat == 0 ) { | ||
324 | |||
325 | /* check if worker thread should be destroyed */ | ||
326 | destroyworker = luaproc_get_destroyworker( lp ); | ||
327 | |||
328 | /* set process status to finished */ | ||
329 | luaproc_set_status( lp, LUAPROC_STAT_FINISHED ); | ||
330 | |||
331 | /* check if lua process should be recycled and, if not, destroy it */ | ||
332 | if ( luaproc_recycle_push( lp ) == FALSE ) { | ||
333 | lua_close( luaproc_get_state( lp )); | ||
334 | } | ||
335 | |||
336 | /* decrease active lua process count */ | ||
337 | sched_lpcount_dec(); | ||
338 | |||
339 | /* check if thread should be finished after lua process conclusion */ | ||
340 | if ( destroyworker ) { | ||
341 | /* if so, finish thread */ | ||
342 | pthread_exit( NULL ); | ||
343 | } | ||
344 | } | ||
345 | |||
346 | /* check if process yielded */ | ||
347 | else if ( procstat == LUA_YIELD ) { | ||
348 | |||
349 | /* if so, further check if yield originated from an unmatched send/recv operation */ | ||
350 | if ( luaproc_get_status( lp ) == LUAPROC_STAT_BLOCKED_SEND ) { | ||
351 | /* queue blocked lua process on corresponding channel */ | ||
352 | luaproc_queue_sender( lp ); | ||
353 | /* unlock channel access */ | ||
354 | luaproc_unlock_channel( luaproc_get_channel( lp )); | ||
355 | } | ||
356 | |||
357 | else if ( luaproc_get_status( lp ) == LUAPROC_STAT_BLOCKED_RECV ) { | ||
358 | /* queue blocked lua process on corresponding channel */ | ||
359 | luaproc_queue_receiver( lp ); | ||
360 | /* unlock channel access */ | ||
361 | luaproc_unlock_channel( luaproc_get_channel( lp )); | ||
362 | } | ||
363 | |||
364 | /* or if yield resulted from an explicit call to coroutine.yield in the lua code being executed */ | ||
365 | else { | ||
366 | /* get exclusive access to the ready process queue */ | ||
367 | pthread_mutex_lock( &mutex_queue_access ); | ||
368 | /* re-insert the job at the end of the ready process queue */ | ||
369 | eina_clist_add_tail(&lpready, &(lp->node)); | ||
370 | /* free access to the process ready queue */ | ||
371 | pthread_mutex_unlock( &mutex_queue_access ); | ||
372 | } | ||
373 | } | ||
374 | |||
375 | /* check if there was any execution error (LUA_ERRRUN, LUA_ERRSYNTAX, LUA_ERRMEM or LUA_ERRERR) */ | ||
376 | else { | ||
377 | /* print error message */ | ||
378 | fprintf( stderr, "close lua_State (error: %s)\n", luaL_checkstring( luaproc_get_state( lp ), -1 )); | ||
379 | /* close lua state */ | ||
380 | lua_close( luaproc_get_state( lp )); | ||
381 | /* decrease active lua process count */ | ||
382 | sched_lpcount_dec(); | ||
383 | } | ||
384 | } | ||
385 | } | ||
386 | |||
387 | /* local scheduler initialization */ | ||
388 | int sched_init_local( int numworkers ) { | ||
389 | |||
390 | int tid; | ||
391 | int workercount = 0; | ||
392 | pthread_t worker; | ||
393 | |||
394 | /* initialize ready process list */ | ||
395 | // lpready = list_new(); | ||
396 | eina_clist_init(&lpready); | ||
397 | |||
398 | /* initialize channels */ | ||
399 | channel_init(); | ||
400 | |||
401 | /* create initial worker threads */ | ||
402 | for ( tid = 0; tid < numworkers; tid++ ) { | ||
403 | if ( pthread_create( &worker, NULL, workermain, NULL ) == 0 ) { | ||
404 | workercount++; | ||
405 | } | ||
406 | } | ||
407 | |||
408 | if ( workercount != numworkers ) { | ||
409 | return LUAPROC_SCHED_INIT_ERROR; | ||
410 | } | ||
411 | |||
412 | return LUAPROC_SCHED_OK; | ||
413 | } | ||
414 | |||
415 | /* exit scheduler */ | ||
416 | void sched_exit( void ) { | ||
417 | |||
418 | /* get exclusive access to the ready process queue */ | ||
419 | pthread_mutex_lock( &mutex_queue_access ); | ||
420 | /* free access to the process ready queue */ | ||
421 | pthread_mutex_unlock( &mutex_queue_access ); | ||
422 | } | ||
423 | |||
424 | /* move process to ready queue (ie, schedule process) */ | ||
425 | int sched_queue_proc( luaproc lp ) { | ||
426 | |||
427 | /* get exclusive access to the ready process queue */ | ||
428 | pthread_mutex_lock( &mutex_queue_access ); | ||
429 | |||
430 | /* add process to ready queue */ | ||
431 | eina_clist_add_tail(&lpready, &(lp->node)); | ||
432 | |||
433 | /* set process status to ready */ | ||
434 | luaproc_set_status( lp, LUAPROC_STAT_READY ); | ||
435 | |||
436 | /* wake worker up */ | ||
437 | pthread_cond_signal( &cond_wakeup_worker ); | ||
438 | /* free access to the process ready queue */ | ||
439 | pthread_mutex_unlock( &mutex_queue_access ); | ||
440 | |||
441 | return LUAPROC_SCHED_QUEUE_PROC_OK; | ||
442 | } | ||
443 | |||
444 | /* synchronize worker threads */ | ||
445 | void sched_join_workerthreads( void ) { | ||
446 | |||
447 | pthread_mutex_lock( &mutex_lp_count ); | ||
448 | |||
449 | /* wait until there is no more active lua processes */ | ||
450 | while( lpcount != 0 ) { | ||
451 | pthread_cond_wait( &cond_no_active_lp, &mutex_lp_count ); | ||
452 | } | ||
453 | /* get exclusive access to the ready process queue */ | ||
454 | pthread_mutex_lock( &mutex_queue_access ); | ||
455 | /* set the no more active lua processes flag to true */ | ||
456 | no_more_processes = TRUE; | ||
457 | /* wake ALL workers up */ | ||
458 | pthread_cond_broadcast( &cond_wakeup_worker ); | ||
459 | /* free access to the process ready queue */ | ||
460 | pthread_mutex_unlock( &mutex_queue_access ); | ||
461 | |||
462 | // We don't need this, as we only get here during shutdown. Linking this to EFL results in a hang otherwise anyway. | ||
463 | /* wait for (join) worker threads */ | ||
464 | // pthread_exit( NULL ); | ||
465 | |||
466 | pthread_mutex_unlock( &mutex_lp_count ); | ||
467 | |||
468 | } | ||
469 | |||
470 | /* increase active lua process count */ | ||
471 | void sched_lpcount_inc( void ) { | ||
472 | pthread_mutex_lock( &mutex_lp_count ); | ||
473 | lpcount++; | ||
474 | pthread_mutex_unlock( &mutex_lp_count ); | ||
475 | } | ||
476 | |||
477 | /* decrease active lua process count */ | ||
478 | void sched_lpcount_dec( void ) { | ||
479 | pthread_mutex_lock( &mutex_lp_count ); | ||
480 | lpcount--; | ||
481 | /* if count reaches zero, signal there are no more active processes */ | ||
482 | if ( lpcount == 0 ) { | ||
483 | pthread_cond_signal( &cond_no_active_lp ); | ||
484 | } | ||
485 | pthread_mutex_unlock( &mutex_lp_count ); | ||
486 | } | ||
487 | |||
488 | /* create a new worker pthread */ | ||
489 | int sched_create_worker( void ) { | ||
490 | |||
491 | pthread_t worker; | ||
492 | |||
493 | /* create a new pthread */ | ||
494 | if ( pthread_create( &worker, NULL, workermain, NULL ) != 0 ) { | ||
495 | return LUAPROC_SCHED_PTHREAD_ERROR; | ||
496 | } | ||
497 | |||
498 | return LUAPROC_SCHED_OK; | ||
499 | } | ||
500 | |||
501 | |||
502 | |||
503 | |||
504 | /* | ||
505 | static void registerlib( lua_State *L, const char *name, lua_CFunction f ) { | ||
506 | lua_getglobal( L, "package" ); | ||
507 | lua_getfield( L, -1, "preload" ); | ||
508 | lua_pushcfunction( L, f ); | ||
509 | lua_setfield( L, -2, name ); | ||
510 | lua_pop( L, 2 ); | ||
511 | } | ||
512 | */ | ||
513 | static void openlibs( lua_State *L ) { | ||
514 | /* | ||
515 | lua_cpcall( L, luaopen_base, NULL ); | ||
516 | lua_cpcall( L, luaopen_package, NULL ); | ||
517 | registerlib( L, "io", luaopen_io ); | ||
518 | registerlib( L, "os", luaopen_os ); | ||
519 | registerlib( L, "table", luaopen_table ); | ||
520 | registerlib( L, "string", luaopen_string ); | ||
521 | registerlib( L, "math", luaopen_math ); | ||
522 | registerlib( L, "debug", luaopen_debug ); | ||
523 | */ | ||
524 | luaL_openlibs(L); | ||
525 | } | ||
526 | |||
527 | /* return status (boolean) indicating if lua process should be recycled */ | ||
528 | luaproc luaproc_recycle_pop( void ) { | ||
529 | |||
530 | luaproc lp; | ||
531 | |||
532 | /* get exclusive access to operate on recycle list */ | ||
533 | pthread_mutex_lock( &mutex_recycle_list ); | ||
534 | |||
535 | /* check if there are any lua processes on recycle list */ | ||
536 | if ( eina_clist_count( &recyclelp ) > 0 ) { | ||
537 | /* pop list head */ | ||
538 | if ((lp = (luaproc) eina_clist_head(&recyclelp))) | ||
539 | eina_clist_remove(&(lp->node)); | ||
540 | /* free access to operate on recycle list */ | ||
541 | pthread_mutex_unlock( &mutex_recycle_list ); | ||
542 | /* return associated luaproc */ | ||
543 | return lp; | ||
544 | } | ||
545 | |||
546 | /* free access to operate on recycle list */ | ||
547 | pthread_mutex_unlock( &mutex_recycle_list ); | ||
548 | |||
549 | /* if no lua processes are available simply return null */ | ||
550 | return NULL; | ||
551 | } | ||
552 | |||
553 | /* check if lua process should be recycled and, in case so, add it to the recycle list */ | ||
554 | int luaproc_recycle_push( luaproc lp ) { | ||
555 | |||
556 | /* get exclusive access to operate on recycle list */ | ||
557 | pthread_mutex_lock( &mutex_recycle_list ); | ||
558 | |||
559 | /* check if amount of lua processes currently on recycle list is greater than | ||
560 | or equal to the maximum amount of lua processes that should be recycled */ | ||
561 | if ( eina_clist_count( &recyclelp ) >= recyclemax ) { | ||
562 | /* free access to operate on recycle list */ | ||
563 | pthread_mutex_unlock( &mutex_recycle_list ); | ||
564 | /* if so, lua process should NOT be recycled and should be destroyed */ | ||
565 | return FALSE; | ||
566 | } | ||
567 | /* otherwise, lua process should be added to recycle list */ | ||
568 | eina_clist_add_tail( &recyclelp, &(lp->node) ); | ||
569 | /* free access to operate on recycle list */ | ||
570 | pthread_mutex_unlock( &mutex_recycle_list ); | ||
571 | /* since lua process will be recycled, it should not be destroyed */ | ||
572 | return TRUE; | ||
573 | } | ||
574 | |||
575 | /* create new luaproc */ | ||
576 | static luaproc luaproc_new( const char *code, int destroyflag, int file) { | ||
577 | |||
578 | luaproc lp; | ||
579 | int ret; | ||
580 | /* create new lua state */ | ||
581 | lua_State *lpst = luaL_newstate( ); | ||
582 | /* store the luaproc struct in its own lua state */ | ||
583 | lp = (luaproc )lua_newuserdata( lpst, sizeof( struct stluaproc )); | ||
584 | lua_setfield( lpst, LUA_REGISTRYINDEX, "_SELF" ); | ||
585 | |||
586 | eina_clist_element_init(&(lp->node)); | ||
587 | lp->lstate = lpst; | ||
588 | lp->stat = LUAPROC_STAT_IDLE; | ||
589 | lp->args = 0; | ||
590 | lp->chan = NULL; | ||
591 | lp->destroyworker = destroyflag; | ||
592 | |||
593 | /* load standard libraries */ | ||
594 | openlibs( lpst ); | ||
595 | |||
596 | /* register luaproc's own functions */ | ||
597 | luaL_register( lpst, "luaproc", luaproc_funcs_child ); | ||
598 | |||
599 | /* load process' code */ | ||
600 | if (file) | ||
601 | ret = luaL_loadfile( lpst, code ); | ||
602 | else | ||
603 | ret = luaL_loadstring( lpst, code ); | ||
604 | /* in case of errors, destroy recently created lua process */ | ||
605 | if ( ret != 0 ) { | ||
606 | lua_close( lpst ); | ||
607 | return NULL; | ||
608 | } | ||
609 | |||
610 | /* return recently created lua process */ | ||
611 | return lp; | ||
612 | } | ||
613 | |||
614 | /* synchronize worker threads and exit */ | ||
615 | static int luaproc_exit( lua_State *L ) { | ||
616 | sched_join_workerthreads(); | ||
617 | return 0; | ||
618 | } | ||
619 | |||
620 | /* create a new worker pthread */ | ||
621 | static int luaproc_create_worker( lua_State *L ) { | ||
622 | |||
623 | if ( sched_create_worker( ) != LUAPROC_SCHED_OK ) { | ||
624 | lua_pushnil( L ); | ||
625 | lua_pushstring( L, "error creating worker" ); | ||
626 | return 2; | ||
627 | } | ||
628 | |||
629 | lua_pushboolean( L, TRUE ); | ||
630 | return 1; | ||
631 | } | ||
632 | |||
633 | /* set amount of lua processes that should be recycled (ie, reused) */ | ||
634 | static int luaproc_recycle_set( lua_State *L ) { | ||
635 | |||
636 | luaproc lp; | ||
637 | int max = luaL_checkint( L, 1 ); | ||
638 | |||
639 | /* check if function argument represents a reasonable value */ | ||
640 | if ( max < 0 ) { | ||
641 | /* in case of errors return nil + error msg */ | ||
642 | lua_pushnil( L ); | ||
643 | lua_pushstring( L, "error setting recycle limit to negative value" ); | ||
644 | return 2; | ||
645 | } | ||
646 | |||
647 | /* get exclusive access to operate on recycle list */ | ||
648 | pthread_mutex_lock( &mutex_recycle_list ); | ||
649 | |||
650 | /* set maximum lua processes that should be recycled */ | ||
651 | recyclemax = max; | ||
652 | |||
653 | /* destroy recycle list excessive nodes (and corresponding lua processes) */ | ||
654 | while ( eina_clist_count( &recyclelp ) > max ) { | ||
655 | if ((lp = (luaproc) eina_clist_head(&recyclelp))) | ||
656 | eina_clist_remove(&(lp->node)); | ||
657 | /* close associated lua_State */ | ||
658 | lua_close( lp->lstate ); | ||
659 | } | ||
660 | |||
661 | /* free access to operate on recycle list */ | ||
662 | pthread_mutex_unlock( &mutex_recycle_list ); | ||
663 | |||
664 | lua_pushboolean( L, TRUE ); | ||
665 | return 1; | ||
666 | } | ||
667 | |||
668 | |||
669 | /* destroy a worker pthread */ | ||
670 | static int luaproc_destroy_worker( lua_State *L ) { | ||
671 | |||
672 | /* new lua process pointer */ | ||
673 | luaproc lp; | ||
674 | |||
675 | /* create new lua process with empty code and destroy worker flag set to true | ||
676 | (ie, conclusion of lua process WILL result in worker thread destruction */ | ||
677 | lp = luaproc_new( "", TRUE, FALSE ); | ||
678 | |||
679 | /* ensure process creation was successfull */ | ||
680 | if ( lp == NULL ) { | ||
681 | /* in case of errors return nil + error msg */ | ||
682 | lua_pushnil( L ); | ||
683 | lua_pushstring( L, "error destroying worker" ); | ||
684 | return 2; | ||
685 | } | ||
686 | |||
687 | /* increase active luaproc count */ | ||
688 | sched_lpcount_inc(); | ||
689 | |||
690 | /* schedule luaproc */ | ||
691 | if ( sched_queue_proc( lp ) != LUAPROC_SCHED_QUEUE_PROC_OK ) { | ||
692 | printf( "[luaproc] error queueing Lua process\n" ); | ||
693 | /* decrease active luaproc count */ | ||
694 | sched_lpcount_dec(); | ||
695 | /* close lua_State */ | ||
696 | lua_close( lp->lstate ); | ||
697 | /* return nil + error msg */ | ||
698 | lua_pushnil( L ); | ||
699 | lua_pushstring( L, "error destroying worker" ); | ||
700 | return 2; | ||
701 | } | ||
702 | |||
703 | lua_pushboolean( L, TRUE ); | ||
704 | return 1; | ||
705 | } | ||
706 | |||
707 | /* recycle a lua process */ | ||
708 | static luaproc luaproc_recycle( luaproc lp, const char *code, int file ) { | ||
709 | |||
710 | int ret; | ||
711 | |||
712 | /* reset struct members */ | ||
713 | lp->stat = LUAPROC_STAT_IDLE; | ||
714 | lp->args = 0; | ||
715 | lp->chan = NULL; | ||
716 | lp->destroyworker = FALSE; | ||
717 | |||
718 | /* load process' code */ | ||
719 | ret = luaL_loadstring( lp->lstate, code ); | ||
720 | |||
721 | /* in case of errors, destroy lua process */ | ||
722 | if ( ret != 0 ) { | ||
723 | lua_close( lp->lstate ); | ||
724 | return NULL; | ||
725 | } | ||
726 | |||
727 | /* return recycled lua process */ | ||
728 | return lp; | ||
729 | } | ||
730 | |||
731 | |||
732 | int newProc(const char *code, int file, Ecore_Cb callback, void *data) | ||
733 | { | ||
734 | /* new lua process pointer */ | ||
735 | luaproc lp; | ||
736 | |||
737 | /* check if existing lua process should be recycled to avoid new creation */ | ||
738 | lp = luaproc_recycle_pop( ); | ||
739 | |||
740 | /* if there is a lua process available on the recycle queue, recycle it */ | ||
741 | if ( lp != NULL ) { | ||
742 | lp = luaproc_recycle( lp, code, file ); | ||
743 | } | ||
744 | /* otherwise create a new one from scratch */ | ||
745 | else { | ||
746 | /* create new lua process with destroy worker flag set to false | ||
747 | (ie, conclusion of lua process will NOT result in worker thread destruction */ | ||
748 | lp = luaproc_new( code, FALSE, file ); | ||
749 | } | ||
750 | |||
751 | /* ensure process creation was successfull */ | ||
752 | if ( lp == NULL ) { | ||
753 | return 1; | ||
754 | } | ||
755 | |||
756 | /* Stash any data and callback given to us. */ | ||
757 | lp->data = data; | ||
758 | lp->callback = callback; | ||
759 | |||
760 | /* increase active luaproc count */ | ||
761 | sched_lpcount_inc(); | ||
762 | |||
763 | /* schedule luaproc */ | ||
764 | if ( sched_queue_proc( lp ) != LUAPROC_SCHED_QUEUE_PROC_OK ) { | ||
765 | printf( "[luaproc] error queueing Lua process\n" ); | ||
766 | /* decrease active luaproc count */ | ||
767 | sched_lpcount_dec(); | ||
768 | /* close lua_State */ | ||
769 | lua_close( lp->lstate ); | ||
770 | return 2; | ||
771 | } | ||
772 | |||
773 | return 0; | ||
774 | } | ||
775 | |||
776 | /* create and schedule a new lua process (luaproc.newproc) */ | ||
777 | static int luaproc_create_newproc( lua_State *L ) { | ||
778 | |||
779 | /* check if first argument is a string (lua code) */ | ||
780 | const char *code = luaL_checkstring( L, 1 ); | ||
781 | |||
782 | switch (newProc(code, FALSE, NULL, NULL)) | ||
783 | { | ||
784 | case 1 : | ||
785 | /* in case of errors return nil + error msg */ | ||
786 | lua_pushnil( L ); | ||
787 | lua_pushstring( L, "error loading code string" ); | ||
788 | return 2; | ||
789 | case 2 : | ||
790 | /* return nil + error msg */ | ||
791 | lua_pushnil( L ); | ||
792 | lua_pushstring( L, "error queuing process" ); | ||
793 | return 2; | ||
794 | } | ||
795 | |||
796 | lua_pushboolean( L, TRUE ); | ||
797 | return 1; | ||
798 | } | ||
799 | |||
800 | /* queue a lua process sending a message without a matching receiver */ | ||
801 | void luaproc_queue_sender( luaproc lp ) { | ||
802 | /* add the sending process to this process' send queue */ | ||
803 | eina_clist_add_tail( channel_get_sendq( lp->chan ), &(lp->node)); | ||
804 | } | ||
805 | |||
806 | /* dequeue a lua process sending a message with a receiver match */ | ||
807 | luaproc luaproc_dequeue_sender( channel chan ) { | ||
808 | |||
809 | luaproc lp; | ||
810 | |||
811 | if ( eina_clist_count( channel_get_sendq( chan )) > 0 ) { | ||
812 | /* get first node from channel's send queue */ | ||
813 | if ((lp = (luaproc) eina_clist_head(channel_get_sendq( chan )))) | ||
814 | eina_clist_remove(&(lp->node)); | ||
815 | /* return associated luaproc */ | ||
816 | return lp; | ||
817 | } | ||
818 | |||
819 | return NULL; | ||
820 | } | ||
821 | |||
822 | /* queue a luc process receiving a message without a matching sender */ | ||
823 | void luaproc_queue_receiver( luaproc lp ) { | ||
824 | /* add the receiving process to this process' receive queue */ | ||
825 | eina_clist_add_tail( channel_get_recvq( lp->chan ), &(lp->node)); | ||
826 | } | ||
827 | |||
828 | /* dequeue a lua process receiving a message with a sender match */ | ||
829 | luaproc luaproc_dequeue_receiver( channel chan ) { | ||
830 | |||
831 | luaproc lp; | ||
832 | |||
833 | if ( eina_clist_count( channel_get_recvq( chan )) > 0 ) { | ||
834 | /* get first node from channel's recv queue */ | ||
835 | if ((lp = (luaproc) eina_clist_head(channel_get_recvq( chan )))) | ||
836 | eina_clist_remove(&(lp->node)); | ||
837 | /* return associated luaproc */ | ||
838 | return lp; | ||
839 | } | ||
840 | |||
841 | return NULL; | ||
842 | } | ||
843 | |||
844 | /* moves values between lua states' stacks */ | ||
845 | void luaproc_movevalues( lua_State *Lfrom, lua_State *Lto ) { | ||
846 | |||
847 | int i; | ||
848 | int n = lua_gettop( Lfrom ); | ||
849 | |||
850 | /* move values between lua states' stacks */ | ||
851 | for ( i = 2; i <= n; i++ ) { | ||
852 | lua_pushstring( Lto, lua_tostring( Lfrom, i )); | ||
853 | } | ||
854 | } | ||
855 | |||
856 | /* return the lua process associated with a given lua state */ | ||
857 | luaproc luaproc_getself( lua_State *L ) { | ||
858 | luaproc lp; | ||
859 | lua_getfield( L, LUA_REGISTRYINDEX, "_SELF" ); | ||
860 | lp = (luaproc )lua_touserdata( L, -1 ); | ||
861 | lua_pop( L, 1 ); | ||
862 | return lp; | ||
863 | } | ||
864 | |||
865 | /* send a message to a lua process */ | ||
866 | static int luaproc_send_back( lua_State *L ) { | ||
867 | |||
868 | luaproc self; | ||
869 | const char *message = luaL_checkstring( L, 1 ); | ||
870 | |||
871 | self = luaproc_getself( L ); | ||
872 | if (self && self->callback && self->data) | ||
873 | { | ||
874 | scriptMessage *sm = calloc(1, sizeof(scriptMessage)); | ||
875 | |||
876 | if (sm) | ||
877 | { | ||
878 | sm->script = self->data; | ||
879 | strcpy((char *) sm->message, message); | ||
880 | ecore_main_loop_thread_safe_call_async(self->callback, sm); | ||
881 | } | ||
882 | } | ||
883 | |||
884 | return 0; | ||
885 | } | ||
886 | |||
887 | /* error messages for the sendToChannel function */ | ||
888 | const char *sendToChannelErrors[] = | ||
889 | { | ||
890 | "non-existent channel", | ||
891 | "error scheduling process" | ||
892 | }; | ||
893 | |||
894 | // TODO - If these come in too quick, then messages might get lost. Also, in at least one case, it locked up this thread I think. | ||
895 | |||
896 | /* send a message to a lua process */ | ||
897 | const char *sendToChannel(const char *chname, const char *message, luaproc *dst, channel *chn) | ||
898 | { | ||
899 | const char *result = NULL; | ||
900 | channel chan; | ||
901 | luaproc dstlp; | ||
902 | |||
903 | /* get exclusive access to operate on channels */ | ||
904 | pthread_mutex_lock(&mutex_channel); | ||
905 | |||
906 | /* wait until channel is not in use */ | ||
907 | while( ((chan = channel_search(chname)) != NULL) && (pthread_mutex_trylock(channel_get_mutex(chan)) != 0 )) | ||
908 | { | ||
909 | pthread_cond_wait(channel_get_cond(chan), &mutex_channel); | ||
910 | } | ||
911 | |||
912 | /* free access to operate on channels */ | ||
913 | pthread_mutex_unlock(&mutex_channel); | ||
914 | |||
915 | /* if channel is not found, return an error */ | ||
916 | if (chan == NULL) | ||
917 | return sendToChannelErrors[0]; | ||
918 | |||
919 | /* try to find a matching receiver */ | ||
920 | dstlp = luaproc_dequeue_receiver(chan); | ||
921 | |||
922 | /* if a match is found, send the message to it and (queue) wake it */ | ||
923 | if (dstlp != NULL) | ||
924 | { | ||
925 | /* push the message onto the receivers stack */ | ||
926 | lua_pushstring( dstlp->lstate, message); | ||
927 | |||
928 | dstlp->args = lua_gettop(dstlp->lstate) - 1; | ||
929 | |||
930 | if (sched_queue_proc(dstlp) != LUAPROC_SCHED_QUEUE_PROC_OK) | ||
931 | { | ||
932 | /* unlock channel access */ | ||
933 | luaproc_unlock_channel(chan); | ||
934 | |||
935 | /* decrease active luaproc count */ | ||
936 | sched_lpcount_dec(); | ||
937 | |||
938 | /* close lua_State */ | ||
939 | lua_close(dstlp->lstate); | ||
940 | return sendToChannelErrors[1]; | ||
941 | } | ||
942 | |||
943 | /* unlock channel access */ | ||
944 | luaproc_unlock_channel(chan); | ||
945 | } | ||
946 | else if (dst) | ||
947 | dst = &dstlp; | ||
948 | |||
949 | if (chn) | ||
950 | chn = &chan; | ||
951 | return result; | ||
952 | } | ||
953 | |||
954 | /* send a message to a lua process */ | ||
955 | static int luaproc_send( lua_State *L ) { | ||
956 | |||
957 | channel chan; | ||
958 | luaproc dstlp, self; | ||
959 | const char *chname = luaL_checkstring( L, 1 ); | ||
960 | const char *message = luaL_checkstring( L, 2 ); | ||
961 | const char *result = sendToChannel(chname, message, &dstlp, &chan); | ||
962 | |||
963 | if (result) { | ||
964 | lua_pushnil( L ); | ||
965 | lua_pushstring( L, result ); | ||
966 | return 2; | ||
967 | } | ||
968 | |||
969 | if ( dstlp == NULL ) { | ||
970 | |||
971 | self = luaproc_getself( L ); | ||
972 | |||
973 | if ( self != NULL ) { | ||
974 | self->stat = LUAPROC_STAT_BLOCKED_SEND; | ||
975 | self->chan = chan; | ||
976 | } | ||
977 | |||
978 | /* just yield the lua process, channel unlocking will be done by the scheduler */ | ||
979 | return lua_yield( L, lua_gettop( L )); | ||
980 | } | ||
981 | |||
982 | lua_pushboolean( L, TRUE ); | ||
983 | return 1; | ||
984 | } | ||
985 | |||
986 | /* receive a message from a lua process */ | ||
987 | static int luaproc_receive( lua_State *L ) { | ||
988 | |||
989 | channel chan; | ||
990 | luaproc srclp, self; | ||
991 | const char *chname = luaL_checkstring( L, 1 ); | ||
992 | |||
993 | /* get exclusive access to operate on channels */ | ||
994 | pthread_mutex_lock( &mutex_channel ); | ||
995 | |||
996 | /* wait until channel is not in use */ | ||
997 | while((( chan = channel_search( chname )) != NULL ) && ( pthread_mutex_trylock( channel_get_mutex( chan )) != 0 )) { | ||
998 | pthread_cond_wait( channel_get_cond( chan ), &mutex_channel ); | ||
999 | } | ||
1000 | |||
1001 | /* free access to operate on channels */ | ||
1002 | pthread_mutex_unlock( &mutex_channel ); | ||
1003 | |||
1004 | /* if channel is not found, free access to operate on channels and return an error to Lua */ | ||
1005 | if ( chan == NULL ) { | ||
1006 | lua_pushnil( L ); | ||
1007 | lua_pushstring( L, "non-existent channel" ); | ||
1008 | return 2; | ||
1009 | } | ||
1010 | |||
1011 | /* try to find a matching sender */ | ||
1012 | srclp = luaproc_dequeue_sender( chan ); | ||
1013 | |||
1014 | /* if a match is found, get values from it and (queue) wake it */ | ||
1015 | if ( srclp != NULL ) { | ||
1016 | |||
1017 | /* move values between Lua states' stacks */ | ||
1018 | luaproc_movevalues( srclp->lstate, L ); | ||
1019 | |||
1020 | /* return to sender indicanting message was sent */ | ||
1021 | lua_pushboolean( srclp->lstate, TRUE ); | ||
1022 | srclp->args = 1; | ||
1023 | |||
1024 | if ( sched_queue_proc( srclp ) != LUAPROC_SCHED_QUEUE_PROC_OK ) { | ||
1025 | |||
1026 | /* unlock channel access */ | ||
1027 | luaproc_unlock_channel( chan ); | ||
1028 | |||
1029 | /* decrease active luaproc count */ | ||
1030 | sched_lpcount_dec(); | ||
1031 | |||
1032 | /* close lua_State */ | ||
1033 | lua_close( srclp->lstate ); | ||
1034 | lua_pushnil( L ); | ||
1035 | lua_pushstring( L, "error scheduling process" ); | ||
1036 | return 2; | ||
1037 | } | ||
1038 | |||
1039 | /* unlock channel access */ | ||
1040 | luaproc_unlock_channel( chan ); | ||
1041 | |||
1042 | return lua_gettop( L ) - 1; | ||
1043 | } | ||
1044 | |||
1045 | /* otherwise queue (block) the receiving process (sync) or return immediatly (async) */ | ||
1046 | else { | ||
1047 | |||
1048 | /* if trying an asynchronous receive, unlock channel access and return an error */ | ||
1049 | if ( lua_toboolean( L, 2 )) { | ||
1050 | /* unlock channel access */ | ||
1051 | luaproc_unlock_channel( chan ); | ||
1052 | /* return an error */ | ||
1053 | lua_pushnil( L ); | ||
1054 | lua_pushfstring( L, "no senders waiting on channel %s", chname ); | ||
1055 | return 2; | ||
1056 | } | ||
1057 | |||
1058 | /* otherwise (synchronous receive) simply block process */ | ||
1059 | else { | ||
1060 | self = luaproc_getself( L ); | ||
1061 | |||
1062 | if ( self != NULL ) { | ||
1063 | self->stat = LUAPROC_STAT_BLOCKED_RECV; | ||
1064 | self->chan = chan; | ||
1065 | } | ||
1066 | |||
1067 | /* just yield the lua process, channel unlocking will be done by the scheduler */ | ||
1068 | return lua_yield( L, lua_gettop( L )); | ||
1069 | } | ||
1070 | } | ||
1071 | } | ||
1072 | |||
1073 | void luaprocInit(void) | ||
1074 | { | ||
1075 | /* initialize recycle list */ | ||
1076 | eina_clist_init(&recyclelp); | ||
1077 | |||
1078 | /* initialize local scheduler */ | ||
1079 | sched_init_local( LUAPROC_SCHED_DEFAULT_WORKER_THREADS ); | ||
1080 | } | ||
1081 | |||
1082 | void luaprocRegister(lua_State *L) | ||
1083 | { | ||
1084 | /* register luaproc functions */ | ||
1085 | luaL_register( L, "luaproc", luaproc_funcs_parent ); | ||
1086 | } | ||
1087 | |||
1088 | LUALIB_API int luaopen_luaproc( lua_State *L ) { | ||
1089 | luaprocRegister(L); | ||
1090 | luaprocInit(); | ||
1091 | return 0; | ||
1092 | } | ||
1093 | |||
1094 | /* return a process' status */ | ||
1095 | int luaproc_get_status( luaproc lp ) { | ||
1096 | return lp->stat; | ||
1097 | } | ||
1098 | |||
1099 | /* set a process' status */ | ||
1100 | void luaproc_set_status( luaproc lp, int status ) { | ||
1101 | lp->stat = status; | ||
1102 | } | ||
1103 | |||
1104 | /* return a process' state */ | ||
1105 | lua_State *luaproc_get_state( luaproc lp ) { | ||
1106 | return lp->lstate; | ||
1107 | } | ||
1108 | |||
1109 | /* return the number of arguments expected by a given process */ | ||
1110 | int luaproc_get_args( luaproc lp ) { | ||
1111 | return lp->args; | ||
1112 | } | ||
1113 | |||
1114 | /* set the number of arguments expected by a given process */ | ||
1115 | void luaproc_set_args( luaproc lp, int n ) { | ||
1116 | lp->args = n; | ||
1117 | } | ||
1118 | |||
1119 | /* create a new channel */ | ||
1120 | static int luaproc_create_channel( lua_State *L ) { | ||
1121 | |||
1122 | const char *chname = luaL_checkstring( L, 1 ); | ||
1123 | |||
1124 | /* get exclusive access to operate on channels */ | ||
1125 | pthread_mutex_lock( &mutex_channel ); | ||
1126 | |||
1127 | /* check if channel exists */ | ||
1128 | if ( channel_search( chname ) != NULL ) { | ||
1129 | /* free access to operate on channels */ | ||
1130 | pthread_mutex_unlock( &mutex_channel ); | ||
1131 | /* return an error to lua */ | ||
1132 | lua_pushnil( L ); | ||
1133 | lua_pushstring( L, "channel already exists" ); | ||
1134 | return 2; | ||
1135 | } | ||
1136 | |||
1137 | channel_create( chname ); | ||
1138 | |||
1139 | /* free access to operate on channels */ | ||
1140 | pthread_mutex_unlock( &mutex_channel ); | ||
1141 | |||
1142 | lua_pushboolean( L, TRUE ); | ||
1143 | |||
1144 | return 1; | ||
1145 | |||
1146 | } | ||
1147 | |||
1148 | /* destroy a channel */ | ||
1149 | static int luaproc_destroy_channel( lua_State *L ) { | ||
1150 | |||
1151 | channel chan; | ||
1152 | luaproc lp; | ||
1153 | pthread_mutex_t *chmutex; | ||
1154 | pthread_cond_t *chcond; | ||
1155 | const char *chname = luaL_checkstring( L, 1 ); | ||
1156 | |||
1157 | |||
1158 | /* get exclusive access to operate on channels */ | ||
1159 | pthread_mutex_lock( &mutex_channel ); | ||
1160 | |||
1161 | /* wait until channel is not in use */ | ||
1162 | while((( chan = channel_search( chname )) != NULL ) && ( pthread_mutex_trylock( channel_get_mutex( chan )) != 0 )) { | ||
1163 | pthread_cond_wait( channel_get_cond( chan ), &mutex_channel ); | ||
1164 | } | ||
1165 | |||
1166 | /* free access to operate on channels */ | ||
1167 | pthread_mutex_unlock( &mutex_channel ); | ||
1168 | |||
1169 | /* if channel is not found, return an error to Lua */ | ||
1170 | if ( chan == NULL ) { | ||
1171 | lua_pushnil( L ); | ||
1172 | lua_pushstring( L, "non-existent channel" ); | ||
1173 | return 2; | ||
1174 | } | ||
1175 | |||
1176 | /* get channel's mutex and conditional pointers */ | ||
1177 | chmutex = channel_get_mutex( chan ); | ||
1178 | chcond = channel_get_cond( chan ); | ||
1179 | |||
1180 | /* search for processes waiting to send a message on this channel */ | ||
1181 | while (( lp = (luaproc) eina_clist_head( channel_get_sendq( chan ))) != NULL ) { | ||
1182 | eina_clist_remove(&(lp->node)); | ||
1183 | |||
1184 | /* return an error so the processe knows the channel was destroyed before the message was sent */ | ||
1185 | lua_settop( lp->lstate, 0 ); | ||
1186 | lua_pushnil( lp->lstate ); | ||
1187 | lua_pushstring( lp->lstate, "channel destroyed while waiting for receiver" ); | ||
1188 | lp->args = 2; | ||
1189 | |||
1190 | /* schedule the process for execution */ | ||
1191 | if ( sched_queue_proc( lp ) != LUAPROC_SCHED_QUEUE_PROC_OK ) { | ||
1192 | |||
1193 | /* decrease active luaproc count */ | ||
1194 | sched_lpcount_dec(); | ||
1195 | |||
1196 | /* close lua_State */ | ||
1197 | lua_close( lp->lstate ); | ||
1198 | } | ||
1199 | } | ||
1200 | |||
1201 | /* search for processes waiting to receive a message on this channel */ | ||
1202 | while (( lp = (luaproc) eina_clist_head( channel_get_recvq( chan ))) != NULL ) { | ||
1203 | eina_clist_remove(&(lp->node)); | ||
1204 | |||
1205 | /* return an error so the processe knows the channel was destroyed before the message was received */ | ||
1206 | lua_settop( lp->lstate, 0 ); | ||
1207 | lua_pushnil( lp->lstate ); | ||
1208 | lua_pushstring( lp->lstate, "channel destroyed while waiting for sender" ); | ||
1209 | lp->args = 2; | ||
1210 | |||
1211 | /* schedule the process for execution */ | ||
1212 | if ( sched_queue_proc( lp ) != LUAPROC_SCHED_QUEUE_PROC_OK ) { | ||
1213 | |||
1214 | /* decrease active luaproc count */ | ||
1215 | sched_lpcount_dec(); | ||
1216 | |||
1217 | /* close lua_State */ | ||
1218 | lua_close( lp->lstate ); | ||
1219 | } | ||
1220 | } | ||
1221 | |||
1222 | /* get exclusive access to operate on channels */ | ||
1223 | pthread_mutex_lock( &mutex_channel ); | ||
1224 | /* destroy channel */ | ||
1225 | channel_destroy( chan, chname ); | ||
1226 | /* broadcast channel not in use */ | ||
1227 | pthread_cond_broadcast( chcond ); | ||
1228 | /* unlock channel access */ | ||
1229 | pthread_mutex_unlock( chmutex ); | ||
1230 | /* destroy channel mutex and conditional */ | ||
1231 | pthread_mutex_destroy( chmutex ); | ||
1232 | pthread_cond_destroy( chcond ); | ||
1233 | /* free memory used by channel mutex and conditional */ | ||
1234 | free( chmutex ); | ||
1235 | free( chcond ); | ||
1236 | /* free access to operate on channels */ | ||
1237 | pthread_mutex_unlock( &mutex_channel ); | ||
1238 | |||
1239 | lua_pushboolean( L, TRUE ); | ||
1240 | |||
1241 | return 1; | ||
1242 | } | ||
1243 | |||
1244 | /* register luaproc's functions in a lua_State */ | ||
1245 | void luaproc_register_funcs( lua_State *L ) { | ||
1246 | luaL_register( L, "luaproc", luaproc_funcs_child ); | ||
1247 | } | ||
1248 | |||
1249 | /* return the channel where the corresponding luaproc is blocked at */ | ||
1250 | channel luaproc_get_channel( luaproc lp ) { | ||
1251 | return lp->chan; | ||
1252 | } | ||
1253 | |||
1254 | /* unlock access to a channel */ | ||
1255 | void luaproc_unlock_channel( channel chan ) { | ||
1256 | /* get exclusive access to operate on channels */ | ||
1257 | pthread_mutex_lock( &mutex_channel ); | ||
1258 | /* unlock channel access */ | ||
1259 | pthread_mutex_unlock( channel_get_mutex( chan )); | ||
1260 | /* signal channel not in use */ | ||
1261 | pthread_cond_signal( channel_get_cond( chan )); | ||
1262 | /* free access to operate on channels */ | ||
1263 | pthread_mutex_unlock( &mutex_channel ); | ||
1264 | } | ||
1265 | |||
1266 | /* return status (boolean) indicating if worker thread should be destroyed after luaproc execution */ | ||
1267 | int luaproc_get_destroyworker( luaproc lp ) { | ||
1268 | return lp->destroyworker; | ||
1269 | } | ||
diff --git a/libraries/luaproc/luaproc.h b/LuaSL/src/LuaSL_threads.h index 1286107..b12a50d 100644 --- a/libraries/luaproc/luaproc.h +++ b/LuaSL/src/LuaSL_threads.h | |||
@@ -1,4 +1,8 @@ | |||
1 | /*************************************************** | 1 | /* This code is heavily based on luaproc. |
2 | * | ||
3 | * The luaproc copyright notice and license is - | ||
4 | |||
5 | *************************************************** | ||
2 | 6 | ||
3 | Copyright 2008 Alexandre Skyrme, Noemi Rodriguez, Roberto Ierusalimschy | 7 | Copyright 2008 Alexandre Skyrme, Noemi Rodriguez, Roberto Ierusalimschy |
4 | 8 | ||
@@ -20,16 +24,48 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |||
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | 24 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
21 | THE SOFTWARE. | 25 | THE SOFTWARE. |
22 | 26 | ||
23 | ***************************************************** | 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 | //#include <Ecore.h> | ||
36 | |||
37 | |||
38 | #define CHANNEL_MAX_NAME_LENGTH 255 | ||
39 | |||
40 | #define CHANNEL_DESTROYED 0 | ||
41 | |||
42 | /* message channel pointer type */ | ||
43 | typedef struct stchannel *channel; | ||
44 | |||
45 | |||
46 | |||
47 | /* scheduler function return constants */ | ||
48 | #define LUAPROC_SCHED_OK 0 | ||
49 | #define LUAPROC_SCHED_SOCKET_ERROR -1 | ||
50 | #define LUAPROC_SCHED_SETSOCKOPT_ERROR -2 | ||
51 | #define LUAPROC_SCHED_BIND_ERROR -3 | ||
52 | #define LUAPROC_SCHED_LISTEN_ERROR -4 | ||
53 | #define LUAPROC_SCHED_FORK_ERROR -5 | ||
54 | #define LUAPROC_SCHED_PTHREAD_ERROR -6 | ||
55 | #define LUAPROC_SCHED_INIT_ERROR -7 | ||
56 | |||
57 | /* ready process queue insertion status */ | ||
58 | #define LUAPROC_SCHED_QUEUE_PROC_OK 0 | ||
59 | #define LUAPROC_SCHED_QUEUE_PROC_ERR -1 | ||
24 | 60 | ||
25 | [luaproc.h] | 61 | /* scheduler listener service default hostname and port */ |
62 | #define LUAPROC_SCHED_DEFAULT_HOST "127.0.0.1" | ||
63 | #define LUAPROC_SCHED_DEFAULT_PORT 3133 | ||
64 | |||
65 | /* scheduler default number of worker threads */ | ||
66 | #define LUAPROC_SCHED_DEFAULT_WORKER_THREADS 1 | ||
26 | 67 | ||
27 | ****************************************************/ | ||
28 | #ifndef _LUAPROC_H_ | ||
29 | #define _LUAPROC_H_ | ||
30 | 68 | ||
31 | #include "channel.h" | ||
32 | #include <Ecore.h> | ||
33 | 69 | ||
34 | /* process is idle */ | 70 | /* process is idle */ |
35 | #define LUAPROC_STAT_IDLE 0 | 71 | #define LUAPROC_STAT_IDLE 0 |
@@ -45,6 +81,68 @@ THE SOFTWARE. | |||
45 | /* lua process pointer type */ | 81 | /* lua process pointer type */ |
46 | typedef struct stluaproc *luaproc; | 82 | typedef struct stluaproc *luaproc; |
47 | 83 | ||
84 | |||
85 | |||
86 | |||
87 | |||
88 | /* initialize channels */ | ||
89 | void channel_init( void ); | ||
90 | |||
91 | /* create new channel */ | ||
92 | channel channel_create( const char *cname ); | ||
93 | |||
94 | /* destroy a channel */ | ||
95 | int channel_destroy( channel chan, const char *chname ); | ||
96 | |||
97 | /* search for and return a channel with a given name */ | ||
98 | channel channel_search( const char *cname ); | ||
99 | |||
100 | /* return a channel's send queue */ | ||
101 | Eina_Clist *channel_get_sendq( channel chan ); | ||
102 | |||
103 | /* return a channel's receive queue */ | ||
104 | Eina_Clist *channel_get_recvq( channel chan ); | ||
105 | |||
106 | /* return a channel's mutex */ | ||
107 | pthread_mutex_t *channel_get_mutex( channel chan ); | ||
108 | |||
109 | /* return a channel's conditional variable */ | ||
110 | pthread_cond_t *channel_get_cond( channel chan ); | ||
111 | |||
112 | |||
113 | |||
114 | |||
115 | |||
116 | |||
117 | /* initialize local scheduler */ | ||
118 | int sched_init_local( int numworkers ); | ||
119 | |||
120 | /* initialize socket enabled scheduler */ | ||
121 | int sched_init_socket( int numworkers, const char *host, int port ); | ||
122 | |||
123 | /* exit scheduler */ | ||
124 | void sched_exit( void ); | ||
125 | |||
126 | /* move process to ready queue (ie, schedule process) */ | ||
127 | int sched_queue_proc( luaproc lp ); | ||
128 | |||
129 | /* join all worker threads and exit */ | ||
130 | void sched_join_workerthreads( void ); | ||
131 | |||
132 | /* increase active luaproc count */ | ||
133 | void sched_lpcount_inc( void ); | ||
134 | |||
135 | /* decrease active luaproc count */ | ||
136 | void sched_lpcount_dec( void ); | ||
137 | |||
138 | /* create a new worker pthread */ | ||
139 | int sched_create_worker( void ); | ||
140 | |||
141 | |||
142 | |||
143 | |||
144 | |||
145 | |||
48 | void luaprocInit(void); | 146 | void luaprocInit(void); |
49 | void luaprocRegister(lua_State *L); | 147 | void luaprocRegister(lua_State *L); |
50 | int newProc(const char *code, int file, Ecore_Cb callback, void *data); | 148 | int newProc(const char *code, int file, Ecore_Cb callback, void *data); |
@@ -97,4 +195,5 @@ luaproc luaproc_recycle_pop( void ); | |||
97 | /* add a lua process to the recycle list */ | 195 | /* add a lua process to the recycle list */ |
98 | int luaproc_recycle_push( luaproc lp ); | 196 | int luaproc_recycle_push( luaproc lp ); |
99 | 197 | ||
198 | |||
100 | #endif | 199 | #endif |
@@ -6,12 +6,6 @@ echo "_______________ BUILDING LuaJIT _______________" | |||
6 | cd $wd/libraries/luajit-2.0 | 6 | cd $wd/libraries/luajit-2.0 |
7 | make amalg PREFIX=$()/src | 7 | make amalg PREFIX=$()/src |
8 | 8 | ||
9 | |||
10 | echo "_______________ BUILDING luaproc _______________" | ||
11 | cd $wd/libraries/luaproc | ||
12 | make | ||
13 | |||
14 | |||
15 | echo "_______________ BUILDING lemon _______________" | 9 | echo "_______________ BUILDING lemon _______________" |
16 | cd $wd/libraries/lemon | 10 | cd $wd/libraries/lemon |
17 | rm -f *.o lemon | 11 | rm -f *.o lemon |
diff --git a/libraries/README b/libraries/README index d24f7d2..f40f9e4 100644 --- a/libraries/README +++ b/libraries/README | |||
@@ -7,5 +7,5 @@ Note that in some cases, there might be changes. Such changes should be | |||
7 | documented. | 7 | documented. |
8 | 8 | ||
9 | luaproc has been hacked up a bit, and will continue to be hacked up. | 9 | luaproc has been hacked up a bit, and will continue to be hacked up. |
10 | Merging it into LuaSL, and converting it to EFL. | 10 | Merged it into LuaSL, so it's no longer here. |
11 | 11 | ||
diff --git a/libraries/luaproc/COPYRIGHT b/libraries/luaproc/COPYRIGHT deleted file mode 100644 index 5f3c3ab..0000000 --- a/libraries/luaproc/COPYRIGHT +++ /dev/null | |||
@@ -1,32 +0,0 @@ | |||
1 | luaproc License | ||
2 | --------------- | ||
3 | |||
4 | luaproc is licensed under the terms of the MIT license reproduced below. | ||
5 | This means that luaproc is free software and can be used for both academic | ||
6 | and commercial purposes at absolutely no cost. | ||
7 | |||
8 | =============================================================================== | ||
9 | |||
10 | Copyright (C) 2008 Alexandre Skyrme, Noemi Rodriguez, Roberto Ierusalimschy | ||
11 | |||
12 | Permission is hereby granted, free of charge, to any person obtaining a copy | ||
13 | of this software and associated documentation files (the "Software"), to deal | ||
14 | in the Software without restriction, including without limitation the rights | ||
15 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
16 | copies of the Software, and to permit persons to whom the Software is | ||
17 | furnished to do so, subject to the following conditions: | ||
18 | |||
19 | The above copyright notice and this permission notice shall be included in | ||
20 | all copies or substantial portions of the Software. | ||
21 | |||
22 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
23 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
24 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
25 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
26 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
27 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
28 | THE SOFTWARE. | ||
29 | |||
30 | =============================================================================== | ||
31 | |||
32 | (end of COPYRIGHT) | ||
diff --git a/libraries/luaproc/Lua_multithreading_ry08-05.pdf b/libraries/luaproc/Lua_multithreading_ry08-05.pdf deleted file mode 100644 index 5caf694..0000000 --- a/libraries/luaproc/Lua_multithreading_ry08-05.pdf +++ /dev/null | |||
Binary files differ | |||
diff --git a/libraries/luaproc/Makefile b/libraries/luaproc/Makefile deleted file mode 100644 index 3ab61bf..0000000 --- a/libraries/luaproc/Makefile +++ /dev/null | |||
@@ -1,65 +0,0 @@ | |||
1 | #################################################### | ||
2 | # | ||
3 | # Copyright 2008 Alexandre Skyrme, Noemi Rodriguez, Roberto Ierusalimschy | ||
4 | # | ||
5 | # Permission is hereby granted, free of charge, to any person obtaining a copy | ||
6 | # of this software and associated documentation files (the "Software"), to deal | ||
7 | # in the Software without restriction, including without limitation the rights | ||
8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
9 | # copies of the Software, and to permit persons to whom the Software is | ||
10 | # furnished to do so, subject to the following conditions: | ||
11 | # | ||
12 | # The above copyright notice and this permission notice shall be included in | ||
13 | # all copies or substantial portions of the Software. | ||
14 | # | ||
15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
21 | # THE SOFTWARE. | ||
22 | # | ||
23 | ###################################################### | ||
24 | # | ||
25 | # [Makefile] | ||
26 | # | ||
27 | ###################################################### | ||
28 | |||
29 | # path to lua header files | ||
30 | LUA_INC_PATH=/usr/include/lua5.1 | ||
31 | # path to lua library | ||
32 | LUA_LIB_PATH=/usr/lib/lua5.1 | ||
33 | |||
34 | # standard makefile variables | ||
35 | CC=gcc | ||
36 | # TODO - hack, hard coded EFL include paths for now. | ||
37 | CFLAGS=-c -Wall -fPIC -I${LUA_INC_PATH} -I/opt/e17/include/eina-1 -I/opt/e17/include/eina-1/eina -I/opt/e17/include/ecore-1 | ||
38 | LDFLAGS=-shared -L${LUA_LIB_PATH} -lpthread | ||
39 | SOURCES=sched.c list.c luaproc.c channel.c | ||
40 | OBJECTS=${SOURCES:.c=.o} | ||
41 | LIB=luaproc.so | ||
42 | |||
43 | all: ${SOURCES} ${LIB} | ||
44 | |||
45 | ${LIB}: ${OBJECTS} | ||
46 | ${CC} ${OBJECTS} -o $@ ${LDFLAGS} | ||
47 | |||
48 | sched.o: sched.c sched.h list.h luaproc.h channel.h | ||
49 | ${CC} ${CFLAGS} sched.c | ||
50 | |||
51 | list.o: list.c list.h | ||
52 | ${CC} ${CFLAGS} list.c | ||
53 | |||
54 | luaproc.o: luaproc.c luaproc.h list.h sched.h channel.h | ||
55 | ${CC} ${CFLAGS} luaproc.c | ||
56 | |||
57 | channel.o: channel.c channel.h list.h | ||
58 | ${CC} ${CFLAGS} channel.c | ||
59 | |||
60 | clean: | ||
61 | rm -f ${OBJECTS} ${LIB} | ||
62 | |||
63 | test: | ||
64 | lua test.lua | ||
65 | |||
diff --git a/libraries/luaproc/README b/libraries/luaproc/README deleted file mode 100644 index bc37dfe..0000000 --- a/libraries/luaproc/README +++ /dev/null | |||
@@ -1,97 +0,0 @@ | |||
1 | *************************************************** | ||
2 | * | ||
3 | * Copyright 2008 Alexandre Skyrme, Noemi Rodriguez, Roberto Ierusalimschy | ||
4 | * | ||
5 | * Permission is hereby granted, free of charge, to any person obtaining a copy | ||
6 | * of this software and associated documentation files (the "Software"), to deal | ||
7 | * in the Software without restriction, including without limitation the rights | ||
8 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
9 | * copies of the Software, and to permit persons to whom the Software is | ||
10 | * furnished to do so, subject to the following conditions: | ||
11 | * | ||
12 | * The above copyright notice and this permission notice shall be included in | ||
13 | * all copies or substantial portions of the Software. | ||
14 | * | ||
15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
18 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
21 | * THE SOFTWARE. | ||
22 | * | ||
23 | ***************************************************** | ||
24 | * | ||
25 | * [README] | ||
26 | * | ||
27 | **************************************************** | ||
28 | |||
29 | |||
30 | ************** | ||
31 | * PARENT API * | ||
32 | ************** | ||
33 | |||
34 | -- Create a new lua process | ||
35 | -- Returns true if sucessful or nil, error_message if failed | ||
36 | luaproc.newproc( <string lua_code> ) | ||
37 | |||
38 | -- Create a new worker (pthread) | ||
39 | -- Returns true if sucessful or nil, error_message if failed | ||
40 | luaproc.createworker( <void> ) | ||
41 | |||
42 | -- Destroy a worker (pthread) | ||
43 | -- Returns true if sucessful or nil, error_message if failed | ||
44 | luaproc.destroyworker( <void> ) | ||
45 | |||
46 | -- Synchronize workers (pthreads) and exit after all lua processes have ended | ||
47 | -- No return, finishes execution. | ||
48 | luaproc.exit( <void> ) | ||
49 | |||
50 | -- Set maximum lua processes that should be recycled (default = 0) | ||
51 | -- Returns true if sucessful or nil, error_message if failed | ||
52 | luaproc.recycle( <int maxrecycle> ) | ||
53 | |||
54 | ************************************************************ | ||
55 | * CHILD API * | ||
56 | * Available only to processes spawned * | ||
57 | * with luaproc.newproc * | ||
58 | ************************************************************ | ||
59 | |||
60 | -- Create a new lua process | ||
61 | -- Returns true if sucessful or nil, error_message if failed | ||
62 | luaproc.newproc( <string lua_code> ) | ||
63 | |||
64 | -- Create a new worker (pthread) | ||
65 | -- Returns true if sucessful or nil, error_message if failed | ||
66 | luaproc.createworker( <void> ) | ||
67 | |||
68 | -- Destroy a worker (pthread) | ||
69 | -- Returns true if sucessful or nil, error_message if failed | ||
70 | luaproc.destroyworker( <void> ) | ||
71 | |||
72 | -- Send a message on a channel | ||
73 | -- Returns true if sucessful or nil, error_message if failed | ||
74 | -- Results in blocking if there is no matching receive | ||
75 | luaproc.send( <string channel_name>, <string msg1>, | ||
76 | [string msg2], [string msg3], ... ) | ||
77 | |||
78 | -- Receive a message on a channel | ||
79 | -- Returns message string(s) if sucessful or nil, error_message if failed | ||
80 | -- Results in blocking if there is no matching send | ||
81 | -- and the asynchronous flag is not set (nil) or set to false | ||
82 | luaproc.receive( <string channel_name>, [boolean asynchronous] ) | ||
83 | |||
84 | -- Create a new channel | ||
85 | -- Returns true if sucessful or nil, error_message if failed | ||
86 | luaproc.newchannel( <string channel_name> ) | ||
87 | |||
88 | -- Destroy a channel | ||
89 | -- Returns true if sucessful or nil, error_message if failed | ||
90 | luaproc.delchannel( <string channel_name> ) | ||
91 | |||
92 | -- Set maximum lua processes that should be recycled (default = 0) | ||
93 | -- Returns true if sucessful or nil, error_message if failed | ||
94 | luaproc.recycle( <int maxrecycle> ) | ||
95 | |||
96 | <> = mandatory arguments | ||
97 | [] = optional arguments | ||
diff --git a/libraries/luaproc/channel.c b/libraries/luaproc/channel.c deleted file mode 100644 index ef4ab4b..0000000 --- a/libraries/luaproc/channel.c +++ /dev/null | |||
@@ -1,151 +0,0 @@ | |||
1 | /*************************************************** | ||
2 | |||
3 | Copyright 2008 Alexandre Skyrme, Noemi Rodriguez, Roberto Ierusalimschy | ||
4 | |||
5 | Permission is hereby granted, free of charge, to any person obtaining a copy | ||
6 | of this software and associated documentation files (the "Software"), to deal | ||
7 | in the Software without restriction, including without limitation the rights | ||
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
9 | copies of the Software, and to permit persons to whom the Software is | ||
10 | furnished to do so, subject to the following conditions: | ||
11 | |||
12 | The above copyright notice and this permission notice shall be included in | ||
13 | all copies or substantial portions of the Software. | ||
14 | |||
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
21 | THE SOFTWARE. | ||
22 | |||
23 | ***************************************************** | ||
24 | |||
25 | [channel.c] | ||
26 | |||
27 | ****************************************************/ | ||
28 | |||
29 | #include <stdio.h> | ||
30 | #include <stdlib.h> | ||
31 | #include <string.h> | ||
32 | #include <lua.h> | ||
33 | #include <lauxlib.h> | ||
34 | #include <lualib.h> | ||
35 | |||
36 | #include "channel.h" | ||
37 | #include "list.h" | ||
38 | |||
39 | /* global channel lua_State mutex */ | ||
40 | pthread_mutex_t mutex_channel_lstate = PTHREAD_MUTEX_INITIALIZER; | ||
41 | |||
42 | /* global lua_State where channel hash table will be stored */ | ||
43 | lua_State *chanls = NULL; | ||
44 | |||
45 | /* message channel */ | ||
46 | struct stchannel { | ||
47 | list send; | ||
48 | list recv; | ||
49 | pthread_mutex_t *mutex; | ||
50 | pthread_cond_t *in_use; | ||
51 | }; | ||
52 | |||
53 | /* initialize channel table */ | ||
54 | void channel_init( void ) { | ||
55 | chanls = luaL_newstate(); | ||
56 | lua_newtable( chanls ); | ||
57 | lua_setglobal( chanls, "channeltb" ); | ||
58 | } | ||
59 | |||
60 | /* create new channel */ | ||
61 | channel channel_create( const char *cname ) { | ||
62 | |||
63 | channel chan; | ||
64 | |||
65 | /* get exclusive access to the channel table */ | ||
66 | pthread_mutex_lock( &mutex_channel_lstate ); | ||
67 | |||
68 | /* create a new channel */ | ||
69 | lua_getglobal( chanls, "channeltb"); | ||
70 | lua_pushstring( chanls, cname ); | ||
71 | chan = (channel )lua_newuserdata( chanls, sizeof( struct stchannel )); | ||
72 | chan->send = list_new(); | ||
73 | chan->recv = list_new(); | ||
74 | chan->mutex = (pthread_mutex_t *)malloc( sizeof( pthread_mutex_t )); | ||
75 | pthread_mutex_init( chan->mutex, NULL ); | ||
76 | chan->in_use = (pthread_cond_t *)malloc( sizeof( pthread_cond_t )); | ||
77 | pthread_cond_init( chan->in_use, NULL ); | ||
78 | lua_settable( chanls, -3 ); | ||
79 | lua_pop( chanls, 1 ); | ||
80 | |||
81 | /* let others access the channel table */ | ||
82 | pthread_mutex_unlock( &mutex_channel_lstate ); | ||
83 | |||
84 | return chan; | ||
85 | } | ||
86 | |||
87 | /* destroy a channel */ | ||
88 | int channel_destroy( channel chan, const char *chname ) { | ||
89 | |||
90 | /* get exclusive access to the channel table */ | ||
91 | pthread_mutex_lock( &mutex_channel_lstate ); | ||
92 | |||
93 | list_destroy( chan->send ); | ||
94 | list_destroy( chan->recv ); | ||
95 | |||
96 | lua_getglobal( chanls, "channeltb"); | ||
97 | lua_pushstring( chanls, chname ); | ||
98 | lua_pushnil( chanls ); | ||
99 | lua_settable( chanls, -3 ); | ||
100 | lua_pop( chanls, 1 ); | ||
101 | |||
102 | /* let others access the channel table */ | ||
103 | pthread_mutex_unlock( &mutex_channel_lstate ); | ||
104 | |||
105 | return CHANNEL_DESTROYED; | ||
106 | } | ||
107 | |||
108 | /* search for and return a channel with a given name */ | ||
109 | channel channel_search( const char *cname ) { | ||
110 | |||
111 | channel chan; | ||
112 | |||
113 | /* get exclusive access to the channel table */ | ||
114 | pthread_mutex_lock( &mutex_channel_lstate ); | ||
115 | |||
116 | /* search for channel */ | ||
117 | lua_getglobal( chanls, "channeltb"); | ||
118 | lua_getfield( chanls, -1, cname ); | ||
119 | if (( lua_type( chanls, -1 )) == LUA_TUSERDATA ) { | ||
120 | chan = (channel )lua_touserdata( chanls, -1 ); | ||
121 | } else { | ||
122 | chan = NULL; | ||
123 | } | ||
124 | lua_pop( chanls, 2 ); | ||
125 | |||
126 | /* let others access channel table */ | ||
127 | pthread_mutex_unlock( &mutex_channel_lstate ); | ||
128 | |||
129 | return chan; | ||
130 | } | ||
131 | |||
132 | /* return a channel's send queue */ | ||
133 | list channel_get_sendq( channel chan ) { | ||
134 | return chan->send; | ||
135 | } | ||
136 | |||
137 | /* return a channel's receive queue */ | ||
138 | list channel_get_recvq( channel chan ) { | ||
139 | return chan->recv; | ||
140 | } | ||
141 | |||
142 | /* return a channel's mutex */ | ||
143 | pthread_mutex_t *channel_get_mutex( channel chan ) { | ||
144 | return chan->mutex; | ||
145 | } | ||
146 | |||
147 | /* return a channel's conditional variable */ | ||
148 | pthread_cond_t *channel_get_cond( channel chan ) { | ||
149 | return chan->in_use; | ||
150 | } | ||
151 | |||
diff --git a/libraries/luaproc/channel.h b/libraries/luaproc/channel.h deleted file mode 100644 index 1cced9e..0000000 --- a/libraries/luaproc/channel.h +++ /dev/null | |||
@@ -1,67 +0,0 @@ | |||
1 | /*************************************************** | ||
2 | |||
3 | Copyright 2008 Alexandre Skyrme, Noemi Rodriguez, Roberto Ierusalimschy | ||
4 | |||
5 | Permission is hereby granted, free of charge, to any person obtaining a copy | ||
6 | of this software and associated documentation files (the "Software"), to deal | ||
7 | in the Software without restriction, including without limitation the rights | ||
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
9 | copies of the Software, and to permit persons to whom the Software is | ||
10 | furnished to do so, subject to the following conditions: | ||
11 | |||
12 | The above copyright notice and this permission notice shall be included in | ||
13 | all copies or substantial portions of the Software. | ||
14 | |||
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
21 | THE SOFTWARE. | ||
22 | |||
23 | ***************************************************** | ||
24 | |||
25 | [channel.h] | ||
26 | |||
27 | ****************************************************/ | ||
28 | |||
29 | #ifndef _CHANNEL_H_ | ||
30 | #define _CHANNEL_H_ | ||
31 | |||
32 | #include <pthread.h> | ||
33 | |||
34 | #include "list.h" | ||
35 | |||
36 | #define CHANNEL_MAX_NAME_LENGTH 255 | ||
37 | |||
38 | #define CHANNEL_DESTROYED 0 | ||
39 | |||
40 | /* message channel pointer type */ | ||
41 | typedef struct stchannel *channel; | ||
42 | |||
43 | /* initialize channels */ | ||
44 | void channel_init( void ); | ||
45 | |||
46 | /* create new channel */ | ||
47 | channel channel_create( const char *cname ); | ||
48 | |||
49 | /* destroy a channel */ | ||
50 | int channel_destroy( channel chan, const char *chname ); | ||
51 | |||
52 | /* search for and return a channel with a given name */ | ||
53 | channel channel_search( const char *cname ); | ||
54 | |||
55 | /* return a channel's send queue */ | ||
56 | list channel_get_sendq( channel chan ); | ||
57 | |||
58 | /* return a channel's receive queue */ | ||
59 | list channel_get_recvq( channel chan ); | ||
60 | |||
61 | /* return a channel's mutex */ | ||
62 | pthread_mutex_t *channel_get_mutex( channel chan ); | ||
63 | |||
64 | /* return a channel's conditional variable */ | ||
65 | pthread_cond_t *channel_get_cond( channel chan ); | ||
66 | |||
67 | #endif | ||
diff --git a/libraries/luaproc/list.c b/libraries/luaproc/list.c deleted file mode 100644 index 0088695..0000000 --- a/libraries/luaproc/list.c +++ /dev/null | |||
@@ -1,241 +0,0 @@ | |||
1 | /*************************************************** | ||
2 | |||
3 | Copyright 2008 Alexandre Skyrme, Noemi Rodriguez, Roberto Ierusalimschy | ||
4 | |||
5 | Permission is hereby granted, free of charge, to any person obtaining a copy | ||
6 | of this software and associated documentation files (the "Software"), to deal | ||
7 | in the Software without restriction, including without limitation the rights | ||
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
9 | copies of the Software, and to permit persons to whom the Software is | ||
10 | furnished to do so, subject to the following conditions: | ||
11 | |||
12 | The above copyright notice and this permission notice shall be included in | ||
13 | all copies or substantial portions of the Software. | ||
14 | |||
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
21 | THE SOFTWARE. | ||
22 | |||
23 | ***************************************************** | ||
24 | |||
25 | [list.c] | ||
26 | |||
27 | ****************************************************/ | ||
28 | #include <stdio.h> | ||
29 | #include <stdlib.h> | ||
30 | |||
31 | #include "list.h" | ||
32 | |||
33 | /* linked list node */ | ||
34 | struct stnode { | ||
35 | void *data; | ||
36 | struct stnode *next; | ||
37 | struct stnode *prev; | ||
38 | }; | ||
39 | |||
40 | /* linked list */ | ||
41 | struct stlist { | ||
42 | node head; | ||
43 | node tail; | ||
44 | int nodes; | ||
45 | }; | ||
46 | |||
47 | /* create new (empty) list */ | ||
48 | list list_new( void ) { | ||
49 | list lst; | ||
50 | lst = (list )malloc( sizeof( struct stlist )); | ||
51 | if ( lst == NULL ) { | ||
52 | return lst; | ||
53 | } | ||
54 | lst->head = NULL; | ||
55 | lst->tail = NULL; | ||
56 | lst->nodes = 0; | ||
57 | return lst; | ||
58 | } | ||
59 | |||
60 | /* create new node */ | ||
61 | node list_new_node( void *data ) { | ||
62 | node n; | ||
63 | n = (node )malloc( sizeof( struct stnode )); | ||
64 | if ( n == NULL ) { | ||
65 | return n; | ||
66 | } | ||
67 | n->data = data; | ||
68 | n->next = NULL; | ||
69 | n->prev = NULL; | ||
70 | return n; | ||
71 | } | ||
72 | |||
73 | /* add node to list */ | ||
74 | node list_add( list lst, node n ) { | ||
75 | |||
76 | /* void list or node */ | ||
77 | if (( lst == NULL ) || ( n == NULL )) { | ||
78 | return NULL; | ||
79 | } | ||
80 | |||
81 | /* list is empty */ | ||
82 | if ( lst->head == NULL ) { | ||
83 | lst->head = n; | ||
84 | lst->tail = n; | ||
85 | } | ||
86 | |||
87 | /* list is _not_ empty */ | ||
88 | else { | ||
89 | lst->tail->next = n; | ||
90 | n->prev = lst->tail; | ||
91 | lst->tail = n; | ||
92 | } | ||
93 | |||
94 | lst->nodes++; | ||
95 | return n; | ||
96 | } | ||
97 | |||
98 | /* search for a node */ | ||
99 | node list_search( list lst, void *data ) { | ||
100 | |||
101 | node nitr; | ||
102 | |||
103 | /* check if list is null or empty */ | ||
104 | if (( lst == NULL ) || ( lst->head == NULL )) { | ||
105 | return NULL; | ||
106 | } | ||
107 | |||
108 | /* look for node between first and last nodes (first and last are included) */ | ||
109 | for ( nitr = lst->head; nitr != NULL; nitr = nitr->next ) { | ||
110 | if ( nitr->data == data ) { | ||
111 | /* node found, return it */ | ||
112 | return nitr; | ||
113 | } | ||
114 | } | ||
115 | |||
116 | /* node not found */ | ||
117 | return NULL; | ||
118 | } | ||
119 | |||
120 | /* remove node from list */ | ||
121 | void list_remove( list lst, node n ) { | ||
122 | |||
123 | node nitr; | ||
124 | |||
125 | /* check if list or node are null and if list is empty */ | ||
126 | if (( lst == NULL ) || ( n == NULL ) || ( lst->head == NULL )) { | ||
127 | return; | ||
128 | } | ||
129 | |||
130 | /* check if node is list's head */ | ||
131 | if ( lst->head == n ) { | ||
132 | lst->head = n->next; | ||
133 | /* if so, also check if it's the only node in the list */ | ||
134 | if ( lst->tail == n ) { | ||
135 | lst->tail = n->next; | ||
136 | } | ||
137 | else { | ||
138 | lst->head->prev = NULL; | ||
139 | } | ||
140 | free( n ); | ||
141 | lst->nodes--; | ||
142 | return; | ||
143 | } | ||
144 | |||
145 | /* look for node between first and last nodes (first and last are excluded) */ | ||
146 | for ( nitr = lst->head->next; nitr != lst->tail; nitr = nitr->next ) { | ||
147 | if ( nitr == n ) { | ||
148 | n->prev->next = n->next; | ||
149 | n->next->prev = n->prev; | ||
150 | free( n ); | ||
151 | lst->nodes--; | ||
152 | return; | ||
153 | } | ||
154 | } | ||
155 | |||
156 | /* check if node is list's tail */ | ||
157 | if ( lst->tail == n ) { | ||
158 | lst->tail = n->prev; | ||
159 | n->prev->next = n->next; | ||
160 | free( n ); | ||
161 | lst->nodes--; | ||
162 | return; | ||
163 | } | ||
164 | |||
165 | return; | ||
166 | } | ||
167 | |||
168 | /* list_destroy */ | ||
169 | void list_destroy( list lst ) { | ||
170 | |||
171 | /* empty list */ | ||
172 | if ( lst == NULL ) { | ||
173 | return; | ||
174 | } | ||
175 | |||
176 | /* non-empty list */ | ||
177 | while ( lst->head != NULL ) { | ||
178 | list_remove( lst, lst->head ); | ||
179 | } | ||
180 | |||
181 | free( lst ); | ||
182 | } | ||
183 | |||
184 | /* return list's first node */ | ||
185 | node list_head( list lst ) { | ||
186 | if ( lst != NULL ) { | ||
187 | return lst->head; | ||
188 | } | ||
189 | return NULL; | ||
190 | } | ||
191 | |||
192 | /* return node's next node */ | ||
193 | node list_next( node n ) { | ||
194 | if ( n != NULL ) { | ||
195 | return n->next; | ||
196 | } | ||
197 | return NULL; | ||
198 | } | ||
199 | |||
200 | /* return a node's data */ | ||
201 | void *list_data( node n ) { | ||
202 | if ( n != NULL ) { | ||
203 | return n->data; | ||
204 | } | ||
205 | return NULL; | ||
206 | } | ||
207 | |||
208 | /* pop the head node from the list */ | ||
209 | node list_pop_head( list lst ) { | ||
210 | node ntmp; | ||
211 | if (( lst == NULL ) || ( lst->head == NULL )) { | ||
212 | return NULL; | ||
213 | } | ||
214 | |||
215 | ntmp = lst->head; | ||
216 | if ( lst->head == lst->tail ) { | ||
217 | lst->head = NULL; | ||
218 | lst->tail = NULL; | ||
219 | } else { | ||
220 | lst->head = ntmp->next; | ||
221 | ntmp->next->prev = NULL; | ||
222 | } | ||
223 | ntmp->next = NULL; | ||
224 | ntmp->prev = NULL; | ||
225 | lst->nodes--; | ||
226 | return ntmp; | ||
227 | } | ||
228 | |||
229 | /* destroy a node */ | ||
230 | void list_destroy_node( node n ) { | ||
231 | free( n ); | ||
232 | } | ||
233 | |||
234 | /* return a list's node count */ | ||
235 | int list_node_count( list lst ) { | ||
236 | if ( lst != NULL ) { | ||
237 | return lst->nodes; | ||
238 | } | ||
239 | return LIST_COUNT_ERROR; | ||
240 | } | ||
241 | |||
diff --git a/libraries/luaproc/list.h b/libraries/luaproc/list.h deleted file mode 100644 index 6aa21c0..0000000 --- a/libraries/luaproc/list.h +++ /dev/null | |||
@@ -1,76 +0,0 @@ | |||
1 | /*************************************************** | ||
2 | |||
3 | Copyright 2008 Alexandre Skyrme, Noemi Rodriguez, Roberto Ierusalimschy | ||
4 | |||
5 | Permission is hereby granted, free of charge, to any person obtaining a copy | ||
6 | of this software and associated documentation files (the "Software"), to deal | ||
7 | in the Software without restriction, including without limitation the rights | ||
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
9 | copies of the Software, and to permit persons to whom the Software is | ||
10 | furnished to do so, subject to the following conditions: | ||
11 | |||
12 | The above copyright notice and this permission notice shall be included in | ||
13 | all copies or substantial portions of the Software. | ||
14 | |||
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
21 | THE SOFTWARE. | ||
22 | |||
23 | ***************************************************** | ||
24 | |||
25 | [list.h] | ||
26 | |||
27 | ****************************************************/ | ||
28 | |||
29 | #ifndef _LIST_H_ | ||
30 | #define _LIST_H_ | ||
31 | |||
32 | #define LIST_COUNT_ERROR -1 | ||
33 | |||
34 | /* node pointer type */ | ||
35 | typedef struct stnode *node; | ||
36 | |||
37 | /* list pointer type */ | ||
38 | typedef struct stlist *list; | ||
39 | |||
40 | /* create new (empty) list */ | ||
41 | list list_new( void ); | ||
42 | |||
43 | /* create new node */ | ||
44 | node list_new_node( void *data ); | ||
45 | |||
46 | /* add node to list */ | ||
47 | node list_add( list lst, node n ); | ||
48 | |||
49 | /* search for a node */ | ||
50 | node list_search( list lst, void *data ); | ||
51 | |||
52 | /* remove node from list */ | ||
53 | void list_remove( list lst, node n ); | ||
54 | |||
55 | /* destroy list */ | ||
56 | void list_destroy( list lst ); | ||
57 | |||
58 | /* return list's first node */ | ||
59 | node list_head( list lst ); | ||
60 | |||
61 | /* return node's next node */ | ||
62 | node list_next( node n ); | ||
63 | |||
64 | /* return a node's data */ | ||
65 | void *list_data( node n ); | ||
66 | |||
67 | /* pop the head node from the list */ | ||
68 | node list_pop_head( list lst ); | ||
69 | |||
70 | /* destroy a node */ | ||
71 | void list_destroy_node( node n ); | ||
72 | |||
73 | /* return a list's node count */ | ||
74 | int list_node_count( list lst ); | ||
75 | |||
76 | #endif | ||
diff --git a/libraries/luaproc/luaproc.c b/libraries/luaproc/luaproc.c deleted file mode 100644 index 78c713f..0000000 --- a/libraries/luaproc/luaproc.c +++ /dev/null | |||
@@ -1,931 +0,0 @@ | |||
1 | /*************************************************** | ||
2 | |||
3 | Copyright 2008 Alexandre Skyrme, Noemi Rodriguez, Roberto Ierusalimschy | ||
4 | |||
5 | Permission is hereby granted, free of charge, to any person obtaining a copy | ||
6 | of this software and associated documentation files (the "Software"), to deal | ||
7 | in the Software without restriction, including without limitation the rights | ||
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
9 | copies of the Software, and to permit persons to whom the Software is | ||
10 | furnished to do so, subject to the following conditions: | ||
11 | |||
12 | The above copyright notice and this permission notice shall be included in | ||
13 | all copies or substantial portions of the Software. | ||
14 | |||
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
21 | THE SOFTWARE. | ||
22 | |||
23 | ***************************************************** | ||
24 | |||
25 | [luaproc.c] | ||
26 | |||
27 | ****************************************************/ | ||
28 | |||
29 | #include <netdb.h> | ||
30 | #include <pthread.h> | ||
31 | #include <stdio.h> | ||
32 | #include <stdlib.h> | ||
33 | #include <string.h> | ||
34 | #include <unistd.h> | ||
35 | #include <lua.h> | ||
36 | #include <lauxlib.h> | ||
37 | #include <lualib.h> | ||
38 | |||
39 | #include "luaproc.h" | ||
40 | #include "list.h" | ||
41 | #include "sched.h" | ||
42 | #include "channel.h" | ||
43 | |||
44 | |||
45 | #define FALSE 0 | ||
46 | #define TRUE 1 | ||
47 | |||
48 | /********* | ||
49 | * globals | ||
50 | *********/ | ||
51 | |||
52 | /* channel operations mutex */ | ||
53 | pthread_mutex_t mutex_channel = PTHREAD_MUTEX_INITIALIZER; | ||
54 | |||
55 | /* recycle list mutex */ | ||
56 | pthread_mutex_t mutex_recycle_list = PTHREAD_MUTEX_INITIALIZER; | ||
57 | |||
58 | /* recycled lua process list */ | ||
59 | list recyclelp = NULL; | ||
60 | |||
61 | /* maximum lua processes to recycle */ | ||
62 | int recyclemax = 0; | ||
63 | |||
64 | /* lua process */ | ||
65 | struct stluaproc { | ||
66 | lua_State *lstate; | ||
67 | int stat; | ||
68 | int args; | ||
69 | channel chan; | ||
70 | int destroyworker; | ||
71 | void *data; | ||
72 | Ecore_Cb callback; | ||
73 | }; | ||
74 | |||
75 | /* TODO - hack, duplicating something from LuaSL for now. */ | ||
76 | typedef struct | ||
77 | { | ||
78 | void *script; | ||
79 | char message[PATH_MAX]; | ||
80 | } scriptMessage; | ||
81 | |||
82 | |||
83 | /****************************** | ||
84 | * library functions prototypes | ||
85 | ******************************/ | ||
86 | /* create a new lua process */ | ||
87 | static int luaproc_create_newproc( lua_State *L ); | ||
88 | /* send a message to a lua process */ | ||
89 | static int luaproc_send( lua_State *L ); | ||
90 | /* receive a message from a lua process */ | ||
91 | static int luaproc_receive( lua_State *L ); | ||
92 | /* create a new channel */ | ||
93 | static int luaproc_create_channel( lua_State *L ); | ||
94 | /* destroy a channel */ | ||
95 | static int luaproc_destroy_channel( lua_State *L ); | ||
96 | /* wait until all luaprocs have finished and exit */ | ||
97 | static int luaproc_exit( lua_State *L ); | ||
98 | /* create a new worker */ | ||
99 | static int luaproc_create_worker( lua_State *L ); | ||
100 | /* destroy a worker */ | ||
101 | static int luaproc_destroy_worker( lua_State *L ); | ||
102 | /* set amount of lua processes that should be recycled (ie, reused) */ | ||
103 | static int luaproc_recycle_set( lua_State *L ); | ||
104 | /* send a message back to the main loop */ | ||
105 | static int luaproc_send_back( lua_State *L ); | ||
106 | |||
107 | /* luaproc function registration array - main (parent) functions */ | ||
108 | static const struct luaL_reg luaproc_funcs_parent[] = { | ||
109 | { "newproc", luaproc_create_newproc }, | ||
110 | { "exit", luaproc_exit }, | ||
111 | { "createworker", luaproc_create_worker }, | ||
112 | { "destroyworker", luaproc_destroy_worker }, | ||
113 | { "recycle", luaproc_recycle_set }, | ||
114 | { "sendback", luaproc_send_back }, | ||
115 | { NULL, NULL } | ||
116 | }; | ||
117 | |||
118 | /* luaproc function registration array - newproc (child) functions */ | ||
119 | static const struct luaL_reg luaproc_funcs_child[] = { | ||
120 | { "newproc", luaproc_create_newproc }, | ||
121 | { "send", luaproc_send }, | ||
122 | { "receive", luaproc_receive }, | ||
123 | { "newchannel", luaproc_create_channel }, | ||
124 | { "delchannel", luaproc_destroy_channel }, | ||
125 | { "createworker", luaproc_create_worker }, | ||
126 | { "destroyworker", luaproc_destroy_worker }, | ||
127 | { "recycle", luaproc_recycle_set }, | ||
128 | { "sendback", luaproc_send_back }, | ||
129 | { NULL, NULL } | ||
130 | }; | ||
131 | |||
132 | /* | ||
133 | static void registerlib( lua_State *L, const char *name, lua_CFunction f ) { | ||
134 | lua_getglobal( L, "package" ); | ||
135 | lua_getfield( L, -1, "preload" ); | ||
136 | lua_pushcfunction( L, f ); | ||
137 | lua_setfield( L, -2, name ); | ||
138 | lua_pop( L, 2 ); | ||
139 | } | ||
140 | */ | ||
141 | static void openlibs( lua_State *L ) { | ||
142 | /* | ||
143 | lua_cpcall( L, luaopen_base, NULL ); | ||
144 | lua_cpcall( L, luaopen_package, NULL ); | ||
145 | registerlib( L, "io", luaopen_io ); | ||
146 | registerlib( L, "os", luaopen_os ); | ||
147 | registerlib( L, "table", luaopen_table ); | ||
148 | registerlib( L, "string", luaopen_string ); | ||
149 | registerlib( L, "math", luaopen_math ); | ||
150 | registerlib( L, "debug", luaopen_debug ); | ||
151 | */ | ||
152 | luaL_openlibs(L); | ||
153 | } | ||
154 | |||
155 | /* return status (boolean) indicating if lua process should be recycled */ | ||
156 | luaproc luaproc_recycle_pop( void ) { | ||
157 | |||
158 | luaproc lp; | ||
159 | node n; | ||
160 | |||
161 | /* get exclusive access to operate on recycle list */ | ||
162 | pthread_mutex_lock( &mutex_recycle_list ); | ||
163 | |||
164 | /* check if there are any lua processes on recycle list */ | ||
165 | if ( list_node_count( recyclelp ) > 0 ) { | ||
166 | /* pop list head */ | ||
167 | n = list_pop_head( recyclelp ); | ||
168 | /* free access to operate on recycle list */ | ||
169 | pthread_mutex_unlock( &mutex_recycle_list ); | ||
170 | /* find associated luaproc */ | ||
171 | lp = (luaproc )list_data( n ); | ||
172 | /* destroy node (but not associated luaproc) */ | ||
173 | list_destroy_node( n ); | ||
174 | /* return associated luaproc */ | ||
175 | return lp; | ||
176 | } | ||
177 | |||
178 | /* free access to operate on recycle list */ | ||
179 | pthread_mutex_unlock( &mutex_recycle_list ); | ||
180 | |||
181 | /* if no lua processes are available simply return null */ | ||
182 | return NULL; | ||
183 | } | ||
184 | |||
185 | /* check if lua process should be recycled and, in case so, add it to the recycle list */ | ||
186 | int luaproc_recycle_push( luaproc lp ) { | ||
187 | |||
188 | node n; | ||
189 | |||
190 | /* get exclusive access to operate on recycle list */ | ||
191 | pthread_mutex_lock( &mutex_recycle_list ); | ||
192 | |||
193 | /* check if amount of lua processes currently on recycle list is greater than | ||
194 | or equal to the maximum amount of lua processes that should be recycled */ | ||
195 | if ( list_node_count( recyclelp ) >= recyclemax ) { | ||
196 | /* free access to operate on recycle list */ | ||
197 | pthread_mutex_unlock( &mutex_recycle_list ); | ||
198 | /* if so, lua process should NOT be recycled and should be destroyed */ | ||
199 | return FALSE; | ||
200 | } | ||
201 | /* otherwise, lua process should be added to recycle list */ | ||
202 | n = list_new_node( lp ); | ||
203 | if ( n == NULL ) { | ||
204 | /* free access to operate on recycle list */ | ||
205 | pthread_mutex_unlock( &mutex_recycle_list ); | ||
206 | /* in case of errors, lua process should be destroyed */ | ||
207 | return FALSE; | ||
208 | } | ||
209 | list_add( recyclelp, n ); | ||
210 | /* free access to operate on recycle list */ | ||
211 | pthread_mutex_unlock( &mutex_recycle_list ); | ||
212 | /* since lua process will be recycled, it should not be destroyed */ | ||
213 | return TRUE; | ||
214 | } | ||
215 | |||
216 | /* create new luaproc */ | ||
217 | static luaproc luaproc_new( const char *code, int destroyflag, int file) { | ||
218 | |||
219 | luaproc lp; | ||
220 | int ret; | ||
221 | /* create new lua state */ | ||
222 | lua_State *lpst = luaL_newstate( ); | ||
223 | /* store the luaproc struct in its own lua state */ | ||
224 | lp = (luaproc )lua_newuserdata( lpst, sizeof( struct stluaproc )); | ||
225 | lua_setfield( lpst, LUA_REGISTRYINDEX, "_SELF" ); | ||
226 | |||
227 | lp->lstate = lpst; | ||
228 | lp->stat = LUAPROC_STAT_IDLE; | ||
229 | lp->args = 0; | ||
230 | lp->chan = NULL; | ||
231 | lp->destroyworker = destroyflag; | ||
232 | |||
233 | /* load standard libraries */ | ||
234 | openlibs( lpst ); | ||
235 | |||
236 | /* register luaproc's own functions */ | ||
237 | luaL_register( lpst, "luaproc", luaproc_funcs_child ); | ||
238 | |||
239 | /* load process' code */ | ||
240 | if (file) | ||
241 | ret = luaL_loadfile( lpst, code ); | ||
242 | else | ||
243 | ret = luaL_loadstring( lpst, code ); | ||
244 | /* in case of errors, destroy recently created lua process */ | ||
245 | if ( ret != 0 ) { | ||
246 | lua_close( lpst ); | ||
247 | return NULL; | ||
248 | } | ||
249 | |||
250 | /* return recently created lua process */ | ||
251 | return lp; | ||
252 | } | ||
253 | |||
254 | /* synchronize worker threads and exit */ | ||
255 | static int luaproc_exit( lua_State *L ) { | ||
256 | sched_join_workerthreads(); | ||
257 | return 0; | ||
258 | } | ||
259 | |||
260 | /* create a new worker pthread */ | ||
261 | static int luaproc_create_worker( lua_State *L ) { | ||
262 | |||
263 | if ( sched_create_worker( ) != LUAPROC_SCHED_OK ) { | ||
264 | lua_pushnil( L ); | ||
265 | lua_pushstring( L, "error creating worker" ); | ||
266 | return 2; | ||
267 | } | ||
268 | |||
269 | lua_pushboolean( L, TRUE ); | ||
270 | return 1; | ||
271 | } | ||
272 | |||
273 | /* set amount of lua processes that should be recycled (ie, reused) */ | ||
274 | static int luaproc_recycle_set( lua_State *L ) { | ||
275 | |||
276 | node n; | ||
277 | luaproc lp; | ||
278 | int max = luaL_checkint( L, 1 ); | ||
279 | |||
280 | /* check if function argument represents a reasonable value */ | ||
281 | if ( max < 0 ) { | ||
282 | /* in case of errors return nil + error msg */ | ||
283 | lua_pushnil( L ); | ||
284 | lua_pushstring( L, "error setting recycle limit to negative value" ); | ||
285 | return 2; | ||
286 | } | ||
287 | |||
288 | /* get exclusive access to operate on recycle list */ | ||
289 | pthread_mutex_lock( &mutex_recycle_list ); | ||
290 | |||
291 | /* set maximum lua processes that should be recycled */ | ||
292 | recyclemax = max; | ||
293 | |||
294 | /* destroy recycle list excessive nodes (and corresponding lua processes) */ | ||
295 | while ( list_node_count( recyclelp ) > max ) { | ||
296 | /* get first node from recycle list */ | ||
297 | n = list_pop_head( recyclelp ); | ||
298 | /* find associated luaproc */ | ||
299 | lp = (luaproc )list_data( n ); | ||
300 | /* destroy node */ | ||
301 | list_destroy_node( n ); | ||
302 | /* close associated lua_State */ | ||
303 | lua_close( lp->lstate ); | ||
304 | } | ||
305 | |||
306 | /* free access to operate on recycle list */ | ||
307 | pthread_mutex_unlock( &mutex_recycle_list ); | ||
308 | |||
309 | lua_pushboolean( L, TRUE ); | ||
310 | return 1; | ||
311 | } | ||
312 | |||
313 | |||
314 | /* destroy a worker pthread */ | ||
315 | static int luaproc_destroy_worker( lua_State *L ) { | ||
316 | |||
317 | /* new lua process pointer */ | ||
318 | luaproc lp; | ||
319 | |||
320 | /* create new lua process with empty code and destroy worker flag set to true | ||
321 | (ie, conclusion of lua process WILL result in worker thread destruction */ | ||
322 | lp = luaproc_new( "", TRUE, FALSE ); | ||
323 | |||
324 | /* ensure process creation was successfull */ | ||
325 | if ( lp == NULL ) { | ||
326 | /* in case of errors return nil + error msg */ | ||
327 | lua_pushnil( L ); | ||
328 | lua_pushstring( L, "error destroying worker" ); | ||
329 | return 2; | ||
330 | } | ||
331 | |||
332 | /* increase active luaproc count */ | ||
333 | sched_lpcount_inc(); | ||
334 | |||
335 | /* schedule luaproc */ | ||
336 | if ( sched_queue_proc( lp ) != LUAPROC_SCHED_QUEUE_PROC_OK ) { | ||
337 | printf( "[luaproc] error queueing Lua process\n" ); | ||
338 | /* decrease active luaproc count */ | ||
339 | sched_lpcount_dec(); | ||
340 | /* close lua_State */ | ||
341 | lua_close( lp->lstate ); | ||
342 | /* return nil + error msg */ | ||
343 | lua_pushnil( L ); | ||
344 | lua_pushstring( L, "error destroying worker" ); | ||
345 | return 2; | ||
346 | } | ||
347 | |||
348 | lua_pushboolean( L, TRUE ); | ||
349 | return 1; | ||
350 | } | ||
351 | |||
352 | /* recycle a lua process */ | ||
353 | static luaproc luaproc_recycle( luaproc lp, const char *code, int file ) { | ||
354 | |||
355 | int ret; | ||
356 | |||
357 | /* reset struct members */ | ||
358 | lp->stat = LUAPROC_STAT_IDLE; | ||
359 | lp->args = 0; | ||
360 | lp->chan = NULL; | ||
361 | lp->destroyworker = FALSE; | ||
362 | |||
363 | /* load process' code */ | ||
364 | ret = luaL_loadstring( lp->lstate, code ); | ||
365 | |||
366 | /* in case of errors, destroy lua process */ | ||
367 | if ( ret != 0 ) { | ||
368 | lua_close( lp->lstate ); | ||
369 | return NULL; | ||
370 | } | ||
371 | |||
372 | /* return recycled lua process */ | ||
373 | return lp; | ||
374 | } | ||
375 | |||
376 | |||
377 | int newProc(const char *code, int file, Ecore_Cb callback, void *data) | ||
378 | { | ||
379 | /* new lua process pointer */ | ||
380 | luaproc lp; | ||
381 | |||
382 | /* check if existing lua process should be recycled to avoid new creation */ | ||
383 | lp = luaproc_recycle_pop( ); | ||
384 | |||
385 | /* if there is a lua process available on the recycle queue, recycle it */ | ||
386 | if ( lp != NULL ) { | ||
387 | lp = luaproc_recycle( lp, code, file ); | ||
388 | } | ||
389 | /* otherwise create a new one from scratch */ | ||
390 | else { | ||
391 | /* create new lua process with destroy worker flag set to false | ||
392 | (ie, conclusion of lua process will NOT result in worker thread destruction */ | ||
393 | lp = luaproc_new( code, FALSE, file ); | ||
394 | } | ||
395 | |||
396 | /* ensure process creation was successfull */ | ||
397 | if ( lp == NULL ) { | ||
398 | return 1; | ||
399 | } | ||
400 | |||
401 | /* Stash any data and callback given to us. */ | ||
402 | lp->data = data; | ||
403 | lp->callback = callback; | ||
404 | |||
405 | /* increase active luaproc count */ | ||
406 | sched_lpcount_inc(); | ||
407 | |||
408 | /* schedule luaproc */ | ||
409 | if ( sched_queue_proc( lp ) != LUAPROC_SCHED_QUEUE_PROC_OK ) { | ||
410 | printf( "[luaproc] error queueing Lua process\n" ); | ||
411 | /* decrease active luaproc count */ | ||
412 | sched_lpcount_dec(); | ||
413 | /* close lua_State */ | ||
414 | lua_close( lp->lstate ); | ||
415 | return 2; | ||
416 | } | ||
417 | |||
418 | return 0; | ||
419 | } | ||
420 | |||
421 | /* create and schedule a new lua process (luaproc.newproc) */ | ||
422 | static int luaproc_create_newproc( lua_State *L ) { | ||
423 | |||
424 | /* check if first argument is a string (lua code) */ | ||
425 | const char *code = luaL_checkstring( L, 1 ); | ||
426 | |||
427 | switch (newProc(code, FALSE, NULL, NULL)) | ||
428 | { | ||
429 | case 1 : | ||
430 | /* in case of errors return nil + error msg */ | ||
431 | lua_pushnil( L ); | ||
432 | lua_pushstring( L, "error loading code string" ); | ||
433 | return 2; | ||
434 | case 2 : | ||
435 | /* return nil + error msg */ | ||
436 | lua_pushnil( L ); | ||
437 | lua_pushstring( L, "error queuing process" ); | ||
438 | return 2; | ||
439 | } | ||
440 | |||
441 | lua_pushboolean( L, TRUE ); | ||
442 | return 1; | ||
443 | } | ||
444 | |||
445 | /* queue a lua process sending a message without a matching receiver */ | ||
446 | void luaproc_queue_sender( luaproc lp ) { | ||
447 | /* add the sending process to this process' send queue */ | ||
448 | list_add( channel_get_sendq( lp->chan ), list_new_node( lp )); | ||
449 | } | ||
450 | |||
451 | /* dequeue a lua process sending a message with a receiver match */ | ||
452 | luaproc luaproc_dequeue_sender( channel chan ) { | ||
453 | |||
454 | node n; | ||
455 | luaproc lp; | ||
456 | |||
457 | if ( list_node_count( channel_get_sendq( chan )) > 0 ) { | ||
458 | /* get first node from channel's send queue */ | ||
459 | n = list_pop_head( channel_get_sendq( chan )); | ||
460 | /* find associated luaproc */ | ||
461 | lp = (luaproc )list_data( n ); | ||
462 | /* destroy node (but not associated luaproc) */ | ||
463 | list_destroy_node( n ); | ||
464 | /* return associated luaproc */ | ||
465 | return lp; | ||
466 | } | ||
467 | |||
468 | return NULL; | ||
469 | } | ||
470 | |||
471 | /* queue a luc process receiving a message without a matching sender */ | ||
472 | void luaproc_queue_receiver( luaproc lp ) { | ||
473 | /* add the receiving process to this process' receive queue */ | ||
474 | list_add( channel_get_recvq( lp->chan ), list_new_node( lp )); | ||
475 | } | ||
476 | |||
477 | /* dequeue a lua process receiving a message with a sender match */ | ||
478 | luaproc luaproc_dequeue_receiver( channel chan ) { | ||
479 | |||
480 | node n; | ||
481 | luaproc lp; | ||
482 | |||
483 | if ( list_node_count( channel_get_recvq( chan )) > 0 ) { | ||
484 | /* get first node from channel's recv queue */ | ||
485 | n = list_pop_head( channel_get_recvq( chan )); | ||
486 | /* find associated luaproc */ | ||
487 | lp = (luaproc )list_data( n ); | ||
488 | /* destroy node (but not associated luaproc) */ | ||
489 | list_destroy_node( n ); | ||
490 | /* return associated luaproc */ | ||
491 | return lp; | ||
492 | } | ||
493 | |||
494 | return NULL; | ||
495 | } | ||
496 | |||
497 | /* moves values between lua states' stacks */ | ||
498 | void luaproc_movevalues( lua_State *Lfrom, lua_State *Lto ) { | ||
499 | |||
500 | int i; | ||
501 | int n = lua_gettop( Lfrom ); | ||
502 | |||
503 | /* move values between lua states' stacks */ | ||
504 | for ( i = 2; i <= n; i++ ) { | ||
505 | lua_pushstring( Lto, lua_tostring( Lfrom, i )); | ||
506 | } | ||
507 | } | ||
508 | |||
509 | /* return the lua process associated with a given lua state */ | ||
510 | luaproc luaproc_getself( lua_State *L ) { | ||
511 | luaproc lp; | ||
512 | lua_getfield( L, LUA_REGISTRYINDEX, "_SELF" ); | ||
513 | lp = (luaproc )lua_touserdata( L, -1 ); | ||
514 | lua_pop( L, 1 ); | ||
515 | return lp; | ||
516 | } | ||
517 | |||
518 | /* send a message to a lua process */ | ||
519 | static int luaproc_send_back( lua_State *L ) { | ||
520 | |||
521 | luaproc self; | ||
522 | const char *message = luaL_checkstring( L, 1 ); | ||
523 | |||
524 | self = luaproc_getself( L ); | ||
525 | if (self && self->callback && self->data) | ||
526 | { | ||
527 | scriptMessage *sm = calloc(1, sizeof(scriptMessage)); | ||
528 | |||
529 | if (sm) | ||
530 | { | ||
531 | sm->script = self->data; | ||
532 | strcpy(sm->message, message); | ||
533 | ecore_main_loop_thread_safe_call_async(self->callback, sm); | ||
534 | } | ||
535 | } | ||
536 | |||
537 | return 0; | ||
538 | } | ||
539 | |||
540 | /* error messages for the sendToChannel function */ | ||
541 | const char *sendToChannelErrors[] = | ||
542 | { | ||
543 | "non-existent channel", | ||
544 | "error scheduling process" | ||
545 | }; | ||
546 | |||
547 | // TODO - If these come in too quick, then messages might get lost. Also, in at least one case, it locked up this thread I think. | ||
548 | |||
549 | /* send a message to a lua process */ | ||
550 | const char *sendToChannel(const char *chname, const char *message, luaproc *dst, channel *chn) | ||
551 | { | ||
552 | const char *result = NULL; | ||
553 | channel chan; | ||
554 | luaproc dstlp; | ||
555 | |||
556 | /* get exclusive access to operate on channels */ | ||
557 | pthread_mutex_lock(&mutex_channel); | ||
558 | |||
559 | /* wait until channel is not in use */ | ||
560 | while( ((chan = channel_search(chname)) != NULL) && (pthread_mutex_trylock(channel_get_mutex(chan)) != 0 )) | ||
561 | { | ||
562 | pthread_cond_wait(channel_get_cond(chan), &mutex_channel); | ||
563 | } | ||
564 | |||
565 | /* free access to operate on channels */ | ||
566 | pthread_mutex_unlock(&mutex_channel); | ||
567 | |||
568 | /* if channel is not found, return an error */ | ||
569 | if (chan == NULL) | ||
570 | return sendToChannelErrors[0]; | ||
571 | |||
572 | /* try to find a matching receiver */ | ||
573 | dstlp = luaproc_dequeue_receiver(chan); | ||
574 | |||
575 | /* if a match is found, send the message to it and (queue) wake it */ | ||
576 | if (dstlp != NULL) | ||
577 | { | ||
578 | /* push the message onto the receivers stack */ | ||
579 | lua_pushstring( dstlp->lstate, message); | ||
580 | |||
581 | dstlp->args = lua_gettop(dstlp->lstate) - 1; | ||
582 | |||
583 | if (sched_queue_proc(dstlp) != LUAPROC_SCHED_QUEUE_PROC_OK) | ||
584 | { | ||
585 | /* unlock channel access */ | ||
586 | luaproc_unlock_channel(chan); | ||
587 | |||
588 | /* decrease active luaproc count */ | ||
589 | sched_lpcount_dec(); | ||
590 | |||
591 | /* close lua_State */ | ||
592 | lua_close(dstlp->lstate); | ||
593 | return sendToChannelErrors[1]; | ||
594 | } | ||
595 | |||
596 | /* unlock channel access */ | ||
597 | luaproc_unlock_channel(chan); | ||
598 | } | ||
599 | else if (dst) | ||
600 | dst = &dstlp; | ||
601 | |||
602 | if (chn) | ||
603 | chn = &chan; | ||
604 | return result; | ||
605 | } | ||
606 | |||
607 | /* send a message to a lua process */ | ||
608 | static int luaproc_send( lua_State *L ) { | ||
609 | |||
610 | channel chan; | ||
611 | luaproc dstlp, self; | ||
612 | const char *chname = luaL_checkstring( L, 1 ); | ||
613 | const char *message = luaL_checkstring( L, 2 ); | ||
614 | const char *result = sendToChannel(chname, message, &dstlp, &chan); | ||
615 | |||
616 | if (result) { | ||
617 | lua_pushnil( L ); | ||
618 | lua_pushstring( L, result ); | ||
619 | return 2; | ||
620 | } | ||
621 | |||
622 | if ( dstlp == NULL ) { | ||
623 | |||
624 | self = luaproc_getself( L ); | ||
625 | |||
626 | if ( self != NULL ) { | ||
627 | self->stat = LUAPROC_STAT_BLOCKED_SEND; | ||
628 | self->chan = chan; | ||
629 | } | ||
630 | |||
631 | /* just yield the lua process, channel unlocking will be done by the scheduler */ | ||
632 | return lua_yield( L, lua_gettop( L )); | ||
633 | } | ||
634 | |||
635 | lua_pushboolean( L, TRUE ); | ||
636 | return 1; | ||
637 | } | ||
638 | |||
639 | /* receive a message from a lua process */ | ||
640 | static int luaproc_receive( lua_State *L ) { | ||
641 | |||
642 | channel chan; | ||
643 | luaproc srclp, self; | ||
644 | const char *chname = luaL_checkstring( L, 1 ); | ||
645 | |||
646 | /* get exclusive access to operate on channels */ | ||
647 | pthread_mutex_lock( &mutex_channel ); | ||
648 | |||
649 | /* wait until channel is not in use */ | ||
650 | while((( chan = channel_search( chname )) != NULL ) && ( pthread_mutex_trylock( channel_get_mutex( chan )) != 0 )) { | ||
651 | pthread_cond_wait( channel_get_cond( chan ), &mutex_channel ); | ||
652 | } | ||
653 | |||
654 | /* free access to operate on channels */ | ||
655 | pthread_mutex_unlock( &mutex_channel ); | ||
656 | |||
657 | /* if channel is not found, free access to operate on channels and return an error to Lua */ | ||
658 | if ( chan == NULL ) { | ||
659 | lua_pushnil( L ); | ||
660 | lua_pushstring( L, "non-existent channel" ); | ||
661 | return 2; | ||
662 | } | ||
663 | |||
664 | /* try to find a matching sender */ | ||
665 | srclp = luaproc_dequeue_sender( chan ); | ||
666 | |||
667 | /* if a match is found, get values from it and (queue) wake it */ | ||
668 | if ( srclp != NULL ) { | ||
669 | |||
670 | /* move values between Lua states' stacks */ | ||
671 | luaproc_movevalues( srclp->lstate, L ); | ||
672 | |||
673 | /* return to sender indicanting message was sent */ | ||
674 | lua_pushboolean( srclp->lstate, TRUE ); | ||
675 | srclp->args = 1; | ||
676 | |||
677 | if ( sched_queue_proc( srclp ) != LUAPROC_SCHED_QUEUE_PROC_OK ) { | ||
678 | |||
679 | /* unlock channel access */ | ||
680 | luaproc_unlock_channel( chan ); | ||
681 | |||
682 | /* decrease active luaproc count */ | ||
683 | sched_lpcount_dec(); | ||
684 | |||
685 | /* close lua_State */ | ||
686 | lua_close( srclp->lstate ); | ||
687 | lua_pushnil( L ); | ||
688 | lua_pushstring( L, "error scheduling process" ); | ||
689 | return 2; | ||
690 | } | ||
691 | |||
692 | /* unlock channel access */ | ||
693 | luaproc_unlock_channel( chan ); | ||
694 | |||
695 | return lua_gettop( L ) - 1; | ||
696 | } | ||
697 | |||
698 | /* otherwise queue (block) the receiving process (sync) or return immediatly (async) */ | ||
699 | else { | ||
700 | |||
701 | /* if trying an asynchronous receive, unlock channel access and return an error */ | ||
702 | if ( lua_toboolean( L, 2 )) { | ||
703 | /* unlock channel access */ | ||
704 | luaproc_unlock_channel( chan ); | ||
705 | /* return an error */ | ||
706 | lua_pushnil( L ); | ||
707 | lua_pushfstring( L, "no senders waiting on channel %s", chname ); | ||
708 | return 2; | ||
709 | } | ||
710 | |||
711 | /* otherwise (synchronous receive) simply block process */ | ||
712 | else { | ||
713 | self = luaproc_getself( L ); | ||
714 | |||
715 | if ( self != NULL ) { | ||
716 | self->stat = LUAPROC_STAT_BLOCKED_RECV; | ||
717 | self->chan = chan; | ||
718 | } | ||
719 | |||
720 | /* just yield the lua process, channel unlocking will be done by the scheduler */ | ||
721 | return lua_yield( L, lua_gettop( L )); | ||
722 | } | ||
723 | } | ||
724 | } | ||
725 | |||
726 | void luaprocInit(void) | ||
727 | { | ||
728 | /* initialize recycle list */ | ||
729 | recyclelp = list_new(); | ||
730 | |||
731 | /* initialize local scheduler */ | ||
732 | sched_init_local( LUAPROC_SCHED_DEFAULT_WORKER_THREADS ); | ||
733 | } | ||
734 | |||
735 | void luaprocRegister(lua_State *L) | ||
736 | { | ||
737 | /* register luaproc functions */ | ||
738 | luaL_register( L, "luaproc", luaproc_funcs_parent ); | ||
739 | } | ||
740 | |||
741 | LUALIB_API int luaopen_luaproc( lua_State *L ) { | ||
742 | luaprocRegister(L); | ||
743 | luaprocInit(); | ||
744 | return 0; | ||
745 | } | ||
746 | |||
747 | /* return a process' status */ | ||
748 | int luaproc_get_status( luaproc lp ) { | ||
749 | return lp->stat; | ||
750 | } | ||
751 | |||
752 | /* set a process' status */ | ||
753 | void luaproc_set_status( luaproc lp, int status ) { | ||
754 | lp->stat = status; | ||
755 | } | ||
756 | |||
757 | /* return a process' state */ | ||
758 | lua_State *luaproc_get_state( luaproc lp ) { | ||
759 | return lp->lstate; | ||
760 | } | ||
761 | |||
762 | /* return the number of arguments expected by a given process */ | ||
763 | int luaproc_get_args( luaproc lp ) { | ||
764 | return lp->args; | ||
765 | } | ||
766 | |||
767 | /* set the number of arguments expected by a given process */ | ||
768 | void luaproc_set_args( luaproc lp, int n ) { | ||
769 | lp->args = n; | ||
770 | } | ||
771 | |||
772 | /* create a new channel */ | ||
773 | static int luaproc_create_channel( lua_State *L ) { | ||
774 | |||
775 | const char *chname = luaL_checkstring( L, 1 ); | ||
776 | |||
777 | /* get exclusive access to operate on channels */ | ||
778 | pthread_mutex_lock( &mutex_channel ); | ||
779 | |||
780 | /* check if channel exists */ | ||
781 | if ( channel_search( chname ) != NULL ) { | ||
782 | /* free access to operate on channels */ | ||
783 | pthread_mutex_unlock( &mutex_channel ); | ||
784 | /* return an error to lua */ | ||
785 | lua_pushnil( L ); | ||
786 | lua_pushstring( L, "channel already exists" ); | ||
787 | return 2; | ||
788 | } | ||
789 | |||
790 | channel_create( chname ); | ||
791 | |||
792 | /* free access to operate on channels */ | ||
793 | pthread_mutex_unlock( &mutex_channel ); | ||
794 | |||
795 | lua_pushboolean( L, TRUE ); | ||
796 | |||
797 | return 1; | ||
798 | |||
799 | } | ||
800 | |||
801 | /* destroy a channel */ | ||
802 | static int luaproc_destroy_channel( lua_State *L ) { | ||
803 | |||
804 | channel chan; | ||
805 | luaproc lp; | ||
806 | node nitr; | ||
807 | pthread_mutex_t *chmutex; | ||
808 | pthread_cond_t *chcond; | ||
809 | const char *chname = luaL_checkstring( L, 1 ); | ||
810 | |||
811 | |||
812 | /* get exclusive access to operate on channels */ | ||
813 | pthread_mutex_lock( &mutex_channel ); | ||
814 | |||
815 | /* wait until channel is not in use */ | ||
816 | while((( chan = channel_search( chname )) != NULL ) && ( pthread_mutex_trylock( channel_get_mutex( chan )) != 0 )) { | ||
817 | pthread_cond_wait( channel_get_cond( chan ), &mutex_channel ); | ||
818 | } | ||
819 | |||
820 | /* free access to operate on channels */ | ||
821 | pthread_mutex_unlock( &mutex_channel ); | ||
822 | |||
823 | /* if channel is not found, return an error to Lua */ | ||
824 | if ( chan == NULL ) { | ||
825 | lua_pushnil( L ); | ||
826 | lua_pushstring( L, "non-existent channel" ); | ||
827 | return 2; | ||
828 | } | ||
829 | |||
830 | /* get channel's mutex and conditional pointers */ | ||
831 | chmutex = channel_get_mutex( chan ); | ||
832 | chcond = channel_get_cond( chan ); | ||
833 | |||
834 | /* search for processes waiting to send a message on this channel */ | ||
835 | while (( nitr = list_pop_head( channel_get_sendq( chan ))) != NULL ) { | ||
836 | |||
837 | lp = (luaproc )list_data( nitr ); | ||
838 | |||
839 | /* destroy node (but not associated luaproc) */ | ||
840 | list_destroy_node( nitr ); | ||
841 | |||
842 | /* return an error so the processe knows the channel was destroyed before the message was sent */ | ||
843 | lua_settop( lp->lstate, 0 ); | ||
844 | lua_pushnil( lp->lstate ); | ||
845 | lua_pushstring( lp->lstate, "channel destroyed while waiting for receiver" ); | ||
846 | lp->args = 2; | ||
847 | |||
848 | /* schedule the process for execution */ | ||
849 | if ( sched_queue_proc( lp ) != LUAPROC_SCHED_QUEUE_PROC_OK ) { | ||
850 | |||
851 | /* decrease active luaproc count */ | ||
852 | sched_lpcount_dec(); | ||
853 | |||
854 | /* close lua_State */ | ||
855 | lua_close( lp->lstate ); | ||
856 | } | ||
857 | } | ||
858 | |||
859 | /* search for processes waiting to receive a message on this channel */ | ||
860 | while (( nitr = list_pop_head( channel_get_recvq( chan ))) != NULL ) { | ||
861 | |||
862 | lp = (luaproc )list_data( nitr ); | ||
863 | |||
864 | /* destroy node (but not associated luaproc) */ | ||
865 | list_destroy_node( nitr ); | ||
866 | |||
867 | /* return an error so the processe knows the channel was destroyed before the message was received */ | ||
868 | lua_settop( lp->lstate, 0 ); | ||
869 | lua_pushnil( lp->lstate ); | ||
870 | lua_pushstring( lp->lstate, "channel destroyed while waiting for sender" ); | ||
871 | lp->args = 2; | ||
872 | |||
873 | /* schedule the process for execution */ | ||
874 | if ( sched_queue_proc( lp ) != LUAPROC_SCHED_QUEUE_PROC_OK ) { | ||
875 | |||
876 | /* decrease active luaproc count */ | ||
877 | sched_lpcount_dec(); | ||
878 | |||
879 | /* close lua_State */ | ||
880 | lua_close( lp->lstate ); | ||
881 | } | ||
882 | } | ||
883 | |||
884 | /* get exclusive access to operate on channels */ | ||
885 | pthread_mutex_lock( &mutex_channel ); | ||
886 | /* destroy channel */ | ||
887 | channel_destroy( chan, chname ); | ||
888 | /* broadcast channel not in use */ | ||
889 | pthread_cond_broadcast( chcond ); | ||
890 | /* unlock channel access */ | ||
891 | pthread_mutex_unlock( chmutex ); | ||
892 | /* destroy channel mutex and conditional */ | ||
893 | pthread_mutex_destroy( chmutex ); | ||
894 | pthread_cond_destroy( chcond ); | ||
895 | /* free memory used by channel mutex and conditional */ | ||
896 | free( chmutex ); | ||
897 | free( chcond ); | ||
898 | /* free access to operate on channels */ | ||
899 | pthread_mutex_unlock( &mutex_channel ); | ||
900 | |||
901 | lua_pushboolean( L, TRUE ); | ||
902 | |||
903 | return 1; | ||
904 | } | ||
905 | |||
906 | /* register luaproc's functions in a lua_State */ | ||
907 | void luaproc_register_funcs( lua_State *L ) { | ||
908 | luaL_register( L, "luaproc", luaproc_funcs_child ); | ||
909 | } | ||
910 | |||
911 | /* return the channel where the corresponding luaproc is blocked at */ | ||
912 | channel luaproc_get_channel( luaproc lp ) { | ||
913 | return lp->chan; | ||
914 | } | ||
915 | |||
916 | /* unlock access to a channel */ | ||
917 | void luaproc_unlock_channel( channel chan ) { | ||
918 | /* get exclusive access to operate on channels */ | ||
919 | pthread_mutex_lock( &mutex_channel ); | ||
920 | /* unlock channel access */ | ||
921 | pthread_mutex_unlock( channel_get_mutex( chan )); | ||
922 | /* signal channel not in use */ | ||
923 | pthread_cond_signal( channel_get_cond( chan )); | ||
924 | /* free access to operate on channels */ | ||
925 | pthread_mutex_unlock( &mutex_channel ); | ||
926 | } | ||
927 | |||
928 | /* return status (boolean) indicating if worker thread should be destroyed after luaproc execution */ | ||
929 | int luaproc_get_destroyworker( luaproc lp ) { | ||
930 | return lp->destroyworker; | ||
931 | } | ||
diff --git a/libraries/luaproc/luaproc.lua b/libraries/luaproc/luaproc.lua deleted file mode 100644 index a1a73e4..0000000 --- a/libraries/luaproc/luaproc.lua +++ /dev/null | |||
@@ -1,34 +0,0 @@ | |||
1 | ---------------------------------------------------- | ||
2 | -- | ||
3 | -- Copyright 2008 Alexandre Skyrme, Noemi Rodriguez, Roberto Ierusalimschy | ||
4 | -- | ||
5 | -- Permission is hereby granted, free of charge, to any person obtaining a copy | ||
6 | -- of this software and associated documentation files (the "Software"), to deal | ||
7 | -- in the Software without restriction, including without limitation the rights | ||
8 | -- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
9 | -- copies of the Software, and to permit persons to whom the Software is | ||
10 | -- furnished to do so, subject to the following conditions: | ||
11 | -- | ||
12 | -- The above copyright notice and this permission notice shall be included in | ||
13 | -- all copies or substantial portions of the Software. | ||
14 | -- | ||
15 | -- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
16 | -- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
17 | -- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
18 | -- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
19 | -- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
20 | -- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
21 | -- THE SOFTWARE. | ||
22 | -- | ||
23 | ----------------------------------------------------- | ||
24 | -- | ||
25 | -- luaproc.lua | ||
26 | -- | ||
27 | ----------------------------------------------------- | ||
28 | |||
29 | local function so( objname ) | ||
30 | local SOPATH = os.getenv( "LUA_SOPATH" ) or "./" | ||
31 | assert( package.loadlib( SOPATH .. objname .. ".so" , "luaopen_" .. objname ))( ) | ||
32 | end | ||
33 | |||
34 | so( "luaproc" ) | ||
diff --git a/libraries/luaproc/sched.c b/libraries/luaproc/sched.c deleted file mode 100644 index 474c82b..0000000 --- a/libraries/luaproc/sched.c +++ /dev/null | |||
@@ -1,356 +0,0 @@ | |||
1 | /*************************************************** | ||
2 | |||
3 | Copyright 2008 Alexandre Skyrme, Noemi Rodriguez, Roberto Ierusalimschy | ||
4 | |||
5 | Permission is hereby granted, free of charge, to any person obtaining a copy | ||
6 | of this software and associated documentation files (the "Software"), to deal | ||
7 | in the Software without restriction, including without limitation the rights | ||
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
9 | copies of the Software, and to permit persons to whom the Software is | ||
10 | furnished to do so, subject to the following conditions: | ||
11 | |||
12 | The above copyright notice and this permission notice shall be included in | ||
13 | all copies or substantial portions of the Software. | ||
14 | |||
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
21 | THE SOFTWARE. | ||
22 | |||
23 | ***************************************************** | ||
24 | |||
25 | [sched.c] | ||
26 | |||
27 | ****************************************************/ | ||
28 | |||
29 | #include <pthread.h> | ||
30 | #include <stdio.h> | ||
31 | #include <stdlib.h> | ||
32 | #include <string.h> | ||
33 | #include <unistd.h> | ||
34 | #include <arpa/inet.h> | ||
35 | #include <sys/select.h> | ||
36 | #include <sys/socket.h> | ||
37 | #include <sys/stat.h> | ||
38 | #include <lua.h> | ||
39 | #include <lauxlib.h> | ||
40 | #include <lualib.h> | ||
41 | |||
42 | #include "list.h" | ||
43 | #include "sched.h" | ||
44 | #include "luaproc.h" | ||
45 | #include "channel.h" | ||
46 | |||
47 | #define TRUE 1 | ||
48 | #define FALSE 0 | ||
49 | |||
50 | /********* | ||
51 | * globals | ||
52 | *********/ | ||
53 | |||
54 | /* ready process list */ | ||
55 | list lpready = NULL; | ||
56 | |||
57 | /* ready process queue access mutex */ | ||
58 | pthread_mutex_t mutex_queue_access = PTHREAD_MUTEX_INITIALIZER; | ||
59 | |||
60 | /* wake worker up conditional variable */ | ||
61 | pthread_cond_t cond_wakeup_worker = PTHREAD_COND_INITIALIZER; | ||
62 | |||
63 | /* active luaproc count access mutex */ | ||
64 | pthread_mutex_t mutex_lp_count = PTHREAD_MUTEX_INITIALIZER; | ||
65 | |||
66 | /* no active luaproc conditional variable */ | ||
67 | pthread_cond_t cond_no_active_lp = PTHREAD_COND_INITIALIZER; | ||
68 | |||
69 | /* number of active luaprocs */ | ||
70 | int lpcount = 0; | ||
71 | |||
72 | /* no more lua processes flag */ | ||
73 | int no_more_processes = FALSE; | ||
74 | |||
75 | /* worker thread main function */ | ||
76 | void *workermain( void *args ) { | ||
77 | |||
78 | node n; | ||
79 | luaproc lp; | ||
80 | int procstat; | ||
81 | int destroyworker; | ||
82 | |||
83 | /* detach thread so resources are freed as soon as thread exits (no further joining) */ | ||
84 | pthread_detach( pthread_self( )); | ||
85 | |||
86 | //printf("NEW WORKER\n"); | ||
87 | /* main worker loop */ | ||
88 | while ( 1 ) { | ||
89 | |||
90 | //printf("a\n"); | ||
91 | /* get exclusive access to the ready process queue */ | ||
92 | pthread_mutex_lock( &mutex_queue_access ); | ||
93 | |||
94 | /* wait until instructed to wake up (because there's work to do or because its time to finish) */ | ||
95 | while (( list_node_count( lpready ) == 0 ) && ( no_more_processes == FALSE )) { | ||
96 | pthread_cond_wait( &cond_wakeup_worker, &mutex_queue_access ); | ||
97 | } | ||
98 | |||
99 | ////printf("b\n"); | ||
100 | /* pop the first node from the ready process queue */ | ||
101 | n = list_pop_head( lpready ); | ||
102 | |||
103 | ////printf("c\n"); | ||
104 | /* ensure list pop succeeded before proceeding */ | ||
105 | if ( n != NULL ) { | ||
106 | //printf("c.0\n"); | ||
107 | /* get the popped node's data content (ie, the lua process struct) */ | ||
108 | lp = (luaproc )list_data( n ); | ||
109 | } | ||
110 | else { | ||
111 | ////printf("c.1\n"); | ||
112 | /* free access to the process ready queue */ | ||
113 | pthread_mutex_unlock( &mutex_queue_access ); | ||
114 | /* finished thread */ | ||
115 | //printf("c.2 pthread_exit\n"); | ||
116 | pthread_exit( NULL ); | ||
117 | //printf("c.3\n"); | ||
118 | } | ||
119 | |||
120 | ////printf("d\n"); | ||
121 | /* free access to the process ready queue */ | ||
122 | pthread_mutex_unlock( &mutex_queue_access ); | ||
123 | |||
124 | //printf("e lua_resum\n"); | ||
125 | /* execute the lua code specified in the lua process struct */ | ||
126 | procstat = lua_resume( luaproc_get_state( lp ), luaproc_get_args( lp )); | ||
127 | |||
128 | //printf("f\n"); | ||
129 | /* reset the process argument count */ | ||
130 | luaproc_set_args( lp, 0 ); | ||
131 | |||
132 | ////printf("g\n"); | ||
133 | /* check if process finished its whole execution */ | ||
134 | if ( procstat == 0 ) { | ||
135 | |||
136 | //printf("g.0\n"); | ||
137 | /* destroy the corresponding list node */ | ||
138 | list_destroy_node( n ); | ||
139 | |||
140 | ////printf("g.1\n"); | ||
141 | /* check if worker thread should be destroyed */ | ||
142 | destroyworker = luaproc_get_destroyworker( lp ); | ||
143 | |||
144 | ////printf("g.2 proc finished\n"); | ||
145 | /* set process status to finished */ | ||
146 | luaproc_set_status( lp, LUAPROC_STAT_FINISHED ); | ||
147 | |||
148 | ////printf("g.3\n"); | ||
149 | /* check if lua process should be recycled and, if not, destroy it */ | ||
150 | if ( luaproc_recycle_push( lp ) == FALSE ) { | ||
151 | //printf("g.3.0 lua_close\n"); | ||
152 | lua_close( luaproc_get_state( lp )); | ||
153 | } | ||
154 | |||
155 | ////printf("g.4\n"); | ||
156 | /* decrease active lua process count */ | ||
157 | sched_lpcount_dec(); | ||
158 | |||
159 | ////printf("g.5\n"); | ||
160 | /* check if thread should be finished after lua process conclusion */ | ||
161 | if ( destroyworker ) { | ||
162 | //printf("g.5.0 pthread_exit\n"); | ||
163 | /* if so, finish thread */ | ||
164 | pthread_exit( NULL ); | ||
165 | } | ||
166 | //printf("g.6\n"); | ||
167 | } | ||
168 | |||
169 | /* check if process yielded */ | ||
170 | else if ( procstat == LUA_YIELD ) { | ||
171 | |||
172 | //printf("??????????????h.0\n"); | ||
173 | /* if so, further check if yield originated from an unmatched send/recv operation */ | ||
174 | if ( luaproc_get_status( lp ) == LUAPROC_STAT_BLOCKED_SEND ) { | ||
175 | //printf("??????????????h.1\n"); | ||
176 | /* queue blocked lua process on corresponding channel */ | ||
177 | luaproc_queue_sender( lp ); | ||
178 | /* unlock channel access */ | ||
179 | luaproc_unlock_channel( luaproc_get_channel( lp )); | ||
180 | /* destroy node (but not the associated Lua process) */ | ||
181 | list_destroy_node( n ); | ||
182 | } | ||
183 | |||
184 | else if ( luaproc_get_status( lp ) == LUAPROC_STAT_BLOCKED_RECV ) { | ||
185 | //printf("??????????????h.2\n"); | ||
186 | /* queue blocked lua process on corresponding channel */ | ||
187 | luaproc_queue_receiver( lp ); | ||
188 | /* unlock channel access */ | ||
189 | luaproc_unlock_channel( luaproc_get_channel( lp )); | ||
190 | /* destroy node (but not the associated Lua process) */ | ||
191 | list_destroy_node( n ); | ||
192 | } | ||
193 | |||
194 | /* or if yield resulted from an explicit call to coroutine.yield in the lua code being executed */ | ||
195 | else { | ||
196 | //printf("??????????????h.3\n"); | ||
197 | /* get exclusive access to the ready process queue */ | ||
198 | pthread_mutex_lock( &mutex_queue_access ); | ||
199 | /* re-insert the job at the end of the ready process queue */ | ||
200 | list_add( lpready, n ); | ||
201 | /* free access to the process ready queue */ | ||
202 | pthread_mutex_unlock( &mutex_queue_access ); | ||
203 | } | ||
204 | } | ||
205 | |||
206 | /* check if there was any execution error (LUA_ERRRUN, LUA_ERRSYNTAX, LUA_ERRMEM or LUA_ERRERR) */ | ||
207 | else { | ||
208 | //printf("??????????????i.0\n"); | ||
209 | /* destroy the corresponding node */ | ||
210 | list_destroy_node( n ); | ||
211 | /* print error message */ | ||
212 | fprintf( stderr, "close lua_State (error: %s)\n", luaL_checkstring( luaproc_get_state( lp ), -1 )); | ||
213 | /* close lua state */ | ||
214 | lua_close( luaproc_get_state( lp )); | ||
215 | /* decrease active lua process count */ | ||
216 | sched_lpcount_dec(); | ||
217 | } | ||
218 | //printf("END\n"); | ||
219 | } | ||
220 | } | ||
221 | |||
222 | /* local scheduler initialization */ | ||
223 | int sched_init_local( int numworkers ) { | ||
224 | |||
225 | int tid; | ||
226 | int workercount = 0; | ||
227 | pthread_t worker; | ||
228 | |||
229 | /* initialize ready process list */ | ||
230 | lpready = list_new(); | ||
231 | |||
232 | /* initialize channels */ | ||
233 | channel_init(); | ||
234 | |||
235 | /* create initial worker threads */ | ||
236 | for ( tid = 0; tid < numworkers; tid++ ) { | ||
237 | if ( pthread_create( &worker, NULL, workermain, NULL ) == 0 ) { | ||
238 | workercount++; | ||
239 | } | ||
240 | } | ||
241 | |||
242 | if ( workercount != numworkers ) { | ||
243 | return LUAPROC_SCHED_INIT_ERROR; | ||
244 | } | ||
245 | |||
246 | return LUAPROC_SCHED_OK; | ||
247 | } | ||
248 | |||
249 | /* exit scheduler */ | ||
250 | void sched_exit( void ) { | ||
251 | |||
252 | /* get exclusive access to the ready process queue */ | ||
253 | pthread_mutex_lock( &mutex_queue_access ); | ||
254 | /* destroy the ready process list */ | ||
255 | list_destroy( lpready ); | ||
256 | /* free access to the process ready queue */ | ||
257 | pthread_mutex_unlock( &mutex_queue_access ); | ||
258 | } | ||
259 | |||
260 | /* move process to ready queue (ie, schedule process) */ | ||
261 | int sched_queue_proc( luaproc lp ) { | ||
262 | |||
263 | /* get exclusive access to the ready process queue */ | ||
264 | pthread_mutex_lock( &mutex_queue_access ); | ||
265 | |||
266 | /* add process to ready queue */ | ||
267 | if ( list_add( lpready, list_new_node( lp )) != NULL ) { | ||
268 | |||
269 | /* set process status to ready */ | ||
270 | luaproc_set_status( lp, LUAPROC_STAT_READY ); | ||
271 | |||
272 | /* wake worker up */ | ||
273 | pthread_cond_signal( &cond_wakeup_worker ); | ||
274 | /* free access to the process ready queue */ | ||
275 | pthread_mutex_unlock( &mutex_queue_access ); | ||
276 | |||
277 | return LUAPROC_SCHED_QUEUE_PROC_OK; | ||
278 | } | ||
279 | else { | ||
280 | /* free access to the process ready queue */ | ||
281 | pthread_mutex_unlock( &mutex_queue_access ); | ||
282 | |||
283 | return LUAPROC_SCHED_QUEUE_PROC_ERR; | ||
284 | } | ||
285 | } | ||
286 | |||
287 | /* synchronize worker threads */ | ||
288 | void sched_join_workerthreads( void ) { | ||
289 | |||
290 | ////printf(" 0\n"); | ||
291 | pthread_mutex_lock( &mutex_lp_count ); | ||
292 | |||
293 | //printf(" 1 wait for procs to end\n"); | ||
294 | /* wait until there is no more active lua processes */ | ||
295 | while( lpcount != 0 ) { | ||
296 | //printf(" 1.0\n"); | ||
297 | pthread_cond_wait( &cond_no_active_lp, &mutex_lp_count ); | ||
298 | } | ||
299 | /* get exclusive access to the ready process queue */ | ||
300 | ////printf(" 2\n"); | ||
301 | pthread_mutex_lock( &mutex_queue_access ); | ||
302 | /* set the no more active lua processes flag to true */ | ||
303 | ////printf(" 3\n"); | ||
304 | no_more_processes = TRUE; | ||
305 | /* wake ALL workers up */ | ||
306 | //printf(" 4 wake up all workers.\n"); | ||
307 | pthread_cond_broadcast( &cond_wakeup_worker ); | ||
308 | /* free access to the process ready queue */ | ||
309 | ////printf(" 5\n"); | ||
310 | pthread_mutex_unlock( &mutex_queue_access ); | ||
311 | |||
312 | // We don't need this, as we only get here during shutdown. Linking this to EFL results in a hang otherwise anyway. | ||
313 | /* wait for (join) worker threads */ | ||
314 | //printf(" 6 pthread_exit, waiting for workers to end\n"); | ||
315 | // pthread_exit( NULL ); | ||
316 | |||
317 | //printf("7\n"); | ||
318 | pthread_mutex_unlock( &mutex_lp_count ); | ||
319 | |||
320 | //printf("8\n"); | ||
321 | } | ||
322 | |||
323 | /* increase active lua process count */ | ||
324 | void sched_lpcount_inc( void ) { | ||
325 | //printf("inc procs++++++++++++++++++++++++++++++++++++++++\n"); | ||
326 | pthread_mutex_lock( &mutex_lp_count ); | ||
327 | lpcount++; | ||
328 | pthread_mutex_unlock( &mutex_lp_count ); | ||
329 | } | ||
330 | |||
331 | /* decrease active lua process count */ | ||
332 | void sched_lpcount_dec( void ) { | ||
333 | //printf("dec procs----------------------------------------\n"); | ||
334 | pthread_mutex_lock( &mutex_lp_count ); | ||
335 | lpcount--; | ||
336 | /* if count reaches zero, signal there are no more active processes */ | ||
337 | if ( lpcount == 0 ) { | ||
338 | //printf("dec procs AND NONE LEFT000000000000000000000000000\n"); | ||
339 | pthread_cond_signal( &cond_no_active_lp ); | ||
340 | } | ||
341 | pthread_mutex_unlock( &mutex_lp_count ); | ||
342 | } | ||
343 | |||
344 | /* create a new worker pthread */ | ||
345 | int sched_create_worker( void ) { | ||
346 | |||
347 | pthread_t worker; | ||
348 | |||
349 | /* create a new pthread */ | ||
350 | if ( pthread_create( &worker, NULL, workermain, NULL ) != 0 ) { | ||
351 | return LUAPROC_SCHED_PTHREAD_ERROR; | ||
352 | } | ||
353 | |||
354 | return LUAPROC_SCHED_OK; | ||
355 | } | ||
356 | |||
diff --git a/libraries/luaproc/sched.h b/libraries/luaproc/sched.h deleted file mode 100644 index c03e6ea..0000000 --- a/libraries/luaproc/sched.h +++ /dev/null | |||
@@ -1,78 +0,0 @@ | |||
1 | /*************************************************** | ||
2 | |||
3 | Copyright 2008 Alexandre Skyrme, Noemi Rodriguez, Roberto Ierusalimschy | ||
4 | |||
5 | Permission is hereby granted, free of charge, to any person obtaining a copy | ||
6 | of this software and associated documentation files (the "Software"), to deal | ||
7 | in the Software without restriction, including without limitation the rights | ||
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
9 | copies of the Software, and to permit persons to whom the Software is | ||
10 | furnished to do so, subject to the following conditions: | ||
11 | |||
12 | The above copyright notice and this permission notice shall be included in | ||
13 | all copies or substantial portions of the Software. | ||
14 | |||
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
21 | THE SOFTWARE. | ||
22 | |||
23 | ***************************************************** | ||
24 | |||
25 | [sched.h] | ||
26 | |||
27 | ****************************************************/ | ||
28 | #ifndef _SCHED_H_ | ||
29 | #define _SCHED_H_ | ||
30 | |||
31 | #include "luaproc.h" | ||
32 | |||
33 | /* scheduler function return constants */ | ||
34 | #define LUAPROC_SCHED_OK 0 | ||
35 | #define LUAPROC_SCHED_SOCKET_ERROR -1 | ||
36 | #define LUAPROC_SCHED_SETSOCKOPT_ERROR -2 | ||
37 | #define LUAPROC_SCHED_BIND_ERROR -3 | ||
38 | #define LUAPROC_SCHED_LISTEN_ERROR -4 | ||
39 | #define LUAPROC_SCHED_FORK_ERROR -5 | ||
40 | #define LUAPROC_SCHED_PTHREAD_ERROR -6 | ||
41 | #define LUAPROC_SCHED_INIT_ERROR -7 | ||
42 | |||
43 | /* ready process queue insertion status */ | ||
44 | #define LUAPROC_SCHED_QUEUE_PROC_OK 0 | ||
45 | #define LUAPROC_SCHED_QUEUE_PROC_ERR -1 | ||
46 | |||
47 | /* scheduler listener service default hostname and port */ | ||
48 | #define LUAPROC_SCHED_DEFAULT_HOST "127.0.0.1" | ||
49 | #define LUAPROC_SCHED_DEFAULT_PORT 3133 | ||
50 | |||
51 | /* scheduler default number of worker threads */ | ||
52 | #define LUAPROC_SCHED_DEFAULT_WORKER_THREADS 1 | ||
53 | |||
54 | /* initialize local scheduler */ | ||
55 | int sched_init_local( int numworkers ); | ||
56 | |||
57 | /* initialize socket enabled scheduler */ | ||
58 | int sched_init_socket( int numworkers, const char *host, int port ); | ||
59 | |||
60 | /* exit scheduler */ | ||
61 | void sched_exit( void ); | ||
62 | |||
63 | /* move process to ready queue (ie, schedule process) */ | ||
64 | int sched_queue_proc( luaproc lp ); | ||
65 | |||
66 | /* join all worker threads and exit */ | ||
67 | void sched_join_workerthreads( void ); | ||
68 | |||
69 | /* increase active luaproc count */ | ||
70 | void sched_lpcount_inc( void ); | ||
71 | |||
72 | /* decrease active luaproc count */ | ||
73 | void sched_lpcount_dec( void ); | ||
74 | |||
75 | /* create a new worker pthread */ | ||
76 | int sched_create_worker( void ); | ||
77 | |||
78 | #endif | ||
diff --git a/libraries/luaproc/test.lua b/libraries/luaproc/test.lua deleted file mode 100644 index 5868d6f..0000000 --- a/libraries/luaproc/test.lua +++ /dev/null | |||
@@ -1,39 +0,0 @@ | |||
1 | ---------------------------------------------------- | ||
2 | -- | ||
3 | -- Copyright 2008 Alexandre Skyrme, Noemi Rodriguez, Roberto Ierusalimschy | ||
4 | -- | ||
5 | -- Permission is hereby granted, free of charge, to any person obtaining a copy | ||
6 | -- of this software and associated documentation files (the "Software"), to deal | ||
7 | -- in the Software without restriction, including without limitation the rights | ||
8 | -- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
9 | -- copies of the Software, and to permit persons to whom the Software is | ||
10 | -- furnished to do so, subject to the following conditions: | ||
11 | -- | ||
12 | -- The above copyright notice and this permission notice shall be included in | ||
13 | -- all copies or substantial portions of the Software. | ||
14 | -- | ||
15 | -- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
16 | -- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
17 | -- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
18 | -- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
19 | -- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
20 | -- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
21 | -- THE SOFTWARE. | ||
22 | -- | ||
23 | ----------------------------------------------------- | ||
24 | -- | ||
25 | -- test.lua | ||
26 | -- | ||
27 | ----------------------------------------------------- | ||
28 | |||
29 | require "luaproc" | ||
30 | |||
31 | luaproc.createworker() | ||
32 | |||
33 | luaproc.newproc( [=[ | ||
34 | luaproc.newchannel( "testchannel" ) | ||
35 | luaproc.newproc( "luaproc.send( 'testchannel', 'luaproc is working fine!' )" ) | ||
36 | luaproc.newproc( "print( luaproc.receive( 'testchannel' ))" ) | ||
37 | ]=] ) | ||
38 | |||
39 | luaproc.exit() | ||