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/lanes.c | |
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/lanes.c')
-rw-r--r-- | src/lanes.c | 161 |
1 files changed, 71 insertions, 90 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 |