diff options
author | Benoit Germain <bnt.germain@gmail.com> | 2011-11-05 17:31:02 +0100 |
---|---|---|
committer | Benoit Germain <bnt.germain@gmail.com> | 2011-11-05 17:31:02 +0100 |
commit | 053f7cff3c95acb915e6babfd306971f11bb7986 (patch) | |
tree | ee38c60b1119d34eb96aea1105ef033e851d266e /src/lanes.c | |
parent | 717eadee9c3644fabb32c7ee59949f2846143690 (diff) | |
download | lanes-053f7cff3c95acb915e6babfd306971f11bb7986.tar.gz lanes-053f7cff3c95acb915e6babfd306971f11bb7986.tar.bz2 lanes-053f7cff3c95acb915e6babfd306971f11bb7986.zip |
* process exit change: close everything at GC when main state closes, not when atexit() handlers are processed
* Lua 5.2-style module:
* module() is no longer used to implement lanes.lua
* a global "lanes" variable is no longer created when the module is required
* the Lanes module table is returned instead
* Lanes must be initialized before used:
* the first occurence of 'require "lanes"' produces a minimal interface that only contains a configure() function
* the remainder of the interface is made available once this function is called
* subsequent calls to configure() do nothing
* configure() controls the number of keeper states and the startup of timers
* LuaJIT 2 compatibility
* non-Lua functions are no longer copied by creating a C closure from a C pointer, but through 2-way lookup tables
* this means that if a lane function body pulls non-Lua functions, the lane generator description must contain the list of libraries and modules that exports them
* introduces a change in configuration .globals management: contents are copied *after* std libs are loaded
* new .required configuration entry to list modules that must be require()'ed before lane body is transferred
* lane:cancel() wakes up waiting lindas like what is done at lane shutdown
Diffstat (limited to 'src/lanes.c')
-rw-r--r-- | src/lanes.c | 311 |
1 files changed, 225 insertions, 86 deletions
diff --git a/src/lanes.c b/src/lanes.c index ed54b0f..44db625 100644 --- a/src/lanes.c +++ b/src/lanes.c | |||
@@ -51,7 +51,7 @@ | |||
51 | * ... | 51 | * ... |
52 | */ | 52 | */ |
53 | 53 | ||
54 | const char *VERSION= "2.2.0"; | 54 | const char *VERSION= "3.0-beta"; |
55 | 55 | ||
56 | /* | 56 | /* |
57 | =============================================================================== | 57 | =============================================================================== |
@@ -787,10 +787,11 @@ static void linda_id( lua_State *L, char const * const which) | |||
787 | /* Clean associated structures in the keeper state. | 787 | /* Clean associated structures in the keeper state. |
788 | */ | 788 | */ |
789 | K= keeper_acquire(s); | 789 | K= keeper_acquire(s); |
790 | if( K) // can be NULL if this happens during main state shutdown (lanes is GC'ed -> no keepers -> no need to cleanup) | ||
790 | { | 791 | { |
791 | keeper_call( K->L, "clear", L, s, 0 ); | 792 | keeper_call( K->L, "clear", L, s, 0 ); |
793 | keeper_release(K); | ||
792 | } | 794 | } |
793 | keeper_release(K); | ||
794 | 795 | ||
795 | /* There aren't any lanes waiting on these lindas, since all proxies | 796 | /* There aren't any lanes waiting on these lindas, since all proxies |
796 | * have been gc'ed. Right? | 797 | * have been gc'ed. Right? |
@@ -1028,9 +1029,9 @@ volatile DEEP_PRELUDE *timer_deep; // = NULL | |||
1028 | /* | 1029 | /* |
1029 | * Process end; cancel any still free-running threads | 1030 | * Process end; cancel any still free-running threads |
1030 | */ | 1031 | */ |
1031 | static void selfdestruct_atexit( void ) | 1032 | static int selfdestruct_atexit( lua_State *L) |
1032 | { | 1033 | { |
1033 | if (selfdestruct_first == SELFDESTRUCT_END) return; // no free-running threads | 1034 | if (selfdestruct_first == SELFDESTRUCT_END) return 0; // no free-running threads |
1034 | 1035 | ||
1035 | // Signal _all_ still running threads to exit (including the timer thread) | 1036 | // Signal _all_ still running threads to exit (including the timer thread) |
1036 | // | 1037 | // |
@@ -1047,7 +1048,7 @@ static void selfdestruct_atexit( void ) | |||
1047 | // signal the linda the wake up the thread so that it can react to the cancel query | 1048 | // signal the linda the wake up the thread so that it can react to the cancel query |
1048 | // let us hope we never land here with a pointer on a linda that has been destroyed... | 1049 | // let us hope we never land here with a pointer on a linda that has been destroyed... |
1049 | SIGNAL_T *waiting_on = s->waiting_on; | 1050 | SIGNAL_T *waiting_on = s->waiting_on; |
1050 | s->waiting_on = NULL; | 1051 | //s->waiting_on = NULL; // useful, or not? |
1051 | SIGNAL_ALL( waiting_on); | 1052 | SIGNAL_ALL( waiting_on); |
1052 | } | 1053 | } |
1053 | s = s->selfdestruct_next; | 1054 | s = s->selfdestruct_next; |
@@ -1117,6 +1118,7 @@ static void selfdestruct_atexit( void ) | |||
1117 | // | 1118 | // |
1118 | if ( selfdestruct_first != SELFDESTRUCT_END ) { | 1119 | if ( selfdestruct_first != SELFDESTRUCT_END ) { |
1119 | unsigned n=0; | 1120 | unsigned n=0; |
1121 | #if 0 | ||
1120 | MUTEX_LOCK( &selfdestruct_cs ); | 1122 | MUTEX_LOCK( &selfdestruct_cs ); |
1121 | { | 1123 | { |
1122 | struct s_lane *s= selfdestruct_first; | 1124 | struct s_lane *s= selfdestruct_first; |
@@ -1131,15 +1133,14 @@ static void selfdestruct_atexit( void ) | |||
1131 | // and works without the block (so let's leave those lanes running) | 1133 | // and works without the block (so let's leave those lanes running) |
1132 | // | 1134 | // |
1133 | //we want to free memory and such when we exit. | 1135 | //we want to free memory and such when we exit. |
1134 | #if 0 | ||
1135 | // 2.0.2: at least timer lane is still here | 1136 | // 2.0.2: at least timer lane is still here |
1136 | // | 1137 | // |
1137 | DEBUGEXEC(fprintf( stderr, "Left %d lane(s) with cancel request at process end.\n", n )); | 1138 | DEBUGEXEC(fprintf( stderr, "Left %d lane(s) with cancel request at process end.\n", n )); |
1139 | n=0; | ||
1138 | #else | 1140 | #else |
1139 | // first thing we did was to raise the linda signals the threads were waiting on (if any) | 1141 | // first thing we did was to raise the linda signals the threads were waiting on (if any) |
1140 | // therefore, any well-behaved thread should be in CANCELLED state | 1142 | // therefore, any well-behaved thread should be in CANCELLED state |
1141 | // these are not running, and the state can be closed | 1143 | // these are not running, and the state can be closed |
1142 | n=0; | ||
1143 | MUTEX_LOCK( &selfdestruct_cs ); | 1144 | MUTEX_LOCK( &selfdestruct_cs ); |
1144 | { | 1145 | { |
1145 | struct s_lane *s= selfdestruct_first; | 1146 | struct s_lane *s= selfdestruct_first; |
@@ -1147,7 +1148,8 @@ static void selfdestruct_atexit( void ) | |||
1147 | { | 1148 | { |
1148 | struct s_lane *next_s= s->selfdestruct_next; | 1149 | struct s_lane *next_s= s->selfdestruct_next; |
1149 | s->selfdestruct_next= NULL; // detach from selfdestruct chain | 1150 | s->selfdestruct_next= NULL; // detach from selfdestruct chain |
1150 | THREAD_KILL( &s->thread); | 1151 | if( s->thread) // can be NULL if previous 'soft' termination succeeded |
1152 | THREAD_KILL( &s->thread); | ||
1151 | // NO lua_close() in this case because we don't know where execution of the state was interrupted | 1153 | // NO lua_close() in this case because we don't know where execution of the state was interrupted |
1152 | free( s); | 1154 | free( s); |
1153 | s = next_s; | 1155 | s = next_s; |
@@ -1161,6 +1163,7 @@ static void selfdestruct_atexit( void ) | |||
1161 | #endif | 1163 | #endif |
1162 | } | 1164 | } |
1163 | close_keepers(); | 1165 | close_keepers(); |
1166 | return 0; | ||
1164 | } | 1167 | } |
1165 | 1168 | ||
1166 | 1169 | ||
@@ -1508,10 +1511,36 @@ LUAG_FUNC( set_debug_threadname) | |||
1508 | // [prio_int=0], | 1511 | // [prio_int=0], |
1509 | // [globals_tbl], | 1512 | // [globals_tbl], |
1510 | // [packagepath], | 1513 | // [packagepath], |
1514 | // [required], | ||
1511 | // [... args ...] ) | 1515 | // [... args ...] ) |
1512 | // | 1516 | // |
1513 | // Upvalues: metatable to use for 'lane_ud' | 1517 | // Upvalues: metatable to use for 'lane_ud' |
1514 | // | 1518 | // |
1519 | |||
1520 | // helper function to require a module in the keeper states and in the target state | ||
1521 | // source state contains module name at the top of the stack | ||
1522 | static void require_one_module( lua_State *L, lua_State *L2, bool_t _fatal) | ||
1523 | { | ||
1524 | size_t len; | ||
1525 | char const *name = lua_tolstring( L, -1, &len); | ||
1526 | // require the module in the target lane | ||
1527 | STACK_GROW( L2, 2); | ||
1528 | lua_getglobal( L2, "require"); | ||
1529 | if( lua_isnil( L2, -1)) | ||
1530 | { | ||
1531 | lua_pop( L2, 1); | ||
1532 | if( _fatal) | ||
1533 | luaL_error( L, "cannot pre-require modules without loading package library first"); | ||
1534 | } | ||
1535 | else | ||
1536 | { | ||
1537 | lua_pushlstring( L2, name, len); | ||
1538 | lua_pcall( L2, 1, 0, 0); | ||
1539 | // we need to require this module in the keeper states as well | ||
1540 | populate_keepers( L); | ||
1541 | } | ||
1542 | } | ||
1543 | |||
1515 | LUAG_FUNC( thread_new ) | 1544 | LUAG_FUNC( thread_new ) |
1516 | { | 1545 | { |
1517 | lua_State *L2; | 1546 | lua_State *L2; |
@@ -1524,8 +1553,9 @@ LUAG_FUNC( thread_new ) | |||
1524 | uint_t glob= luaG_isany(L,5) ? 5:0; | 1553 | uint_t glob= luaG_isany(L,5) ? 5:0; |
1525 | uint_t ppath = luaG_isany(L,6) ? 6:0; | 1554 | uint_t ppath = luaG_isany(L,6) ? 6:0; |
1526 | uint_t pcpath = luaG_isany(L,7) ? 7:0; | 1555 | uint_t pcpath = luaG_isany(L,7) ? 7:0; |
1556 | uint_t required = luaG_isany(L,8) ? 8:0; | ||
1527 | 1557 | ||
1528 | #define FIXED_ARGS (7) | 1558 | #define FIXED_ARGS (8) |
1529 | uint_t args= lua_gettop(L) - FIXED_ARGS; | 1559 | uint_t args= lua_gettop(L) - FIXED_ARGS; |
1530 | 1560 | ||
1531 | if (prio < THREAD_PRIO_MIN || prio > THREAD_PRIO_MAX) | 1561 | if (prio < THREAD_PRIO_MIN || prio > THREAD_PRIO_MAX) |
@@ -1541,40 +1571,20 @@ LUAG_FUNC( thread_new ) | |||
1541 | 1571 | ||
1542 | if (!L2) luaL_error( L, "'luaL_newstate()' failed; out of memory" ); | 1572 | if (!L2) luaL_error( L, "'luaL_newstate()' failed; out of memory" ); |
1543 | 1573 | ||
1544 | STACK_GROW( L,2 ); | 1574 | STACK_GROW( L, 2); |
1545 | |||
1546 | // Setting the globals table (needs to be done before loading stdlibs, | ||
1547 | // and the lane function) | ||
1548 | // | ||
1549 | if (glob!=0) | ||
1550 | { | ||
1551 | STACK_CHECK(L) | ||
1552 | if (!lua_istable(L,glob)) | ||
1553 | luaL_error( L, "Expected table, got %s", luaG_typename(L,glob) ); | ||
1554 | |||
1555 | lua_pushvalue( L, glob ); | ||
1556 | |||
1557 | luaG_inter_move( L, L2, 1); // moves the table to L2 | ||
1558 | |||
1559 | // L2 [-1]: table of globals | ||
1560 | |||
1561 | // "You can change the global environment of a Lua thread using lua_replace" | ||
1562 | // (refman-5.0.pdf p. 30) | ||
1563 | // | ||
1564 | lua_replace( L2, LUA_GLOBALSINDEX ); | ||
1565 | STACK_END(L,0) | ||
1566 | } | ||
1567 | 1575 | ||
1568 | // Selected libraries | 1576 | // Selected libraries |
1569 | // | 1577 | // |
1570 | if (libs) | 1578 | if (libs) |
1571 | { | 1579 | { |
1572 | const char *err= luaG_openlibs( L2, libs ); | 1580 | const char *err= luaG_openlibs( L2, libs); |
1573 | ASSERT_L( !err ); // bad libs should have been noticed by 'lanes.lua' | 1581 | ASSERT_L( !err ); // bad libs should have been noticed by 'lanes.lua' |
1574 | 1582 | ||
1575 | serialize_require( L2 ); | 1583 | serialize_require( L2); |
1576 | } | 1584 | } |
1577 | 1585 | ||
1586 | ASSERT_L( lua_gettop(L2) == 0); | ||
1587 | |||
1578 | // package.path | 1588 | // package.path |
1579 | STACK_CHECK(L2) | 1589 | STACK_CHECK(L2) |
1580 | if( ppath) | 1590 | if( ppath) |
@@ -1582,15 +1592,17 @@ LUAG_FUNC( thread_new ) | |||
1582 | if (lua_type(L,ppath) != LUA_TSTRING) | 1592 | if (lua_type(L,ppath) != LUA_TSTRING) |
1583 | luaL_error( L, "expected packagepath as string, got %s", luaG_typename(L,ppath)); | 1593 | luaL_error( L, "expected packagepath as string, got %s", luaG_typename(L,ppath)); |
1584 | lua_getglobal( L2, "package"); | 1594 | lua_getglobal( L2, "package"); |
1585 | if( lua_isnil( L2, -1)) | 1595 | if( lua_isnil( L2, -1)) // package library not loaded: do nothing |
1586 | { | 1596 | { |
1587 | lua_pop( L2, 1); | 1597 | lua_pop( L2, 1); |
1588 | luaL_error( L, "specifying a new path for packages, but lane doesn't load package library"); | ||
1589 | } | 1598 | } |
1590 | lua_pushvalue( L, ppath); | 1599 | else |
1591 | luaG_inter_move( L, L2, 1); // moves the new path to L2 | 1600 | { |
1592 | lua_setfield( L2, -2, "path"); // set package.path | 1601 | lua_pushvalue( L, ppath); |
1593 | lua_pop( L2, 1); | 1602 | luaG_inter_move( L, L2, 1); // moves the new path to L2 |
1603 | lua_setfield( L2, -2, "path"); // set package.path | ||
1604 | lua_pop( L2, 1); | ||
1605 | } | ||
1594 | } | 1606 | } |
1595 | STACK_END(L2,0) | 1607 | STACK_END(L2,0) |
1596 | 1608 | ||
@@ -1601,18 +1613,83 @@ LUAG_FUNC( thread_new ) | |||
1601 | if (lua_type(L,pcpath) != LUA_TSTRING) | 1613 | if (lua_type(L,pcpath) != LUA_TSTRING) |
1602 | luaL_error( L, "expected packagecpath as string, got %s", luaG_typename(L,pcpath)); | 1614 | luaL_error( L, "expected packagecpath as string, got %s", luaG_typename(L,pcpath)); |
1603 | lua_getglobal( L2, "package"); | 1615 | lua_getglobal( L2, "package"); |
1604 | if( lua_isnil( L2, -1)) | 1616 | if( lua_isnil( L2, -1)) // // package library not loaded: do nothing |
1605 | { | 1617 | { |
1606 | lua_pop( L2, 1); | 1618 | lua_pop( L2, 1); |
1607 | luaL_error( L, "specifying a new cpath for packages, but lane doesn't load package library"); | ||
1608 | } | 1619 | } |
1609 | lua_pushvalue( L, pcpath); | 1620 | else |
1610 | luaG_inter_move( L, L2, 1); // moves the new cpath to L2 | 1621 | { |
1611 | lua_setfield( L2, -2, "cpath"); // set package.cpath | 1622 | lua_pushvalue( L, pcpath); |
1612 | lua_pop( L2, 1); | 1623 | luaG_inter_move( L, L2, 1); // moves the new cpath to L2 |
1624 | lua_setfield( L2, -2, "cpath"); // set package.cpath | ||
1625 | lua_pop( L2, 1); | ||
1626 | } | ||
1613 | } | 1627 | } |
1614 | STACK_END(L2,0) | 1628 | STACK_END(L2,0) |
1615 | 1629 | ||
1630 | // modules to require in the target lane *before* the function is transfered! | ||
1631 | |||
1632 | //start by requiring lua51-lanes, since it is a bit special | ||
1633 | // it not fatal if 'require' isn't loaded, just ignore (may cause function transfer errors later on if the lane pulls the lanes module itself) | ||
1634 | STACK_CHECK(L) | ||
1635 | STACK_CHECK(L2) | ||
1636 | lua_pushliteral( L, "lua51-lanes"); | ||
1637 | require_one_module( L, L2, FALSE); | ||
1638 | lua_pop( L, 1); | ||
1639 | STACK_END(L2,0) | ||
1640 | STACK_END(L,0) | ||
1641 | |||
1642 | STACK_CHECK(L) | ||
1643 | STACK_CHECK(L2) | ||
1644 | if( required) | ||
1645 | { | ||
1646 | int nbRequired = 1; | ||
1647 | // should not happen, was checked in lanes.lua before calling thread_new() | ||
1648 | if (lua_type(L, required) != LUA_TTABLE) | ||
1649 | luaL_error( L, "expected required module list as a table, got %s", luaG_typename( L, required)); | ||
1650 | lua_pushnil( L); | ||
1651 | while( lua_next( L, required) != 0) | ||
1652 | { | ||
1653 | if (lua_type(L,-1) != LUA_TSTRING || lua_type(L,-2) != LUA_TNUMBER || lua_tonumber( L, -2) != nbRequired) | ||
1654 | { | ||
1655 | luaL_error( L, "required module list should be a list of strings."); | ||
1656 | } | ||
1657 | else | ||
1658 | { | ||
1659 | require_one_module( L, L2, TRUE); | ||
1660 | } | ||
1661 | lua_pop( L, 1); | ||
1662 | ++ nbRequired; | ||
1663 | } | ||
1664 | } | ||
1665 | STACK_END(L2,0) | ||
1666 | STACK_END(L,0) | ||
1667 | |||
1668 | // Appending the specified globals to the global environment | ||
1669 | // *after* stdlibs have been loaded and modules required, in case we transfer references to native functions they exposed... | ||
1670 | // | ||
1671 | if (glob!=0) | ||
1672 | { | ||
1673 | STACK_CHECK(L) | ||
1674 | STACK_CHECK(L2) | ||
1675 | if (!lua_istable(L,glob)) | ||
1676 | luaL_error( L, "Expected table, got %s", luaG_typename(L,glob)); | ||
1677 | |||
1678 | lua_pushnil( L); | ||
1679 | while( lua_next( L, glob)) | ||
1680 | { | ||
1681 | luaG_inter_copy( L, L2, 2); // moves the key/value pair to the L2 stack | ||
1682 | // assign it in the globals table | ||
1683 | lua_rawset( L2, LUA_GLOBALSINDEX); | ||
1684 | lua_pop( L, 1); | ||
1685 | } | ||
1686 | |||
1687 | STACK_END(L2, 0) | ||
1688 | STACK_END(L, 0) | ||
1689 | } | ||
1690 | |||
1691 | ASSERT_L( lua_gettop(L2) == 0); | ||
1692 | |||
1616 | // Lane main function | 1693 | // Lane main function |
1617 | // | 1694 | // |
1618 | STACK_CHECK(L) | 1695 | STACK_CHECK(L) |
@@ -1677,7 +1754,7 @@ LUAG_FUNC( thread_new ) | |||
1677 | lua_newtable( L); | 1754 | lua_newtable( L); |
1678 | lua_setfenv( L, -2); | 1755 | lua_setfenv( L, -2); |
1679 | 1756 | ||
1680 | // Place 's' to registry, for 'cancel_test()' (even if 'cs'==0 we still | 1757 | // Place 's' in registry, for 'cancel_test()' (even if 'cs'==0 we still |
1681 | // do cancel tests at pending send/receive). | 1758 | // do cancel tests at pending send/receive). |
1682 | // | 1759 | // |
1683 | lua_pushlightuserdata( L2, CANCEL_TEST_KEY ); | 1760 | lua_pushlightuserdata( L2, CANCEL_TEST_KEY ); |
@@ -1792,6 +1869,17 @@ static bool_t thread_cancel( struct s_lane *s, double secs, bool_t force) | |||
1792 | // | 1869 | // |
1793 | if( s->status < DONE) | 1870 | if( s->status < DONE) |
1794 | { | 1871 | { |
1872 | // signal the linda the wake up the thread so that it can react to the cancel query | ||
1873 | // let us hope we never land here with a pointer on a linda that has been destroyed... | ||
1874 | //MUTEX_LOCK( &selfdestruct_cs ); | ||
1875 | { | ||
1876 | SIGNAL_T *waiting_on = s->waiting_on; | ||
1877 | if( s->status == WAITING && waiting_on != NULL) | ||
1878 | { | ||
1879 | SIGNAL_ALL( waiting_on); | ||
1880 | } | ||
1881 | } | ||
1882 | //MUTEX_UNLOCK( &selfdestruct_cs ); | ||
1795 | s->cancel_request = TRUE; // it's now signalled to stop | 1883 | s->cancel_request = TRUE; // it's now signalled to stop |
1796 | done= | 1884 | done= |
1797 | #if (defined PLATFORM_WIN32) || (defined PLATFORM_POCKETPC) || (defined PTHREAD_TIMEDJOIN) | 1885 | #if (defined PLATFORM_WIN32) || (defined PLATFORM_POCKETPC) || (defined PTHREAD_TIMEDJOIN) |
@@ -1816,23 +1904,32 @@ static bool_t thread_cancel( struct s_lane *s, double secs, bool_t force) | |||
1816 | 1904 | ||
1817 | LUAG_FUNC( thread_cancel) | 1905 | LUAG_FUNC( thread_cancel) |
1818 | { | 1906 | { |
1819 | struct s_lane *s= lua_toLane(L,1); | 1907 | if( lua_gettop( L) != 1 || lua_type( L, 1) != LUA_TUSERDATA) |
1820 | double secs= 0.0; | 1908 | { |
1821 | uint_t force_i=2; | 1909 | return luaL_error( L, "invalid argument #1, did you use ':' as you should?"); |
1822 | bool_t force, done= TRUE; | 1910 | } |
1911 | else | ||
1912 | { | ||
1913 | struct s_lane *s = lua_toLane( L, 1); | ||
1914 | double secs = 0.0; | ||
1915 | uint_t force_i = 2; | ||
1916 | bool_t force, done= TRUE; | ||
1823 | 1917 | ||
1824 | if (lua_isnumber(L,2)) { | 1918 | if( lua_isnumber( L, 2)) |
1825 | secs= lua_tonumber(L,2); | 1919 | { |
1826 | force_i++; | 1920 | secs = lua_tonumber( L, 2); |
1827 | } else if (lua_isnil(L,2)) | 1921 | ++ force_i; |
1828 | force_i++; | 1922 | } |
1923 | else if( lua_isnil( L, 2)) | ||
1924 | ++ force_i; | ||
1829 | 1925 | ||
1830 | force= lua_toboolean(L,force_i); // FALSE if nothing there | 1926 | force = lua_toboolean( L, force_i); // FALSE if nothing there |
1831 | 1927 | ||
1832 | done = thread_cancel( s, secs, force); | 1928 | done = thread_cancel( s, secs, force); |
1833 | 1929 | ||
1834 | lua_pushboolean( L, done); | 1930 | lua_pushboolean( L, done); |
1835 | return 1; | 1931 | return 1; |
1932 | } | ||
1836 | } | 1933 | } |
1837 | 1934 | ||
1838 | //--- | 1935 | //--- |
@@ -2183,7 +2280,7 @@ static void init_once_LOCKED( lua_State *L, volatile DEEP_PRELUDE ** timer_deep_ | |||
2183 | // Selfdestruct chain handling | 2280 | // Selfdestruct chain handling |
2184 | // | 2281 | // |
2185 | MUTEX_INIT( &selfdestruct_cs ); | 2282 | MUTEX_INIT( &selfdestruct_cs ); |
2186 | atexit( selfdestruct_atexit ); | 2283 | //atexit( selfdestruct_atexit ); |
2187 | 2284 | ||
2188 | //--- | 2285 | //--- |
2189 | // Linux needs SCHED_RR to change thread priorities, and that is only | 2286 | // Linux needs SCHED_RR to change thread priorities, and that is only |
@@ -2233,7 +2330,17 @@ static void init_once_LOCKED( lua_State *L, volatile DEEP_PRELUDE ** timer_deep_ | |||
2233 | 2330 | ||
2234 | // The host Lua state must always have a reference to this Linda object in order for our 'timer_deep_ref' to be valid. | 2331 | // The host Lua state must always have a reference to this Linda object in order for our 'timer_deep_ref' to be valid. |
2235 | // So store a reference that we will never actually use. | 2332 | // So store a reference that we will never actually use. |
2236 | lua_pushlightuserdata(L, (void *)init_once_LOCKED); | 2333 | // at the same time, use this object as a 'desinit' marker: |
2334 | // when the main lua State is closed, this object will be GC'ed | ||
2335 | { | ||
2336 | lua_newuserdata( L, 1); | ||
2337 | lua_newtable( L); | ||
2338 | lua_pushcfunction( L, selfdestruct_atexit); | ||
2339 | lua_setfield( L, -2, "__gc"); | ||
2340 | lua_pushliteral( L, "AtExit"); | ||
2341 | lua_setfield( L, -2, "__metatable"); | ||
2342 | lua_setmetatable( L, -2); | ||
2343 | } | ||
2237 | lua_insert(L, -2); // Swap key with the Linda object | 2344 | lua_insert(L, -2); // Swap key with the Linda object |
2238 | lua_rawset(L, LUA_REGISTRYINDEX); | 2345 | lua_rawset(L, LUA_REGISTRYINDEX); |
2239 | 2346 | ||
@@ -2241,14 +2348,12 @@ static void init_once_LOCKED( lua_State *L, volatile DEEP_PRELUDE ** timer_deep_ | |||
2241 | STACK_END(L,0) | 2348 | STACK_END(L,0) |
2242 | } | 2349 | } |
2243 | 2350 | ||
2244 | int | 2351 | static volatile long s_initCount = 0; |
2245 | #if (defined PLATFORM_WIN32) || (defined PLATFORM_POCKETPC) | 2352 | |
2246 | __declspec(dllexport) | 2353 | LUAG_FUNC( configure ) |
2247 | #endif | ||
2248 | luaopen_lanes( lua_State *L ) | ||
2249 | { | 2354 | { |
2250 | static volatile int /*bool*/ go_ahead; // = 0 | 2355 | char const *name = luaL_checkstring( L, lua_upvalueindex( 1)); |
2251 | int const nbKeepers = luaL_optint( L, 2, 1); | 2356 | int const nbKeepers = luaL_optint( L, 1, 1); |
2252 | luaL_argcheck( L, nbKeepers > 0, 2, "Number of keeper states must be > 0"); | 2357 | luaL_argcheck( L, nbKeepers > 0, 2, "Number of keeper states must be > 0"); |
2253 | /* | 2358 | /* |
2254 | * Making one-time initializations. | 2359 | * Making one-time initializations. |
@@ -2259,31 +2364,29 @@ luaopen_lanes( lua_State *L ) | |||
2259 | */ | 2364 | */ |
2260 | #ifdef PLATFORM_WIN32 | 2365 | #ifdef PLATFORM_WIN32 |
2261 | { | 2366 | { |
2262 | // TBD: Someone please replace this with reliable Win32 API code. Problem is, | 2367 | static volatile int /*bool*/ go_ahead; // = 0 |
2263 | // there's no autoinitializing locks (s.a. PTHREAD_MUTEX_INITIALIZER) in | 2368 | if( InterlockedCompareExchange( &s_initCount, 1, 0) == 0) |
2264 | // Windows so 'InterlockedIncrement' or something needs to be used. | 2369 | { |
2265 | // This is 99.9999% safe, though (and always safe if host is single-threaded) | ||
2266 | // -- AKa 24-Jun-2009 | ||
2267 | // | ||
2268 | static volatile unsigned my_number; // = 0 | ||
2269 | |||
2270 | if (my_number++ == 0) { // almost atomic | ||
2271 | init_once_LOCKED(L, &timer_deep, nbKeepers); | 2370 | init_once_LOCKED(L, &timer_deep, nbKeepers); |
2272 | go_ahead= 1; // let others pass | 2371 | go_ahead= 1; // let others pass |
2273 | } else { | 2372 | } |
2373 | else | ||
2374 | { | ||
2274 | while( !go_ahead ) { Sleep(1); } // changes threads | 2375 | while( !go_ahead ) { Sleep(1); } // changes threads |
2275 | } | 2376 | } |
2276 | } | 2377 | } |
2277 | #else | 2378 | #else |
2278 | if (!go_ahead) { | 2379 | if( s_initCount == 0) |
2380 | { | ||
2279 | static pthread_mutex_t my_lock= PTHREAD_MUTEX_INITIALIZER; | 2381 | static pthread_mutex_t my_lock= PTHREAD_MUTEX_INITIALIZER; |
2280 | pthread_mutex_lock(&my_lock); | 2382 | pthread_mutex_lock(&my_lock); |
2281 | { | 2383 | { |
2282 | // Recheck now that we're within the lock | 2384 | // Recheck now that we're within the lock |
2283 | // | 2385 | // |
2284 | if (!go_ahead) { | 2386 | if (s_initCount == 0) |
2387 | { | ||
2285 | init_once_LOCKED(L, &timer_deep, nbKeepers); | 2388 | init_once_LOCKED(L, &timer_deep, nbKeepers); |
2286 | go_ahead= 1; | 2389 | s_initCount = 1; |
2287 | } | 2390 | } |
2288 | } | 2391 | } |
2289 | pthread_mutex_unlock(&my_lock); | 2392 | pthread_mutex_unlock(&my_lock); |
@@ -2292,7 +2395,10 @@ luaopen_lanes( lua_State *L ) | |||
2292 | assert( timer_deep != 0 ); | 2395 | assert( timer_deep != 0 ); |
2293 | 2396 | ||
2294 | // Create main module interface table | 2397 | // Create main module interface table |
2295 | lua_newtable(L); | 2398 | lua_pushvalue( L, lua_upvalueindex( 2)); |
2399 | // remove configure() (this function) from the module interface | ||
2400 | lua_pushnil( L); | ||
2401 | lua_setfield( L, -2, "configure"); | ||
2296 | luaL_register(L, NULL, lanes_functions); | 2402 | luaL_register(L, NULL, lanes_functions); |
2297 | 2403 | ||
2298 | // metatable for threads | 2404 | // metatable for threads |
@@ -2313,7 +2419,7 @@ luaopen_lanes( lua_State *L ) | |||
2313 | lua_setfield( L, -2, "join"); | 2419 | lua_setfield( L, -2, "join"); |
2314 | lua_pushcfunction( L, LG_thread_cancel); | 2420 | lua_pushcfunction( L, LG_thread_cancel); |
2315 | lua_setfield( L, -2, "cancel"); | 2421 | lua_setfield( L, -2, "cancel"); |
2316 | lua_pushboolean( L, 0); | 2422 | lua_pushliteral( L, "Lane"); |
2317 | lua_setfield( L, -2, "__metatable"); | 2423 | lua_setfield( L, -2, "__metatable"); |
2318 | 2424 | ||
2319 | lua_pushcclosure( L, LG_thread_new, 1 ); // metatable as closure param | 2425 | lua_pushcclosure( L, LG_thread_new, 1 ); // metatable as closure param |
@@ -2331,8 +2437,41 @@ luaopen_lanes( lua_State *L ) | |||
2331 | lua_pushlightuserdata( L, CANCEL_ERROR ); | 2437 | lua_pushlightuserdata( L, CANCEL_ERROR ); |
2332 | lua_setfield(L, -2, "cancel_error"); | 2438 | lua_setfield(L, -2, "cancel_error"); |
2333 | 2439 | ||
2334 | // Return the local module table | 2440 | // register all native functions found in that module in the transferable functions database |
2335 | return 1; | 2441 | // we process it before _G because we don't want to find the module when scanning _G (this would generate longer names) |
2442 | populate_func_lookup_table( L, -1, name); | ||
2443 | // record all existing C/JIT-fast functions | ||
2444 | populate_func_lookup_table( L, LUA_GLOBALSINDEX, NULL); | ||
2445 | // Return nothing | ||
2446 | lua_pop( L, 1); | ||
2447 | return 0; | ||
2448 | } | ||
2449 | |||
2450 | int | ||
2451 | #if (defined PLATFORM_WIN32) || (defined PLATFORM_POCKETPC) | ||
2452 | __declspec(dllexport) | ||
2453 | #endif | ||
2454 | luaopen_lanes( lua_State *L ) | ||
2455 | { | ||
2456 | // Create main module interface table | ||
2457 | // we only have 1 closure, which must be called to configure Lanes | ||
2458 | STACK_GROW( L, 3); | ||
2459 | STACK_CHECK( L) | ||
2460 | lua_newtable(L); | ||
2461 | lua_pushvalue(L, 1); // module name | ||
2462 | lua_pushvalue(L, -2); // module table | ||
2463 | lua_pushcclosure( L, LG_configure, 2); | ||
2464 | if( s_initCount == 0) | ||
2465 | { | ||
2466 | lua_setfield( L, -2, "configure"); | ||
2467 | } | ||
2468 | else // already initialized: call it mmediately and be done | ||
2469 | { | ||
2470 | lua_pushinteger( L, 666); // any value will do, it will be ignored | ||
2471 | lua_call( L, 1, 0); | ||
2472 | } | ||
2473 | STACK_END( L, 1) | ||
2474 | return 1; | ||
2336 | } | 2475 | } |
2337 | 2476 | ||
2338 | 2477 | ||