diff options
| author | Benoit Germain <bnt.germain@gmail.com> | 2011-02-12 17:06:03 +0100 |
|---|---|---|
| committer | Benoit Germain <bnt.germain@gmail.com> | 2011-02-12 17:06:03 +0100 |
| commit | a661736f7984292a41d71847de68590f6b8ca08a (patch) | |
| tree | 43e0799c20e835f1cc2d8c5fa1324b64301763e0 /src | |
| parent | c91a03bd956bf19848253bded8217687ccd2ad81 (diff) | |
| download | lanes-a661736f7984292a41d71847de68590f6b8ca08a.tar.gz lanes-a661736f7984292a41d71847de68590f6b8ca08a.tar.bz2 lanes-a661736f7984292a41d71847de68590f6b8ca08a.zip | |
Changed idfunc signature and contract to clarify that fact it is not lua-callable and to be able to require the module it was exported from in the target lanes.
Diffstat (limited to 'src')
| -rw-r--r-- | src/lanes.c | 102 | ||||
| -rw-r--r-- | src/lanes.lua | 12 | ||||
| -rw-r--r-- | src/tools.c | 170 | ||||
| -rw-r--r-- | src/tools.h | 8 |
4 files changed, 163 insertions, 129 deletions
diff --git a/src/lanes.c b/src/lanes.c index f4bef7b..16a8edc 100644 --- a/src/lanes.c +++ b/src/lanes.c | |||
| @@ -64,7 +64,7 @@ | |||
| 64 | * ... | 64 | * ... |
| 65 | */ | 65 | */ |
| 66 | 66 | ||
| 67 | const char *VERSION= "2.0.10"; | 67 | const char *VERSION= "2.0.11"; |
| 68 | 68 | ||
| 69 | /* | 69 | /* |
| 70 | =============================================================================== | 70 | =============================================================================== |
| @@ -359,7 +359,8 @@ static const char *init_keepers(void) { | |||
| 359 | lua_State *L= luaL_newstate(); | 359 | lua_State *L= luaL_newstate(); |
| 360 | if (!L) return "out of memory"; | 360 | if (!L) return "out of memory"; |
| 361 | 361 | ||
| 362 | luaG_openlibs( L, "io,table" ); // 'io' for debugging messages | 362 | luaG_openlibs( L, "io,table,package" ); // 'io' for debugging messages, package because we need to require modules exporting idfuncs |
| 363 | serialize_require( L); | ||
| 363 | 364 | ||
| 364 | lua_pushlightuserdata( L, &nil_sentinel ); | 365 | lua_pushlightuserdata( L, &nil_sentinel ); |
| 365 | lua_setglobal( L, "nil_sentinel" ); | 366 | lua_setglobal( L, "nil_sentinel" ); |
| @@ -449,9 +450,9 @@ struct s_Linda { | |||
| 449 | SIGNAL_T write_happened; | 450 | SIGNAL_T write_happened; |
| 450 | }; | 451 | }; |
| 451 | 452 | ||
| 452 | static int LG_linda_id( lua_State* ); | 453 | static void linda_id( lua_State*, char const * const which); |
| 453 | 454 | ||
| 454 | #define lua_toLinda(L,n) ((struct s_Linda *)luaG_todeep( L, LG_linda_id, n )) | 455 | #define lua_toLinda(L,n) ((struct s_Linda *)luaG_todeep( L, linda_id, n )) |
| 455 | 456 | ||
| 456 | 457 | ||
| 457 | /* | 458 | /* |
| @@ -462,7 +463,8 @@ static int LG_linda_id( lua_State* ); | |||
| 462 | * Returns: 'true' if the value was queued | 463 | * Returns: 'true' if the value was queued |
| 463 | * 'false' for timeout (only happens when the queue size is limited) | 464 | * 'false' for timeout (only happens when the queue size is limited) |
| 464 | */ | 465 | */ |
| 465 | LUAG_FUNC( linda_send ) { | 466 | LUAG_FUNC( linda_send ) |
| 467 | { | ||
| 466 | struct s_Linda *linda= lua_toLinda( L, 1 ); | 468 | struct s_Linda *linda= lua_toLinda( L, 1 ); |
| 467 | bool_t ret; | 469 | bool_t ret; |
| 468 | bool_t cancel= FALSE; | 470 | bool_t cancel= FALSE; |
| @@ -750,21 +752,22 @@ LUAG_FUNC( linda_deep ) { | |||
| 750 | * Returns a metatable for the proxy objects ('__gc' method not needed; will | 752 | * Returns a metatable for the proxy objects ('__gc' method not needed; will |
| 751 | * be added by 'luaG_...') | 753 | * be added by 'luaG_...') |
| 752 | * | 754 | * |
| 755 | * string= linda_id( "module") | ||
| 756 | * | ||
| 757 | * Returns the name of the module that a state should require | ||
| 758 | * in order to keep a handle on the shared library that exported the idfunc | ||
| 759 | * | ||
| 753 | * = linda_id( str, ... ) | 760 | * = linda_id( str, ... ) |
| 754 | * | 761 | * |
| 755 | * For any other strings, the ID function must not react at all. This allows | 762 | * For any other strings, the ID function must not react at all. This allows |
| 756 | * future extensions of the system. | 763 | * future extensions of the system. |
| 757 | */ | 764 | */ |
| 758 | LUAG_FUNC( linda_id ) { | 765 | static void linda_id( lua_State *L, char const * const which) |
| 759 | const char *which= lua_tostring(L,1); | 766 | { |
| 760 | 767 | if (strcmp( which, "new" )==0) | |
| 761 | if (strcmp( which, "new" )==0) { | 768 | { |
| 762 | struct s_Linda *s; | 769 | struct s_Linda *s; |
| 763 | 770 | ||
| 764 | /* We don't use any parameters, but one could (they're at [2..TOS]) | ||
| 765 | */ | ||
| 766 | ASSERT_L( lua_gettop(L)==1 ); | ||
| 767 | |||
| 768 | /* The deep data is allocated separately of Lua stack; we might no | 771 | /* The deep data is allocated separately of Lua stack; we might no |
| 769 | * longer be around when last reference to it is being released. | 772 | * longer be around when last reference to it is being released. |
| 770 | * One can use any memory allocation scheme. | 773 | * One can use any memory allocation scheme. |
| @@ -776,11 +779,11 @@ LUAG_FUNC( linda_id ) { | |||
| 776 | SIGNAL_INIT( &s->write_happened ); | 779 | SIGNAL_INIT( &s->write_happened ); |
| 777 | 780 | ||
| 778 | lua_pushlightuserdata( L, s ); | 781 | lua_pushlightuserdata( L, s ); |
| 779 | return 1; | 782 | } |
| 780 | 783 | else if (strcmp( which, "delete" )==0) | |
| 781 | } else if (strcmp( which, "delete" )==0) { | 784 | { |
| 782 | struct s_Keeper *K; | 785 | struct s_Keeper *K; |
| 783 | struct s_Linda *s= lua_touserdata(L,2); | 786 | struct s_Linda *s= lua_touserdata(L,1); |
| 784 | ASSERT_L(s); | 787 | ASSERT_L(s); |
| 785 | 788 | ||
| 786 | /* Clean associated structures in the keeper state. | 789 | /* Clean associated structures in the keeper state. |
| @@ -797,18 +800,20 @@ LUAG_FUNC( linda_id ) { | |||
| 797 | SIGNAL_FREE( &s->read_happened ); | 800 | SIGNAL_FREE( &s->read_happened ); |
| 798 | SIGNAL_FREE( &s->write_happened ); | 801 | SIGNAL_FREE( &s->write_happened ); |
| 799 | free(s); | 802 | free(s); |
| 803 | } | ||
| 804 | else if (strcmp( which, "metatable" )==0) | ||
| 805 | { | ||
| 800 | 806 | ||
| 801 | return 0; | 807 | STACK_CHECK(L) |
| 802 | |||
| 803 | } else if (strcmp( which, "metatable" )==0) { | ||
| 804 | |||
| 805 | STACK_CHECK(L) | ||
| 806 | lua_newtable(L); | 808 | lua_newtable(L); |
| 807 | lua_newtable(L); | 809 | // metatable is its own index |
| 808 | // | 810 | lua_pushvalue( L, -1); |
| 809 | // [-2]: linda metatable | 811 | lua_setfield( L, -2, "__index"); |
| 810 | // [-1]: metatable's to-be .__index table | 812 | // protect metatable from external access |
| 811 | 813 | lua_pushboolean( L, 0); | |
| 814 | lua_setfield( L, -2, "__metatable"); | ||
| 815 | // | ||
| 816 | // [-1]: linda metatable | ||
| 812 | lua_pushcfunction( L, LG_linda_send ); | 817 | lua_pushcfunction( L, LG_linda_send ); |
| 813 | lua_setfield( L, -2, "send" ); | 818 | lua_setfield( L, -2, "send" ); |
| 814 | 819 | ||
| @@ -827,13 +832,17 @@ LUAG_FUNC( linda_id ) { | |||
| 827 | lua_pushcfunction( L, LG_linda_deep ); | 832 | lua_pushcfunction( L, LG_linda_deep ); |
| 828 | lua_setfield( L, -2, "deep" ); | 833 | lua_setfield( L, -2, "deep" ); |
| 829 | 834 | ||
| 830 | lua_setfield( L, -2, "__index" ); | 835 | STACK_END(L,1) |
| 831 | STACK_END(L,1) | ||
| 832 | |||
| 833 | return 1; | ||
| 834 | } | 836 | } |
| 835 | 837 | else if( strcmp( which, "module") == 0) | |
| 836 | return 0; // unknown request, be quiet | 838 | { |
| 839 | lua_pushliteral( L, "lua51-lanes"); | ||
| 840 | } | ||
| 841 | } | ||
| 842 | |||
| 843 | LUAG_FUNC( linda) | ||
| 844 | { | ||
| 845 | return luaG_deep_userdata( L, linda_id); | ||
| 837 | } | 846 | } |
| 838 | 847 | ||
| 839 | 848 | ||
| @@ -1014,8 +1023,10 @@ static void selfdestruct_atexit( void ) { | |||
| 1014 | MUTEX_UNLOCK( &selfdestruct_cs ); | 1023 | MUTEX_UNLOCK( &selfdestruct_cs ); |
| 1015 | 1024 | ||
| 1016 | // Tell the timer thread to check it's cancel request | 1025 | // Tell the timer thread to check it's cancel request |
| 1017 | struct s_Linda *td = timer_deep->deep; | 1026 | { |
| 1018 | SIGNAL_ALL( &td->write_happened); | 1027 | struct s_Linda *td = timer_deep->deep; |
| 1028 | SIGNAL_ALL( &td->write_happened); | ||
| 1029 | } | ||
| 1019 | 1030 | ||
| 1020 | // When noticing their cancel, the lanes will remove themselves from | 1031 | // When noticing their cancel, the lanes will remove themselves from |
| 1021 | // the selfdestruct chain. | 1032 | // the selfdestruct chain. |
| @@ -1855,21 +1866,21 @@ LUAG_FUNC( wakeup_conv ) | |||
| 1855 | */ | 1866 | */ |
| 1856 | 1867 | ||
| 1857 | static const struct luaL_reg lanes_functions [] = { | 1868 | static const struct luaL_reg lanes_functions [] = { |
| 1858 | {"linda_id", LG_linda_id}, | 1869 | {"linda", LG_linda}, |
| 1859 | {"thread_status", LG_thread_status}, | 1870 | {"thread_status", LG_thread_status}, |
| 1860 | {"thread_join", LG_thread_join}, | 1871 | {"thread_join", LG_thread_join}, |
| 1861 | {"thread_cancel", LG_thread_cancel}, | 1872 | {"thread_cancel", LG_thread_cancel}, |
| 1862 | {"now_secs", LG_now_secs}, | 1873 | {"now_secs", LG_now_secs}, |
| 1863 | {"wakeup_conv", LG_wakeup_conv}, | 1874 | {"wakeup_conv", LG_wakeup_conv}, |
| 1864 | {"_single", LG__single}, | 1875 | {"_single", LG__single}, |
| 1865 | {"_deep_userdata", luaG_deep_userdata}, | ||
| 1866 | {NULL, NULL} | 1876 | {NULL, NULL} |
| 1867 | }; | 1877 | }; |
| 1868 | 1878 | ||
| 1869 | /* | 1879 | /* |
| 1870 | * One-time initializations | 1880 | * One-time initializations |
| 1871 | */ | 1881 | */ |
| 1872 | static void init_once_LOCKED( lua_State *L, volatile DEEP_PRELUDE ** timer_deep_ref ) { | 1882 | static void init_once_LOCKED( lua_State *L, volatile DEEP_PRELUDE ** timer_deep_ref ) |
| 1883 | { | ||
| 1873 | const char *err; | 1884 | const char *err; |
| 1874 | 1885 | ||
| 1875 | #if (defined PLATFORM_WIN32) || (defined PLATFORM_POCKETPC) | 1886 | #if (defined PLATFORM_WIN32) || (defined PLATFORM_POCKETPC) |
| @@ -1919,8 +1930,9 @@ static void init_once_LOCKED( lua_State *L, volatile DEEP_PRELUDE ** timer_deep_ | |||
| 1919 | } | 1930 | } |
| 1920 | #endif | 1931 | #endif |
| 1921 | #endif | 1932 | #endif |
| 1922 | err= init_keepers(); | 1933 | err= init_keepers(); |
| 1923 | if (err) { | 1934 | if (err) |
| 1935 | { | ||
| 1924 | luaL_error( L, "Unable to initialize: %s", err ); | 1936 | luaL_error( L, "Unable to initialize: %s", err ); |
| 1925 | } | 1937 | } |
| 1926 | 1938 | ||
| @@ -1928,13 +1940,11 @@ static void init_once_LOCKED( lua_State *L, volatile DEEP_PRELUDE ** timer_deep_ | |||
| 1928 | // | 1940 | // |
| 1929 | ASSERT_L( timer_deep_ref && (!(*timer_deep_ref)) ); | 1941 | ASSERT_L( timer_deep_ref && (!(*timer_deep_ref)) ); |
| 1930 | 1942 | ||
| 1931 | STACK_CHECK(L) | 1943 | STACK_CHECK(L) |
| 1932 | { | 1944 | { |
| 1933 | // proxy_ud= deep_userdata( idfunc ) | 1945 | // proxy_ud= deep_userdata( idfunc ) |
| 1934 | // | 1946 | // |
| 1935 | lua_pushcfunction( L, luaG_deep_userdata ); | 1947 | luaG_deep_userdata( L, linda_id); |
| 1936 | lua_pushcfunction( L, LG_linda_id ); | ||
| 1937 | lua_call( L, 1 /*args*/, 1 /*retvals*/ ); | ||
| 1938 | 1948 | ||
| 1939 | ASSERT_L( lua_isuserdata(L,-1) ); | 1949 | ASSERT_L( lua_isuserdata(L,-1) ); |
| 1940 | 1950 | ||
| @@ -1950,7 +1960,7 @@ static void init_once_LOCKED( lua_State *L, volatile DEEP_PRELUDE ** timer_deep_ | |||
| 1950 | lua_rawset(L, LUA_REGISTRYINDEX); | 1960 | lua_rawset(L, LUA_REGISTRYINDEX); |
| 1951 | 1961 | ||
| 1952 | } | 1962 | } |
| 1953 | STACK_END(L,0) | 1963 | STACK_END(L,0) |
| 1954 | } | 1964 | } |
| 1955 | 1965 | ||
| 1956 | int | 1966 | int |
| @@ -2014,7 +2024,7 @@ __declspec(dllexport) | |||
| 2014 | lua_pushcclosure( L, LG_thread_new, 1 ); // metatable as closure param | 2024 | lua_pushcclosure( L, LG_thread_new, 1 ); // metatable as closure param |
| 2015 | lua_setfield(L, -2, "thread_new"); | 2025 | lua_setfield(L, -2, "thread_new"); |
| 2016 | 2026 | ||
| 2017 | luaG_push_proxy( L, LG_linda_id, (DEEP_PRELUDE *) timer_deep ); | 2027 | luaG_push_proxy( L, linda_id, (DEEP_PRELUDE *) timer_deep ); |
| 2018 | lua_setfield(L, -2, "timer_gateway"); | 2028 | lua_setfield(L, -2, "timer_gateway"); |
| 2019 | 2029 | ||
| 2020 | lua_pushstring(L, VERSION); | 2030 | lua_pushstring(L, VERSION); |
diff --git a/src/lanes.lua b/src/lanes.lua index 42e946b..b6fbc08 100644 --- a/src/lanes.lua +++ b/src/lanes.lua | |||
| @@ -45,8 +45,6 @@ local mm = require "lua51-lanes" | |||
| 45 | assert( type(mm)=="table" ) | 45 | assert( type(mm)=="table" ) |
| 46 | 46 | ||
| 47 | 47 | ||
| 48 | local linda_id= assert( mm.linda_id ) | ||
| 49 | |||
| 50 | local thread_new= assert(mm.thread_new) | 48 | local thread_new= assert(mm.thread_new) |
| 51 | local thread_status= assert(mm.thread_status) | 49 | local thread_status= assert(mm.thread_status) |
| 52 | local thread_join= assert(mm.thread_join) | 50 | local thread_join= assert(mm.thread_join) |
| @@ -55,8 +53,6 @@ local thread_cancel= assert(mm.thread_cancel) | |||
| 55 | local _single= assert(mm._single) | 53 | local _single= assert(mm._single) |
| 56 | local _version= assert(mm._version) | 54 | local _version= assert(mm._version) |
| 57 | 55 | ||
| 58 | local _deep_userdata= assert(mm._deep_userdata) | ||
| 59 | |||
| 60 | local now_secs= assert( mm.now_secs ) | 56 | local now_secs= assert( mm.now_secs ) |
| 61 | local wakeup_conv= assert( mm.wakeup_conv ) | 57 | local wakeup_conv= assert( mm.wakeup_conv ) |
| 62 | local timer_gateway= assert( mm.timer_gateway ) | 58 | local timer_gateway= assert( mm.timer_gateway ) |
| @@ -336,11 +332,7 @@ end | |||
| 336 | ----- | 332 | ----- |
| 337 | -- linda_ud= lanes.linda() | 333 | -- linda_ud= lanes.linda() |
| 338 | -- | 334 | -- |
| 339 | function linda() | 335 | linda = mm.linda |
| 340 | local proxy= _deep_userdata( linda_id ) | ||
| 341 | assert( (type(proxy) == "userdata") and getmetatable(proxy) ) | ||
| 342 | return proxy | ||
| 343 | end | ||
| 344 | 336 | ||
| 345 | 337 | ||
| 346 | ---=== Timers ===--- | 338 | ---=== Timers ===--- |
| @@ -505,7 +497,7 @@ if first_time then | |||
| 505 | -- We let the timer lane be a "free running" thread; no handle to it | 497 | -- We let the timer lane be a "free running" thread; no handle to it |
| 506 | -- remains. | 498 | -- remains. |
| 507 | -- | 499 | -- |
| 508 | gen( "io", { priority=max_prio, globals={threadName="LanesTimer"} }, function() | 500 | gen( "io,package", { priority=max_prio, globals={threadName="LanesTimer"} }, function() |
| 509 | 501 | ||
| 510 | while true do | 502 | while true do |
| 511 | local next_wakeup= check_timers() | 503 | local next_wakeup= check_timers() |
diff --git a/src/tools.c b/src/tools.c index 6692890..d09b11e 100644 --- a/src/tools.c +++ b/src/tools.c | |||
| @@ -280,26 +280,27 @@ void get_deep_lookup( lua_State *L ) { | |||
| 280 | * or NULL if 'index' is not a deep userdata proxy. | 280 | * or NULL if 'index' is not a deep userdata proxy. |
| 281 | */ | 281 | */ |
| 282 | static | 282 | static |
| 283 | lua_CFunction get_idfunc( lua_State *L, int index ) { | 283 | luaG_IdFunction get_idfunc( lua_State *L, int index ) |
| 284 | lua_CFunction ret; | 284 | { |
| 285 | luaG_IdFunction ret; | ||
| 285 | 286 | ||
| 286 | index= STACK_ABS(L,index); | 287 | index= STACK_ABS(L,index); |
| 287 | 288 | ||
| 288 | STACK_GROW(L,1); | 289 | STACK_GROW(L,1); |
| 289 | 290 | ||
| 290 | STACK_CHECK(L) | 291 | STACK_CHECK(L) |
| 291 | if (!lua_getmetatable( L, index )) | 292 | if (!lua_getmetatable( L, index )) |
| 292 | return NULL; // no metatable | 293 | return NULL; // no metatable |
| 293 | 294 | ||
| 294 | // [-1]: metatable of [index] | 295 | // [-1]: metatable of [index] |
| 295 | 296 | ||
| 296 | get_deep_lookup(L); | 297 | get_deep_lookup(L); |
| 297 | // | 298 | // |
| 298 | // [-1]: idfunc/nil | 299 | // [-1]: idfunc/nil |
| 299 | 300 | ||
| 300 | ret= lua_tocfunction(L,-1); | 301 | ret= (luaG_IdFunction)lua_touserdata(L,-1); |
| 301 | lua_pop(L,1); | 302 | lua_pop(L,1); |
| 302 | STACK_END(L,0) | 303 | STACK_END(L,0) |
| 303 | return ret; | 304 | return ret; |
| 304 | } | 305 | } |
| 305 | 306 | ||
| @@ -311,7 +312,8 @@ lua_CFunction get_idfunc( lua_State *L, int index ) { | |||
| 311 | * it up if reaches 0. | 312 | * it up if reaches 0. |
| 312 | */ | 313 | */ |
| 313 | static | 314 | static |
| 314 | int deep_userdata_gc( lua_State *L ) { | 315 | int deep_userdata_gc( lua_State *L ) |
| 316 | { | ||
| 315 | DEEP_PRELUDE **proxy= (DEEP_PRELUDE**)lua_touserdata( L, 1 ); | 317 | DEEP_PRELUDE **proxy= (DEEP_PRELUDE**)lua_touserdata( L, 1 ); |
| 316 | DEEP_PRELUDE *p= *proxy; | 318 | DEEP_PRELUDE *p= *proxy; |
| 317 | int v; | 319 | int v; |
| @@ -319,27 +321,26 @@ int deep_userdata_gc( lua_State *L ) { | |||
| 319 | *proxy= 0; // make sure we don't use it any more | 321 | *proxy= 0; // make sure we don't use it any more |
| 320 | 322 | ||
| 321 | MUTEX_LOCK( &deep_lock ); | 323 | MUTEX_LOCK( &deep_lock ); |
| 322 | v= --(p->refcount); | 324 | v= --(p->refcount); |
| 323 | MUTEX_UNLOCK( &deep_lock ); | 325 | MUTEX_UNLOCK( &deep_lock ); |
| 324 | 326 | ||
| 325 | if (v==0) { | 327 | if (v==0) |
| 326 | int pushed; | 328 | { |
| 327 | |||
| 328 | // Call 'idfunc( "delete", deep_ptr )' to make deep cleanup | 329 | // Call 'idfunc( "delete", deep_ptr )' to make deep cleanup |
| 329 | // | 330 | // |
| 330 | lua_CFunction idfunc= get_idfunc(L,1); | 331 | luaG_IdFunction idfunc = get_idfunc(L,1); |
| 331 | ASSERT_L(idfunc); | 332 | ASSERT_L(idfunc); |
| 332 | 333 | ||
| 333 | lua_settop(L,0); // clean stack so we can call 'idfunc' directly | 334 | lua_settop( L, 0); // clean stack so we can call 'idfunc' directly |
| 334 | 335 | ||
| 335 | // void= idfunc( "delete", lightuserdata ) | 336 | // void= idfunc( "delete", lightuserdata ) |
| 336 | // | 337 | // |
| 337 | lua_pushliteral( L, "delete" ); | ||
| 338 | lua_pushlightuserdata( L, p->deep ); | 338 | lua_pushlightuserdata( L, p->deep ); |
| 339 | pushed= idfunc(L); | 339 | idfunc( L, "delete"); |
| 340 | 340 | ||
| 341 | if (pushed) | 341 | // top was set to 0, then userdata was pushed. "delete" might want to pop the userdata (we don't care), but should not push anything! |
| 342 | luaL_error( L, "Bad idfunc on \"delete\": returned something" ); | 342 | if ( lua_gettop( L) > 1) |
| 343 | luaL_error( L, "Bad idfunc on \"delete\": returned something"); | ||
| 343 | 344 | ||
| 344 | DEEP_FREE( (void*)p ); | 345 | DEEP_FREE( (void*)p ); |
| 345 | } | 346 | } |
| @@ -354,28 +355,31 @@ int deep_userdata_gc( lua_State *L ) { | |||
| 354 | * used in this Lua state (metatable, registring it). Otherwise, increments the | 355 | * used in this Lua state (metatable, registring it). Otherwise, increments the |
| 355 | * reference count. | 356 | * reference count. |
| 356 | */ | 357 | */ |
| 357 | void luaG_push_proxy( lua_State *L, lua_CFunction idfunc, DEEP_PRELUDE *prelude ) { | 358 | void luaG_push_proxy( lua_State *L, luaG_IdFunction idfunc, DEEP_PRELUDE *prelude ) |
| 359 | { | ||
| 358 | DEEP_PRELUDE **proxy; | 360 | DEEP_PRELUDE **proxy; |
| 359 | 361 | ||
| 360 | // Check if a proxy already exists | 362 | // Check if a proxy already exists |
| 361 | push_registry_subtable_mode(L, DEEP_PROXY_CACHE_KEY, "v"); | 363 | push_registry_subtable_mode(L, DEEP_PROXY_CACHE_KEY, "v"); |
| 362 | lua_pushlightuserdata(L, prelude->deep); | 364 | lua_pushlightuserdata(L, prelude->deep); |
| 363 | lua_rawget(L, -2); | 365 | lua_rawget(L, -2); |
| 364 | if (!lua_isnil(L, -1)) { | 366 | if (!lua_isnil(L, -1)) |
| 367 | { | ||
| 365 | lua_remove(L, -2); // deep proxy cache table | 368 | lua_remove(L, -2); // deep proxy cache table |
| 366 | return; | 369 | return; |
| 367 | } else { | 370 | } |
| 371 | else | ||
| 372 | { | ||
| 368 | lua_pop(L, 2); // Pop the nil and proxy cache table | 373 | lua_pop(L, 2); // Pop the nil and proxy cache table |
| 369 | } | 374 | } |
| 370 | 375 | ||
| 371 | |||
| 372 | MUTEX_LOCK( &deep_lock ); | 376 | MUTEX_LOCK( &deep_lock ); |
| 373 | ++(prelude->refcount); // one more proxy pointing to this deep data | 377 | ++(prelude->refcount); // one more proxy pointing to this deep data |
| 374 | MUTEX_UNLOCK( &deep_lock ); | 378 | MUTEX_UNLOCK( &deep_lock ); |
| 375 | 379 | ||
| 376 | STACK_GROW(L,4); | 380 | STACK_GROW(L,4); |
| 377 | 381 | ||
| 378 | STACK_CHECK(L) | 382 | STACK_CHECK(L) |
| 379 | 383 | ||
| 380 | proxy= lua_newuserdata( L, sizeof( DEEP_PRELUDE* ) ); | 384 | proxy= lua_newuserdata( L, sizeof( DEEP_PRELUDE* ) ); |
| 381 | ASSERT_L(proxy); | 385 | ASSERT_L(proxy); |
| @@ -383,28 +387,32 @@ void luaG_push_proxy( lua_State *L, lua_CFunction idfunc, DEEP_PRELUDE *prelude | |||
| 383 | 387 | ||
| 384 | // Get/create metatable for 'idfunc' (in this state) | 388 | // Get/create metatable for 'idfunc' (in this state) |
| 385 | // | 389 | // |
| 386 | lua_pushcfunction( L, idfunc ); // key | 390 | lua_pushlightuserdata( L, idfunc ); // key |
| 387 | get_deep_lookup(L); | 391 | get_deep_lookup(L); |
| 388 | // | 392 | // |
| 389 | // [-2]: proxy | 393 | // [-2]: proxy |
| 390 | // [-1]: metatable / nil | 394 | // [-1]: metatable / nil |
| 391 | 395 | ||
| 392 | if (lua_isnil(L,-1)) { | 396 | if (lua_isnil(L,-1)) |
| 393 | // No metatable yet; make one and register it | 397 | { |
| 394 | // | 398 | int oldtop; |
| 399 | // No metatable yet. We have two things to do: | ||
| 400 | |||
| 401 | // 1 - make one and register it | ||
| 395 | lua_pop(L,1); | 402 | lua_pop(L,1); |
| 396 | 403 | ||
| 397 | // tbl= idfunc( "metatable" ) | 404 | // tbl= idfunc( "metatable" ) |
| 398 | // | 405 | // |
| 399 | lua_pushcfunction( L, idfunc ); | 406 | oldtop = lua_gettop( L); |
| 400 | lua_pushliteral( L, "metatable" ); | 407 | idfunc( L, "metatable"); |
| 401 | lua_call( L, 1 /*args*/, 1 /*results*/ ); | 408 | // |
| 402 | // | 409 | // [-2]: proxy |
| 403 | // [-2]: proxy | 410 | // [-1]: metatable (returned by 'idfunc') |
| 404 | // [-1]: metatable (returned by 'idfunc') | ||
| 405 | 411 | ||
| 406 | if (!lua_istable(L,-1)) | 412 | if (lua_gettop( L) - oldtop != 1 || !lua_istable(L, -1)) |
| 413 | { | ||
| 407 | luaL_error( L, "Bad idfunc on \"metatable\": did not return one" ); | 414 | luaL_error( L, "Bad idfunc on \"metatable\": did not return one" ); |
| 415 | } | ||
| 408 | 416 | ||
| 409 | // Add '__gc' method | 417 | // Add '__gc' method |
| 410 | // | 418 | // |
| @@ -414,16 +422,40 @@ void luaG_push_proxy( lua_State *L, lua_CFunction idfunc, DEEP_PRELUDE *prelude | |||
| 414 | // Memorize for later rounds | 422 | // Memorize for later rounds |
| 415 | // | 423 | // |
| 416 | lua_pushvalue( L,-1 ); | 424 | lua_pushvalue( L,-1 ); |
| 417 | lua_pushcfunction( L, idfunc ); | 425 | lua_pushlightuserdata( L, idfunc ); |
| 418 | // | 426 | // |
| 419 | // [-4]: proxy | 427 | // [-4]: proxy |
| 420 | // [-3]: metatable (2nd ref) | 428 | // [-3]: metatable (2nd ref) |
| 421 | // [-2]: metatable | 429 | // [-2]: metatable |
| 422 | // [-1]: idfunc | 430 | // [-1]: idfunc |
| 423 | 431 | ||
| 424 | set_deep_lookup(L); | 432 | set_deep_lookup(L); |
| 425 | } | 433 | |
| 426 | STACK_MID(L,2) | 434 | // 2 - cause the target state to require the module that exported the idfunc |
| 435 | // this is needed because we must make sure the shared library is still loaded as long as we hold a pointer on the idfunc | ||
| 436 | lua_getglobal( L, "require"); | ||
| 437 | if( lua_isfunction( L, -1)) // just in case... | ||
| 438 | { | ||
| 439 | // make sure the function pushed a single value on the stack! | ||
| 440 | int oldtop = lua_gettop( L); | ||
| 441 | idfunc( L, "module"); | ||
| 442 | if( lua_gettop( L) - oldtop != 1 || !lua_isstring( L, -1)) | ||
| 443 | { | ||
| 444 | luaL_error( L, "Bad idfunc on \"module\": should return a string"); | ||
| 445 | } | ||
| 446 | // if we are inside a call to require, this will raise a "reentrency" error that we absorb silently (we don't care, this probably means the module is already being required, which is what we need) | ||
| 447 | if( lua_pcall( L, 1, 0, 0) != 0) | ||
| 448 | { | ||
| 449 | //char const * const errMsg = lua_tostring( L, -1); // just to see it in the debugger | ||
| 450 | lua_pop( L, 1); | ||
| 451 | } | ||
| 452 | } | ||
| 453 | else | ||
| 454 | { | ||
| 455 | lua_pop( L, 1); | ||
| 456 | } | ||
| 457 | } | ||
| 458 | STACK_MID(L,2) | ||
| 427 | ASSERT_L( lua_isuserdata(L,-2) ); | 459 | ASSERT_L( lua_isuserdata(L,-2) ); |
| 428 | ASSERT_L( lua_istable(L,-1) ); | 460 | ASSERT_L( lua_istable(L,-1) ); |
| 429 | 461 | ||
| @@ -439,7 +471,7 @@ void luaG_push_proxy( lua_State *L, lua_CFunction idfunc, DEEP_PRELUDE *prelude | |||
| 439 | lua_rawset(L, -3); | 471 | lua_rawset(L, -3); |
| 440 | lua_pop(L, 1); // Remove the cache proxy table | 472 | lua_pop(L, 1); // Remove the cache proxy table |
| 441 | 473 | ||
| 442 | STACK_END(L,1) | 474 | STACK_END(L,1) |
| 443 | // [-1]: proxy userdata | 475 | // [-1]: proxy userdata |
| 444 | } | 476 | } |
| 445 | 477 | ||
| @@ -466,9 +498,9 @@ void luaG_push_proxy( lua_State *L, lua_CFunction idfunc, DEEP_PRELUDE *prelude | |||
| 466 | * | 498 | * |
| 467 | * Returns: 'proxy' userdata for accessing the deep data via 'luaG_todeep()' | 499 | * Returns: 'proxy' userdata for accessing the deep data via 'luaG_todeep()' |
| 468 | */ | 500 | */ |
| 469 | int luaG_deep_userdata( lua_State *L ) { | 501 | int luaG_deep_userdata( lua_State *L, luaG_IdFunction idfunc) |
| 470 | lua_CFunction idfunc= lua_tocfunction( L,1 ); | 502 | { |
| 471 | int pushed; | 503 | int oldtop; |
| 472 | 504 | ||
| 473 | DEEP_PRELUDE *prelude= DEEP_MALLOC( sizeof(DEEP_PRELUDE) ); | 505 | DEEP_PRELUDE *prelude= DEEP_MALLOC( sizeof(DEEP_PRELUDE) ); |
| 474 | ASSERT_L(prelude); | 506 | ASSERT_L(prelude); |
| @@ -476,20 +508,17 @@ int luaG_deep_userdata( lua_State *L ) { | |||
| 476 | prelude->refcount= 0; // 'luaG_push_proxy' will lift it to 1 | 508 | prelude->refcount= 0; // 'luaG_push_proxy' will lift it to 1 |
| 477 | 509 | ||
| 478 | STACK_GROW(L,1); | 510 | STACK_GROW(L,1); |
| 479 | STACK_CHECK(L) | 511 | STACK_CHECK(L) |
| 480 | |||
| 481 | // Replace 'idfunc' with "new" in the stack (keep possible other params) | ||
| 482 | // | ||
| 483 | lua_remove(L,1); | ||
| 484 | lua_pushliteral( L, "new" ); | ||
| 485 | lua_insert(L,1); | ||
| 486 | 512 | ||
| 487 | // lightuserdata= idfunc( "new" [, ...] ) | 513 | // lightuserdata= idfunc( "new" [, ...] ) |
| 488 | // | 514 | // |
| 489 | pushed= idfunc(L); | 515 | oldtop = lua_gettop( L); |
| 516 | idfunc(L, "new"); | ||
| 490 | 517 | ||
| 491 | if ((pushed!=1) || lua_type(L,-1) != LUA_TLIGHTUSERDATA) | 518 | if( lua_gettop( L) - oldtop != 1 || lua_type( L, -1) != LUA_TLIGHTUSERDATA) |
| 492 | luaL_error( L, "Bad idfunc on \"new\": did not return light userdata" ); | 519 | { |
| 520 | luaL_error( L, "Bad idfunc on \"new\": did not return light userdata"); | ||
| 521 | } | ||
| 493 | 522 | ||
| 494 | prelude->deep= lua_touserdata(L,-1); | 523 | prelude->deep= lua_touserdata(L,-1); |
| 495 | ASSERT_L(prelude->deep); | 524 | ASSERT_L(prelude->deep); |
| @@ -497,10 +526,10 @@ int luaG_deep_userdata( lua_State *L ) { | |||
| 497 | lua_pop(L,1); // pop deep data | 526 | lua_pop(L,1); // pop deep data |
| 498 | 527 | ||
| 499 | luaG_push_proxy( L, idfunc, prelude ); | 528 | luaG_push_proxy( L, idfunc, prelude ); |
| 500 | // | 529 | // |
| 501 | // [-1]: proxy userdata | 530 | // [-1]: proxy userdata |
| 502 | 531 | ||
| 503 | STACK_END(L,1) | 532 | STACK_END(L,1) |
| 504 | return 1; | 533 | return 1; |
| 505 | } | 534 | } |
| 506 | 535 | ||
| @@ -511,15 +540,16 @@ int luaG_deep_userdata( lua_State *L ) { | |||
| 511 | * Reference count is not changed, and access to the deep userdata is not | 540 | * Reference count is not changed, and access to the deep userdata is not |
| 512 | * serialized. It is the module's responsibility to prevent conflicting usage. | 541 | * serialized. It is the module's responsibility to prevent conflicting usage. |
| 513 | */ | 542 | */ |
| 514 | void *luaG_todeep( lua_State *L, lua_CFunction idfunc, int index ) { | 543 | void *luaG_todeep( lua_State *L, luaG_IdFunction idfunc, int index ) |
| 544 | { | ||
| 515 | DEEP_PRELUDE **proxy; | 545 | DEEP_PRELUDE **proxy; |
| 516 | 546 | ||
| 517 | STACK_CHECK(L) | 547 | STACK_CHECK(L) |
| 518 | if (get_idfunc(L,index) != idfunc) | 548 | if( get_idfunc(L,index) != idfunc) |
| 519 | return NULL; // no metatable, or wrong kind | 549 | return NULL; // no metatable, or wrong kind |
| 520 | 550 | ||
| 521 | proxy= (DEEP_PRELUDE**)lua_touserdata( L, index ); | 551 | proxy= (DEEP_PRELUDE**)lua_touserdata( L, index ); |
| 522 | STACK_END(L,0) | 552 | STACK_END(L,0) |
| 523 | 553 | ||
| 524 | return (*proxy)->deep; | 554 | return (*proxy)->deep; |
| 525 | } | 555 | } |
| @@ -533,14 +563,14 @@ void *luaG_todeep( lua_State *L, lua_CFunction idfunc, int index ) { | |||
| 533 | * (not copied) | 563 | * (not copied) |
| 534 | */ | 564 | */ |
| 535 | static | 565 | static |
| 536 | lua_CFunction luaG_copydeep( lua_State *L, lua_State *L2, int index ) { | 566 | luaG_IdFunction luaG_copydeep( lua_State *L, lua_State *L2, int index ) |
| 567 | { | ||
| 537 | DEEP_PRELUDE **proxy; | 568 | DEEP_PRELUDE **proxy; |
| 538 | DEEP_PRELUDE *p; | 569 | DEEP_PRELUDE *p; |
| 539 | 570 | ||
| 540 | lua_CFunction idfunc; | 571 | luaG_IdFunction idfunc = get_idfunc( L, index); |
| 541 | 572 | if (!idfunc) | |
| 542 | idfunc= get_idfunc( L, index ); | 573 | return NULL; // not a deep userdata |
| 543 | if (!idfunc) return NULL; // not a deep userdata | ||
| 544 | 574 | ||
| 545 | // Increment reference count | 575 | // Increment reference count |
| 546 | // | 576 | // |
diff --git a/src/tools.h b/src/tools.h index aad26df..05bee59 100644 --- a/src/tools.h +++ b/src/tools.h | |||
| @@ -48,19 +48,21 @@ | |||
| 48 | 48 | ||
| 49 | #define luaG_typename( L, index ) lua_typename( L, lua_type(L,index) ) | 49 | #define luaG_typename( L, index ) lua_typename( L, lua_type(L,index) ) |
| 50 | 50 | ||
| 51 | typedef void (*luaG_IdFunction)( lua_State *L, char const * const which); | ||
| 52 | |||
| 51 | void luaG_dump( lua_State* L ); | 53 | void luaG_dump( lua_State* L ); |
| 52 | 54 | ||
| 53 | const char *luaG_openlibs( lua_State *L, const char *libs ); | 55 | const char *luaG_openlibs( lua_State *L, const char *libs ); |
| 54 | 56 | ||
| 55 | int luaG_deep_userdata( lua_State *L ); | 57 | int luaG_deep_userdata( lua_State *L, luaG_IdFunction idfunc); |
| 56 | void *luaG_todeep( lua_State *L, lua_CFunction idfunc, int index ); | 58 | void *luaG_todeep( lua_State *L, luaG_IdFunction idfunc, int index ); |
| 57 | 59 | ||
| 58 | typedef struct { | 60 | typedef struct { |
| 59 | volatile int refcount; | 61 | volatile int refcount; |
| 60 | void *deep; | 62 | void *deep; |
| 61 | } DEEP_PRELUDE; | 63 | } DEEP_PRELUDE; |
| 62 | 64 | ||
| 63 | void luaG_push_proxy( lua_State *L, lua_CFunction idfunc, DEEP_PRELUDE *deep_userdata ); | 65 | void luaG_push_proxy( lua_State *L, luaG_IdFunction idfunc, DEEP_PRELUDE *deep_userdata ); |
| 64 | 66 | ||
| 65 | void luaG_inter_copy( lua_State *L, lua_State *L2, uint_t n ); | 67 | void luaG_inter_copy( lua_State *L, lua_State *L2, uint_t n ); |
| 66 | void luaG_inter_move( lua_State *L, lua_State *L2, uint_t n ); | 68 | void luaG_inter_move( lua_State *L, lua_State *L2, uint_t n ); |
