diff options
Diffstat (limited to 'src/deep.cpp')
-rw-r--r-- | src/deep.cpp | 79 |
1 files changed, 36 insertions, 43 deletions
diff --git a/src/deep.cpp b/src/deep.cpp index cd5a844..dd682e4 100644 --- a/src/deep.cpp +++ b/src/deep.cpp | |||
@@ -143,10 +143,13 @@ static inline luaG_IdFunction* get_idfunc( lua_State* L, int index, LookupMode m | |||
143 | 143 | ||
144 | void free_deep_prelude( lua_State* L, DeepPrelude* prelude_) | 144 | void free_deep_prelude( lua_State* L, DeepPrelude* prelude_) |
145 | { | 145 | { |
146 | ASSERT_L(prelude_->idfunc); | ||
147 | STACK_CHECK_START_REL(L, 0); | ||
146 | // Call 'idfunc( "delete", deep_ptr )' to make deep cleanup | 148 | // Call 'idfunc( "delete", deep_ptr )' to make deep cleanup |
147 | lua_pushlightuserdata( L, prelude_); | 149 | lua_pushlightuserdata( L, prelude_); |
148 | ASSERT_L( prelude_->idfunc); | ||
149 | prelude_->idfunc( L, eDO_delete); | 150 | prelude_->idfunc( L, eDO_delete); |
151 | lua_pop(L, 1); | ||
152 | STACK_CHECK(L, 0); | ||
150 | } | 153 | } |
151 | 154 | ||
152 | 155 | ||
@@ -160,14 +163,10 @@ static int deep_userdata_gc( lua_State* L) | |||
160 | { | 163 | { |
161 | DeepPrelude** proxy = (DeepPrelude**) lua_touserdata( L, 1); | 164 | DeepPrelude** proxy = (DeepPrelude**) lua_touserdata( L, 1); |
162 | DeepPrelude* p = *proxy; | 165 | DeepPrelude* p = *proxy; |
163 | Universe* U = universe_get( L); | ||
164 | int v; | ||
165 | 166 | ||
166 | // can work without a universe if creating a deep userdata from some external C module when Lanes isn't loaded | 167 | // can work without a universe if creating a deep userdata from some external C module when Lanes isn't loaded |
167 | // in that case, we are not multithreaded and locking isn't necessary anyway | 168 | // in that case, we are not multithreaded and locking isn't necessary anyway |
168 | if( U) MUTEX_LOCK( &U->deep_lock); | 169 | int v{ p->m_refcount.fetch_sub(1, std::memory_order_relaxed) }; |
169 | v = -- (p->refcount); | ||
170 | if (U) MUTEX_UNLOCK( &U->deep_lock); | ||
171 | 170 | ||
172 | if( v == 0) | 171 | if( v == 0) |
173 | { | 172 | { |
@@ -202,7 +201,7 @@ static int deep_userdata_gc( lua_State* L) | |||
202 | * used in this Lua state (metatable, registring it). Otherwise, increments the | 201 | * used in this Lua state (metatable, registring it). Otherwise, increments the |
203 | * reference count. | 202 | * reference count. |
204 | */ | 203 | */ |
205 | char const* push_deep_proxy( Universe* U, lua_State* L, DeepPrelude* prelude, int nuv_, LookupMode mode_) | 204 | char const* push_deep_proxy(lua_State* L, DeepPrelude* prelude, int nuv_, LookupMode mode_) |
206 | { | 205 | { |
207 | DeepPrelude** proxy; | 206 | DeepPrelude** proxy; |
208 | 207 | ||
@@ -220,12 +219,6 @@ char const* push_deep_proxy( Universe* U, lua_State* L, DeepPrelude* prelude, in | |||
220 | lua_pop( L, 1); // DPC | 219 | lua_pop( L, 1); // DPC |
221 | } | 220 | } |
222 | 221 | ||
223 | // can work without a universe if creating a deep userdata from some external C module when Lanes isn't loaded | ||
224 | // in that case, we are not multithreaded and locking isn't necessary anyway | ||
225 | if( U) MUTEX_LOCK( &U->deep_lock); | ||
226 | ++ (prelude->refcount); // one more proxy pointing to this deep data | ||
227 | if( U) MUTEX_UNLOCK( &U->deep_lock); | ||
228 | |||
229 | STACK_GROW( L, 7); | 222 | STACK_GROW( L, 7); |
230 | STACK_CHECK_START_REL(L, 0); | 223 | STACK_CHECK_START_REL(L, 0); |
231 | 224 | ||
@@ -233,6 +226,7 @@ char const* push_deep_proxy( Universe* U, lua_State* L, DeepPrelude* prelude, in | |||
233 | proxy = (DeepPrelude**) lua_newuserdatauv( L, sizeof(DeepPrelude*), nuv_); // DPC proxy | 226 | proxy = (DeepPrelude**) lua_newuserdatauv( L, sizeof(DeepPrelude*), nuv_); // DPC proxy |
234 | ASSERT_L( proxy); | 227 | ASSERT_L( proxy); |
235 | *proxy = prelude; | 228 | *proxy = prelude; |
229 | prelude->m_refcount.fetch_add(1, std::memory_order_relaxed); // one more proxy pointing to this deep data | ||
236 | 230 | ||
237 | // Get/create metatable for 'idfunc' (in this state) | 231 | // Get/create metatable for 'idfunc' (in this state) |
238 | lua_pushlightuserdata( L, (void*)(ptrdiff_t)(prelude->idfunc)); // DPC proxy idfunc | 232 | lua_pushlightuserdata( L, (void*)(ptrdiff_t)(prelude->idfunc)); // DPC proxy idfunc |
@@ -378,39 +372,38 @@ char const* push_deep_proxy( Universe* U, lua_State* L, DeepPrelude* prelude, in | |||
378 | */ | 372 | */ |
379 | int luaG_newdeepuserdata( lua_State* L, luaG_IdFunction* idfunc, int nuv_) | 373 | int luaG_newdeepuserdata( lua_State* L, luaG_IdFunction* idfunc, int nuv_) |
380 | { | 374 | { |
381 | char const* errmsg; | ||
382 | |||
383 | STACK_GROW( L, 1); | 375 | STACK_GROW( L, 1); |
384 | STACK_CHECK_START_REL(L, 0); | 376 | STACK_CHECK_START_REL(L, 0); |
377 | int const oldtop{ lua_gettop(L) }; | ||
378 | DeepPrelude* const prelude{ static_cast<DeepPrelude*>(idfunc(L, eDO_new)) }; | ||
379 | if (prelude == nullptr) | ||
385 | { | 380 | { |
386 | int const oldtop = lua_gettop( L); | 381 | return luaL_error( L, "idfunc(eDO_new) failed to create deep userdata (out of memory)"); |
387 | DeepPrelude* prelude = (DeepPrelude*) idfunc( L, eDO_new); | 382 | } |
388 | if (prelude == nullptr) | ||
389 | { | ||
390 | return luaL_error( L, "idfunc(eDO_new) failed to create deep userdata (out of memory)"); | ||
391 | } | ||
392 | if( prelude->magic != DEEP_VERSION) | ||
393 | { | ||
394 | // just in case, don't leak the newly allocated deep userdata object | ||
395 | lua_pushlightuserdata( L, prelude); | ||
396 | idfunc( L, eDO_delete); | ||
397 | return luaL_error( L, "Bad idfunc(eDO_new): DEEP_VERSION is incorrect, rebuild your implementation with the latest deep implementation"); | ||
398 | } | ||
399 | prelude->refcount = 0; // 'push_deep_proxy' will lift it to 1 | ||
400 | prelude->idfunc = idfunc; | ||
401 | 383 | ||
402 | if( lua_gettop( L) - oldtop != 0) | 384 | if( prelude->magic != DEEP_VERSION) |
403 | { | 385 | { |
404 | // just in case, don't leak the newly allocated deep userdata object | 386 | // just in case, don't leak the newly allocated deep userdata object |
405 | lua_pushlightuserdata( L, prelude); | 387 | lua_pushlightuserdata( L, prelude); |
406 | idfunc( L, eDO_delete); | 388 | idfunc( L, eDO_delete); |
407 | return luaL_error( L, "Bad idfunc(eDO_new): should not push anything on the stack"); | 389 | return luaL_error( L, "Bad idfunc(eDO_new): DEEP_VERSION is incorrect, rebuild your implementation with the latest deep implementation"); |
408 | } | 390 | } |
409 | errmsg = push_deep_proxy( universe_get( L), L, prelude, nuv_, eLM_LaneBody); // proxy | 391 | |
410 | if (errmsg != nullptr) | 392 | ASSERT_L(prelude->m_refcount.load(std::memory_order_relaxed) == 0); // 'push_deep_proxy' will lift it to 1 |
411 | { | 393 | prelude->idfunc = idfunc; |
412 | return luaL_error( L, errmsg); | 394 | |
413 | } | 395 | if( lua_gettop( L) - oldtop != 0) |
396 | { | ||
397 | // just in case, don't leak the newly allocated deep userdata object | ||
398 | lua_pushlightuserdata( L, prelude); | ||
399 | idfunc( L, eDO_delete); | ||
400 | return luaL_error( L, "Bad idfunc(eDO_new): should not push anything on the stack"); | ||
401 | } | ||
402 | |||
403 | char const* const errmsg{ push_deep_proxy(L, prelude, nuv_, eLM_LaneBody) }; // proxy | ||
404 | if (errmsg != nullptr) | ||
405 | { | ||
406 | return luaL_error( L, errmsg); | ||
414 | } | 407 | } |
415 | STACK_CHECK( L, 1); | 408 | STACK_CHECK( L, 1); |
416 | return 1; | 409 | return 1; |
@@ -471,7 +464,7 @@ bool copydeep(Universe* U, lua_State* L2, int L2_cache_i, lua_State* L, int i, L | |||
471 | lua_pop( L, 1); // ... u [uv]* | 464 | lua_pop( L, 1); // ... u [uv]* |
472 | STACK_CHECK( L, nuv); | 465 | STACK_CHECK( L, nuv); |
473 | 466 | ||
474 | errmsg = push_deep_proxy( U, L2, *(DeepPrelude**) lua_touserdata( L, i), nuv, mode_); // u | 467 | errmsg = push_deep_proxy(L2, *(DeepPrelude**) lua_touserdata( L, i), nuv, mode_); // u |
475 | 468 | ||
476 | // transfer all uservalues of the source in the destination | 469 | // transfer all uservalues of the source in the destination |
477 | { | 470 | { |