diff options
author | Benoit Germain <bnt.germain@gmail.com> | 2011-11-14 19:41:28 +0100 |
---|---|---|
committer | Benoit Germain <bnt.germain@gmail.com> | 2011-11-14 19:41:28 +0100 |
commit | 87431bcc0ece1eaf9305593223bb0c5145004044 (patch) | |
tree | e1a76ea727e8019d3c26c4829dbb95253dd7e1f6 /src | |
parent | 1d2b45823fd2a13761bd2d19b1b5a1e8bb11f7b9 (diff) | |
download | lanes-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.c | 161 | ||||
-rw-r--r-- | src/lanes.lua | 13 | ||||
-rw-r--r-- | src/threading.c | 54 | ||||
-rw-r--r-- | src/threading.h | 55 |
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) | 1385 | static 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 ) | |||
2453 | int | 2434 | int |
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) |
2457 | luaopen_lanes( lua_State *L ) | 2438 | luaopen_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 |
246 | end | 243 | end |
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 |
75 | static void FAIL( const char *funcname, int rc ) { | 75 | static 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 | */ |
91 | time_d now_secs(void) { | 91 | time_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 ) { | 285 | bool_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 | 664 | bool_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 | ||
730 | static const lua_Alloc alloc_f= 0; | 728 | static 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 | */ |
46 | enum e_status { PENDING, RUNNING, WAITING, DONE, ERROR_ST, CANCELLED }; | 46 | enum 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 | ||
119 | void SIGNAL_INIT( SIGNAL_T *ref ); | 129 | void SIGNAL_INIT( SIGNAL_T *ref ); |
120 | void SIGNAL_FREE( SIGNAL_T *ref ); | 130 | void 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 | ||
210 | bool_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 | ||
213 | bool_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 | ||
193 | void THREAD_KILL( THREAD_T *ref ); | 217 | void THREAD_KILL( THREAD_T *ref ); |
194 | 218 | ||
195 | #endif | 219 | #endif // __threading_h__ |
196 | // THREADING_H | ||