diff options
Diffstat (limited to 'src/lanes.c')
-rw-r--r-- | src/lanes.c | 371 |
1 files changed, 211 insertions, 160 deletions
diff --git a/src/lanes.c b/src/lanes.c index 8a67621..6fec951 100644 --- a/src/lanes.c +++ b/src/lanes.c | |||
@@ -52,13 +52,13 @@ | |||
52 | * ... | 52 | * ... |
53 | */ | 53 | */ |
54 | 54 | ||
55 | char const* VERSION = "3.4.2"; | 55 | char const* VERSION = "3.4.3"; |
56 | 56 | ||
57 | /* | 57 | /* |
58 | =============================================================================== | 58 | =============================================================================== |
59 | 59 | ||
60 | Copyright (C) 2007-10 Asko Kauppi <akauppi@gmail.com> | 60 | Copyright (C) 2007-10 Asko Kauppi <akauppi@gmail.com> |
61 | 2011-12 Benoit Germain <bnt.germain@gmail.com> | 61 | 2011-13 Benoit Germain <bnt.germain@gmail.com> |
62 | 62 | ||
63 | Permission is hereby granted, free of charge, to any person obtaining a copy | 63 | Permission is hereby granted, free of charge, to any person obtaining a copy |
64 | of this software and associated documentation files (the "Software"), to deal | 64 | of this software and associated documentation files (the "Software"), to deal |
@@ -1114,7 +1114,8 @@ static int run_finalizers( lua_State*L, int lua_rc ) | |||
1114 | // | 1114 | // |
1115 | // LUA_ERRRUN / LUA_ERRMEM | 1115 | // LUA_ERRRUN / LUA_ERRMEM |
1116 | 1116 | ||
1117 | if (rc!=0) { | 1117 | if( rc != LUA_OK) |
1118 | { | ||
1118 | // [-1]: error message | 1119 | // [-1]: error message |
1119 | // | 1120 | // |
1120 | // If one finalizer fails, don't run the others. Return this | 1121 | // If one finalizer fails, don't run the others. Return this |
@@ -1269,7 +1270,7 @@ static bool_t selfdestruct_remove( struct s_lane *s ) | |||
1269 | // Initialized by 'init_once_LOCKED()': the deep userdata Linda object | 1270 | // Initialized by 'init_once_LOCKED()': the deep userdata Linda object |
1270 | // used for timers (each lane will get a proxy to this) | 1271 | // used for timers (each lane will get a proxy to this) |
1271 | // | 1272 | // |
1272 | volatile DEEP_PRELUDE *timer_deep; // = NULL | 1273 | volatile DEEP_PRELUDE* timer_deep; // = NULL |
1273 | 1274 | ||
1274 | /* | 1275 | /* |
1275 | * Process end; cancel any still free-running threads | 1276 | * Process end; cancel any still free-running threads |
@@ -1349,7 +1350,7 @@ static int selfdestruct_gc( lua_State*L) | |||
1349 | t_now = now_secs(); | 1350 | t_now = now_secs(); |
1350 | if( n == 0 || ( t_now >= t_until)) | 1351 | if( n == 0 || ( t_now >= t_until)) |
1351 | { | 1352 | { |
1352 | DEBUGEXEC(fprintf( stderr, "%d uncancelled lane(s) remain after waiting %fs at process end.\n", n, shutdown_timeout - (t_until - t_now))); | 1353 | DEBUGSPEW_CODE( fprintf( stderr, "%d uncancelled lane(s) remain after waiting %fs at process end.\n", n, shutdown_timeout - (t_until - t_now))); |
1353 | break; | 1354 | break; |
1354 | } | 1355 | } |
1355 | } | 1356 | } |
@@ -1379,7 +1380,7 @@ static int selfdestruct_gc( lua_State*L) | |||
1379 | //we want to free memory and such when we exit. | 1380 | //we want to free memory and such when we exit. |
1380 | // 2.0.2: at least timer lane is still here | 1381 | // 2.0.2: at least timer lane is still here |
1381 | // | 1382 | // |
1382 | DEBUGEXEC(fprintf( stderr, "Left %d lane(s) with cancel request at process end.\n", n )); | 1383 | DEBUGSPEW_CODE( fprintf( stderr, "Left %d lane(s) with cancel request at process end.\n", n )); |
1383 | n=0; | 1384 | n=0; |
1384 | #else | 1385 | #else |
1385 | // first thing we did was to raise the linda signals the threads were waiting on (if any) | 1386 | // first thing we did was to raise the linda signals the threads were waiting on (if any) |
@@ -1409,7 +1410,7 @@ static int selfdestruct_gc( lua_State*L) | |||
1409 | } | 1410 | } |
1410 | MUTEX_UNLOCK( &selfdestruct_cs ); | 1411 | MUTEX_UNLOCK( &selfdestruct_cs ); |
1411 | 1412 | ||
1412 | DEBUGEXEC(fprintf( stderr, "Killed %d lane(s) at process end.\n", n )); | 1413 | DEBUGSPEW_CODE( fprintf( stderr, "Killed %d lane(s) at process end.\n", n)); |
1413 | #endif | 1414 | #endif |
1414 | } | 1415 | } |
1415 | #if !HAVE_KEEPER_ATEXIT_DESINIT | 1416 | #if !HAVE_KEEPER_ATEXIT_DESINIT |
@@ -1654,6 +1655,39 @@ LUAG_FUNC( set_debug_threadname) | |||
1654 | return 0; | 1655 | return 0; |
1655 | } | 1656 | } |
1656 | 1657 | ||
1658 | #if USE_DEBUG_SPEW | ||
1659 | // can't use direct LUA_x errcode indexing because the sequence is not the same between Lua 5.1 and 5.2 :-( | ||
1660 | // LUA_ERRERR doesn't have the same value | ||
1661 | struct errcode_name | ||
1662 | { | ||
1663 | int code; | ||
1664 | char const* name; | ||
1665 | }; | ||
1666 | |||
1667 | static struct errcode_name s_errcodes[] = | ||
1668 | { | ||
1669 | { LUA_OK, "LUA_OK"}, | ||
1670 | { LUA_YIELD, "LUA_YIELD"}, | ||
1671 | { LUA_ERRRUN, "LUA_ERRRUN"}, | ||
1672 | { LUA_ERRSYNTAX, "LUA_ERRSYNTAX"}, | ||
1673 | { LUA_ERRMEM, "LUA_ERRMEM"}, | ||
1674 | { LUA_ERRGCMM, "LUA_ERRGCMM"}, | ||
1675 | { LUA_ERRERR, "LUA_ERRERR"}, | ||
1676 | }; | ||
1677 | static char const* get_errcode_name( int _code) | ||
1678 | { | ||
1679 | int i; | ||
1680 | for( i = 0; i < 7; ++ i) | ||
1681 | { | ||
1682 | if( s_errcodes[i].code == _code) | ||
1683 | { | ||
1684 | return s_errcodes[i].name; | ||
1685 | } | ||
1686 | } | ||
1687 | return "<NULL>"; | ||
1688 | } | ||
1689 | #endif // USE_DEBUG_SPEW | ||
1690 | |||
1657 | //--- | 1691 | //--- |
1658 | static THREAD_RETURN_T THREAD_CALLCONV lane_main( void *vs) | 1692 | static THREAD_RETURN_T THREAD_CALLCONV lane_main( void *vs) |
1659 | { | 1693 | { |
@@ -1713,7 +1747,8 @@ static THREAD_RETURN_T THREAD_CALLCONV lane_main( void *vs) | |||
1713 | // Lua 5.1 error handler is limited to one return value; taking stack trace | 1747 | // Lua 5.1 error handler is limited to one return value; taking stack trace |
1714 | // via registry | 1748 | // via registry |
1715 | // | 1749 | // |
1716 | if (rc!=0) { | 1750 | if( rc != 0) |
1751 | { | ||
1717 | STACK_GROW(L,1); | 1752 | STACK_GROW(L,1); |
1718 | lua_pushlightuserdata( L, STACK_TRACE_KEY ); | 1753 | lua_pushlightuserdata( L, STACK_TRACE_KEY ); |
1719 | lua_gettable(L, LUA_REGISTRYINDEX); | 1754 | lua_gettable(L, LUA_REGISTRYINDEX); |
@@ -1733,16 +1768,19 @@ static THREAD_RETURN_T THREAD_CALLCONV lane_main( void *vs) | |||
1733 | // [2..top]: parameters | 1768 | // [2..top]: parameters |
1734 | // | 1769 | // |
1735 | rc= lua_pcall( L, lua_gettop(L)-1, LUA_MULTRET, 0 /*no error handler*/ ); | 1770 | rc= lua_pcall( L, lua_gettop(L)-1, LUA_MULTRET, 0 /*no error handler*/ ); |
1736 | // 0: no error | 1771 | // LUA_OK(0): no error |
1737 | // LUA_ERRRUN: a runtime error (error pushed on stack) | 1772 | // LUA_ERRRUN(2): a runtime error (error pushed on stack) |
1738 | // LUA_ERRMEM: memory allocation error | 1773 | // LUA_ERRMEM(4): memory allocation error |
1739 | #endif | 1774 | #endif |
1740 | 1775 | ||
1741 | //STACK_DUMP(L); | 1776 | DEBUGSPEW_CODE( fprintf( stderr, "Lane %p body: %s\n", L, get_errcode_name( rc))); |
1777 | //STACK_DUMP(L); | ||
1742 | // Call finalizers, if the script has set them up. | 1778 | // Call finalizers, if the script has set them up. |
1743 | // | 1779 | // |
1744 | rc2= run_finalizers(L,rc); | 1780 | rc2 = run_finalizers( L, rc); |
1745 | if (rc2!=0) { | 1781 | DEBUGSPEW_CODE( fprintf( stderr, "Lane %p finalizer: %s\n", L, get_errcode_name( rc2))); |
1782 | if( rc2 != LUA_OK) | ||
1783 | { | ||
1746 | // Error within a finalizer! | 1784 | // Error within a finalizer! |
1747 | // | 1785 | // |
1748 | // [-1]: error message | 1786 | // [-1]: error message |
@@ -1766,7 +1804,6 @@ static THREAD_RETURN_T THREAD_CALLCONV lane_main( void *vs) | |||
1766 | s->L = L = 0; | 1804 | s->L = L = 0; |
1767 | 1805 | ||
1768 | lane_cleanup( s); | 1806 | lane_cleanup( s); |
1769 | |||
1770 | } | 1807 | } |
1771 | else | 1808 | else |
1772 | { | 1809 | { |
@@ -1809,10 +1846,10 @@ static THREAD_RETURN_T THREAD_CALLCONV lane_main( void *vs) | |||
1809 | 1846 | ||
1810 | // helper function to require a module in the keeper states and in the target state | 1847 | // helper function to require a module in the keeper states and in the target state |
1811 | // source state contains module name at the top of the stack | 1848 | // source state contains module name at the top of the stack |
1812 | static void require_one_module( lua_State*L, lua_State*L2, bool_t _fatal) | 1849 | static void require_one_module( lua_State* L, lua_State* L2, bool_t _fatal) |
1813 | { | 1850 | { |
1814 | size_t len; | 1851 | size_t len; |
1815 | char const *name = lua_tolstring( L, -1, &len); | 1852 | char const* name = lua_tolstring( L, -1, &len); |
1816 | // require the module in the target lane | 1853 | // require the module in the target lane |
1817 | STACK_GROW( L2, 2); | 1854 | STACK_GROW( L2, 2); |
1818 | lua_getglobal( L2, "require"); | 1855 | lua_getglobal( L2, "require"); |
@@ -1872,39 +1909,11 @@ LUAG_FUNC( thread_new ) | |||
1872 | 1909 | ||
1873 | ASSERT_L( lua_gettop(L2) == 0); | 1910 | ASSERT_L( lua_gettop(L2) == 0); |
1874 | 1911 | ||
1875 | // package.path | 1912 | // package |
1876 | STACK_CHECK(L) | ||
1877 | STACK_CHECK(L2) | ||
1878 | if( package) | 1913 | if( package) |
1879 | { | 1914 | { |
1880 | if( lua_type( L, package) != LUA_TTABLE) | 1915 | luaG_inter_copy_package( L, L2, package); |
1881 | { | ||
1882 | return luaL_error( L, "expected package as table, got %s", luaL_typename( L, package)); | ||
1883 | } | ||
1884 | lua_getglobal( L2, "package"); | ||
1885 | if( !lua_isnil( L2, -1)) // package library not loaded: do nothing | ||
1886 | { | ||
1887 | int i; | ||
1888 | // package.loaders is renamed package.searchers in Lua 5.2 | ||
1889 | char const* entries[] = { "path", "cpath", "preload", (LUA_VERSION_NUM == 501) ? "loaders" : "searchers", NULL}; | ||
1890 | for( i = 0; entries[i]; ++ i) | ||
1891 | { | ||
1892 | lua_getfield( L, package, entries[i]); | ||
1893 | if( lua_isnil( L, -1)) | ||
1894 | { | ||
1895 | lua_pop( L, 1); | ||
1896 | } | ||
1897 | else | ||
1898 | { | ||
1899 | luaG_inter_move( L, L2, 1); // moves the entry to L2 | ||
1900 | lua_setfield( L2, -2, entries[i]); // set package[entries[i]] | ||
1901 | } | ||
1902 | } | ||
1903 | } | ||
1904 | lua_pop( L2, 1); | ||
1905 | } | 1916 | } |
1906 | STACK_END(L2,0) | ||
1907 | STACK_END(L,0) | ||
1908 | 1917 | ||
1909 | // modules to require in the target lane *before* the function is transfered! | 1918 | // modules to require in the target lane *before* the function is transfered! |
1910 | 1919 | ||
@@ -1924,14 +1933,14 @@ LUAG_FUNC( thread_new ) | |||
1924 | { | 1933 | { |
1925 | int nbRequired = 1; | 1934 | int nbRequired = 1; |
1926 | // should not happen, was checked in lanes.lua before calling thread_new() | 1935 | // should not happen, was checked in lanes.lua before calling thread_new() |
1927 | if (lua_type(L, required) != LUA_TTABLE) | 1936 | if( lua_type( L, required) != LUA_TTABLE) |
1928 | { | 1937 | { |
1929 | return luaL_error( L, "expected required module list as a table, got %s", luaL_typename( L, required)); | 1938 | return luaL_error( L, "expected required module list as a table, got %s", luaL_typename( L, required)); |
1930 | } | 1939 | } |
1931 | lua_pushnil( L); | 1940 | lua_pushnil( L); |
1932 | while( lua_next( L, required) != 0) | 1941 | while( lua_next( L, required) != 0) |
1933 | { | 1942 | { |
1934 | if (lua_type(L,-1) != LUA_TSTRING || lua_type(L,-2) != LUA_TNUMBER || lua_tonumber( L, -2) != nbRequired) | 1943 | if( lua_type( L, -1) != LUA_TSTRING || lua_type( L, -2) != LUA_TNUMBER || lua_tonumber( L, -2) != nbRequired) |
1935 | { | 1944 | { |
1936 | return luaL_error( L, "required module list should be a list of strings"); | 1945 | return luaL_error( L, "required module list should be a list of strings"); |
1937 | } | 1946 | } |
@@ -1949,13 +1958,13 @@ LUAG_FUNC( thread_new ) | |||
1949 | // Appending the specified globals to the global environment | 1958 | // Appending the specified globals to the global environment |
1950 | // *after* stdlibs have been loaded and modules required, in case we transfer references to native functions they exposed... | 1959 | // *after* stdlibs have been loaded and modules required, in case we transfer references to native functions they exposed... |
1951 | // | 1960 | // |
1952 | if (glob!=0) | 1961 | if( glob != 0) |
1953 | { | 1962 | { |
1954 | STACK_CHECK(L) | 1963 | STACK_CHECK(L) |
1955 | STACK_CHECK(L2) | 1964 | STACK_CHECK(L2) |
1956 | if( !lua_istable( L, glob)) | 1965 | if( !lua_istable( L, glob)) |
1957 | { | 1966 | { |
1958 | return luaL_error( L, "Expected table, got %s", luaL_typename(L,glob)); | 1967 | return luaL_error( L, "Expected table, got %s", luaL_typename( L, glob)); |
1959 | } | 1968 | } |
1960 | 1969 | ||
1961 | lua_pushnil( L); | 1970 | lua_pushnil( L); |
@@ -1987,7 +1996,7 @@ LUAG_FUNC( thread_new ) | |||
1987 | } | 1996 | } |
1988 | STACK_MID(L,0) | 1997 | STACK_MID(L,0) |
1989 | } | 1998 | } |
1990 | else if( lua_type(L, 1) == LUA_TSTRING) | 1999 | else if( lua_type( L, 1) == LUA_TSTRING) |
1991 | { | 2000 | { |
1992 | // compile the string | 2001 | // compile the string |
1993 | if( luaL_loadstring( L2, lua_tostring( L, 1)) != 0) | 2002 | if( luaL_loadstring( L2, lua_tostring( L, 1)) != 0) |
@@ -2089,7 +2098,7 @@ LUAG_FUNC( thread_gc) | |||
2089 | // Make sure a kill has proceeded, before cleaning up the data structure. | 2098 | // Make sure a kill has proceeded, before cleaning up the data structure. |
2090 | // | 2099 | // |
2091 | // NO lua_close() in this case because we don't know where execution of the state was interrupted | 2100 | // NO lua_close() in this case because we don't know where execution of the state was interrupted |
2092 | DEBUGEXEC(fprintf( stderr, "** Joining with a killed thread (needs testing) **" )); | 2101 | DEBUGSPEW_CODE( fprintf( stderr, "** Joining with a killed thread (needs testing) **")); |
2093 | // make sure the thread is no longer running, just like thread_join() | 2102 | // make sure the thread is no longer running, just like thread_join() |
2094 | if(! THREAD_ISNULL( s->thread)) | 2103 | if(! THREAD_ISNULL( s->thread)) |
2095 | THREAD_WAIT( &s->thread, -1, &s->done_signal, &s->done_lock, &s->status); | 2104 | THREAD_WAIT( &s->thread, -1, &s->done_signal, &s->done_lock, &s->status); |
@@ -2100,7 +2109,7 @@ LUAG_FUNC( thread_gc) | |||
2100 | lua_close( s->L); | 2109 | lua_close( s->L); |
2101 | s->L = 0; | 2110 | s->L = 0; |
2102 | } | 2111 | } |
2103 | DEBUGEXEC(fprintf( stderr, "** Joined ok **" )); | 2112 | DEBUGSPEW_CODE( fprintf( stderr, "** Joined ok **")); |
2104 | } | 2113 | } |
2105 | else if( s->status < DONE) | 2114 | else if( s->status < DONE) |
2106 | { | 2115 | { |
@@ -2265,7 +2274,7 @@ LUAG_FUNC( thread_join) | |||
2265 | break; | 2274 | break; |
2266 | 2275 | ||
2267 | default: | 2276 | default: |
2268 | DEBUGEXEC(fprintf( stderr, "Status: %d\n", s->status)); | 2277 | DEBUGSPEW_CODE( fprintf( stderr, "Status: %d\n", s->status)); |
2269 | ASSERT_L( FALSE ); ret= 0; | 2278 | ASSERT_L( FALSE ); ret= 0; |
2270 | } | 2279 | } |
2271 | lua_close( L2); | 2280 | lua_close( L2); |
@@ -2547,9 +2556,9 @@ static const struct luaL_Reg lanes_functions [] = { | |||
2547 | /* | 2556 | /* |
2548 | * One-time initializations | 2557 | * One-time initializations |
2549 | */ | 2558 | */ |
2550 | static void init_once_LOCKED( lua_State* L, volatile DEEP_PRELUDE** timer_deep_ref, int const nbKeepers, lua_CFunction _on_state_create, lua_Number _shutdown_timeout, bool_t _track_lanes) | 2559 | static void init_once_LOCKED( lua_State* L, int const nbKeepers, lua_CFunction _on_state_create, lua_Number _shutdown_timeout, bool_t _track_lanes) |
2551 | { | 2560 | { |
2552 | const char *err; | 2561 | char const* err; |
2553 | 2562 | ||
2554 | #if (defined PLATFORM_WIN32) || (defined PLATFORM_POCKETPC) | 2563 | #if (defined PLATFORM_WIN32) || (defined PLATFORM_POCKETPC) |
2555 | now_secs(); // initialize 'now_secs()' internal offset | 2564 | now_secs(); // initialize 'now_secs()' internal offset |
@@ -2604,7 +2613,7 @@ static void init_once_LOCKED( lua_State* L, volatile DEEP_PRELUDE** timer_deep_r | |||
2604 | } | 2613 | } |
2605 | #endif | 2614 | #endif |
2606 | #endif | 2615 | #endif |
2607 | err = init_keepers( nbKeepers, _on_state_create); | 2616 | err = init_keepers( L, nbKeepers, _on_state_create); |
2608 | if (err) | 2617 | if (err) |
2609 | { | 2618 | { |
2610 | (void) luaL_error( L, "Unable to initialize: %s", err ); | 2619 | (void) luaL_error( L, "Unable to initialize: %s", err ); |
@@ -2612,7 +2621,7 @@ static void init_once_LOCKED( lua_State* L, volatile DEEP_PRELUDE** timer_deep_r | |||
2612 | 2621 | ||
2613 | // Initialize 'timer_deep'; a common Linda object shared by all states | 2622 | // Initialize 'timer_deep'; a common Linda object shared by all states |
2614 | // | 2623 | // |
2615 | ASSERT_L( timer_deep_ref && (!(*timer_deep_ref)) ); | 2624 | ASSERT_L( timer_deep == NULL); |
2616 | 2625 | ||
2617 | STACK_CHECK(L) | 2626 | STACK_CHECK(L) |
2618 | { | 2627 | { |
@@ -2627,8 +2636,8 @@ static void init_once_LOCKED( lua_State* L, volatile DEEP_PRELUDE** timer_deep_r | |||
2627 | 2636 | ||
2628 | // Proxy userdata contents is only a 'DEEP_PRELUDE*' pointer | 2637 | // Proxy userdata contents is only a 'DEEP_PRELUDE*' pointer |
2629 | // | 2638 | // |
2630 | *timer_deep_ref= * (DEEP_PRELUDE**) lua_touserdata( L, -1 ); | 2639 | timer_deep = * (DEEP_PRELUDE**) lua_touserdata( L, -1); |
2631 | ASSERT_L( (*timer_deep_ref) && (*timer_deep_ref)->refcount==1 && (*timer_deep_ref)->deep ); | 2640 | ASSERT_L( timer_deep && (timer_deep->refcount == 1) && timer_deep->deep); |
2632 | 2641 | ||
2633 | // The host Lua state must always have a reference to this Linda object in order for our 'timer_deep_ref' to be valid. | 2642 | // The host Lua state must always have a reference to this Linda object in order for our 'timer_deep_ref' to be valid. |
2634 | // So store a reference that we will never actually use. | 2643 | // So store a reference that we will never actually use. |
@@ -2644,8 +2653,8 @@ static void init_once_LOCKED( lua_State* L, volatile DEEP_PRELUDE** timer_deep_r | |||
2644 | lua_setfield( L, -2, "__metatable"); | 2653 | lua_setfield( L, -2, "__metatable"); |
2645 | lua_setmetatable( L, -2); | 2654 | lua_setmetatable( L, -2); |
2646 | } | 2655 | } |
2647 | lua_insert(L, -2); // Swap key with the Linda object | 2656 | lua_insert( L, -2); // Swap key with the Linda object |
2648 | lua_rawset(L, LUA_REGISTRYINDEX); | 2657 | lua_rawset( L, LUA_REGISTRYINDEX); |
2649 | 2658 | ||
2650 | } | 2659 | } |
2651 | STACK_END(L,0) | 2660 | STACK_END(L,0) |
@@ -2653,107 +2662,147 @@ static void init_once_LOCKED( lua_State* L, volatile DEEP_PRELUDE** timer_deep_r | |||
2653 | 2662 | ||
2654 | static volatile long s_initCount = 0; | 2663 | static volatile long s_initCount = 0; |
2655 | 2664 | ||
2656 | LUAG_FUNC( configure ) | 2665 | // upvalue 1: module name |
2666 | // upvalue 2: module table | ||
2667 | LUAG_FUNC( configure) | ||
2657 | { | 2668 | { |
2658 | char const* name = luaL_checkstring( L, lua_upvalueindex( 1)); | 2669 | char const* name = luaL_checkstring( L, lua_upvalueindex( 1)); |
2659 | // all parameter checks are done lua-side | 2670 | // all parameter checks are done lua-side |
2660 | int const nbKeepers = (int)lua_tointeger( L, 1); | 2671 | int const nbKeepers = (int)lua_tointeger( L, 1); |
2661 | lua_CFunction on_state_create = lua_iscfunction( L, 2) ? lua_tocfunction( L, 2) : NULL; | 2672 | lua_CFunction on_state_create = lua_iscfunction( L, 2) ? lua_tocfunction( L, 2) : NULL; |
2662 | lua_Number shutdown_timeout = lua_tonumber( L, 3); | 2673 | lua_Number shutdown_timeout = lua_tonumber( L, 3); |
2663 | bool_t track_lanes = lua_toboolean( L, 4); | 2674 | bool_t track_lanes = lua_toboolean( L, 4); |
2664 | /* | 2675 | |
2665 | * Making one-time initializations. | 2676 | STACK_CHECK( L) |
2666 | * | 2677 | // Create main module interface table |
2667 | * When the host application is single-threaded (and all threading happens via Lanes) | 2678 | lua_pushvalue( L, lua_upvalueindex( 2)); // ... M |
2668 | * there is no problem. But if the host is multithreaded, we need to lock around the | 2679 | // remove configure() (this function) from the module interface |
2669 | * initializations. | 2680 | lua_pushnil( L); // ... M nil |
2670 | */ | 2681 | lua_setfield( L, -2, "configure"); // ... M |
2682 | // add functions to the module's table | ||
2683 | luaG_registerlibfuncs( L, lanes_functions); | ||
2684 | STACK_MID( L, 1) | ||
2685 | |||
2686 | // metatable for threads | ||
2687 | // contains keys: { __gc, __index, cached_error, cached_tostring, cancel, join } | ||
2688 | // | ||
2689 | lua_newtable( L); // ... M mt | ||
2690 | lua_pushcfunction( L, LG_thread_gc); // ... M mt LG_thread_gc | ||
2691 | lua_setfield( L, -2, "__gc"); // ... M mt | ||
2692 | lua_pushcfunction( L, LG_thread_index); // ... M mt LG_thread_index | ||
2693 | lua_setfield( L, -2, "__index"); // ... M mt | ||
2694 | lua_getglobal( L, "error"); // ... M mt error | ||
2695 | ASSERT_L( lua_isfunction( L, -1)); | ||
2696 | lua_setfield( L, -2, "cached_error"); // ... M mt | ||
2697 | lua_getglobal( L, "tostring"); // ... M mt tostring | ||
2698 | ASSERT_L( lua_isfunction( L, -1)); | ||
2699 | lua_setfield( L, -2, "cached_tostring"); // ... M mt | ||
2700 | lua_pushcfunction( L, LG_thread_join); // ... M mt LG_thread_join | ||
2701 | lua_setfield( L, -2, "join"); // ... M mt | ||
2702 | lua_pushcfunction( L, LG_thread_cancel); // ... M mt LG_thread_cancel | ||
2703 | lua_setfield( L, -2, "cancel"); // ... M mt | ||
2704 | lua_pushliteral( L, "Lane"); // ... M mt "Lane" | ||
2705 | lua_setfield( L, -2, "__metatable"); // ... M mt | ||
2706 | |||
2707 | lua_pushcclosure( L, LG_thread_new, 1); // ... M LG_thread_new | ||
2708 | lua_setfield(L, -2, "thread_new"); // ... M | ||
2709 | |||
2710 | lua_pushstring(L, VERSION); // ... M VERSION | ||
2711 | lua_setfield(L, -2, "version"); // ... M | ||
2712 | |||
2713 | lua_pushinteger(L, THREAD_PRIO_MAX); // ... M THREAD_PRIO_MAX | ||
2714 | lua_setfield(L, -2, "max_prio"); // ... M | ||
2715 | |||
2716 | lua_pushlightuserdata( L, CANCEL_ERROR); // ... M CANCEL_ERROR | ||
2717 | lua_setfield(L, -2, "cancel_error"); // ... M | ||
2718 | |||
2719 | // register all native functions found in that module in the transferable functions database | ||
2720 | // we process it before _G because we don't want to find the module when scanning _G (this would generate longer names) | ||
2721 | // for example in package.loaded.lanes.core.* | ||
2722 | populate_func_lookup_table( L, -1, name); | ||
2723 | |||
2724 | // record all existing C/JIT-fast functions | ||
2725 | // Lua 5.2 no longer has LUA_GLOBALSINDEX: we must push globals table on the stack | ||
2726 | lua_pushglobaltable( L); // ... M _G | ||
2727 | populate_func_lookup_table( L, -1, NULL); | ||
2728 | lua_pop( L, 1); // ... M | ||
2729 | |||
2730 | STACK_MID( L, 1) | ||
2731 | /* | ||
2732 | * Making one-time initializations. | ||
2733 | * | ||
2734 | * When the host application is single-threaded (and all threading happens via Lanes) | ||
2735 | * there is no problem. But if the host is multithreaded, we need to lock around the | ||
2736 | * initializations. | ||
2737 | * | ||
2738 | * we must do this after the populate_func_lookup_table is called, else populating the keepers will fail | ||
2739 | * because this makes a copy of packages.loaders, which requires the lookup tables to exist! | ||
2740 | */ | ||
2671 | #if THREADAPI == THREADAPI_WINDOWS | 2741 | #if THREADAPI == THREADAPI_WINDOWS |
2672 | { | 2742 | { |
2673 | static volatile int /*bool*/ go_ahead; // = 0 | 2743 | static volatile int /*bool*/ go_ahead; // = 0 |
2674 | if( InterlockedCompareExchange( &s_initCount, 1, 0) == 0) | 2744 | if( InterlockedCompareExchange( &s_initCount, 1, 0) == 0) |
2675 | { | 2745 | { |
2676 | init_once_LOCKED( L, &timer_deep, nbKeepers, on_state_create, shutdown_timeout, track_lanes); | 2746 | init_once_LOCKED( L, nbKeepers, on_state_create, shutdown_timeout, track_lanes); |
2677 | go_ahead= 1; // let others pass | 2747 | go_ahead = 1; // let others pass |
2678 | } | 2748 | } |
2679 | else | 2749 | else |
2680 | { | 2750 | { |
2681 | while( !go_ahead ) { Sleep(1); } // changes threads | 2751 | while( !go_ahead ) { Sleep(1); } // changes threads |
2682 | } | 2752 | } |
2683 | } | 2753 | } |
2684 | #else // THREADAPI == THREADAPI_PTHREAD | 2754 | #else // THREADAPI == THREADAPI_PTHREAD |
2685 | if( s_initCount == 0) | 2755 | if( s_initCount == 0) |
2686 | { | 2756 | { |
2687 | static pthread_mutex_t my_lock= PTHREAD_MUTEX_INITIALIZER; | 2757 | static pthread_mutex_t my_lock = PTHREAD_MUTEX_INITIALIZER; |
2688 | pthread_mutex_lock( &my_lock); | 2758 | pthread_mutex_lock( &my_lock); |
2689 | { | 2759 | { |
2690 | // Recheck now that we're within the lock | 2760 | // Recheck now that we're within the lock |
2691 | // | 2761 | // |
2692 | if( s_initCount == 0) | 2762 | if( s_initCount == 0) |
2693 | { | 2763 | { |
2694 | init_once_LOCKED( L, &timer_deep, nbKeepers, on_state_create, shutdown_timeout, track_lanes); | 2764 | init_once_LOCKED( L, nbKeepers, on_state_create, shutdown_timeout, track_lanes); |
2695 | s_initCount = 1; | 2765 | s_initCount = 1; |
2696 | } | 2766 | } |
2697 | } | 2767 | } |
2698 | pthread_mutex_unlock(&my_lock); | 2768 | pthread_mutex_unlock( &my_lock); |
2699 | } | 2769 | } |
2700 | #endif // THREADAPI == THREADAPI_PTHREAD | 2770 | #endif // THREADAPI == THREADAPI_PTHREAD |
2701 | assert( timer_deep != 0 ); | 2771 | assert( timer_deep != NULL); |
2702 | 2772 | STACK_MID( L, 1) | |
2703 | // Create main module interface table | 2773 | |
2704 | lua_pushvalue( L, lua_upvalueindex( 2)); | 2774 | // init_once_LOCKED initializes timer_deep, so we must do this after, of course |
2705 | // remove configure() (this function) from the module interface | 2775 | luaG_push_proxy( L, linda_id, (DEEP_PRELUDE*) timer_deep); // ... M timer_deep |
2706 | lua_pushnil( L); | 2776 | lua_setfield( L, -2, "timer_gateway"); // ... M |
2707 | lua_setfield( L, -2, "configure"); | 2777 | |
2708 | // add functions to the module's table | 2778 | lua_pop( L, 1); // ... |
2709 | luaG_registerlibfuncs(L, lanes_functions); | 2779 | STACK_END( L, 0) |
2710 | 2780 | // Return nothing | |
2711 | // metatable for threads | 2781 | return 0; |
2712 | // contains keys: { __gc, __index, cached_error, cached_tostring, cancel, join } | 2782 | } |
2713 | // | 2783 | |
2714 | lua_newtable( L); | 2784 | // helper to have correct callstacks when crashing a Win32 running on 64 bits Windows |
2715 | lua_pushcfunction( L, LG_thread_gc); | 2785 | // don't forget to toggle Debug/Exceptions/Win32 in visual Studio too! |
2716 | lua_setfield( L, -2, "__gc"); | 2786 | void EnableCrashingOnCrashes() |
2717 | lua_pushcfunction( L, LG_thread_index); | 2787 | { |
2718 | lua_setfield( L, -2, "__index"); | 2788 | #if 0 && defined PLATFORM_WIN32 |
2719 | lua_getglobal( L, "error"); | 2789 | typedef BOOL (WINAPI *tGetPolicy)(LPDWORD lpFlags); |
2720 | ASSERT_L( lua_isfunction( L, -1)); | 2790 | typedef BOOL (WINAPI *tSetPolicy)(DWORD dwFlags); |
2721 | lua_setfield( L, -2, "cached_error"); | 2791 | const DWORD EXCEPTION_SWALLOWING = 0x1; |
2722 | lua_getglobal( L, "tostring"); | 2792 | |
2723 | ASSERT_L( lua_isfunction( L, -1)); | 2793 | HMODULE kernel32 = LoadLibraryA("kernel32.dll"); |
2724 | lua_setfield( L, -2, "cached_tostring"); | 2794 | tGetPolicy pGetPolicy = (tGetPolicy)GetProcAddress(kernel32, "GetProcessUserModeExceptionPolicy"); |
2725 | lua_pushcfunction( L, LG_thread_join); | 2795 | tSetPolicy pSetPolicy = (tSetPolicy)GetProcAddress(kernel32, "SetProcessUserModeExceptionPolicy"); |
2726 | lua_setfield( L, -2, "join"); | 2796 | if (pGetPolicy && pSetPolicy) |
2727 | lua_pushcfunction( L, LG_thread_cancel); | 2797 | { |
2728 | lua_setfield( L, -2, "cancel"); | 2798 | DWORD dwFlags; |
2729 | lua_pushliteral( L, "Lane"); | 2799 | if (pGetPolicy(&dwFlags)) |
2730 | lua_setfield( L, -2, "__metatable"); | 2800 | { |
2731 | 2801 | // Turn off the filter | |
2732 | lua_pushcclosure( L, LG_thread_new, 1 ); // metatable as closure param | 2802 | pSetPolicy(dwFlags & ~EXCEPTION_SWALLOWING); |
2733 | lua_setfield(L, -2, "thread_new"); | 2803 | } |
2734 | 2804 | } | |
2735 | luaG_push_proxy( L, linda_id, (DEEP_PRELUDE *) timer_deep ); | 2805 | #endif // PLATFORM_WIN32 |
2736 | lua_setfield(L, -2, "timer_gateway"); | ||
2737 | |||
2738 | lua_pushstring(L, VERSION); | ||
2739 | lua_setfield(L, -2, "version"); | ||
2740 | |||
2741 | lua_pushinteger(L, THREAD_PRIO_MAX); | ||
2742 | lua_setfield(L, -2, "max_prio"); | ||
2743 | |||
2744 | lua_pushlightuserdata( L, CANCEL_ERROR ); | ||
2745 | lua_setfield(L, -2, "cancel_error"); | ||
2746 | |||
2747 | // register all native functions found in that module in the transferable functions database | ||
2748 | // we process it before _G because we don't want to find the module when scanning _G (this would generate longer names) | ||
2749 | populate_func_lookup_table( L, -1, name); | ||
2750 | lua_pop( L, 1); | ||
2751 | // record all existing C/JIT-fast functions | ||
2752 | lua_pushglobaltable( L); // Lua 5.2 no longer has LUA_GLOBALSINDEX: we must push globals table on the stack | ||
2753 | populate_func_lookup_table( L, -1, NULL); | ||
2754 | lua_pop( L, 1); // done with globals table, pop it | ||
2755 | // Return nothing | ||
2756 | return 0; | ||
2757 | } | 2806 | } |
2758 | 2807 | ||
2759 | int | 2808 | int |
@@ -2762,6 +2811,8 @@ __declspec(dllexport) | |||
2762 | #endif // (defined PLATFORM_WIN32) || (defined PLATFORM_POCKETPC) | 2811 | #endif // (defined PLATFORM_WIN32) || (defined PLATFORM_POCKETPC) |
2763 | luaopen_lanes_core( lua_State* L) | 2812 | luaopen_lanes_core( lua_State* L) |
2764 | { | 2813 | { |
2814 | EnableCrashingOnCrashes(); | ||
2815 | |||
2765 | STACK_GROW( L, 3); | 2816 | STACK_GROW( L, 3); |
2766 | STACK_CHECK( L) | 2817 | STACK_CHECK( L) |
2767 | 2818 | ||