aboutsummaryrefslogtreecommitdiff
path: root/src/lanes.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lanes.c')
-rw-r--r--src/lanes.c732
1 files changed, 459 insertions, 273 deletions
diff --git a/src/lanes.c b/src/lanes.c
index 9b36e4d..ba9e59a 100644
--- a/src/lanes.c
+++ b/src/lanes.c
@@ -4,6 +4,13 @@
4 * Multithreading in Lua. 4 * Multithreading in Lua.
5 * 5 *
6 * History: 6 * History:
7 * 3-Jan-11 (2.0.10): linda_send bugfix, was waiting on the wrong signal
8 * 3-Dec-10 (2.0.9): Added support to generate a lane from a string
9 * 2-Dec-10 (2.0.8): Fix LuaJIT2 incompatibility (no 'tostring' hijack anymore)
10 * ???????? (2.0.7): Fixed 'memory leak' in some situations where a free running
11 * lane is collected before application shutdown
12 * 24-Aug-10 (2.0.6): Mem fixes, argument checking (lua_toLinda result), thread name
13 * 24-Jun-09 (2.0.4): Made friendly to already multithreaded host apps.
7 * 20-Oct-08 (2.0.2): Added closing of free-running threads, but it does 14 * 20-Oct-08 (2.0.2): Added closing of free-running threads, but it does
8 * not seem to eliminate the occasional segfaults at process 15 * not seem to eliminate the occasional segfaults at process
9 * exit. 16 * exit.
@@ -13,10 +20,9 @@
13 * 18-Sep-06 AKa: Started the module. 20 * 18-Sep-06 AKa: Started the module.
14 * 21 *
15 * Platforms (tested internally): 22 * Platforms (tested internally):
16 * OS X (10.5.4 PowerPC/Intel) 23 * OS X (10.5.7 PowerPC/Intel)
17 * Linux x86 (Ubuntu 8.04) 24 * Linux x86 (Ubuntu 8.04)
18 * Win32 (Windows XP Home SP2, Visual C++ 2005/2008 Express) 25 * Win32 (Windows XP Home SP2, Visual C++ 2005/2008 Express)
19 * PocketPC (TBD)
20 * 26 *
21 * Platforms (tested externally): 27 * Platforms (tested externally):
22 * Win32 (MSYS) by Ross Berteig. 28 * Win32 (MSYS) by Ross Berteig.
@@ -54,15 +60,16 @@
54 * 60 *
55 * To-do: 61 * To-do:
56 * 62 *
63 * Make waiting threads cancelable.
57 * ... 64 * ...
58 */ 65 */
59 66
60const char *VERSION= "2.0.3"; 67const char *VERSION= "2.0.10";
61 68
62/* 69/*
63=============================================================================== 70===============================================================================
64 71
65Copyright (C) 2007-08 Asko Kauppi <akauppi@gmail.com> 72Copyright (C) 2007-10 Asko Kauppi <akauppi@gmail.com>
66 73
67Permission is hereby granted, free of charge, to any person obtaining a copy 74Permission is hereby granted, free of charge, to any person obtaining a copy
68of this software and associated documentation files (the "Software"), to deal 75of this software and associated documentation files (the "Software"), to deal
@@ -84,10 +91,11 @@ THE SOFTWARE.
84 91
85=============================================================================== 92===============================================================================
86*/ 93*/
94
87#include <string.h> 95#include <string.h>
88#include <stdio.h> 96#include <stdio.h>
89#include <ctype.h>
90#include <stdlib.h> 97#include <stdlib.h>
98#include <ctype.h>
91 99
92#include "lua.h" 100#include "lua.h"
93#include "lauxlib.h" 101#include "lauxlib.h"
@@ -127,7 +135,59 @@ THE SOFTWARE.
127static char keeper_chunk[]= 135static char keeper_chunk[]=
128#include "keeper.lch" 136#include "keeper.lch"
129 137
130struct s_lane; 138// NOTE: values to be changed by either thread, during execution, without
139// locking, are marked "volatile"
140//
141struct s_lane {
142 THREAD_T thread;
143 //
144 // M: sub-thread OS thread
145 // S: not used
146
147 char threadName[64]; //Optional, for debugging and such. owerflowable by a strcpy.
148
149 lua_State *L;
150 //
151 // M: prepares the state, and reads results
152 // S: while S is running, M must keep out of modifying the state
153
154 volatile enum e_status status;
155 //
156 // M: sets to PENDING (before launching)
157 // S: updates -> RUNNING/WAITING -> DONE/ERROR_ST/CANCELLED
158
159 volatile bool_t cancel_request;
160 //
161 // M: sets to FALSE, flags TRUE for cancel request
162 // S: reads to see if cancel is requested
163
164#if !( (defined PLATFORM_WIN32) || (defined PLATFORM_POCKETPC) || (defined PTHREAD_TIMEDJOIN) )
165 SIGNAL_T done_signal_;
166 //
167 // M: Waited upon at lane ending (if Posix with no PTHREAD_TIMEDJOIN)
168 // S: sets the signal once cancellation is noticed (avoids a kill)
169
170 MUTEX_T done_lock_;
171 //
172 // Lock required by 'done_signal' condition variable, protecting
173 // lane status changes to DONE/ERROR_ST/CANCELLED.
174#endif
175
176 volatile enum {
177 NORMAL, // normal master side state
178 KILLED // issued an OS kill
179 } mstatus;
180 //
181 // M: sets to NORMAL, if issued a kill changes to KILLED
182 // S: not used
183
184 struct s_lane * volatile selfdestruct_next;
185 //
186 // M: sets to non-NULL if facing lane handle '__gc' cycle but the lane
187 // is still running
188 // S: cleans up after itself if non-NULL at lane exit
189};
190
131static bool_t cancel_test( lua_State *L ); 191static bool_t cancel_test( lua_State *L );
132static void cancel_error( lua_State *L ); 192static void cancel_error( lua_State *L );
133 193
@@ -360,10 +420,11 @@ int keeper_call( lua_State* K, const char *func_name,
360 int Ktos= lua_gettop(K); 420 int Ktos= lua_gettop(K);
361 int retvals; 421 int retvals;
362 422
423 STACK_GROW( K, 2 );
424
363 lua_getglobal( K, func_name ); 425 lua_getglobal( K, func_name );
364 ASSERT_L( lua_isfunction(K,-1) ); 426 ASSERT_L( lua_isfunction(K,-1) );
365 427
366 STACK_GROW( K, 1 );
367 lua_pushlightuserdata( K, linda ); 428 lua_pushlightuserdata( K, linda );
368 429
369 luaG_inter_copy( L,K, args ); // L->K 430 luaG_inter_copy( L,K, args ); // L->K
@@ -408,6 +469,8 @@ LUAG_FUNC( linda_send ) {
408 struct s_Keeper *K; 469 struct s_Keeper *K;
409 time_d timeout= -1.0; 470 time_d timeout= -1.0;
410 uint_t key_i= 2; // index of first key, if timeout not there 471 uint_t key_i= 2; // index of first key, if timeout not there
472
473 luaL_argcheck( L, linda, 1, "expected a linda object!");
411 474
412 if (lua_isnumber(L,2)) { 475 if (lua_isnumber(L,2)) {
413 timeout= SIGNAL_TIMEOUT_PREPARE( lua_tonumber(L,2) ); 476 timeout= SIGNAL_TIMEOUT_PREPARE( lua_tonumber(L,2) );
@@ -449,10 +512,36 @@ STACK_MID(KL,0)
449 cancel= cancel_test( L ); // testing here causes no delays 512 cancel= cancel_test( L ); // testing here causes no delays
450 if (cancel) break; 513 if (cancel) break;
451 514
515// Bugfix by Benoit Germain Dec-2009: change status of lane to "waiting"
516//
517#if 1
518{
519 struct s_lane *s;
520 enum e_status prev_status = ERROR_ST; // prevent 'might be used uninitialized' warnings
521 STACK_GROW(L,1);
522
523 STACK_CHECK(L)
524 lua_pushlightuserdata( L, CANCEL_TEST_KEY );
525 lua_rawget( L, LUA_REGISTRYINDEX );
526 s= lua_touserdata( L, -1 ); // lightuserdata (true 's_lane' pointer) / nil
527 lua_pop(L,1);
528 STACK_END(L,0)
529 if (s) {
530 prev_status = s->status;
531 s->status = WAITING;
532 }
533 if (!SIGNAL_WAIT( &linda->read_happened, &K->lock_, timeout )) {
534 if (s) { s->status = prev_status; }
535 break;
536 }
537 if (s) s->status = prev_status;
538}
539#else
452 // K lock will be released for the duration of wait and re-acquired 540 // K lock will be released for the duration of wait and re-acquired
453 // 541 //
454 if (!SIGNAL_WAIT( &linda->read_happened, &K->lock_, timeout )) 542 if (!SIGNAL_WAIT( &linda->read_happened, &K->lock_, timeout ))
455 break; // timeout 543 break; // timeout
544#endif
456 } 545 }
457 } 546 }
458STACK_END(KL,0) 547STACK_END(KL,0)
@@ -483,6 +572,8 @@ LUAG_FUNC( linda_receive ) {
483 time_d timeout= -1.0; 572 time_d timeout= -1.0;
484 uint_t key_i= 2; 573 uint_t key_i= 2;
485 574
575 luaL_argcheck( L, linda, 1, "expected a linda object!");
576
486 if (lua_isnumber(L,2)) { 577 if (lua_isnumber(L,2)) {
487 timeout= SIGNAL_TIMEOUT_PREPARE( lua_tonumber(L,2) ); 578 timeout= SIGNAL_TIMEOUT_PREPARE( lua_tonumber(L,2) );
488 key_i++; 579 key_i++;
@@ -509,10 +600,36 @@ LUAG_FUNC( linda_receive ) {
509 cancel= cancel_test( L ); // testing here causes no delays 600 cancel= cancel_test( L ); // testing here causes no delays
510 if (cancel) break; 601 if (cancel) break;
511 602
603// Bugfix by Benoit Germain Dec-2009: change status of lane to "waiting"
604//
605#if 1
606{
607 struct s_lane *s;
608 enum e_status prev_status = ERROR_ST; // prevent 'might be used uninitialized' warnings
609 STACK_GROW(L,1);
610
611 STACK_CHECK(L)
612 lua_pushlightuserdata( L, CANCEL_TEST_KEY );
613 lua_rawget( L, LUA_REGISTRYINDEX );
614 s= lua_touserdata( L, -1 ); // lightuserdata (true 's_lane' pointer) / nil
615 lua_pop(L,1);
616 STACK_END(L,0)
617 if (s) {
618 prev_status = s->status;
619 s->status = WAITING;
620 }
621 if (!SIGNAL_WAIT( &linda->write_happened, &K->lock_, timeout )) {
622 if (s) { s->status = prev_status; }
623 break;
624 }
625 if (s) s->status = prev_status;
626}
627#else
512 // Release the K lock for the duration of wait, and re-acquire 628 // Release the K lock for the duration of wait, and re-acquire
513 // 629 //
514 if (!SIGNAL_WAIT( &linda->write_happened, &K->lock_, timeout )) 630 if (!SIGNAL_WAIT( &linda->write_happened, &K->lock_, timeout ))
515 break; 631 break;
632#endif
516 } 633 }
517 } 634 }
518 } 635 }
@@ -535,8 +652,11 @@ LUAG_FUNC( linda_receive ) {
535LUAG_FUNC( linda_set ) { 652LUAG_FUNC( linda_set ) {
536 struct s_Linda *linda= lua_toLinda( L, 1 ); 653 struct s_Linda *linda= lua_toLinda( L, 1 );
537 bool_t has_value= !lua_isnil(L,3); 654 bool_t has_value= !lua_isnil(L,3);
655 struct s_Keeper *K;
538 656
539 struct s_Keeper *K= keeper_acquire( linda ); 657 luaL_argcheck( L, linda, 1, "expected a linda object!");
658
659 K= keeper_acquire( linda );
540 { 660 {
541 int pushed= keeper_call( K->L, "set", L, linda, 2 ); 661 int pushed= keeper_call( K->L, "set", L, linda, 2 );
542 ASSERT_L( pushed==0 ); 662 ASSERT_L( pushed==0 );
@@ -561,8 +681,11 @@ LUAG_FUNC( linda_set ) {
561LUAG_FUNC( linda_get ) { 681LUAG_FUNC( linda_get ) {
562 struct s_Linda *linda= lua_toLinda( L, 1 ); 682 struct s_Linda *linda= lua_toLinda( L, 1 );
563 int pushed; 683 int pushed;
684 struct s_Keeper *K;
564 685
565 struct s_Keeper *K= keeper_acquire( linda ); 686 luaL_argcheck( L, linda, 1, "expected a linda object!");
687
688 K= keeper_acquire( linda );
566 { 689 {
567 pushed= keeper_call( K->L, "get", L, linda, 2 ); 690 pushed= keeper_call( K->L, "get", L, linda, 2 );
568 ASSERT_L( pushed==0 || pushed==1 ); 691 ASSERT_L( pushed==0 || pushed==1 );
@@ -580,8 +703,11 @@ LUAG_FUNC( linda_get ) {
580*/ 703*/
581LUAG_FUNC( linda_limit ) { 704LUAG_FUNC( linda_limit ) {
582 struct s_Linda *linda= lua_toLinda( L, 1 ); 705 struct s_Linda *linda= lua_toLinda( L, 1 );
706 struct s_Keeper *K;
707
708 luaL_argcheck( L, linda, 1, "expected a linda object!");
583 709
584 struct s_Keeper *K= keeper_acquire( linda ); 710 K= keeper_acquire( linda );
585 { 711 {
586 int pushed= keeper_call( K->L, "limit", L, linda, 2 ); 712 int pushed= keeper_call( K->L, "limit", L, linda, 2 );
587 ASSERT_L( pushed==0 ); 713 ASSERT_L( pushed==0 );
@@ -604,6 +730,7 @@ LUAG_FUNC( linda_limit ) {
604*/ 730*/
605LUAG_FUNC( linda_deep ) { 731LUAG_FUNC( linda_deep ) {
606 struct s_Linda *linda= lua_toLinda( L, 1 ); 732 struct s_Linda *linda= lua_toLinda( L, 1 );
733 luaL_argcheck( L, linda, 1, "expected a linda object!");
607 lua_pushlightuserdata( L, linda ); // just the address 734 lua_pushlightuserdata( L, linda ); // just the address
608 return 1; 735 return 1;
609} 736}
@@ -761,13 +888,13 @@ static int run_finalizers( lua_State *L, int lua_rc )
761 return 0; // no finalizers 888 return 0; // no finalizers
762 889
763 tbl_index= lua_gettop(L); 890 tbl_index= lua_gettop(L);
764 error_index= (lua_rc!=0) ? tbl_index-1 : 0; // absolute indices 891 error_index= (lua_rc!=0) ? tbl_index-2 : 0; // absolute indices
765 892
766 STACK_GROW(L,4); 893 STACK_GROW(L,4);
767 894
768 // [-1]: { func [, ...] } 895 // [-1]: { func [, ...] }
769 // 896 //
770 for( n= lua_objlen(L,-1); n>0; n-- ) { 897 for( n= (unsigned int)lua_objlen(L,-1); n>0; n-- ) {
771 unsigned args= 0; 898 unsigned args= 0;
772 lua_pushinteger( L,n ); 899 lua_pushinteger( L,n );
773 lua_gettable( L, -2 ); 900 lua_gettable( L, -2 );
@@ -805,57 +932,6 @@ static int run_finalizers( lua_State *L, int lua_rc )
805/*---=== Threads ===--- 932/*---=== Threads ===---
806*/ 933*/
807 934
808// NOTE: values to be changed by either thread, during execution, without
809// locking, are marked "volatile"
810//
811struct s_lane {
812 THREAD_T thread;
813 //
814 // M: sub-thread OS thread
815 // S: not used
816
817 lua_State *L;
818 //
819 // M: prepares the state, and reads results
820 // S: while S is running, M must keep out of modifying the state
821
822 volatile enum e_status status;
823 //
824 // M: sets to PENDING (before launching)
825 // S: updates -> RUNNING/WAITING -> DONE/ERROR_ST/CANCELLED
826
827 volatile bool_t cancel_request;
828 //
829 // M: sets to FALSE, flags TRUE for cancel request
830 // S: reads to see if cancel is requested
831
832#if !( (defined PLATFORM_WIN32) || (defined PLATFORM_POCKETPC) || (defined PTHREAD_TIMEDJOIN) )
833 SIGNAL_T done_signal_;
834 //
835 // M: Waited upon at lane ending (if Posix with no PTHREAD_TIMEDJOIN)
836 // S: sets the signal once cancellation is noticed (avoids a kill)
837
838 MUTEX_T done_lock_;
839 //
840 // Lock required by 'done_signal' condition variable, protecting
841 // lane status changes to DONE/ERROR_ST/CANCELLED.
842#endif
843
844 volatile enum {
845 NORMAL, // normal master side state
846 KILLED // issued an OS kill
847 } mstatus;
848 //
849 // M: sets to NORMAL, if issued a kill changes to KILLED
850 // S: not used
851
852 struct s_lane * volatile selfdestruct_next;
853 //
854 // M: sets to non-NULL if facing lane handle '__gc' cycle but the lane
855 // is still running
856 // S: cleans up after itself if non-NULL at lane exit
857};
858
859static MUTEX_T selfdestruct_cs; 935static MUTEX_T selfdestruct_cs;
860 // 936 //
861 // Protects modifying the selfdestruct chain 937 // Protects modifying the selfdestruct chain
@@ -985,11 +1061,13 @@ static void selfdestruct_atexit( void ) {
985 // Linux (at least 64-bit): CAUSES A SEGFAULT IF THIS BLOCK IS ENABLED 1061 // Linux (at least 64-bit): CAUSES A SEGFAULT IF THIS BLOCK IS ENABLED
986 // and works without the block (so let's leave those lanes running) 1062 // and works without the block (so let's leave those lanes running)
987 // 1063 //
988#if 1 1064//we want to free memory and such when we exit.
1065#if 0
989 // 2.0.2: at least timer lane is still here 1066 // 2.0.2: at least timer lane is still here
990 // 1067 //
991 //fprintf( stderr, "Left %d lane(s) with cancel request at process end.\n", n ); 1068 DEBUGEXEC(fprintf( stderr, "Left %d lane(s) with cancel request at process end.\n", n ));
992#else 1069#else
1070 n=0;
993 MUTEX_LOCK( &selfdestruct_cs ); 1071 MUTEX_LOCK( &selfdestruct_cs );
994 { 1072 {
995 struct s_lane *s= selfdestruct_first; 1073 struct s_lane *s= selfdestruct_first;
@@ -998,6 +1076,8 @@ static void selfdestruct_atexit( void ) {
998 s->selfdestruct_next= NULL; // detach from selfdestruct chain 1076 s->selfdestruct_next= NULL; // detach from selfdestruct chain
999 1077
1000 THREAD_KILL( &s->thread ); 1078 THREAD_KILL( &s->thread );
1079 lua_close(s->L);
1080 free(s);
1001 s= next_s; 1081 s= next_s;
1002 n++; 1082 n++;
1003 } 1083 }
@@ -1005,9 +1085,16 @@ static void selfdestruct_atexit( void ) {
1005 } 1085 }
1006 MUTEX_UNLOCK( &selfdestruct_cs ); 1086 MUTEX_UNLOCK( &selfdestruct_cs );
1007 1087
1008 fprintf( stderr, "Killed %d lane(s) at process end.\n", n ); 1088 DEBUGEXEC(fprintf( stderr, "Killed %d lane(s) at process end.\n", n ));
1009#endif 1089#endif
1010 } 1090 }
1091 {
1092 int i;
1093 for(i=0;i<KEEPER_STATES_N;i++){
1094 lua_close(keeper[i].L);
1095 keeper[i].L = 0;
1096 }
1097 }
1011} 1098}
1012 1099
1013 1100
@@ -1153,6 +1240,38 @@ static int lane_error( lua_State *L ) {
1153} 1240}
1154#endif 1241#endif
1155 1242
1243#if defined PLATFORM_WIN32 && !defined __GNUC__
1244//see http://msdn.microsoft.com/en-us/library/xcb2z8hs.aspx
1245#define MS_VC_EXCEPTION 0x406D1388
1246#pragma pack(push,8)
1247typedef struct tagTHREADNAME_INFO
1248{
1249 DWORD dwType; // Must be 0x1000.
1250 LPCSTR szName; // Pointer to name (in user addr space).
1251 DWORD dwThreadID; // Thread ID (-1=caller thread).
1252 DWORD dwFlags; // Reserved for future use, must be zero.
1253} THREADNAME_INFO;
1254#pragma pack(pop)
1255
1256void SetThreadName( DWORD dwThreadID, char* threadName)
1257{
1258 THREADNAME_INFO info;
1259 Sleep(10);
1260 info.dwType = 0x1000;
1261 info.szName = threadName;
1262 info.dwThreadID = dwThreadID;
1263 info.dwFlags = 0;
1264
1265 __try
1266 {
1267 RaiseException( MS_VC_EXCEPTION, 0, sizeof(info)/sizeof(ULONG_PTR), (ULONG_PTR*)&info );
1268 }
1269 __except(EXCEPTION_EXECUTE_HANDLER)
1270 {
1271 }
1272}
1273#endif
1274
1156 1275
1157//--- 1276//---
1158#if (defined PLATFORM_WIN32) || (defined PLATFORM_POCKETPC) 1277#if (defined PLATFORM_WIN32) || (defined PLATFORM_POCKETPC)
@@ -1165,7 +1284,12 @@ static int lane_error( lua_State *L ) {
1165 int rc, rc2; 1284 int rc, rc2;
1166 lua_State *L= s->L; 1285 lua_State *L= s->L;
1167 1286
1168 s->status= RUNNING; // PENDING -> RUNNING 1287
1288#if defined PLATFORM_WIN32 && !defined __GNUC__
1289 SetThreadName(-1, s->threadName);
1290#endif
1291
1292 s->status= RUNNING; // PENDING -> RUNNING
1169 1293
1170 // Tie "set_finalizer()" to the state 1294 // Tie "set_finalizer()" to the state
1171 // 1295 //
@@ -1243,7 +1367,7 @@ static int lane_error( lua_State *L ) {
1243 // We're a free-running thread and no-one's there to clean us up. 1367 // We're a free-running thread and no-one's there to clean us up.
1244 // 1368 //
1245 lua_close( s->L ); 1369 lua_close( s->L );
1246 L= 0; 1370 s->L = L = 0;
1247 1371
1248 #if !( (defined PLATFORM_WIN32) || (defined PLATFORM_POCKETPC) || (defined PTHREAD_TIMEDJOIN) ) 1372 #if !( (defined PLATFORM_WIN32) || (defined PLATFORM_POCKETPC) || (defined PTHREAD_TIMEDJOIN) )
1249 SIGNAL_FREE( &s->done_signal_ ); 1373 SIGNAL_FREE( &s->done_signal_ );
@@ -1290,121 +1414,144 @@ static int lane_error( lua_State *L ) {
1290// 1414//
1291LUAG_FUNC( thread_new ) 1415LUAG_FUNC( thread_new )
1292{ 1416{
1293 lua_State *L2; 1417 lua_State *L2;
1294 struct s_lane *s; 1418 struct s_lane *s;
1295 struct s_lane **ud; 1419 struct s_lane **ud;
1296 1420 const char *threadName = 0;
1297 const char *libs= lua_tostring( L, 2 ); 1421
1298 uint_t cs= luaG_optunsigned( L, 3,0); 1422 const char *libs= lua_tostring( L, 2 );
1299 int prio= luaL_optinteger( L, 4,0); 1423 uint_t cs= luaG_optunsigned( L, 3,0);
1300 uint_t glob= luaG_isany(L,5) ? 5:0; 1424 int prio= (int)luaL_optinteger( L, 4,0);
1301 1425 uint_t glob= luaG_isany(L,5) ? 5:0;
1302 #define FIXED_ARGS (5) 1426
1303 uint_t args= lua_gettop(L) - FIXED_ARGS; 1427#define FIXED_ARGS (5)
1304 1428 uint_t args= lua_gettop(L) - FIXED_ARGS;
1305 if (prio < THREAD_PRIO_MIN || prio > THREAD_PRIO_MAX) { 1429
1306 luaL_error( L, "Priority out of range: %d..+%d (%d)", 1430 if (prio < THREAD_PRIO_MIN || prio > THREAD_PRIO_MAX)
1307 THREAD_PRIO_MIN, THREAD_PRIO_MAX, prio ); 1431 {
1308 } 1432 luaL_error( L, "Priority out of range: %d..+%d (%d)",
1309 1433 THREAD_PRIO_MIN, THREAD_PRIO_MAX, prio );
1310 /* --- Create and prepare the sub state --- */ 1434 }
1311 1435
1312 L2 = luaL_newstate(); // uses standard 'realloc()'-based allocator, 1436 /* --- Create and prepare the sub state --- */
1313 // sets the panic callback 1437
1314 1438 L2 = luaL_newstate(); // uses standard 'realloc()'-based allocator,
1315 if (!L2) luaL_error( L, "'luaL_newstate()' failed; out of memory" ); 1439 // sets the panic callback
1316 1440
1317 STACK_GROW( L,2 ); 1441 if (!L2) luaL_error( L, "'luaL_newstate()' failed; out of memory" );
1318 1442
1319 // Setting the globals table (needs to be done before loading stdlibs, 1443 STACK_GROW( L,2 );
1320 // and the lane function) 1444
1321 // 1445 // Setting the globals table (needs to be done before loading stdlibs,
1322 if (glob!=0) { 1446 // and the lane function)
1323STACK_CHECK(L) 1447 //
1324 if (!lua_istable(L,glob)) 1448 if (glob!=0)
1325 luaL_error( L, "Expected table, got %s", luaG_typename(L,glob) ); 1449 {
1326 1450 STACK_CHECK(L)
1327 lua_pushvalue( L, glob ); 1451 if (!lua_istable(L,glob))
1328 luaG_inter_move( L,L2, 1 ); // moves the table to L2 1452 luaL_error( L, "Expected table, got %s", luaG_typename(L,glob) );
1329 1453
1330 // L2 [-1]: table of globals 1454 lua_pushvalue( L, glob );
1331 1455 lua_pushstring( L, "threadName");
1332 // "You can change the global environment of a Lua thread using lua_replace" 1456 lua_gettable( L, -2);
1333 // (refman-5.0.pdf p. 30) 1457 threadName = lua_tostring( L, -1);
1334 // 1458 lua_pop( L, 1);
1335 lua_replace( L2, LUA_GLOBALSINDEX ); 1459 luaG_inter_move( L,L2, 1 ); // moves the table to L2
1336STACK_END(L,0) 1460
1337 } 1461 // L2 [-1]: table of globals
1338 1462
1339 // Selected libraries 1463 // "You can change the global environment of a Lua thread using lua_replace"
1340 // 1464 // (refman-5.0.pdf p. 30)
1341 if (libs) { 1465 //
1342 const char *err= luaG_openlibs( L2, libs ); 1466 lua_replace( L2, LUA_GLOBALSINDEX );
1343 ASSERT_L( !err ); // bad libs should have been noticed by 'lanes.lua' 1467 STACK_END(L,0)
1344 1468 }
1345 serialize_require( L2 ); 1469
1346 } 1470 // Selected libraries
1347 1471 //
1348 // Lane main function 1472 if (libs)
1349 // 1473 {
1350STACK_CHECK(L) 1474 const char *err= luaG_openlibs( L2, libs );
1351 lua_pushvalue( L, 1 ); 1475 ASSERT_L( !err ); // bad libs should have been noticed by 'lanes.lua'
1352 luaG_inter_move( L,L2, 1 ); // L->L2 1476
1353STACK_MID(L,0) 1477 serialize_require( L2 );
1354 1478 }
1355 ASSERT_L( lua_gettop(L2) == 1 ); 1479
1356 ASSERT_L( lua_isfunction(L2,1) ); 1480 // Lane main function
1357 1481 //
1358 // revive arguments 1482 STACK_CHECK(L)
1359 // 1483 if( lua_type(L, 1) == LUA_TFUNCTION)
1360 if (args) luaG_inter_copy( L,L2, args ); // L->L2 1484 {
1361STACK_MID(L,0) 1485 lua_pushvalue( L, 1 );
1362 1486 luaG_inter_move( L,L2, 1 ); // L->L2
1363ASSERT_L( (uint_t)lua_gettop(L2) == 1+args ); 1487 STACK_MID(L,0)
1364ASSERT_L( lua_isfunction(L2,1) ); 1488 }
1365 1489 else if( lua_type(L, 1) == LUA_TSTRING)
1366 // 's' is allocated from heap, not Lua, since its life span may surpass 1490 {
1367 // the handle's (if free running thread) 1491 // compile the string
1368 // 1492 if( luaL_loadstring( L2, lua_tostring( L, 1)) != 0)
1369 ud= lua_newuserdata( L, sizeof(struct s_lane*) ); 1493 {
1370 ASSERT_L(ud); 1494 luaL_error( L, "error when parsing lane function code");
1371 1495 }
1372 s= *ud= malloc( sizeof(struct s_lane) ); 1496 }
1373 ASSERT_L(s); 1497
1374 1498 ASSERT_L( lua_gettop(L2) == 1 );
1375 //memset( s, 0, sizeof(struct s_lane) ); 1499 ASSERT_L( lua_isfunction(L2,1) );
1376 s->L= L2; 1500
1377 s->status= PENDING; 1501 // revive arguments
1378 s->cancel_request= FALSE; 1502 //
1503 if (args) luaG_inter_copy( L,L2, args ); // L->L2
1504 STACK_MID(L,0)
1505
1506 ASSERT_L( (uint_t)lua_gettop(L2) == 1+args );
1507 ASSERT_L( lua_isfunction(L2,1) );
1508
1509 // 's' is allocated from heap, not Lua, since its life span may surpass
1510 // the handle's (if free running thread)
1511 //
1512 ud= lua_newuserdata( L, sizeof(struct s_lane*) );
1513 ASSERT_L(ud);
1514
1515 s= *ud= malloc( sizeof(struct s_lane) );
1516 ASSERT_L(s);
1517
1518 //memset( s, 0, sizeof(struct s_lane) );
1519 s->L= L2;
1520 s->status= PENDING;
1521 s->cancel_request= FALSE;
1522
1523 threadName = threadName ? threadName : "<unnamed thread>";
1524 strcpy(s->threadName, threadName);
1379 1525
1380#if !( (defined PLATFORM_WIN32) || (defined PLATFORM_POCKETPC) || (defined PTHREAD_TIMEDJOIN) ) 1526#if !( (defined PLATFORM_WIN32) || (defined PLATFORM_POCKETPC) || (defined PTHREAD_TIMEDJOIN) )
1381 MUTEX_INIT( &s->done_lock_ ); 1527 MUTEX_INIT( &s->done_lock_ );
1382 SIGNAL_INIT( &s->done_signal_ ); 1528 SIGNAL_INIT( &s->done_signal_ );
1383#endif 1529#endif
1384 s->mstatus= NORMAL; 1530 s->mstatus= NORMAL;
1385 s->selfdestruct_next= NULL; 1531 s->selfdestruct_next= NULL;
1386 1532
1387 // Set metatable for the userdata 1533 // Set metatable for the userdata
1388 // 1534 //
1389 lua_pushvalue( L, lua_upvalueindex(1) ); 1535 lua_pushvalue( L, lua_upvalueindex(1) );
1390 lua_setmetatable( L, -2 ); 1536 lua_setmetatable( L, -2 );
1391STACK_MID(L,1) 1537 STACK_MID(L,1)
1392 1538
1393 // Place 's' to registry, for 'cancel_test()' (even if 'cs'==0 we still 1539 // Place 's' to registry, for 'cancel_test()' (even if 'cs'==0 we still
1394 // do cancel tests at pending send/receive). 1540 // do cancel tests at pending send/receive).
1395 // 1541 //
1396 lua_pushlightuserdata( L2, CANCEL_TEST_KEY ); 1542 lua_pushlightuserdata( L2, CANCEL_TEST_KEY );
1397 lua_pushlightuserdata( L2, s ); 1543 lua_pushlightuserdata( L2, s );
1398 lua_rawset( L2, LUA_REGISTRYINDEX ); 1544 lua_rawset( L2, LUA_REGISTRYINDEX );
1399 1545
1400 if (cs) { 1546 if (cs)
1401 lua_sethook( L2, cancel_hook, LUA_MASKCOUNT, cs ); 1547 {
1402 } 1548 lua_sethook( L2, cancel_hook, LUA_MASKCOUNT, cs );
1403 1549 }
1404 THREAD_CREATE( &s->thread, lane_main, s, prio ); 1550
1405STACK_END(L,1) 1551 THREAD_CREATE( &s->thread, lane_main, s, prio );
1406 1552 STACK_END(L,1)
1407 return 1; 1553
1554 return 1;
1408} 1555}
1409 1556
1410 1557
@@ -1428,45 +1575,56 @@ STACK_END(L,1)
1428// 1575//
1429// Todo: Maybe we should have a clear #define for selecting either behaviour. 1576// Todo: Maybe we should have a clear #define for selecting either behaviour.
1430// 1577//
1431LUAG_FUNC( thread_gc ) { 1578LUAG_FUNC( thread_gc )
1432 struct s_lane *s= lua_toLane(L,1); 1579{
1433 1580 struct s_lane *s= lua_toLane(L,1);
1434 // We can read 's->status' without locks, but not wait for it 1581
1435 // 1582 // We can read 's->status' without locks, but not wait for it
1436 if (s->status < DONE) { 1583 //
1437 // 1584 if (s->status < DONE)
1438 selfdestruct_add(s); 1585 {
1439 assert( s->selfdestruct_next ); 1586 //
1440 return 0; 1587 selfdestruct_add(s);
1441 1588 assert( s->selfdestruct_next );
1442 } else if (s->mstatus==KILLED) { 1589 return 0;
1443 // Make sure a kill has proceeded, before cleaning up the data structure. 1590
1444 // 1591 }
1445 // If not doing 'THREAD_WAIT()' we should close the Lua state here 1592 else if (s->mstatus==KILLED)
1446 // (can it be out of order, since we killed the lane abruptly?) 1593 {
1447 // 1594 // Make sure a kill has proceeded, before cleaning up the data structure.
1595 //
1596 // If not doing 'THREAD_WAIT()' we should close the Lua state here
1597 // (can it be out of order, since we killed the lane abruptly?)
1598 //
1448#if 0 1599#if 0
1449 lua_close( s->L ); 1600 lua_close( s->L );
1601 s->L = 0;
1450#else 1602#else
1451fprintf( stderr, "** Joining with a killed thread (needs testing) **" ); 1603 DEBUGEXEC(fprintf( stderr, "** Joining with a killed thread (needs testing) **" ));
1452#if (defined PLATFORM_WIN32) || (defined PLATFORM_POCKETPC) || (defined PTHREAD_TIMEDJOIN) 1604#if (defined PLATFORM_WIN32) || (defined PLATFORM_POCKETPC) || (defined PTHREAD_TIMEDJOIN)
1453 THREAD_WAIT( &s->thread, -1 ); 1605 THREAD_WAIT( &s->thread, -1 );
1454#else 1606#else
1455 THREAD_WAIT( &s->thread, &s->done_signal_, &s->done_lock_, &s->status, -1 ); 1607 THREAD_WAIT( &s->thread, &s->done_signal_, &s->done_lock_, &s->status, -1 );
1456#endif 1608#endif
1457fprintf( stderr, "** Joined ok **" ); 1609 DEBUGEXEC(fprintf( stderr, "** Joined ok **" ));
1458#endif 1610#endif
1459 } 1611 }
1460 1612 else if( s->L)
1461 // Clean up after a (finished) thread 1613 {
1462 // 1614 lua_close( s->L);
1615 s->L = 0;
1616 }
1617
1618 // Clean up after a (finished) thread
1619 //
1463#if (! ((defined PLATFORM_WIN32) || (defined PLATFORM_POCKETPC) || (defined PTHREAD_TIMEDJOIN))) 1620#if (! ((defined PLATFORM_WIN32) || (defined PLATFORM_POCKETPC) || (defined PTHREAD_TIMEDJOIN)))
1464 SIGNAL_FREE( &s->done_signal_ ); 1621 SIGNAL_FREE( &s->done_signal_ );
1465 MUTEX_FREE( &s->done_lock_ ); 1622 MUTEX_FREE( &s->done_lock_ );
1466 free(s);
1467#endif 1623#endif
1468 1624
1469 return 0; 1625 free(s);
1626
1627 return 0;
1470} 1628}
1471 1629
1472 1630
@@ -1614,10 +1772,11 @@ LUAG_FUNC( thread_join )
1614 break; 1772 break;
1615 1773
1616 default: 1774 default:
1617 fprintf( stderr, "Status: %d\n", s->status ); 1775 DEBUGEXEC(fprintf( stderr, "Status: %d\n", s->status ));
1618 ASSERT_L( FALSE ); ret= 0; 1776 ASSERT_L( FALSE ); ret= 0;
1619 } 1777 }
1620 lua_close(L2); 1778 lua_close(L2);
1779 s->L = L2 = 0;
1621 1780
1622 return ret; 1781 return ret;
1623} 1782}
@@ -1627,48 +1786,6 @@ LUAG_FUNC( thread_join )
1627*/ 1786*/
1628 1787
1629/* 1788/*
1630* Push a timer gateway Linda object; only one deep userdata is
1631* created for this, each lane will get its own proxy.
1632*
1633* Note: this needs to be done on the C side; Lua wouldn't be able
1634* to even see, when we've been initialized for the very first
1635* time (with us, they will be).
1636*/
1637static
1638void push_timer_gateway( lua_State *L ) {
1639
1640 /* No need to lock; 'static' is just fine
1641 */
1642 static DEEP_PRELUDE *p; // = NULL
1643
1644 STACK_CHECK(L)
1645 if (!p) {
1646 // Create the Linda (only on first time)
1647 //
1648 // proxy_ud= deep_userdata( idfunc )
1649 //
1650 lua_pushcfunction( L, luaG_deep_userdata );
1651 lua_pushcfunction( L, LG_linda_id );
1652 lua_call( L, 1 /*args*/, 1 /*retvals*/ );
1653
1654 ASSERT_L( lua_isuserdata(L,-1) );
1655
1656 // Proxy userdata contents is only a 'DEEP_PRELUDE*' pointer
1657 //
1658 p= * (DEEP_PRELUDE**) lua_touserdata( L, -1 );
1659 ASSERT_L(p && p->refcount==1 && p->deep);
1660
1661 // [-1]: proxy for accessing the Linda
1662
1663 } else {
1664 /* Push a proxy based on the deep userdata we stored.
1665 */
1666 luaG_push_proxy( L, LG_linda_id, p );
1667 }
1668 STACK_END(L,1)
1669}
1670
1671/*
1672* secs= now_secs() 1789* secs= now_secs()
1673* 1790*
1674* Returns the current time, as seconds (millisecond resolution). 1791* Returns the current time, as seconds (millisecond resolution).
@@ -1697,12 +1814,12 @@ LUAG_FUNC( wakeup_conv )
1697 // .isdst (daylight saving on/off) 1814 // .isdst (daylight saving on/off)
1698 1815
1699 STACK_CHECK(L) 1816 STACK_CHECK(L)
1700 lua_getfield( L, 1, "year" ); year= lua_tointeger(L,-1); lua_pop(L,1); 1817 lua_getfield( L, 1, "year" ); year= (int)lua_tointeger(L,-1); lua_pop(L,1);
1701 lua_getfield( L, 1, "month" ); month= lua_tointeger(L,-1); lua_pop(L,1); 1818 lua_getfield( L, 1, "month" ); month= (int)lua_tointeger(L,-1); lua_pop(L,1);
1702 lua_getfield( L, 1, "day" ); day= lua_tointeger(L,-1); lua_pop(L,1); 1819 lua_getfield( L, 1, "day" ); day= (int)lua_tointeger(L,-1); lua_pop(L,1);
1703 lua_getfield( L, 1, "hour" ); hour= lua_tointeger(L,-1); lua_pop(L,1); 1820 lua_getfield( L, 1, "hour" ); hour= (int)lua_tointeger(L,-1); lua_pop(L,1);
1704 lua_getfield( L, 1, "min" ); min= lua_tointeger(L,-1); lua_pop(L,1); 1821 lua_getfield( L, 1, "min" ); min= (int)lua_tointeger(L,-1); lua_pop(L,1);
1705 lua_getfield( L, 1, "sec" ); sec= lua_tointeger(L,-1); lua_pop(L,1); 1822 lua_getfield( L, 1, "sec" ); sec= (int)lua_tointeger(L,-1); lua_pop(L,1);
1706 1823
1707 // If Lua table has '.isdst' we trust that. If it does not, we'll let 1824 // If Lua table has '.isdst' we trust that. If it does not, we'll let
1708 // 'mktime' decide on whether the time is within DST or not (value -1). 1825 // 'mktime' decide on whether the time is within DST or not (value -1).
@@ -1744,19 +1861,11 @@ LUAG_FUNC( wakeup_conv )
1744 lua_pushinteger( L, val ); \ 1861 lua_pushinteger( L, val ); \
1745 lua_setglobal( L, #name ) 1862 lua_setglobal( L, #name )
1746 1863
1747 1864/*
1748int 1865* One-time initializations
1749#if (defined PLATFORM_WIN32) || (defined PLATFORM_POCKETPC) 1866*/
1750__declspec(dllexport) 1867static void init_once_LOCKED( lua_State *L, volatile DEEP_PRELUDE ** timer_deep_ref ) {
1751#endif
1752 luaopen_lanes( lua_State *L ) {
1753 const char *err; 1868 const char *err;
1754 static volatile char been_here; // =0
1755
1756 // One time initializations:
1757 //
1758 if (!been_here) {
1759 been_here= TRUE;
1760 1869
1761#if (defined PLATFORM_WIN32) || (defined PLATFORM_POCKETPC) 1870#if (defined PLATFORM_WIN32) || (defined PLATFORM_POCKETPC)
1762 now_secs(); // initialize 'now_secs()' internal offset 1871 now_secs(); // initialize 'now_secs()' internal offset
@@ -1806,10 +1915,87 @@ __declspec(dllexport)
1806 #endif 1915 #endif
1807#endif 1916#endif
1808 err= init_keepers(); 1917 err= init_keepers();
1809 if (err) 1918 if (err) {
1810 luaL_error( L, "Unable to initialize: %s", err ); 1919 luaL_error( L, "Unable to initialize: %s", err );
1811 } 1920 }
1812 1921
1922 // Initialize 'timer_deep'; a common Linda object shared by all states
1923 //
1924 ASSERT_L( timer_deep_ref && (!(*timer_deep_ref)) );
1925
1926 STACK_CHECK(L)
1927 {
1928 // proxy_ud= deep_userdata( idfunc )
1929 //
1930 lua_pushcfunction( L, luaG_deep_userdata );
1931 lua_pushcfunction( L, LG_linda_id );
1932 lua_call( L, 1 /*args*/, 1 /*retvals*/ );
1933
1934 ASSERT_L( lua_isuserdata(L,-1) );
1935
1936 // Proxy userdata contents is only a 'DEEP_PRELUDE*' pointer
1937 //
1938 *timer_deep_ref= * (DEEP_PRELUDE**) lua_touserdata( L, -1 );
1939 ASSERT_L( (*timer_deep_ref) && (*timer_deep_ref)->refcount==1 && (*timer_deep_ref)->deep );
1940
1941 lua_pop(L,1); // we don't need the proxy
1942 }
1943 STACK_END(L,0)
1944}
1945
1946int
1947#if (defined PLATFORM_WIN32) || (defined PLATFORM_POCKETPC)
1948__declspec(dllexport)
1949#endif
1950 luaopen_lanes( lua_State *L ) {
1951
1952 // Initialized by 'init_once_LOCKED()': the deep userdata Linda object
1953 // used for timers (each lane will get a proxy to this)
1954 //
1955 static volatile DEEP_PRELUDE *timer_deep; // = NULL
1956
1957 /*
1958 * Making one-time initializations.
1959 *
1960 * When the host application is single-threaded (and all threading happens via Lanes)
1961 * there is no problem. But if the host is multithreaded, we need to lock around the
1962 * initializations.
1963 */
1964 static volatile int /*bool*/ go_ahead; // = 0
1965#ifdef PLATFORM_WIN32
1966 {
1967 // TBD: Someone please replace this with reliable Win32 API code. Problem is,
1968 // there's no autoinitializing locks (s.a. PTHREAD_MUTEX_INITIALIZER) in
1969 // Windows so 'InterlockedIncrement' or something needs to be used.
1970 // This is 99.9999% safe, though (and always safe if host is single-threaded)
1971 // -- AKa 24-Jun-2009
1972 //
1973 static volatile unsigned my_number; // = 0
1974
1975 if (my_number++ == 0) { // almost atomic
1976 init_once_LOCKED(L, &timer_deep);
1977 go_ahead= 1; // let others pass
1978 } else {
1979 while( !go_ahead ) { Sleep(1); } // changes threads
1980 }
1981 }
1982#else
1983 if (!go_ahead) {
1984 static pthread_mutex_t my_lock= PTHREAD_MUTEX_INITIALIZER;
1985 pthread_mutex_lock(&my_lock);
1986 {
1987 // Recheck now that we're within the lock
1988 //
1989 if (!go_ahead) {
1990 init_once_LOCKED(L, &timer_deep);
1991 go_ahead= 1;
1992 }
1993 }
1994 pthread_mutex_unlock(&my_lock);
1995 }
1996#endif
1997 assert( timer_deep != 0 );
1998
1813 // Linda identity function 1999 // Linda identity function
1814 // 2000 //
1815 REG_FUNC( linda_id ); 2001 REG_FUNC( linda_id );
@@ -1835,7 +2021,7 @@ __declspec(dllexport)
1835 REG_FUNC( now_secs ); 2021 REG_FUNC( now_secs );
1836 REG_FUNC( wakeup_conv ); 2022 REG_FUNC( wakeup_conv );
1837 2023
1838 push_timer_gateway(L); 2024 luaG_push_proxy( L, LG_linda_id, (DEEP_PRELUDE *) timer_deep );
1839 lua_setglobal( L, "timer_gateway" ); 2025 lua_setglobal( L, "timer_gateway" );
1840 2026
1841 REG_INT2( max_prio, THREAD_PRIO_MAX ); 2027 REG_INT2( max_prio, THREAD_PRIO_MAX );