diff options
author | Benoit Germain <bnt.germain@gmail.com> | 2018-11-15 11:20:14 +0100 |
---|---|---|
committer | Benoit Germain <bnt.germain@gmail.com> | 2018-11-15 11:20:14 +0100 |
commit | 01f83215a2ad235fbf306f591c6c0547b1bb7047 (patch) | |
tree | 51d1edff1c3f684bac388c64d91ee30d8f6fbbf2 | |
parent | 55acf8e19728ac39581c35f1324debf9449bd185 (diff) | |
download | lanes-01f83215a2ad235fbf306f591c6c0547b1bb7047.tar.gz lanes-01f83215a2ad235fbf306f591c6c0547b1bb7047.tar.bz2 lanes-01f83215a2ad235fbf306f591c6c0547b1bb7047.zip |
Deep userdata must embed DeepPrelude to save an allocation (also changes Deep protocol)
-rw-r--r-- | CHANGES | 3 | ||||
-rw-r--r-- | deep_test/deep_test.c | 3 | ||||
-rw-r--r-- | docs/index.html | 18 | ||||
-rw-r--r-- | src/deep.c | 66 | ||||
-rw-r--r-- | src/deep.h | 12 | ||||
-rw-r--r-- | src/keeper.c | 2 | ||||
-rw-r--r-- | src/lanes.c | 6 | ||||
-rw-r--r-- | src/lanes_private.h | 2 | ||||
-rw-r--r-- | src/linda.c | 5 |
9 files changed, 56 insertions, 61 deletions
@@ -1,5 +1,8 @@ | |||
1 | CHANGES: | 1 | CHANGES: |
2 | 2 | ||
3 | CHANGE 137: BGe 15-Nov-18 | ||
4 | * Deep userdata must embed DeepPrelude to save an allocation (also changes Deep protocol) | ||
5 | |||
3 | CHANGE 136: BGe 15-Nov-18 | 6 | CHANGE 136: BGe 15-Nov-18 |
4 | * split linda code in a separate file | 7 | * split linda code in a separate file |
5 | * rockspec for version v3.13.0 | 8 | * rockspec for version v3.13.0 |
diff --git a/deep_test/deep_test.c b/deep_test/deep_test.c index 4aac586..7edd33f 100644 --- a/deep_test/deep_test.c +++ b/deep_test/deep_test.c | |||
@@ -17,6 +17,7 @@ | |||
17 | 17 | ||
18 | struct s_MyDeepUserdata | 18 | struct s_MyDeepUserdata |
19 | { | 19 | { |
20 | DeepPrelude prelude; // Deep userdata MUST start with this header | ||
20 | lua_Integer val; | 21 | lua_Integer val; |
21 | }; | 22 | }; |
22 | static void* deep_test_id( lua_State* L, enum eDeepOp op_); | 23 | static void* deep_test_id( lua_State* L, enum eDeepOp op_); |
@@ -67,6 +68,7 @@ static void* deep_test_id( lua_State* L, enum eDeepOp op_) | |||
67 | case eDO_new: | 68 | case eDO_new: |
68 | { | 69 | { |
69 | struct s_MyDeepUserdata* deep_test = (struct s_MyDeepUserdata*) malloc( sizeof(struct s_MyDeepUserdata)); | 70 | struct s_MyDeepUserdata* deep_test = (struct s_MyDeepUserdata*) malloc( sizeof(struct s_MyDeepUserdata)); |
71 | deep_test->prelude.magic.value = DEEP_VERSION.value; | ||
70 | deep_test->val = 0; | 72 | deep_test->val = 0; |
71 | return deep_test; | 73 | return deep_test; |
72 | } | 74 | } |
@@ -81,7 +83,6 @@ static void* deep_test_id( lua_State* L, enum eDeepOp op_) | |||
81 | case eDO_metatable: | 83 | case eDO_metatable: |
82 | { | 84 | { |
83 | luaL_getmetatable( L, "deep"); // mt | 85 | luaL_getmetatable( L, "deep"); // mt |
84 | luaG_pushdeepversion( L); // mt version | ||
85 | return NULL; | 86 | return NULL; |
86 | } | 87 | } |
87 | 88 | ||
diff --git a/docs/index.html b/docs/index.html index ddb9ed3..723766d 100644 --- a/docs/index.html +++ b/docs/index.html | |||
@@ -1607,9 +1607,9 @@ int luaD_new_clonable( lua_State* L) | |||
1607 | <table border="1" bgcolor="#E0E0FF" cellpadding="10" style="width:50%"><tr><td><pre> void* idfunc( lua_State* L, DeepOp op_);</pre></td></tr></table> | 1607 | <table border="1" bgcolor="#E0E0FF" cellpadding="10" style="width:50%"><tr><td><pre> void* idfunc( lua_State* L, DeepOp op_);</pre></td></tr></table> |
1608 | <tt>op_</tt> can be one of: | 1608 | <tt>op_</tt> can be one of: |
1609 | <ul> | 1609 | <ul> |
1610 | <li><tt>eDO_new</tt>: requests the creation of a new object, whose pointer is returned.</li> | 1610 | <li><tt>eDO_new</tt>: requests the creation of a new object, whose pointer is returned. Starting with version 3.13.0, object should embed <tt>DeepPrelude</tt> structure as header and initialize its <tt>magic</tt> member with the current <tt>DEEP_VERSION</tt>.</li> |
1611 | <li><tt>eDO_delete</tt>: receives this same pointer on the stack as a light userdata, and should cleanup the object.</li> | 1611 | <li><tt>eDO_delete</tt>: receives this same pointer on the stack as a light userdata, and should cleanup the object.</li> |
1612 | <li><tt>eDO_metatable</tt>: should build a metatable for the object. Don't cache the metatable yourself, Lanes takes care of it (<tt>eDO_metatable</tt> should only be invoked once per state). Push the metatable on the stack, then call <tt>luaG_pushdeepversion()</tt> before returning (new in version 3.9.5).</li> | 1612 | <li><tt>eDO_metatable</tt>: should build a metatable for the object. Don't cache the metatable yourself, Lanes takes care of it (<tt>eDO_metatable</tt> should only be invoked once per state). Just push the metatable on the stack.</li> |
1613 | <li><tt>eDO_module</tt>: requests the name of the module that exports the idfunc, to be returned. It is necessary so that Lanes can require it in any lane state that receives a userdata. This is to prevent crashes in situations where the module could be unloaded while the idfunc pointer is still held.</li> | 1613 | <li><tt>eDO_module</tt>: requests the name of the module that exports the idfunc, to be returned. It is necessary so that Lanes can require it in any lane state that receives a userdata. This is to prevent crashes in situations where the module could be unloaded while the idfunc pointer is still held.</li> |
1614 | </ul> | 1614 | </ul> |
1615 | Take a look at <tt>linda_id</tt> in <tt>lanes.c</tt> or <tt>deep_test_id</tt> in <tt>deep_test.c</tt>. | 1615 | Take a look at <tt>linda_id</tt> in <tt>lanes.c</tt> or <tt>deep_test_id</tt> in <tt>deep_test.c</tt>. |
@@ -1624,13 +1624,13 @@ int luaD_new_clonable( lua_State* L) | |||
1624 | </p> | 1624 | </p> |
1625 | 1625 | ||
1626 | <p> | 1626 | <p> |
1627 | Deep userdata in transit inside keeper states (sent in a linda but not yet consumed) don't call <tt>idfunc(eDO_delete)</tt> and aren't considered by reference counting. The rationale is the following: | 1627 | Deep userdata in transit inside keeper states (sent in a linda but not yet consumed) don't call <tt>idfunc(eDO_delete)</tt> and aren't considered by reference counting. The rationale is the following: |
1628 | <br/> | 1628 | <br /> |
1629 | If some non-keeper state holds a deep userdata for some deep object, then even if the keeper collects its own deep userdata, it shouldn't be cleaned up since the refcount is not 0. | 1629 | If some non-keeper state holds a deep userdata for some deep object, then even if the keeper collects its own deep userdata, it shouldn't be cleaned up since the refcount is not 0. |
1630 | <br/> | 1630 | <br /> |
1631 | OTOH, if a keeper state holds the last deep userdata for some deep object, then no lane can do actual work with it. But as it happens, deep userdata are only copied to and from keeper states. Most notably, the object's <tt>idfunc()</tt> is never called from a keeper state. | 1631 | OTOH, if a keeper state holds the last deep userdata for some deep object, then no lane can do actual work with it. Deep userdata's <tt>idfunc()</tt> is never called from a keeper state. |
1632 | <br/> | 1632 | <br /> |
1633 | Therefore, Lanes can just call <tt>idfunc(eDO_delete)</tt> when the last non-keeper-held deep userdata is collected, as long as it doens't do the same in a keeper state after that, since any remaining deep userdata in keeper states now hold stale pointers. | 1633 | Therefore, Lanes can just call <tt>idfunc(eDO_delete)</tt> when the last non-keeper-held deep userdata is collected, as long as it doesn't do the same in a keeper state after that, since any remaining deep userdata in keeper states now hold stale pointers. |
1634 | </p> | 1634 | </p> |
1635 | 1635 | ||
1636 | <p> | 1636 | <p> |
@@ -105,16 +105,6 @@ void push_registry_subtable( lua_State* L, UniqueKey key_) | |||
105 | 105 | ||
106 | /*---=== Deep userdata ===---*/ | 106 | /*---=== Deep userdata ===---*/ |
107 | 107 | ||
108 | void luaG_pushdeepversion( lua_State* L) { (void) lua_pushliteral( L, "ab8743e5-84f8-485d-9c39-008e84656188");} | ||
109 | |||
110 | |||
111 | |||
112 | /* The deep portion must be allocated separately of any Lua state's; it's | ||
113 | * lifespan may be longer than that of the creating state. | ||
114 | */ | ||
115 | #define DEEP_MALLOC malloc | ||
116 | #define DEEP_FREE free | ||
117 | |||
118 | /* | 108 | /* |
119 | * 'registry[REGKEY]' is a two-way lookup table for 'idfunc's and those type's | 109 | * 'registry[REGKEY]' is a two-way lookup table for 'idfunc's and those type's |
120 | * metatables: | 110 | * metatables: |
@@ -211,10 +201,9 @@ static inline luaG_IdFunction get_idfunc( lua_State* L, int index, LookupMode mo | |||
211 | void free_deep_prelude( lua_State* L, DeepPrelude* prelude_) | 201 | void free_deep_prelude( lua_State* L, DeepPrelude* prelude_) |
212 | { | 202 | { |
213 | // Call 'idfunc( "delete", deep_ptr )' to make deep cleanup | 203 | // Call 'idfunc( "delete", deep_ptr )' to make deep cleanup |
214 | lua_pushlightuserdata( L, prelude_->deep); | 204 | lua_pushlightuserdata( L, prelude_); |
215 | ASSERT_L( prelude_->idfunc); | 205 | ASSERT_L( prelude_->idfunc); |
216 | prelude_->idfunc( L, eDO_delete); | 206 | prelude_->idfunc( L, eDO_delete); |
217 | DEEP_FREE( (void*) prelude_); | ||
218 | } | 207 | } |
219 | 208 | ||
220 | 209 | ||
@@ -276,7 +265,7 @@ char const* push_deep_proxy( Universe* U, lua_State* L, DeepPrelude* prelude, Lo | |||
276 | 265 | ||
277 | // Check if a proxy already exists | 266 | // Check if a proxy already exists |
278 | push_registry_subtable_mode( L, DEEP_PROXY_CACHE_KEY, "v"); // DPC | 267 | push_registry_subtable_mode( L, DEEP_PROXY_CACHE_KEY, "v"); // DPC |
279 | lua_pushlightuserdata( L, prelude->deep); // DPC deep | 268 | lua_pushlightuserdata( L, prelude); // DPC deep |
280 | lua_rawget( L, -2); // DPC proxy | 269 | lua_rawget( L, -2); // DPC proxy |
281 | if ( !lua_isnil( L, -1)) | 270 | if ( !lua_isnil( L, -1)) |
282 | { | 271 | { |
@@ -313,20 +302,13 @@ char const* push_deep_proxy( Universe* U, lua_State* L, DeepPrelude* prelude, Lo | |||
313 | // 1 - make one and register it | 302 | // 1 - make one and register it |
314 | if( mode_ != eLM_ToKeeper) | 303 | if( mode_ != eLM_ToKeeper) |
315 | { | 304 | { |
316 | (void) prelude->idfunc( L, eDO_metatable); // DPC proxy metatable deepversion | 305 | (void) prelude->idfunc( L, eDO_metatable); // DPC proxy metatable |
317 | if( lua_gettop( L) - oldtop != 1 || !lua_istable( L, -2) || !lua_isstring( L, -1)) | 306 | if( lua_gettop( L) - oldtop != 0 || !lua_istable( L, -1)) |
318 | { | 307 | { |
319 | lua_settop( L, oldtop); // DPC proxy X | 308 | lua_settop( L, oldtop); // DPC proxy X |
320 | lua_pop( L, 3); // | 309 | lua_pop( L, 3); // |
321 | return "Bad idfunc(eOP_metatable): unexpected pushed value"; | 310 | return "Bad idfunc(eOP_metatable): unexpected pushed value"; |
322 | } | 311 | } |
323 | luaG_pushdeepversion( L); // DPC proxy metatable deepversion deepversion | ||
324 | if( !lua501_equal( L, -1, -2)) | ||
325 | { | ||
326 | lua_pop( L, 5); // | ||
327 | return "Bad idfunc(eOP_metatable): mismatched deep version"; | ||
328 | } | ||
329 | lua_pop( L, 2); // DPC proxy metatable | ||
330 | // if the metatable contains a __gc, we will call it from our own | 312 | // if the metatable contains a __gc, we will call it from our own |
331 | lua_getfield( L, -1, "__gc"); // DPC proxy metatable __gc | 313 | lua_getfield( L, -1, "__gc"); // DPC proxy metatable __gc |
332 | } | 314 | } |
@@ -420,7 +402,7 @@ char const* push_deep_proxy( Universe* U, lua_State* L, DeepPrelude* prelude, Lo | |||
420 | lua_setmetatable( L, -2); // DPC proxy | 402 | lua_setmetatable( L, -2); // DPC proxy |
421 | 403 | ||
422 | // If we're here, we obviously had to create a new proxy, so cache it. | 404 | // If we're here, we obviously had to create a new proxy, so cache it. |
423 | lua_pushlightuserdata( L, (*proxy)->deep); // DPC proxy deep | 405 | lua_pushlightuserdata( L, prelude); // DPC proxy deep |
424 | lua_pushvalue( L, -2); // DPC proxy deep proxy | 406 | lua_pushvalue( L, -2); // DPC proxy deep proxy |
425 | lua_rawset( L, -4); // DPC proxy | 407 | lua_rawset( L, -4); // DPC proxy |
426 | lua_remove( L, -2); // proxy | 408 | lua_remove( L, -2); // proxy |
@@ -454,34 +436,38 @@ char const* push_deep_proxy( Universe* U, lua_State* L, DeepPrelude* prelude, Lo | |||
454 | int luaG_newdeepuserdata( lua_State* L, luaG_IdFunction idfunc) | 436 | int luaG_newdeepuserdata( lua_State* L, luaG_IdFunction idfunc) |
455 | { | 437 | { |
456 | char const* errmsg; | 438 | char const* errmsg; |
457 | DeepPrelude* prelude = DEEP_MALLOC( sizeof( DeepPrelude)); | ||
458 | if( prelude == NULL) | ||
459 | { | ||
460 | return luaL_error( L, "couldn't not allocate deep prelude: out of memory"); | ||
461 | } | ||
462 | |||
463 | prelude->refcount = 0; // 'push_deep_proxy' will lift it to 1 | ||
464 | prelude->idfunc = idfunc; | ||
465 | 439 | ||
466 | STACK_GROW( L, 1); | 440 | STACK_GROW( L, 1); |
467 | STACK_CHECK( L); | 441 | STACK_CHECK( L); |
468 | { | 442 | { |
469 | int oldtop = lua_gettop( L); | 443 | int oldtop = lua_gettop( L); |
470 | prelude->deep = idfunc( L, eDO_new); | 444 | DeepPrelude* prelude = idfunc( L, eDO_new); |
471 | if( prelude->deep == NULL) | 445 | if( prelude == NULL) |
472 | { | 446 | { |
473 | luaL_error( L, "idfunc(eDO_new) failed to create deep userdata (out of memory)"); | 447 | luaL_error( L, "idfunc(eDO_new) failed to create deep userdata (out of memory)"); |
474 | } | 448 | } |
449 | if( prelude->magic.value != DEEP_VERSION.value) | ||
450 | { | ||
451 | // just in case, don't leak the newly allocated deep userdata object | ||
452 | lua_pushlightuserdata( L, prelude); | ||
453 | idfunc( L, eDO_delete); | ||
454 | return luaL_error( L, "Bad idfunc(eDO_new): DEEP_VERSION is incorrect, rebuild your implementation with the latest deep implementation"); | ||
455 | } | ||
456 | prelude->refcount = 0; // 'push_deep_proxy' will lift it to 1 | ||
457 | prelude->idfunc = idfunc; | ||
475 | 458 | ||
476 | if( lua_gettop( L) - oldtop != 0) | 459 | if( lua_gettop( L) - oldtop != 0) |
477 | { | 460 | { |
478 | luaL_error( L, "Bad idfunc(eDO_new): should not push anything on the stack"); | 461 | // just in case, don't leak the newly allocated deep userdata object |
462 | lua_pushlightuserdata( L, prelude); | ||
463 | idfunc( L, eDO_delete); | ||
464 | return luaL_error( L, "Bad idfunc(eDO_new): should not push anything on the stack"); | ||
465 | } | ||
466 | errmsg = push_deep_proxy( universe_get( L), L, prelude, eLM_LaneBody); // proxy | ||
467 | if( errmsg != NULL) | ||
468 | { | ||
469 | return luaL_error( L, errmsg); | ||
479 | } | 470 | } |
480 | } | ||
481 | errmsg = push_deep_proxy( universe_get( L), L, prelude, eLM_LaneBody); // proxy | ||
482 | if( errmsg != NULL) | ||
483 | { | ||
484 | luaL_error( L, errmsg); | ||
485 | } | 471 | } |
486 | STACK_END( L, 1); | 472 | STACK_END( L, 1); |
487 | return 1; | 473 | return 1; |
@@ -508,7 +494,7 @@ void* luaG_todeep( lua_State* L, luaG_IdFunction idfunc, int index) | |||
508 | proxy = (DeepPrelude**) lua_touserdata( L, index); | 494 | proxy = (DeepPrelude**) lua_touserdata( L, index); |
509 | STACK_END( L, 0); | 495 | STACK_END( L, 0); |
510 | 496 | ||
511 | return (*proxy)->deep; | 497 | return *proxy; |
512 | } | 498 | } |
513 | 499 | ||
514 | 500 | ||
@@ -8,6 +8,7 @@ | |||
8 | 8 | ||
9 | #include "lua.h" | 9 | #include "lua.h" |
10 | #include "platform.h" | 10 | #include "platform.h" |
11 | #include "uniquekey.h" | ||
11 | 12 | ||
12 | // forwards | 13 | // forwards |
13 | struct s_Universe; | 14 | struct s_Universe; |
@@ -42,13 +43,17 @@ typedef void* (*luaG_IdFunction)( lua_State* L, DeepOp op_); | |||
42 | 43 | ||
43 | // ################################################################################################ | 44 | // ################################################################################################ |
44 | 45 | ||
45 | // this is pointed to by full userdata proxies, and allocated with malloc() to survive any lua_State lifetime | 46 | // crc64/we of string "DEEP_VERSION_1" generated at http://www.nitrxgen.net/hashgen/ |
47 | static DECLARE_CONST_UNIQUE_KEY( DEEP_VERSION, 0x4f4eadf0accf6c73); | ||
48 | |||
49 | // should be used as header for full userdata | ||
46 | struct s_DeepPrelude | 50 | struct s_DeepPrelude |
47 | { | 51 | { |
48 | volatile int refcount; | 52 | DECLARE_UNIQUE_KEY( magic); // must be filled by the Deep userdata idfunc that allocates it on eDO_new operation |
49 | void* deep; | ||
50 | // when stored in a keeper state, the full userdata doesn't have a metatable, so we need direct access to the idfunc | 53 | // when stored in a keeper state, the full userdata doesn't have a metatable, so we need direct access to the idfunc |
51 | luaG_IdFunction idfunc; | 54 | luaG_IdFunction idfunc; |
55 | // data is destroyed when refcount is 0 | ||
56 | volatile int refcount; | ||
52 | }; | 57 | }; |
53 | typedef struct s_DeepPrelude DeepPrelude; | 58 | typedef struct s_DeepPrelude DeepPrelude; |
54 | 59 | ||
@@ -57,6 +62,5 @@ void free_deep_prelude( lua_State* L, DeepPrelude* prelude_); | |||
57 | 62 | ||
58 | extern LANES_API int luaG_newdeepuserdata( lua_State* L, luaG_IdFunction idfunc); | 63 | extern LANES_API int luaG_newdeepuserdata( lua_State* L, luaG_IdFunction idfunc); |
59 | extern LANES_API void* luaG_todeep( lua_State* L, luaG_IdFunction idfunc, int index); | 64 | extern LANES_API void* luaG_todeep( lua_State* L, luaG_IdFunction idfunc, int index); |
60 | extern LANES_API void luaG_pushdeepversion( lua_State* L); | ||
61 | 65 | ||
62 | #endif // __LANES_DEEP_H__ | 66 | #endif // __LANES_DEEP_H__ |
diff --git a/src/keeper.c b/src/keeper.c index 091463e..0471cb7 100644 --- a/src/keeper.c +++ b/src/keeper.c | |||
@@ -754,7 +754,7 @@ void keeper_release( Keeper* K) | |||
754 | if( K) MUTEX_UNLOCK( &K->keeper_cs); | 754 | if( K) MUTEX_UNLOCK( &K->keeper_cs); |
755 | } | 755 | } |
756 | 756 | ||
757 | void keeper_toggle_nil_sentinels( lua_State* L, int val_i_, LookupMode mode_) | 757 | void keeper_toggle_nil_sentinels( lua_State* L, int val_i_, LookupMode const mode_) |
758 | { | 758 | { |
759 | int i, n = lua_gettop( L); | 759 | int i, n = lua_gettop( L); |
760 | for( i = val_i_; i <= n; ++ i) | 760 | for( i = val_i_; i <= n; ++ i) |
diff --git a/src/lanes.c b/src/lanes.c index f2e3065..037e44f 100644 --- a/src/lanes.c +++ b/src/lanes.c | |||
@@ -733,7 +733,10 @@ static int selfdestruct_gc( lua_State* L) | |||
733 | // necessary so that calling free_deep_prelude doesn't crash because linda_id expects a linda lightuserdata at absolute slot 1 | 733 | // necessary so that calling free_deep_prelude doesn't crash because linda_id expects a linda lightuserdata at absolute slot 1 |
734 | lua_settop( L, 0); | 734 | lua_settop( L, 0); |
735 | // no need to mutex-protect this as all threads in the universe are gone at that point | 735 | // no need to mutex-protect this as all threads in the universe are gone at that point |
736 | -- U->timer_deep->refcount; // should be 0 now | 736 | if( U->timer_deep != NULL) // test ins case some early internal error prevented Lanes from creating the deep timer |
737 | { | ||
738 | -- U->timer_deep->refcount; // should be 0 now | ||
739 | } | ||
737 | free_deep_prelude( L, (DeepPrelude*) U->timer_deep); | 740 | free_deep_prelude( L, (DeepPrelude*) U->timer_deep); |
738 | U->timer_deep = NULL; | 741 | U->timer_deep = NULL; |
739 | 742 | ||
@@ -2162,7 +2165,6 @@ LUAG_FUNC( configure) | |||
2162 | 2165 | ||
2163 | // Proxy userdata contents is only a 'DEEP_PRELUDE*' pointer | 2166 | // Proxy userdata contents is only a 'DEEP_PRELUDE*' pointer |
2164 | U->timer_deep = *(DeepPrelude**) lua_touserdata( L, -1); | 2167 | U->timer_deep = *(DeepPrelude**) lua_touserdata( L, -1); |
2165 | ASSERT_L( U->timer_deep && (U->timer_deep->refcount == 1) && U->timer_deep->deep && U->timer_deep->idfunc == linda_id); | ||
2166 | // increment refcount that this linda remains alive as long as the universe is. | 2168 | // increment refcount that this linda remains alive as long as the universe is. |
2167 | ++ U->timer_deep->refcount; | 2169 | ++ U->timer_deep->refcount; |
2168 | lua_pop( L, 1); // settings | 2170 | lua_pop( L, 1); // settings |
diff --git a/src/lanes_private.h b/src/lanes_private.h index a7e21d7..1adfa31 100644 --- a/src/lanes_private.h +++ b/src/lanes_private.h | |||
@@ -112,6 +112,4 @@ static inline int cancel_error( lua_State* L) | |||
112 | return lua_error( L); // doesn't return | 112 | return lua_error( L); // doesn't return |
113 | } | 113 | } |
114 | 114 | ||
115 | |||
116 | |||
117 | #endif // __lanes_private_h__ \ No newline at end of file | 115 | #endif // __lanes_private_h__ \ No newline at end of file |
diff --git a/src/linda.c b/src/linda.c index 98d2a8e..ee60ebc 100644 --- a/src/linda.c +++ b/src/linda.c | |||
@@ -46,6 +46,7 @@ THE SOFTWARE. | |||
46 | */ | 46 | */ |
47 | struct s_Linda | 47 | struct s_Linda |
48 | { | 48 | { |
49 | DeepPrelude prelude; // Deep userdata MUST start with this header | ||
49 | SIGNAL_T read_happened; | 50 | SIGNAL_T read_happened; |
50 | SIGNAL_T write_happened; | 51 | SIGNAL_T write_happened; |
51 | Universe* U; // the universe this linda belongs to | 52 | Universe* U; // the universe this linda belongs to |
@@ -794,6 +795,7 @@ static void* linda_id( lua_State* L, DeepOp op_) | |||
794 | s = (struct s_Linda*) malloc( sizeof(struct s_Linda) + name_len); // terminating 0 is already included | 795 | s = (struct s_Linda*) malloc( sizeof(struct s_Linda) + name_len); // terminating 0 is already included |
795 | if( s) | 796 | if( s) |
796 | { | 797 | { |
798 | s->prelude.magic.value = DEEP_VERSION.value; | ||
797 | SIGNAL_INIT( &s->read_happened); | 799 | SIGNAL_INIT( &s->read_happened); |
798 | SIGNAL_INIT( &s->write_happened); | 800 | SIGNAL_INIT( &s->write_happened); |
799 | s->U = universe_get( L); | 801 | s->U = universe_get( L); |
@@ -895,8 +897,7 @@ static void* linda_id( lua_State* L, DeepOp op_) | |||
895 | push_unique_key( L, NIL_SENTINEL); | 897 | push_unique_key( L, NIL_SENTINEL); |
896 | lua_setfield(L, -2, "null"); | 898 | lua_setfield(L, -2, "null"); |
897 | 899 | ||
898 | luaG_pushdeepversion( L); | 900 | STACK_END( L, 1); |
899 | STACK_END( L, 2); | ||
900 | return NULL; | 901 | return NULL; |
901 | } | 902 | } |
902 | 903 | ||