aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorBenoit Germain <bnt.germain@gmail.com>2011-11-14 19:41:28 +0100
committerBenoit Germain <bnt.germain@gmail.com>2011-11-14 19:41:28 +0100
commit87431bcc0ece1eaf9305593223bb0c5145004044 (patch)
treee1a76ea727e8019d3c26c4829dbb95253dd7e1f6 /src
parent1d2b45823fd2a13761bd2d19b1b5a1e8bb11f7b9 (diff)
downloadlanes-87431bcc0ece1eaf9305593223bb0c5145004044.tar.gz
lanes-87431bcc0ece1eaf9305593223bb0c5145004044.tar.bz2
lanes-87431bcc0ece1eaf9305593223bb0c5145004044.zip
* removed packagepath and packagecpath options, replaced by a package table, whose fields path, cpath, loaders, preload are transfered
* code cleanup to facilitate transition between WIN32 and PTHREAD impleentations * tentative fix for desinit crashes when free running lanes are killed at process shutdown
Diffstat (limited to 'src')
-rw-r--r--src/lanes.c161
-rw-r--r--src/lanes.lua13
-rw-r--r--src/threading.c54
-rw-r--r--src/threading.h55
4 files changed, 141 insertions, 142 deletions
diff --git a/src/lanes.c b/src/lanes.c
index aef1015..40af6c0 100644
--- a/src/lanes.c
+++ b/src/lanes.c
@@ -139,7 +139,7 @@ struct s_lane {
139 // M: sets to FALSE, flags TRUE for cancel request 139 // M: sets to FALSE, flags TRUE for cancel request
140 // S: reads to see if cancel is requested 140 // S: reads to see if cancel is requested
141 141
142#if !( (defined PLATFORM_WIN32) || (defined PLATFORM_POCKETPC) || (defined PTHREAD_TIMEDJOIN) ) 142#if THREADWAIT_METHOD == THREADWAIT_CONDVAR
143 SIGNAL_T done_signal_; 143 SIGNAL_T done_signal_;
144 // 144 //
145 // M: Waited upon at lane ending (if Posix with no PTHREAD_TIMEDJOIN) 145 // M: Waited upon at lane ending (if Posix with no PTHREAD_TIMEDJOIN)
@@ -149,7 +149,7 @@ struct s_lane {
149 // 149 //
150 // Lock required by 'done_signal' condition variable, protecting 150 // Lock required by 'done_signal' condition variable, protecting
151 // lane status changes to DONE/ERROR_ST/CANCELLED. 151 // lane status changes to DONE/ERROR_ST/CANCELLED.
152#endif 152#endif // THREADWAIT_METHOD == THREADWAIT_CONDVAR
153 153
154 volatile enum { 154 volatile enum {
155 NORMAL, // normal master side state 155 NORMAL, // normal master side state
@@ -1150,9 +1150,17 @@ static int selfdestruct_atexit( lua_State *L)
1150 { 1150 {
1151 struct s_lane *next_s= s->selfdestruct_next; 1151 struct s_lane *next_s= s->selfdestruct_next;
1152 s->selfdestruct_next= NULL; // detach from selfdestruct chain 1152 s->selfdestruct_next= NULL; // detach from selfdestruct chain
1153 if( s->thread) // can be NULL if previous 'soft' termination succeeded 1153 if( !THREAD_ISNULL( s->thread)) // can be NULL if previous 'soft' termination succeeded
1154 {
1154 THREAD_KILL( &s->thread); 1155 THREAD_KILL( &s->thread);
1156 // make sure the thread is really stopped!
1157 THREAD_WAIT( &s->thread, -1, &s->done_signal_, &s->done_lock_, &s->status);
1158 }
1155 // NO lua_close() in this case because we don't know where execution of the state was interrupted 1159 // NO lua_close() in this case because we don't know where execution of the state was interrupted
1160#if THREADWAIT_METHOD == THREADWAIT_CONDVAR
1161 SIGNAL_FREE( &s->done_signal_);
1162 MUTEX_FREE( &s->done_lock_);
1163#endif // THREADWAIT_METHOD == THREADWAIT_CONDVAR
1156 free( s); 1164 free( s);
1157 s = next_s; 1165 s = next_s;
1158 n++; 1166 n++;
@@ -1374,11 +1382,7 @@ LUAG_FUNC( set_debug_threadname)
1374} 1382}
1375 1383
1376//--- 1384//---
1377#if (defined PLATFORM_WIN32) || (defined PLATFORM_POCKETPC) 1385static THREAD_RETURN_T THREAD_CALLCONV lane_main( void *vs)
1378 static THREAD_RETURN_T __stdcall lane_main( void *vs )
1379#else
1380 static THREAD_RETURN_T lane_main( void *vs )
1381#endif
1382{ 1386{
1383 struct s_lane *s= (struct s_lane *)vs; 1387 struct s_lane *s= (struct s_lane *)vs;
1384 int rc, rc2; 1388 int rc, rc2;
@@ -1475,13 +1479,15 @@ LUAG_FUNC( set_debug_threadname)
1475 lua_close( s->L ); 1479 lua_close( s->L );
1476 s->L = L = 0; 1480 s->L = L = 0;
1477 1481
1478 #if !( (defined PLATFORM_WIN32) || (defined PLATFORM_POCKETPC) || (defined PTHREAD_TIMEDJOIN) ) 1482 #if THREADWAIT_METHOD == THREADWAIT_CONDVAR
1479 SIGNAL_FREE( &s->done_signal_ ); 1483 SIGNAL_FREE( &s->done_signal_);
1480 MUTEX_FREE( &s->done_lock_ ); 1484 MUTEX_FREE( &s->done_lock_);
1481 #endif 1485 #endif // THREADWAIT_METHOD == THREADWAIT_CONDVAR
1482 free(s); 1486 free(s);
1483 1487
1484 } else { 1488 }
1489 else
1490 {
1485 // leave results (1..top) or error message + stack trace (1..2) on the stack - master will copy them 1491 // leave results (1..top) or error message + stack trace (1..2) on the stack - master will copy them
1486 1492
1487 enum e_status st= 1493 enum e_status st=
@@ -1492,16 +1498,16 @@ LUAG_FUNC( set_debug_threadname)
1492 // Posix no PTHREAD_TIMEDJOIN: 1498 // Posix no PTHREAD_TIMEDJOIN:
1493 // 'done_lock' protects the -> DONE|ERROR_ST|CANCELLED state change 1499 // 'done_lock' protects the -> DONE|ERROR_ST|CANCELLED state change
1494 // 1500 //
1495 #if (defined PLATFORM_WIN32) || (defined PLATFORM_POCKETPC) || (defined PTHREAD_TIMEDJOIN) 1501#if THREADWAIT_METHOD == THREADWAIT_CONDVAR
1496 s->status= st; 1502 MUTEX_LOCK( &s->done_lock_);
1497 #else
1498 MUTEX_LOCK( &s->done_lock_ );
1499 { 1503 {
1500 s->status= st; 1504#endif // THREADWAIT_METHOD == THREADWAIT_CONDVAR
1501 SIGNAL_ONE( &s->done_signal_ ); // wake up master (while 's->done_lock' is on) 1505 s->status = st;
1506#if THREADWAIT_METHOD == THREADWAIT_CONDVAR
1507 SIGNAL_ONE( &s->done_signal_); // wake up master (while 's->done_lock' is on)
1502 } 1508 }
1503 MUTEX_UNLOCK( &s->done_lock_ ); 1509 MUTEX_UNLOCK( &s->done_lock_);
1504 #endif 1510#endif // THREADWAIT_METHOD == THREADWAIT_CONDVAR
1505 } 1511 }
1506 return 0; // ignored 1512 return 0; // ignored
1507} 1513}
@@ -1512,7 +1518,7 @@ LUAG_FUNC( set_debug_threadname)
1512// [cancelstep_uint=0], 1518// [cancelstep_uint=0],
1513// [prio_int=0], 1519// [prio_int=0],
1514// [globals_tbl], 1520// [globals_tbl],
1515// [packagepath], 1521// [package_tbl],
1516// [required], 1522// [required],
1517// [... args ...] ) 1523// [... args ...] )
1518// 1524//
@@ -1553,11 +1559,10 @@ LUAG_FUNC( thread_new )
1553 uint_t cs= luaG_optunsigned( L, 3,0); 1559 uint_t cs= luaG_optunsigned( L, 3,0);
1554 int prio= (int)luaL_optinteger( L, 4,0); 1560 int prio= (int)luaL_optinteger( L, 4,0);
1555 uint_t glob= luaG_isany(L,5) ? 5:0; 1561 uint_t glob= luaG_isany(L,5) ? 5:0;
1556 uint_t ppath = luaG_isany(L,6) ? 6:0; 1562 uint_t package = luaG_isany(L,6) ? 6:0;
1557 uint_t pcpath = luaG_isany(L,7) ? 7:0; 1563 uint_t required = luaG_isany(L,7) ? 7:0;
1558 uint_t required = luaG_isany(L,8) ? 8:0;
1559 1564
1560#define FIXED_ARGS (8) 1565#define FIXED_ARGS (7)
1561 uint_t args= lua_gettop(L) - FIXED_ARGS; 1566 uint_t args= lua_gettop(L) - FIXED_ARGS;
1562 1567
1563 if (prio < THREAD_PRIO_MIN || prio > THREAD_PRIO_MAX) 1568 if (prio < THREAD_PRIO_MIN || prio > THREAD_PRIO_MAX)
@@ -1588,46 +1593,35 @@ LUAG_FUNC( thread_new )
1588 ASSERT_L( lua_gettop(L2) == 0); 1593 ASSERT_L( lua_gettop(L2) == 0);
1589 1594
1590 // package.path 1595 // package.path
1596 STACK_CHECK(L)
1591 STACK_CHECK(L2) 1597 STACK_CHECK(L2)
1592 if( ppath) 1598 if( package)
1593 {
1594 if (lua_type(L,ppath) != LUA_TSTRING)
1595 luaL_error( L, "expected packagepath as string, got %s", luaG_typename(L,ppath));
1596 lua_getglobal( L2, "package");
1597 if( lua_isnil( L2, -1)) // package library not loaded: do nothing
1598 {
1599 lua_pop( L2, 1);
1600 }
1601 else
1602 {
1603 lua_pushvalue( L, ppath);
1604 luaG_inter_move( L, L2, 1); // moves the new path to L2
1605 lua_setfield( L2, -2, "path"); // set package.path
1606 lua_pop( L2, 1);
1607 }
1608 }
1609 STACK_END(L2,0)
1610
1611 // package.cpath
1612 STACK_CHECK(L2)
1613 if( pcpath)
1614 { 1599 {
1615 if (lua_type(L,pcpath) != LUA_TSTRING) 1600 if (lua_type(L,package) != LUA_TTABLE)
1616 luaL_error( L, "expected packagecpath as string, got %s", luaG_typename(L,pcpath)); 1601 luaL_error( L, "expected package as table, got %s", luaG_typename(L,package));
1617 lua_getglobal( L2, "package"); 1602 lua_getglobal( L2, "package");
1618 if( lua_isnil( L2, -1)) // // package library not loaded: do nothing 1603 if( !lua_isnil( L2, -1)) // package library not loaded: do nothing
1619 { 1604 {
1620 lua_pop( L2, 1); 1605 int i;
1621 } 1606 char const *entries[] = { "path", "cpath", "preload", "loaders", NULL};
1622 else 1607 for( i = 0; entries[i]; ++ i)
1623 { 1608 {
1624 lua_pushvalue( L, pcpath); 1609 lua_getfield( L, package, entries[i]);
1625 luaG_inter_move( L, L2, 1); // moves the new cpath to L2 1610 if( lua_isnil( L, -1))
1626 lua_setfield( L2, -2, "cpath"); // set package.cpath 1611 {
1627 lua_pop( L2, 1); 1612 lua_pop( L, 1);
1613 }
1614 else
1615 {
1616 luaG_inter_move( L, L2, 1); // moves the entry to L2
1617 lua_setfield( L2, -2, entries[i]); // set package[entries[i]]
1618 }
1619 }
1628 } 1620 }
1621 lua_pop( L2, 1);
1629 } 1622 }
1630 STACK_END(L2,0) 1623 STACK_END(L2,0)
1624 STACK_END(L,0)
1631 1625
1632 // modules to require in the target lane *before* the function is transfered! 1626 // modules to require in the target lane *before* the function is transfered!
1633 1627
@@ -1738,10 +1732,10 @@ LUAG_FUNC( thread_new )
1738 s->waiting_on = NULL; 1732 s->waiting_on = NULL;
1739 s->cancel_request= FALSE; 1733 s->cancel_request= FALSE;
1740 1734
1741#if !( (defined PLATFORM_WIN32) || (defined PLATFORM_POCKETPC) || (defined PTHREAD_TIMEDJOIN) ) 1735#if THREADWAIT_METHOD == THREADWAIT_CONDVAR
1742 MUTEX_INIT( &s->done_lock_ ); 1736 MUTEX_INIT( &s->done_lock_);
1743 SIGNAL_INIT( &s->done_signal_ ); 1737 SIGNAL_INIT( &s->done_signal_);
1744#endif 1738#endif // THREADWAIT_METHOD == THREADWAIT_CONDVAR
1745 s->mstatus= NORMAL; 1739 s->mstatus= NORMAL;
1746 s->selfdestruct_next= NULL; 1740 s->selfdestruct_next= NULL;
1747 1741
@@ -1813,6 +1807,7 @@ LUAG_FUNC( thread_gc )
1813 { 1807 {
1814 // Make sure a kill has proceeded, before cleaning up the data structure. 1808 // Make sure a kill has proceeded, before cleaning up the data structure.
1815 // 1809 //
1810 // NO lua_close() in this case because we don't know where execution of the state was interrupted
1816 // If not doing 'THREAD_WAIT()' we should close the Lua state here 1811 // If not doing 'THREAD_WAIT()' we should close the Lua state here
1817 // (can it be out of order, since we killed the lane abruptly?) 1812 // (can it be out of order, since we killed the lane abruptly?)
1818 // 1813 //
@@ -1821,11 +1816,7 @@ LUAG_FUNC( thread_gc )
1821 s->L = 0; 1816 s->L = 0;
1822#else // 0 1817#else // 0
1823 DEBUGEXEC(fprintf( stderr, "** Joining with a killed thread (needs testing) **" )); 1818 DEBUGEXEC(fprintf( stderr, "** Joining with a killed thread (needs testing) **" ));
1824#if (defined PLATFORM_WIN32) || (defined PLATFORM_POCKETPC) || (defined PTHREAD_TIMEDJOIN) 1819 THREAD_WAIT( &s->thread, -1, &s->done_signal_, &s->done_lock_, &s->status);
1825 THREAD_WAIT( &s->thread, -1 );
1826#else
1827 THREAD_WAIT( &s->thread, &s->done_signal_, &s->done_lock_, &s->status, -1 );
1828#endif
1829 DEBUGEXEC(fprintf( stderr, "** Joined ok **" )); 1820 DEBUGEXEC(fprintf( stderr, "** Joined ok **" ));
1830#endif // 0 1821#endif // 0
1831 } 1822 }
@@ -1837,12 +1828,12 @@ LUAG_FUNC( thread_gc )
1837 1828
1838 // Clean up after a (finished) thread 1829 // Clean up after a (finished) thread
1839 // 1830 //
1840#if (! ((defined PLATFORM_WIN32) || (defined PLATFORM_POCKETPC) || (defined PTHREAD_TIMEDJOIN))) 1831#if THREADWAIT_METHOD == THREADWAIT_CONDVAR
1841 SIGNAL_FREE( &s->done_signal_ ); 1832 SIGNAL_FREE( &s->done_signal_);
1842 MUTEX_FREE( &s->done_lock_ ); 1833 MUTEX_FREE( &s->done_lock_);
1843#endif 1834#endif // THREADWAIT_METHOD == THREADWAIT_CONDVAR
1844 1835
1845 free(s); 1836 free( s);
1846 1837
1847 return 0; 1838 return 0;
1848} 1839}
@@ -1871,6 +1862,7 @@ static bool_t thread_cancel( struct s_lane *s, double secs, bool_t force)
1871 // 1862 //
1872 if( s->status < DONE) 1863 if( s->status < DONE)
1873 { 1864 {
1865 s->cancel_request = TRUE; // it's now signaled to stop
1874 // signal the linda the wake up the thread so that it can react to the cancel query 1866 // signal the linda the wake up the thread so that it can react to the cancel query
1875 // let us hope we never land here with a pointer on a linda that has been destroyed... 1867 // let us hope we never land here with a pointer on a linda that has been destroyed...
1876 //MUTEX_LOCK( &selfdestruct_cs ); 1868 //MUTEX_LOCK( &selfdestruct_cs );
@@ -1882,13 +1874,7 @@ static bool_t thread_cancel( struct s_lane *s, double secs, bool_t force)
1882 } 1874 }
1883 } 1875 }
1884 //MUTEX_UNLOCK( &selfdestruct_cs ); 1876 //MUTEX_UNLOCK( &selfdestruct_cs );
1885 s->cancel_request = TRUE; // it's now signalled to stop 1877 done = THREAD_WAIT( &s->thread, secs, &s->done_signal_, &s->done_lock_, &s->status);
1886 done=
1887#if (defined PLATFORM_WIN32) || (defined PLATFORM_POCKETPC) || (defined PTHREAD_TIMEDJOIN)
1888 THREAD_WAIT( &s->thread, secs);
1889#else
1890 THREAD_WAIT( &s->thread, &s->done_signal_, &s->done_lock_, &s->status, secs);
1891#endif
1892 1878
1893 if ((!done) && force) 1879 if ((!done) && force)
1894 { 1880 {
@@ -1986,12 +1972,7 @@ LUAG_FUNC( thread_join )
1986 int ret; 1972 int ret;
1987 bool_t done; 1973 bool_t done;
1988 1974
1989 done = (s->thread == 0) || 1975 done = THREAD_ISNULL( s->thread) || THREAD_WAIT( &s->thread, wait_secs, &s->done_signal_, &s->done_lock_, &s->status);
1990#if (defined PLATFORM_WIN32) || (defined PLATFORM_POCKETPC) || (defined PTHREAD_TIMEDJOIN)
1991 THREAD_WAIT( &s->thread, wait_secs );
1992#else
1993 THREAD_WAIT( &s->thread, &s->done_signal_, &s->done_lock_, &s->status, wait_secs);
1994#endif
1995 if (!done || !L2) 1976 if (!done || !L2)
1996 return 0; // timeout: pushes none, leaves 'L2' alive 1977 return 0; // timeout: pushes none, leaves 'L2' alive
1997 1978
@@ -2365,7 +2346,7 @@ LUAG_FUNC( configure )
2365 * there is no problem. But if the host is multithreaded, we need to lock around the 2346 * there is no problem. But if the host is multithreaded, we need to lock around the
2366 * initializations. 2347 * initializations.
2367 */ 2348 */
2368#ifdef PLATFORM_WIN32 2349#if THREADAPI == THREADAPI_WINDOWS
2369 { 2350 {
2370 static volatile int /*bool*/ go_ahead; // = 0 2351 static volatile int /*bool*/ go_ahead; // = 0
2371 if( InterlockedCompareExchange( &s_initCount, 1, 0) == 0) 2352 if( InterlockedCompareExchange( &s_initCount, 1, 0) == 0)
@@ -2378,7 +2359,7 @@ LUAG_FUNC( configure )
2378 while( !go_ahead ) { Sleep(1); } // changes threads 2359 while( !go_ahead ) { Sleep(1); } // changes threads
2379 } 2360 }
2380 } 2361 }
2381#else 2362#else // THREADAPI == THREADAPI_PTHREAD
2382 if( s_initCount == 0) 2363 if( s_initCount == 0)
2383 { 2364 {
2384 static pthread_mutex_t my_lock= PTHREAD_MUTEX_INITIALIZER; 2365 static pthread_mutex_t my_lock= PTHREAD_MUTEX_INITIALIZER;
@@ -2394,7 +2375,7 @@ LUAG_FUNC( configure )
2394 } 2375 }
2395 pthread_mutex_unlock(&my_lock); 2376 pthread_mutex_unlock(&my_lock);
2396 } 2377 }
2397#endif 2378#endif // THREADAPI == THREADAPI_PTHREAD
2398 assert( timer_deep != 0 ); 2379 assert( timer_deep != 0 );
2399 2380
2400 // Create main module interface table 2381 // Create main module interface table
@@ -2453,7 +2434,7 @@ LUAG_FUNC( configure )
2453int 2434int
2454#if (defined PLATFORM_WIN32) || (defined PLATFORM_POCKETPC) 2435#if (defined PLATFORM_WIN32) || (defined PLATFORM_POCKETPC)
2455__declspec(dllexport) 2436__declspec(dllexport)
2456#endif 2437#endif // (defined PLATFORM_WIN32) || (defined PLATFORM_POCKETPC)
2457luaopen_lanes( lua_State *L ) 2438luaopen_lanes( lua_State *L )
2458{ 2439{
2459 // Create main module interface table 2440 // Create main module interface table
diff --git a/src/lanes.lua b/src/lanes.lua
index 005ce28..6ba0ef3 100644
--- a/src/lanes.lua
+++ b/src/lanes.lua
@@ -214,7 +214,7 @@ local function gen( ... )
214 end 214 end
215 end 215 end
216 216
217 local prio, cs, g_tbl, packagepath, packagecpath, required 217 local prio, cs, g_tbl, package_tbl, required
218 218
219 for k,v in pairs(opt) do 219 for k,v in pairs(opt) do
220 if k=="priority" then prio= v 220 if k=="priority" then prio= v
@@ -224,10 +224,8 @@ local function gen( ... )
224 type(v)=="number" and v or 224 type(v)=="number" and v or
225 error( "Bad cancelstep: "..tostring(v), lev ) 225 error( "Bad cancelstep: "..tostring(v), lev )
226 elseif k=="globals" then g_tbl= v 226 elseif k=="globals" then g_tbl= v
227 elseif k=="packagepath" then 227 elseif k=="package" then
228 packagepath = (type( v) == "string") and v or error( "Bad packagepath: " .. tostring( v), lev) 228 package_tbl = (type( v) == "table") and v or error( "Bad package: " .. tostring( v), lev)
229 elseif k=="packagecpath" then
230 packagecpath = (type( v) == "string") and v or error( "Bad packagecpath: " .. tostring( v), lev)
231 elseif k=="required" then 229 elseif k=="required" then
232 required= (type( v) == "table") and v or error( "Bad required: " .. tostring( v), lev) 230 required= (type( v) == "table") and v or error( "Bad required: " .. tostring( v), lev)
233 --.. 231 --..
@@ -236,12 +234,11 @@ local function gen( ... )
236 end 234 end
237 end 235 end
238 236
239 if not packagepath then packagepath = package.path end 237 if not package_tbl then package_tbl = package end
240 if not packagecpath then packagecpath = package.cpath end
241 -- Lane generator 238 -- Lane generator
242 -- 239 --
243 return function(...) 240 return function(...)
244 return thread_new( func, libs, cs, prio, g_tbl, packagepath, packagecpath, required, ...) -- args 241 return thread_new( func, libs, cs, prio, g_tbl, package_tbl, required, ...) -- args
245 end 242 end
246end 243end
247 244
diff --git a/src/threading.c b/src/threading.c
index 22d18d4..8966dc6 100644
--- a/src/threading.c
+++ b/src/threading.c
@@ -41,9 +41,9 @@ THE SOFTWARE.
41#include "threading.h" 41#include "threading.h"
42#include "lua.h" 42#include "lua.h"
43 43
44#if !((defined PLATFORM_WIN32) || (defined PLATFORM_POCKETPC)) 44#if THREADAPI == THREADAPI_PTHREAD
45# include <sys/time.h> 45# include <sys/time.h>
46#endif 46#endif // THREADAPI == THREADAPI_PTHREAD
47 47
48 48
49#if defined(PLATFORM_LINUX) || defined(PLATFORM_CYGWIN) 49#if defined(PLATFORM_LINUX) || defined(PLATFORM_CYGWIN)
@@ -71,7 +71,7 @@ THE SOFTWARE.
71* FAIL is for unexpected API return values - essentially programming 71* FAIL is for unexpected API return values - essentially programming
72* error in _this_ code. 72* error in _this_ code.
73*/ 73*/
74#if (defined PLATFORM_WIN32) || (defined PLATFORM_POCKETPC) 74#if THREADAPI == THREADAPI_WINDOWS
75static void FAIL( const char *funcname, int rc ) { 75static void FAIL( const char *funcname, int rc ) {
76 fprintf( stderr, "%s() failed! (%d)\n", funcname, rc ); 76 fprintf( stderr, "%s() failed! (%d)\n", funcname, rc );
77#ifdef _MSC_VER 77#ifdef _MSC_VER
@@ -79,7 +79,7 @@ static void FAIL( const char *funcname, int rc ) {
79#endif // _MSC_VER 79#endif // _MSC_VER
80 abort(); 80 abort();
81} 81}
82#endif 82#endif // THREADAPI == THREADAPI_WINDOWS
83 83
84 84
85/* 85/*
@@ -90,7 +90,7 @@ static void FAIL( const char *funcname, int rc ) {
90*/ 90*/
91time_d now_secs(void) { 91time_d now_secs(void) {
92 92
93#if (defined PLATFORM_WIN32) || (defined PLATFORM_POCKETPC) 93#if THREADAPI == THREADAPI_WINDOWS
94 /* 94 /*
95 * Windows FILETIME values are "100-nanosecond intervals since 95 * Windows FILETIME values are "100-nanosecond intervals since
96 * January 1, 1601 (UTC)" (MSDN). Well, we'd want Unix Epoch as 96 * January 1, 1601 (UTC)" (MSDN). Well, we'd want Unix Epoch as
@@ -145,7 +145,7 @@ time_d now_secs(void) {
145 // <= 2.0.2 code 145 // <= 2.0.2 code
146 return (double)(uli.QuadPart - uli_epoch.QuadPart) / 10000000.0; 146 return (double)(uli.QuadPart - uli_epoch.QuadPart) / 10000000.0;
147# endif 147# endif
148#else 148#else // THREADAPI == THREADAPI_PTHREAD
149 struct timeval tv; 149 struct timeval tv;
150 // { 150 // {
151 // time_t tv_sec; /* seconds since Jan. 1, 1970 */ 151 // time_t tv_sec; /* seconds since Jan. 1, 1970 */
@@ -156,7 +156,7 @@ time_d now_secs(void) {
156 assert( rc==0 ); 156 assert( rc==0 );
157 157
158 return ((double)tv.tv_sec) + ((tv.tv_usec)/1000) / 1000.0; 158 return ((double)tv.tv_sec) + ((tv.tv_usec)/1000) / 1000.0;
159#endif 159#endif // THREADAPI THREADAPI_PTHREAD
160} 160}
161 161
162 162
@@ -168,7 +168,7 @@ time_d SIGNAL_TIMEOUT_PREPARE( double secs ) {
168} 168}
169 169
170 170
171#if !((defined PLATFORM_WIN32) || (defined PLATFORM_POCKETPC)) 171#if THREADAPI == THREADAPI_PTHREAD
172/* 172/*
173* Prepare 'abs_secs' kind of timeout to 'timespec' format 173* Prepare 'abs_secs' kind of timeout to 'timespec' format
174*/ 174*/
@@ -187,7 +187,7 @@ static void prepare_timeout( struct timespec *ts, time_d abs_secs ) {
187 ts->tv_sec = ts->tv_sec + 1; 187 ts->tv_sec = ts->tv_sec + 1;
188 } 188 }
189} 189}
190#endif 190#endif // THREADAPI == THREADAPI_PTHREAD
191 191
192 192
193/*---=== Threading ===---*/ 193/*---=== Threading ===---*/
@@ -230,7 +230,7 @@ static void prepare_timeout( struct timespec *ts, time_d abs_secs ) {
230# endif 230# endif
231#endif 231#endif
232 232
233#if (defined PLATFORM_WIN32) || (defined PLATFORM_POCKETPC) 233#if THREADAPI == THREADAPI_WINDOWS
234 // 234 //
235 void MUTEX_INIT( MUTEX_T *ref ) { 235 void MUTEX_INIT( MUTEX_T *ref ) {
236 *ref= CreateMutex( NULL /*security attr*/, FALSE /*not locked*/, NULL ); 236 *ref= CreateMutex( NULL /*security attr*/, FALSE /*not locked*/, NULL );
@@ -282,7 +282,8 @@ static void prepare_timeout( struct timespec *ts, time_d abs_secs ) {
282 *ref= h; 282 *ref= h;
283 } 283 }
284 // 284 //
285 bool_t THREAD_WAIT( THREAD_T *ref, double secs ) { 285bool_t THREAD_WAIT_IMPL( THREAD_T *ref, double secs)
286{
286 DWORD ms = (secs<0.0) ? INFINITE : (DWORD)((secs*1000.0)+0.5); 287 DWORD ms = (secs<0.0) ? INFINITE : (DWORD)((secs*1000.0)+0.5);
287 288
288 DWORD rc= WaitForSingleObject( *ref, ms /*timeout*/ ); 289 DWORD rc= WaitForSingleObject( *ref, ms /*timeout*/ );
@@ -373,7 +374,7 @@ static void prepare_timeout( struct timespec *ts, time_d abs_secs ) {
373 if (!PulseEvent( *ref )) 374 if (!PulseEvent( *ref ))
374 FAIL( "PulseEvent", GetLastError() ); 375 FAIL( "PulseEvent", GetLastError() );
375 } 376 }
376#else 377#else // THREADAPI == THREADAPI_PTHREAD
377 // PThread (Linux, OS X, ...) 378 // PThread (Linux, OS X, ...)
378 // 379 //
379 // On OS X, user processes seem to be able to change priorities. 380 // On OS X, user processes seem to be able to change priorities.
@@ -652,7 +653,7 @@ static void prepare_timeout( struct timespec *ts, time_d abs_secs ) {
652 } 653 }
653 } 654 }
654 // 655 //
655 /* 656 /*
656 * Wait for a thread to finish. 657 * Wait for a thread to finish.
657 * 658 *
658 * 'mu_ref' is a lock we should use for the waiting; initially unlocked. 659 * 'mu_ref' is a lock we should use for the waiting; initially unlocked.
@@ -660,11 +661,7 @@ static void prepare_timeout( struct timespec *ts, time_d abs_secs ) {
660 * 661 *
661 * Returns TRUE for succesful wait, FALSE for timed out 662 * Returns TRUE for succesful wait, FALSE for timed out
662 */ 663 */
663#ifdef PTHREAD_TIMEDJOIN 664bool_t THREAD_WAIT( THREAD_T *ref, double secs , SIGNAL_T *signal_ref, MUTEX_T *mu_ref, volatile enum e_status *st_ref)
664 bool_t THREAD_WAIT( THREAD_T *ref, double secs )
665#else
666 bool_t THREAD_WAIT( THREAD_T *ref, SIGNAL_T *signal_ref, MUTEX_T *mu_ref, volatile enum e_status *st_ref, double secs )
667#endif
668{ 665{
669 struct timespec ts_store; 666 struct timespec ts_store;
670 const struct timespec *timeout= NULL; 667 const struct timespec *timeout= NULL;
@@ -672,16 +669,17 @@ static void prepare_timeout( struct timespec *ts, time_d abs_secs ) {
672 669
673 // Do timeout counting before the locks 670 // Do timeout counting before the locks
674 // 671 //
675#ifdef PTHREAD_TIMEDJOIN 672#if THREADWAIT_METHOD == THREADWAIT_TIMEOUT
676 if (secs>=0.0) { 673 if (secs>=0.0)
677#else 674#else // THREADWAIT_METHOD == THREADWAIT_CONDVAR
678 if (secs>0.0) { 675 if (secs>0.0)
679#endif 676#endif // THREADWAIT_METHOD == THREADWAIT_CONDVAR
677 {
680 prepare_timeout( &ts_store, now_secs()+secs ); 678 prepare_timeout( &ts_store, now_secs()+secs );
681 timeout= &ts_store; 679 timeout= &ts_store;
682 } 680 }
683 681
684#ifdef PTHREAD_TIMEDJOIN 682#if THREADWAIT_METHOD == THREADWAIT_TIMEOUT
685 /* Thread is joinable 683 /* Thread is joinable
686 */ 684 */
687 if (!timeout) { 685 if (!timeout) {
@@ -694,7 +692,7 @@ static void prepare_timeout( struct timespec *ts, time_d abs_secs ) {
694 } 692 }
695 done= rc==0; 693 done= rc==0;
696 } 694 }
697#else 695#else // THREADWAIT_METHOD == THREADWAIT_CONDVAR
698 /* Since we've set the thread up as PTHREAD_CREATE_DETACHED, we cannot 696 /* Since we've set the thread up as PTHREAD_CREATE_DETACHED, we cannot
699 * join with it. Use the cond.var. 697 * join with it. Use the cond.var.
700 */ 698 */
@@ -718,13 +716,13 @@ static void prepare_timeout( struct timespec *ts, time_d abs_secs ) {
718 done= *st_ref >= DONE; // DONE|ERROR_ST|CANCELLED 716 done= *st_ref >= DONE; // DONE|ERROR_ST|CANCELLED
719 717
720 MUTEX_UNLOCK( mu_ref ); 718 MUTEX_UNLOCK( mu_ref );
721#endif 719#endif // THREADWAIT_METHOD == THREADWAIT_CONDVAR
722 return done; 720 return done;
723 } 721 }
724 // 722 //
725 void THREAD_KILL( THREAD_T *ref ) { 723 void THREAD_KILL( THREAD_T *ref ) {
726 pthread_cancel( *ref ); 724 pthread_cancel( *ref );
727 } 725 }
728#endif 726#endif // THREADAPI == THREADAPI_PTHREAD
729 727
730static const lua_Alloc alloc_f= 0; 728static const lua_Alloc alloc_f= 0;
diff --git a/src/threading.h b/src/threading.h
index 4a83229..7387764 100644
--- a/src/threading.h
+++ b/src/threading.h
@@ -1,8 +1,8 @@
1/* 1/*
2* THREADING.H 2* THREADING.H
3*/ 3*/
4#ifndef THREADING_H 4#ifndef __threading_h__
5#define THREADING_H 5#define __threading_h__ 1
6 6
7/* Platform detection 7/* Platform detection
8*/ 8*/
@@ -45,11 +45,19 @@ typedef unsigned int uint_t;
45*/ 45*/
46enum e_status { PENDING, RUNNING, WAITING, DONE, ERROR_ST, CANCELLED }; 46enum e_status { PENDING, RUNNING, WAITING, DONE, ERROR_ST, CANCELLED };
47 47
48#define THREADAPI_WINDOWS 1
49#define THREADAPI_PTHREAD 2
50
51#if (defined PLATFORM_WIN32) || (defined PLATFORM_POCKETPC)
52#define THREADAPI THREADAPI_WINDOWS
53#else // (defined PLATFORM_WIN32) || (defined PLATFORM_POCKETPC)
54#define THREADAPI THREADAPI_PTHREAD
55#endif // (defined PLATFORM_WIN32) || (defined PLATFORM_POCKETPC)
48 56
49/*---=== Locks & Signals ===--- 57/*---=== Locks & Signals ===---
50*/ 58*/
51 59
52#if (defined PLATFORM_WIN32) || (defined PLATFORM_POCKETPC) 60#if THREADAPI == THREADAPI_WINDOWS
53 #define WIN32_LEAN_AND_MEAN 61 #define WIN32_LEAN_AND_MEAN
54 // 'SignalObjectAndWait' needs this (targets Windows 2000 and above) 62 // 'SignalObjectAndWait' needs this (targets Windows 2000 and above)
55 #define _WIN32_WINNT 0x0400 63 #define _WIN32_WINNT 0x0400
@@ -68,12 +76,13 @@ enum e_status { PENDING, RUNNING, WAITING, DONE, ERROR_ST, CANCELLED };
68 void MUTEX_LOCK( MUTEX_T *ref ); 76 void MUTEX_LOCK( MUTEX_T *ref );
69 void MUTEX_UNLOCK( MUTEX_T *ref ); 77 void MUTEX_UNLOCK( MUTEX_T *ref );
70 78
71 typedef unsigned THREAD_RETURN_T; 79 typedef unsigned int THREAD_RETURN_T;
72 80
73 #define SIGNAL_T HANDLE 81 #define SIGNAL_T HANDLE
74 82
75 #define YIELD() Sleep(0) 83 #define YIELD() Sleep(0)
76#else 84 #define THREAD_CALLCONV __stdcall
85#else // THREADAPI == THREADAPI_PTHREAD
77 // PThread (Linux, OS X, ...) 86 // PThread (Linux, OS X, ...)
78 // 87 //
79 #include <pthread.h> 88 #include <pthread.h>
@@ -114,7 +123,8 @@ enum e_status { PENDING, RUNNING, WAITING, DONE, ERROR_ST, CANCELLED };
114 #else 123 #else
115 #define YIELD() pthread_yield() 124 #define YIELD() pthread_yield()
116 #endif 125 #endif
117#endif 126 #define THREAD_CALLCONV
127#endif //THREADAPI == THREADAPI_PTHREAD
118 128
119void SIGNAL_INIT( SIGNAL_T *ref ); 129void SIGNAL_INIT( SIGNAL_T *ref );
120void SIGNAL_FREE( SIGNAL_T *ref ); 130void SIGNAL_FREE( SIGNAL_T *ref );
@@ -136,9 +146,10 @@ bool_t SIGNAL_WAIT( SIGNAL_T *ref, MUTEX_T *mu, time_d timeout );
136/*---=== Threading ===--- 146/*---=== Threading ===---
137*/ 147*/
138 148
139#if (defined PLATFORM_WIN32) || (defined PLATFORM_POCKETPC) 149#if THREADAPI == THREADAPI_WINDOWS
140 150
141 typedef HANDLE THREAD_T; 151 typedef HANDLE THREAD_T;
152# define THREAD_ISNULL( _h) (_h == 0)
142 // 153 //
143 void THREAD_CREATE( THREAD_T *ref, 154 void THREAD_CREATE( THREAD_T *ref,
144 THREAD_RETURN_T (__stdcall *func)( void * ), 155 THREAD_RETURN_T (__stdcall *func)( void * ),
@@ -147,7 +158,7 @@ bool_t SIGNAL_WAIT( SIGNAL_T *ref, MUTEX_T *mu, time_d timeout );
147# define THREAD_PRIO_MIN (-3) 158# define THREAD_PRIO_MIN (-3)
148# define THREAD_PRIO_MAX (+3) 159# define THREAD_PRIO_MAX (+3)
149 160
150#else 161#else // THREADAPI == THREADAPI_PTHREAD
151 /* Platforms that have a timed 'pthread_join()' can get away with a simpler 162 /* Platforms that have a timed 'pthread_join()' can get away with a simpler
152 * implementation. Others will use a condition variable. 163 * implementation. Others will use a condition variable.
153 */ 164 */
@@ -161,6 +172,7 @@ bool_t SIGNAL_WAIT( SIGNAL_T *ref, MUTEX_T *mu, time_d timeout );
161# endif 172# endif
162 173
163 typedef pthread_t THREAD_T; 174 typedef pthread_t THREAD_T;
175# define THREAD_ISNULL( _h) 0 // pthread_t may be a structure: never 'null' by itself
164 176
165 void THREAD_CREATE( THREAD_T *ref, 177 void THREAD_CREATE( THREAD_T *ref,
166 THREAD_RETURN_T (*func)( void * ), 178 THREAD_RETURN_T (*func)( void * ),
@@ -178,19 +190,30 @@ bool_t SIGNAL_WAIT( SIGNAL_T *ref, MUTEX_T *mu, time_d timeout );
178# define THREAD_PRIO_MIN (-2) 190# define THREAD_PRIO_MIN (-2)
179# define THREAD_PRIO_MAX (+2) 191# define THREAD_PRIO_MAX (+2)
180# endif 192# endif
181#endif 193#endif // THREADAPI == THREADAPI_WINDOWS
182 194
183/* 195/*
184* Win32 and PTHREAD_TIMEDJOIN allow waiting for a thread with a timeout. 196* Win32 and PTHREAD_TIMEDJOIN allow waiting for a thread with a timeout.
185* Posix without PTHREAD_TIMEDJOIN needs to use a condition variable approach. 197* Posix without PTHREAD_TIMEDJOIN needs to use a condition variable approach.
186*/ 198*/
187#if (defined PLATFORM_WIN32) || (defined PLATFORM_POCKETPC) || (defined PTHREAD_TIMEDJOIN) 199#define THREADWAIT_TIMEOUT 1
188 bool_t THREAD_WAIT( THREAD_T *ref, double secs ); 200#define THREADWAIT_CONDVAR 2
189#else 201
190 bool_t THREAD_WAIT( THREAD_T *ref, SIGNAL_T *signal_ref, MUTEX_T *mu_ref, volatile enum e_status *st_ref, double secs ); 202#if THREADAPI == THREADAPI_WINDOWS || (defined PTHREAD_TIMEDJOIN)
191#endif 203#define THREADWAIT_METHOD THREADWAIT_TIMEOUT
204#else // THREADAPI == THREADAPI_WINDOWS || (defined PTHREAD_TIMEDJOIN)
205#define THREADWAIT_METHOD THREADWAIT_CONDVAR
206#endif // THREADAPI == THREADAPI_WINDOWS || (defined PTHREAD_TIMEDJOIN)
207
208
209#if THREADWAIT_METHOD == THREADWAIT_TIMEOUT
210bool_t THREAD_WAIT_IMPL( THREAD_T *ref, double secs);
211#define THREAD_WAIT( a, b, c, d, e) THREAD_WAIT_IMPL( a, b)
212#else // THREADWAIT_METHOD == THREADWAIT_CONDVAR
213bool_t THREAD_WAIT_IMPL( THREAD_T *ref, double secs, SIGNAL_T *signal_ref, MUTEX_T *mu_ref, volatile enum e_status *st_ref);
214#define THREAD_WAIT THREAD_WAIT_IMPL
215#endif // // THREADWAIT_METHOD == THREADWAIT_CONDVAR
192 216
193void THREAD_KILL( THREAD_T *ref ); 217void THREAD_KILL( THREAD_T *ref );
194 218
195#endif 219#endif // __threading_h__
196 // THREADING_H