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 ); |