aboutsummaryrefslogtreecommitdiff
path: root/src/lanes.c
diff options
context:
space:
mode:
authorBenoit Germain <bnt.germain@gmail.com>2011-01-04 21:31:17 +0100
committerBenoit Germain <bnt.germain@gmail.com>2011-01-04 21:31:17 +0100
commit79e46938c5d8daf164ab2d934f668fa27b32e4cf (patch)
tree407761f25bbdc3d5b2066a705dcbcf8711690242 /src/lanes.c
parented07b457b6b45ece85d367dc8b89bf3c040abd9a (diff)
downloadlanes-79e46938c5d8daf164ab2d934f668fa27b32e4cf.tar.gz
lanes-79e46938c5d8daf164ab2d934f668fa27b32e4cf.tar.bz2
lanes-79e46938c5d8daf164ab2d934f668fa27b32e4cf.zip
Take all code from Asko Kauppi's SVN server, and push it here so that the github repository becomes the official Lanes source codebase.
Note that Asko's SVN server holds version 2.0.9, whereas this is version 2.0.10, but I don't see any real need to update SVN if it is to become deprecated. Next steps: - upgrade the rockspec to the latest version - make the html help available online somewhere Signed-off-by: Benoit Germain <bnt.germain@gmail.com>
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 );