aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGES6
-rw-r--r--docs/index.html18
-rw-r--r--src/keeper.c9
-rw-r--r--src/lanes.c68
-rw-r--r--src/threading.c12
-rw-r--r--src/threading.h12
-rw-r--r--src/tools.c9
-rw-r--r--src/tools.h11
8 files changed, 105 insertions, 40 deletions
diff --git a/CHANGES b/CHANGES
index 16faa44..52fcf5f 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,5 +1,11 @@
1CHANGES: 1CHANGES:
2 2
3CHANGE 85: BGe 28-Nov-13
4 * version 3.7.3
5 * set pthread thread cancel type to PTHREAD_CANCEL_ASYNCHRONOUS
6 * lane_h:cancel() accepts a 3rd timeout argument used when waiting for actual thread termination (hitting the timeout raises an error)
7 * added PROPAGATE_ALLOCF macro to select state creation mode (lua_newstate or luaL_newstate)
8
3CHANGE 84: BGe 18-Nov-13 9CHANGE 84: BGe 18-Nov-13
4 * Fix a deadlock when GCing during a linda operation. 10 * Fix a deadlock when GCing during a linda operation.
5 * Fix a compilation warning about an unused variable 11 * Fix a compilation warning about an unused variable
diff --git a/docs/index.html b/docs/index.html
index 40930d8..25f9e22 100644
--- a/docs/index.html
+++ b/docs/index.html
@@ -70,7 +70,7 @@
70 </p> 70 </p>
71 71
72 <p> 72 <p>
73 This document was revised on 16-Nov-13, and applies to version <tt>3.7.2</tt>. 73 This document was revised on 28-Nov-13, and applies to version <tt>3.7.3</tt>.
74 </p> 74 </p>
75 </font> 75 </font>
76 </center> 76 </center>
@@ -102,7 +102,7 @@
102 <li>Data passing uses fast inter-state copies (no serialization required).</li> 102 <li>Data passing uses fast inter-state copies (no serialization required).</li>
103 <li>"Deep userdata" concept, for sharing userdata over multiple lanes.</li> 103 <li>"Deep userdata" concept, for sharing userdata over multiple lanes.</li>
104 <li>Millisecond level timers, integrated with the Linda system.</li> 104 <li>Millisecond level timers, integrated with the Linda system.</li>
105 <li>Threads can be given priorities -2..+2 (default is 0).</li> 105 <li>Threads can be given priorities.</li>
106 <li>Lanes are cancellable, with proper cleanup.</li> 106 <li>Lanes are cancellable, with proper cleanup.</li>
107 <li>No Lua-side application level locking - ever!</li> 107 <li>No Lua-side application level locking - ever!</li>
108 </ul> 108 </ul>
@@ -587,9 +587,10 @@
587 <td> 587 <td>
588 <code>.priority</code> 588 <code>.priority</code>
589 </td> 589 </td>
590 <td> integer -2..+2</td> 590 <td>integer</td>
591 <td> 591 <td>
592 The priority of lanes generated. -2 is lowest, +2 is highest. 592 The priority of lanes generated in the range -3..+3 (MinGW pthread and Windows thread API), or -2..+2 otherwise (default is 0).
593 These values are a mapping over the actual priority range of the underlying implementation.
593 <br> 594 <br>
594 Implementation and dependability of priorities varies by platform. Especially Linux kernel 2.6 is not supporting priorities in user mode. 595 Implementation and dependability of priorities varies by platform. Especially Linux kernel 2.6 is not supporting priorities in user mode.
595 </td> 596 </td>
@@ -842,14 +843,15 @@
842<h2 id="cancelling">Cancelling</h2> 843<h2 id="cancelling">Cancelling</h2>
843 844
844<table border="1" bgcolor="#E0E0FF" cellpadding="10" style="width:50%"><tr><td><pre> 845<table border="1" bgcolor="#E0E0FF" cellpadding="10" style="width:50%"><tr><td><pre>
845 bool[,reason] = lane_h:cancel( [timeout_secs=0.0,] [force_kill_bool = false] ) 846 bool[,reason] = lane_h:cancel( [timeout_secs=0.0,] [force_kill_bool = false] [, forcekill_timeout=0.0])
846</pre></td></tr></table> 847</pre></td></tr></table>
847 848
848<p> 849<p>
849 <tt>cancel()</tt>sends a cancellation request to the lane.<br/> 850 <tt>cancel()</tt> sends a cancellation request to the lane.<br/>
851 If <tt>timeout_secs</tt> is negative (aka "soft cancel"), starting with version 3.6.3, will only cause <tt>cancel_test()</tt> to return <tt>true</tt>, so that the lane can cleanup manually (the actual value is irrelevant). You can't provide the additional arguments in that case.<br/>
850 If <tt>timeout_secs</tt> is positive (aka "hard cancel"), waits for the request to be processed, or a timeout to occur.<br/> 852 If <tt>timeout_secs</tt> is positive (aka "hard cancel"), waits for the request to be processed, or a timeout to occur.<br/>
851 If <tt>timeout_secs</tt> is negative (aka "soft cancel"), starting with version 3.6.3, will only cause <tt>cancel_test()</tt> to return true, so that the lane can cleanup manually. You can't provide a second argument in that case.<br/> 853 If <tt>force_kill_bool</tt> is <tt>true</tt>, <tt>forcekill_timeout</tt> can be set to tell how long lanes will wait for the OS thread to terminate before raising an error. Windows threads always terminate immediately, but it might not always be the case with some pthread implementations.
852 Returns <tt>true</tt> if soft cancelling, or the lane was already done (in <tt>"done"</tt>, <tt>"error"</tt> or <tt>"cancelled"</tt> status), or the cancellation was fruitful within timeout period. 854 Returns <tt>true</tt> if soft cancelling, or the lane was already done (in <tt>"done"</tt>, <tt>"error"</tt> or <tt>"cancelled"</tt> status), or the cancellation was fruitful within <tt>timeout_secs</tt> timeout period.
853</p> 855</p>
854 856
855<p> 857<p>
diff --git a/src/keeper.c b/src/keeper.c
index 8da3c08..99f510b 100644
--- a/src/keeper.c
+++ b/src/keeper.c
@@ -567,8 +567,7 @@ void close_keepers( void)
567char const* init_keepers( lua_State* L) 567char const* init_keepers( lua_State* L)
568{ 568{
569 int i; 569 int i;
570 void* allocUD; 570 PROPAGATE_ALLOCF_PREP( L);
571 lua_Alloc allocF = lua_getallocf( L, &allocUD);
572 571
573 STACK_CHECK( L); 572 STACK_CHECK( L);
574 lua_getfield( L, 1, "nb_keepers"); 573 lua_getfield( L, 1, "nb_keepers");
@@ -580,10 +579,10 @@ char const* init_keepers( lua_State* L)
580 GKeepers = malloc( GNbKeepers * sizeof( struct s_Keeper)); 579 GKeepers = malloc( GNbKeepers * sizeof( struct s_Keeper));
581 for( i = 0; i < GNbKeepers; ++ i) 580 for( i = 0; i < GNbKeepers; ++ i)
582 { 581 {
583 lua_State* K = lua_newstate( allocF, allocUD); 582 lua_State* K = PROPAGATE_ALLOCF_ALLOC();
584 if( K == NULL) 583 if( K == NULL)
585 { 584 {
586 (void) luaL_error( L, "'lua_newstate()' failed while creating keeper state; out of memory"); 585 (void) luaL_error( L, "init_keepers() failed while creating keeper state; out of memory");
587 } 586 }
588 STACK_CHECK( K); 587 STACK_CHECK( K);
589 588
@@ -627,7 +626,7 @@ struct s_Keeper* keeper_acquire( void const* ptr)
627 * have to cast to unsigned long to avoid compilation warnings about loss of data when converting pointer-to-integer 626 * have to cast to unsigned long to avoid compilation warnings about loss of data when converting pointer-to-integer
628 */ 627 */
629 unsigned int i = (unsigned int)(((unsigned long)(ptr) >> 3) % GNbKeepers); 628 unsigned int i = (unsigned int)(((unsigned long)(ptr) >> 3) % GNbKeepers);
630 struct s_Keeper* K = &GKeepers[i]; 629 struct s_Keeper *K= &GKeepers[i];
631 630
632 MUTEX_LOCK( &K->lock_); 631 MUTEX_LOCK( &K->lock_);
633 //++ K->count; 632 //++ K->count;
diff --git a/src/lanes.c b/src/lanes.c
index 53ed5e4..9e32f9a 100644
--- a/src/lanes.c
+++ b/src/lanes.c
@@ -52,7 +52,7 @@
52 * ... 52 * ...
53 */ 53 */
54 54
55char const* VERSION = "3.7.2"; 55char const* VERSION = "3.7.3";
56 56
57/* 57/*
58=============================================================================== 58===============================================================================
@@ -1197,7 +1197,7 @@ typedef enum
1197 CR_Killed 1197 CR_Killed
1198} cancel_result; 1198} cancel_result;
1199 1199
1200static cancel_result thread_cancel( struct s_lane *s, double secs, bool_t force) 1200static cancel_result thread_cancel( lua_State* L, struct s_lane* s, double secs, bool_t force, double waitkill_timeout_)
1201{ 1201{
1202 cancel_result result; 1202 cancel_result result;
1203 1203
@@ -1239,6 +1239,15 @@ static cancel_result thread_cancel( struct s_lane *s, double secs, bool_t force)
1239 // PThread seems to have). 1239 // PThread seems to have).
1240 // 1240 //
1241 THREAD_KILL( &s->thread); 1241 THREAD_KILL( &s->thread);
1242#if THREADAPI == THREADAPI_PTHREAD
1243 // pthread: make sure the thread is really stopped!
1244 // note that this may block forever if the lane doesn't call a cancellation point and pthread doesn't honor PTHREAD_CANCEL_ASYNCHRONOUS
1245 result = THREAD_WAIT( &s->thread, waitkill_timeout_, &s->done_signal, &s->done_lock, &s->status);
1246 if( result == CR_Timeout)
1247 {
1248 return luaL_error( L, "force-killed lane failed to terminate within %f second%s", waitkill_timeout_, waitkill_timeout_ > 1 ? "s" : "");
1249 }
1250#endif // THREADAPI == THREADAPI_PTHREAD
1242 s->mstatus = KILLED; // mark 'gc' to wait for it 1251 s->mstatus = KILLED; // mark 'gc' to wait for it
1243 // note that s->status value must remain to whatever it was at the time of the kill 1252 // note that s->status value must remain to whatever it was at the time of the kill
1244 // because we need to know if we can lua_close() the Lua State or not. 1253 // because we need to know if we can lua_close() the Lua State or not.
@@ -1357,7 +1366,7 @@ static int selfdestruct_gc( lua_State* L)
1357 while( s != SELFDESTRUCT_END) 1366 while( s != SELFDESTRUCT_END)
1358 { 1367 {
1359 // attempt a regular unforced hard cancel with a small timeout 1368 // attempt a regular unforced hard cancel with a small timeout
1360 bool_t cancelled = THREAD_ISNULL( s->thread) || thread_cancel( s, 0.0001, FALSE); 1369 bool_t cancelled = THREAD_ISNULL( s->thread) || thread_cancel( L, s, 0.0001, FALSE, 0.0);
1361 // if we failed, and we know the thread is waiting on a linda 1370 // if we failed, and we know the thread is waiting on a linda
1362 if( cancelled == FALSE && s->status == WAITING && s->waiting_on != NULL) 1371 if( cancelled == FALSE && s->status == WAITING && s->waiting_on != NULL)
1363 { 1372 {
@@ -1758,6 +1767,17 @@ static char const* get_errcode_name( int _code)
1758} 1767}
1759#endif // USE_DEBUG_SPEW 1768#endif // USE_DEBUG_SPEW
1760 1769
1770#if THREADWAIT_METHOD == THREADWAIT_CONDVAR // implies THREADAPI == THREADAPI_PTHREAD
1771static void thread_cleanup_handler( void* opaque)
1772{
1773 struct s_lane* s= (struct s_lane*) opaque;
1774 MUTEX_LOCK( &s->done_lock);
1775 s->status = CANCELLED;
1776 SIGNAL_ONE( &s->done_signal); // wake up master (while 's->done_lock' is on)
1777 MUTEX_UNLOCK( &s->done_lock);
1778}
1779#endif // THREADWAIT_METHOD == THREADWAIT_CONDVAR
1780
1761//--- 1781//---
1762static THREAD_RETURN_T THREAD_CALLCONV lane_main( void *vs) 1782static THREAD_RETURN_T THREAD_CALLCONV lane_main( void *vs)
1763{ 1783{
@@ -1770,7 +1790,8 @@ static THREAD_RETURN_T THREAD_CALLCONV lane_main( void *vs)
1770 tracking_add( s); 1790 tracking_add( s);
1771 } 1791 }
1772#endif // HAVE_LANE_TRACKING 1792#endif // HAVE_LANE_TRACKING
1773 1793 THREAD_MAKE_ASYNCH_CANCELLABLE();
1794 THREAD_CLEANUP_PUSH( thread_cleanup_handler, s);
1774 s->status= RUNNING; // PENDING -> RUNNING 1795 s->status= RUNNING; // PENDING -> RUNNING
1775 1796
1776 // Tie "set_finalizer()" to the state 1797 // Tie "set_finalizer()" to the state
@@ -1888,7 +1909,7 @@ static THREAD_RETURN_T THREAD_CALLCONV lane_main( void *vs)
1888 : ERROR_ST; 1909 : ERROR_ST;
1889 1910
1890 // Posix no PTHREAD_TIMEDJOIN: 1911 // Posix no PTHREAD_TIMEDJOIN:
1891 // 'done_lock' protects the -> DONE|ERROR_ST|CANCELLED state change 1912 // 'done_lock' protects the -> DONE|ERROR_ST|CANCELLED state change
1892 // 1913 //
1893#if THREADWAIT_METHOD == THREADWAIT_CONDVAR 1914#if THREADWAIT_METHOD == THREADWAIT_CONDVAR
1894 MUTEX_LOCK( &s->done_lock); 1915 MUTEX_LOCK( &s->done_lock);
@@ -1901,6 +1922,7 @@ static THREAD_RETURN_T THREAD_CALLCONV lane_main( void *vs)
1901 MUTEX_UNLOCK( &s->done_lock); 1922 MUTEX_UNLOCK( &s->done_lock);
1902#endif // THREADWAIT_METHOD == THREADWAIT_CONDVAR 1923#endif // THREADWAIT_METHOD == THREADWAIT_CONDVAR
1903 } 1924 }
1925 THREAD_CLEANUP_POP( FALSE);
1904 return 0; // ignored 1926 return 0; // ignored
1905} 1927}
1906 1928
@@ -2248,6 +2270,7 @@ LUAG_FUNC( thread_gc)
2248 return 0; 2270 return 0;
2249} 2271}
2250 2272
2273// lane_h:cancel( [timeout,] force[, forcekill_timeout])
2251LUAG_FUNC( thread_cancel) 2274LUAG_FUNC( thread_cancel)
2252{ 2275{
2253 if( lua_gettop( L) < 1 || lua_type( L, 1) != LUA_TUSERDATA) 2276 if( lua_gettop( L) < 1 || lua_type( L, 1) != LUA_TUSERDATA)
@@ -2258,9 +2281,8 @@ LUAG_FUNC( thread_cancel)
2258 { 2281 {
2259 struct s_lane* s = lua_toLane( L, 1); 2282 struct s_lane* s = lua_toLane( L, 1);
2260 double secs = 0.0; 2283 double secs = 0.0;
2261 uint_t force_i = 2; 2284 int force_i = 2;
2262 cancel_result result; 2285 int forcekill_timeout_i = 3;
2263 bool_t force;
2264 2286
2265 if( lua_isnumber( L, 2)) 2287 if( lua_isnumber( L, 2))
2266 { 2288 {
@@ -2270,30 +2292,34 @@ LUAG_FUNC( thread_cancel)
2270 return luaL_error( L, "can't force a soft cancel"); 2292 return luaL_error( L, "can't force a soft cancel");
2271 } 2293 }
2272 ++ force_i; 2294 ++ force_i;
2295 ++ forcekill_timeout_i;
2273 } 2296 }
2274 else if( lua_isnil( L, 2)) 2297 else if( lua_isnil( L, 2))
2275 { 2298 {
2276 ++ force_i; 2299 ++ force_i;
2300 ++ forcekill_timeout_i;
2277 } 2301 }
2278 2302
2279 force = lua_toboolean( L, force_i); // FALSE if nothing there
2280
2281 result = thread_cancel( s, secs, force);
2282 switch( result)
2283 { 2303 {
2304 bool_t force = lua_toboolean( L, force_i); // FALSE if nothing there
2305 double forcekill_timeout = luaL_optnumber( L, forcekill_timeout_i, 0.0);
2306
2307 switch( thread_cancel( L, s, secs, force, forcekill_timeout))
2308 {
2284 case CR_Timeout: 2309 case CR_Timeout:
2285 lua_pushboolean( L, 0); 2310 lua_pushboolean( L, 0);
2286 lua_pushstring( L, "timeout"); 2311 lua_pushstring( L, "timeout");
2287 return 2; 2312 return 2;
2288 2313
2289 case CR_Cancelled: 2314 case CR_Cancelled:
2290 lua_pushboolean( L, 1); 2315 lua_pushboolean( L, 1);
2291 return 1; 2316 return 1;
2292 2317
2293 case CR_Killed: 2318 case CR_Killed:
2294 lua_pushboolean( L, 0); 2319 lua_pushboolean( L, 0);
2295 lua_pushstring( L, "killed"); 2320 lua_pushstring( L, "killed");
2296 return 2; 2321 return 2;
2322 }
2297 } 2323 }
2298 } 2324 }
2299 // should never happen, only here to prevent the compiler from complaining of "not all control paths returning a value" 2325 // should never happen, only here to prevent the compiler from complaining of "not all control paths returning a value"
diff --git a/src/threading.c b/src/threading.c
index 63c39ae..ad5b473 100644
--- a/src/threading.c
+++ b/src/threading.c
@@ -330,6 +330,8 @@ bool_t THREAD_WAIT_IMPL( THREAD_T *ref, double secs)
330 *ref= NULL; 330 *ref= NULL;
331 } 331 }
332 332
333 void THREAD_MAKE_ASYNCH_CANCELLABLE() {} // nothing to do for windows threads, we can cancel them anytime we want
334
333#if !defined __GNUC__ 335#if !defined __GNUC__
334 //see http://msdn.microsoft.com/en-us/library/xcb2z8hs.aspx 336 //see http://msdn.microsoft.com/en-us/library/xcb2z8hs.aspx
335 #define MS_VC_EXCEPTION 0x406D1388 337 #define MS_VC_EXCEPTION 0x406D1388
@@ -896,11 +898,19 @@ bool_t THREAD_WAIT( THREAD_T *ref, double secs , SIGNAL_T *signal_ref, MUTEX_T *
896#endif // THREADWAIT_METHOD == THREADWAIT_CONDVAR 898#endif // THREADWAIT_METHOD == THREADWAIT_CONDVAR
897 return done; 899 return done;
898 } 900 }
899 // 901 //
900 void THREAD_KILL( THREAD_T *ref ) { 902 void THREAD_KILL( THREAD_T *ref ) {
901 pthread_cancel( *ref ); 903 pthread_cancel( *ref );
902 } 904 }
903 905
906 void THREAD_MAKE_ASYNCH_CANCELLABLE()
907 {
908 // that's the default, but just in case...
909 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
910 // we want cancellation to take effect immediately if possible, instead of waiting for a cancellation point (which is the default)
911 pthread_setcanceltype( PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
912 }
913
904 void THREAD_SETNAME( char const* _name) 914 void THREAD_SETNAME( char const* _name)
905 { 915 {
906 // exact API to set the thread name is platform-dependant 916 // exact API to set the thread name is platform-dependant
diff --git a/src/threading.h b/src/threading.h
index aa34248..4b28ce8 100644
--- a/src/threading.h
+++ b/src/threading.h
@@ -194,10 +194,16 @@ bool_t SIGNAL_WAIT( SIGNAL_T *ref, MUTEX_T *mu, time_d timeout );
194# define THREAD_PRIO_MIN (-3) 194# define THREAD_PRIO_MIN (-3)
195# define THREAD_PRIO_MAX (+3) 195# define THREAD_PRIO_MAX (+3)
196 196
197#define THREAD_CLEANUP_PUSH( cb_, val_)
198#define THREAD_CLEANUP_POP( execute_)
199
197#else // THREADAPI == THREADAPI_PTHREAD 200#else // THREADAPI == THREADAPI_PTHREAD
198 /* Platforms that have a timed 'pthread_join()' can get away with a simpler 201 /* Platforms that have a timed 'pthread_join()' can get away with a simpler
199 * implementation. Others will use a condition variable. 202 * implementation. Others will use a condition variable.
200 */ 203 */
204#if defined __WINPTHREADS_VERSION
205#define USE_PTHREAD_TIMEDJOIN
206#endif // __WINPTHREADS_VERSION
201# ifdef USE_PTHREAD_TIMEDJOIN 207# ifdef USE_PTHREAD_TIMEDJOIN
202# ifdef PLATFORM_OSX 208# ifdef PLATFORM_OSX
203# error "No 'pthread_timedjoin()' on this system" 209# error "No 'pthread_timedjoin()' on this system"
@@ -229,6 +235,9 @@ bool_t SIGNAL_WAIT( SIGNAL_T *ref, MUTEX_T *mu, time_d timeout );
229# define THREAD_PRIO_MIN (-2) 235# define THREAD_PRIO_MIN (-2)
230# define THREAD_PRIO_MAX (+2) 236# define THREAD_PRIO_MAX (+2)
231# endif 237# endif
238
239#define THREAD_CLEANUP_PUSH( cb_, val_) pthread_cleanup_push( cb_, val_)
240#define THREAD_CLEANUP_POP( execute_) pthread_cleanup_pop( execute_)
232#endif // THREADAPI == THREADAPI_WINDOWS 241#endif // THREADAPI == THREADAPI_WINDOWS
233 242
234/* 243/*
@@ -253,7 +262,8 @@ bool_t THREAD_WAIT_IMPL( THREAD_T *ref, double secs, SIGNAL_T *signal_ref, MUTEX
253#define THREAD_WAIT THREAD_WAIT_IMPL 262#define THREAD_WAIT THREAD_WAIT_IMPL
254#endif // // THREADWAIT_METHOD == THREADWAIT_CONDVAR 263#endif // // THREADWAIT_METHOD == THREADWAIT_CONDVAR
255 264
256void THREAD_KILL( THREAD_T *ref ); 265void THREAD_KILL( THREAD_T* ref);
257void THREAD_SETNAME( char const* _name); 266void THREAD_SETNAME( char const* _name);
267void THREAD_MAKE_ASYNCH_CANCELLABLE();
258 268
259#endif // __threading_h__ 269#endif // __threading_h__
diff --git a/src/tools.c b/src/tools.c
index 754605b..b5f2f4b 100644
--- a/src/tools.c
+++ b/src/tools.c
@@ -570,13 +570,14 @@ void populate_func_lookup_table( lua_State* L, int _i, char const* name_)
570lua_State* luaG_newstate( lua_State* _from, int const _on_state_create, char const* libs) 570lua_State* luaG_newstate( lua_State* _from, int const _on_state_create, char const* libs)
571{ 571{
572 // reuse alloc function from the originating state 572 // reuse alloc function from the originating state
573 void* allocUD; 573#if PROPAGATE_ALLOCF
574 lua_Alloc allocF = lua_getallocf( _from, &allocUD); 574 PROPAGATE_ALLOCF_PREP( _from);
575 lua_State* L = lua_newstate( allocF, allocUD); 575#endif // PROPAGATE_ALLOCF
576 lua_State* L = PROPAGATE_ALLOCF_ALLOC();
576 577
577 if( L == NULL) 578 if( L == NULL)
578 { 579 {
579 (void) luaL_error( _from, "'lua_newstate()' failed; out of memory"); 580 (void) luaL_error( _from, "luaG_newstate() failed while creating state; out of memory");
580 } 581 }
581 582
582 // we'll need this everytime we transfer some C function from/to this state 583 // we'll need this everytime we transfer some C function from/to this state
diff --git a/src/tools.h b/src/tools.h
index e984ec2..19dca70 100644
--- a/src/tools.h
+++ b/src/tools.h
@@ -41,6 +41,17 @@ void luaL_requiref (lua_State* L, const char* modname, lua_CFunction openf, int
41#define luaG_registerlibfuncs( L, _funcs) luaL_setfuncs( L, _funcs, 0) 41#define luaG_registerlibfuncs( L, _funcs) luaL_setfuncs( L, _funcs, 0)
42#endif // LUA_VERSION_NUM == 502 42#endif // LUA_VERSION_NUM == 502
43 43
44// For some reason, LuaJIT 64bits doesn't support lua_newstate()
45// If you build specifically for this situation, change value to 0
46#define PROPAGATE_ALLOCF 1
47#if PROPAGATE_ALLOCF
48#define PROPAGATE_ALLOCF_PREP( L) void* allocUD; lua_Alloc allocF = lua_getallocf( L, &allocUD)
49#define PROPAGATE_ALLOCF_ALLOC() lua_newstate( allocF, allocUD)
50#else // PROPAGATE_ALLOCF
51#define PROPAGATE_ALLOCF_PREP( L)
52#define PROPAGATE_ALLOCF_ALLOC() luaL_newstate()
53#endif // PROPAGATE_ALLOCF
54
44#define USE_DEBUG_SPEW 0 55#define USE_DEBUG_SPEW 0
45#if USE_DEBUG_SPEW 56#if USE_DEBUG_SPEW
46extern char const* debugspew_indent; 57extern char const* debugspew_indent;