diff options
-rw-r--r-- | deep_test/deep_test.cpp | 3 | ||||
-rw-r--r-- | deep_test/deep_test.vcxproj.user | 4 | ||||
-rw-r--r-- | src/deep.cpp | 79 | ||||
-rw-r--r-- | src/deep.h | 10 | ||||
-rw-r--r-- | src/lanes.cpp | 70 | ||||
-rw-r--r-- | src/linda.cpp | 8 | ||||
-rw-r--r-- | src/state.cpp | 6 | ||||
-rw-r--r-- | src/tools.cpp | 18 | ||||
-rw-r--r-- | src/universe.cpp | 15 | ||||
-rw-r--r-- | src/universe.h | 47 |
10 files changed, 115 insertions, 145 deletions
diff --git a/deep_test/deep_test.cpp b/deep_test/deep_test.cpp index bbae48e..d7ecd33 100644 --- a/deep_test/deep_test.cpp +++ b/deep_test/deep_test.cpp | |||
@@ -8,9 +8,8 @@ | |||
8 | // ################################################################################################ | 8 | // ################################################################################################ |
9 | 9 | ||
10 | // a lanes-deep userdata. needs DeepPrelude and luaG_newdeepuserdata from Lanes code. | 10 | // a lanes-deep userdata. needs DeepPrelude and luaG_newdeepuserdata from Lanes code. |
11 | struct MyDeepUserdata | 11 | struct MyDeepUserdata : public DeepPrelude // Deep userdata MUST start with a DeepPrelude |
12 | { | 12 | { |
13 | DeepPrelude prelude; // Deep userdata MUST start with this header | ||
14 | lua_Integer val{ 0 }; | 13 | lua_Integer val{ 0 }; |
15 | }; | 14 | }; |
16 | 15 | ||
diff --git a/deep_test/deep_test.vcxproj.user b/deep_test/deep_test.vcxproj.user index abaec72..24e3d31 100644 --- a/deep_test/deep_test.vcxproj.user +++ b/deep_test/deep_test.vcxproj.user | |||
@@ -33,9 +33,9 @@ | |||
33 | <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug 5.4|x64'"> | 33 | <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug 5.4|x64'"> |
34 | <LocalDebuggerCommand>$(SolutionDir)..\framework\lua54.exe</LocalDebuggerCommand> | 34 | <LocalDebuggerCommand>$(SolutionDir)..\framework\lua54.exe</LocalDebuggerCommand> |
35 | <DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor> | 35 | <DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor> |
36 | <LocalDebuggerCommandArguments>-i deeptest.lua</LocalDebuggerCommandArguments> | 36 | <LocalDebuggerCommandArguments>deeptest.lua</LocalDebuggerCommandArguments> |
37 | <LocalDebuggerWorkingDirectory>$(SolutionDir)Lanes\lanes\deep_test\</LocalDebuggerWorkingDirectory> | 37 | <LocalDebuggerWorkingDirectory>$(SolutionDir)Lanes\lanes\deep_test\</LocalDebuggerWorkingDirectory> |
38 | <RemoteDebuggerCommandArguments>-i deeptest.lua</RemoteDebuggerCommandArguments> | 38 | <RemoteDebuggerCommandArguments>deeptest.lua</RemoteDebuggerCommandArguments> |
39 | </PropertyGroup> | 39 | </PropertyGroup> |
40 | <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug MoonJIT|x64'"> | 40 | <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug MoonJIT|x64'"> |
41 | <LocalDebuggerCommand>$(SolutionDir)..\MoonJIT\bin\$(Platform)\moonjit.exe</LocalDebuggerCommand> | 41 | <LocalDebuggerCommand>$(SolutionDir)..\MoonJIT\bin\$(Platform)\moonjit.exe</LocalDebuggerCommand> |
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 | { |
@@ -16,6 +16,8 @@ extern "C" { | |||
16 | #include "lanesconf.h" | 16 | #include "lanesconf.h" |
17 | #include "uniquekey.h" | 17 | #include "uniquekey.h" |
18 | 18 | ||
19 | #include <atomic> | ||
20 | |||
19 | // forwards | 21 | // forwards |
20 | struct Universe; | 22 | struct Universe; |
21 | 23 | ||
@@ -38,8 +40,8 @@ using luaG_IdFunction = void*( lua_State* L, DeepOp op_); | |||
38 | 40 | ||
39 | // ################################################################################################ | 41 | // ################################################################################################ |
40 | 42 | ||
41 | // fnv164 of string "DEEP_VERSION_2" generated at https://www.pelock.com/products/hash-calculator | 43 | // xxh64 of string "DEEP_VERSION_3" generated at https://www.pelock.com/products/hash-calculator |
42 | static constexpr UniqueKey DEEP_VERSION{ 0xB4B0119C10642B29ull }; | 44 | static constexpr UniqueKey DEEP_VERSION{ 0xB2CC0FD9C0AE9674ull }; |
43 | 45 | ||
44 | // should be used as header for full userdata | 46 | // should be used as header for full userdata |
45 | struct DeepPrelude | 47 | struct DeepPrelude |
@@ -48,10 +50,10 @@ struct DeepPrelude | |||
48 | // when stored in a keeper state, the full userdata doesn't have a metatable, so we need direct access to the idfunc | 50 | // when stored in a keeper state, the full userdata doesn't have a metatable, so we need direct access to the idfunc |
49 | luaG_IdFunction* idfunc { nullptr }; | 51 | luaG_IdFunction* idfunc { nullptr }; |
50 | // data is destroyed when refcount is 0 | 52 | // data is destroyed when refcount is 0 |
51 | volatile int refcount{ 0 }; | 53 | std::atomic<int> m_refcount{ 0 }; |
52 | }; | 54 | }; |
53 | 55 | ||
54 | char const* push_deep_proxy( Universe* U, lua_State* L, DeepPrelude* prelude, int nuv_, LookupMode mode_); | 56 | char const* push_deep_proxy(lua_State* L, DeepPrelude* prelude, int nuv_, LookupMode mode_); |
55 | void free_deep_prelude( lua_State* L, DeepPrelude* prelude_); | 57 | void free_deep_prelude( lua_State* L, DeepPrelude* prelude_); |
56 | 58 | ||
57 | LANES_API int luaG_newdeepuserdata( lua_State* L, luaG_IdFunction* idfunc, int nuv_); | 59 | LANES_API int luaG_newdeepuserdata( lua_State* L, luaG_IdFunction* idfunc, int nuv_); |
diff --git a/src/lanes.cpp b/src/lanes.cpp index 6123766..99c5812 100644 --- a/src/lanes.cpp +++ b/src/lanes.cpp | |||
@@ -185,26 +185,26 @@ static bool push_registry_table( lua_State* L, UniqueKey key, bool create) | |||
185 | * Add the lane to tracking chain; the ones still running at the end of the | 185 | * Add the lane to tracking chain; the ones still running at the end of the |
186 | * whole process will be cancelled. | 186 | * whole process will be cancelled. |
187 | */ | 187 | */ |
188 | static void tracking_add( Lane* s) | 188 | static void tracking_add(Lane* s) |
189 | { | 189 | { |
190 | 190 | ||
191 | MUTEX_LOCK( &s->U->tracking_cs); | 191 | s->U->tracking_cs.lock(); |
192 | { | 192 | { |
193 | assert( s->tracking_next == nullptr); | 193 | assert( s->tracking_next == nullptr); |
194 | 194 | ||
195 | s->tracking_next = s->U->tracking_first; | 195 | s->tracking_next = s->U->tracking_first; |
196 | s->U->tracking_first = s; | 196 | s->U->tracking_first = s; |
197 | } | 197 | } |
198 | MUTEX_UNLOCK( &s->U->tracking_cs); | 198 | s->U->tracking_cs.unlock(); |
199 | } | 199 | } |
200 | 200 | ||
201 | /* | 201 | /* |
202 | * A free-running lane has ended; remove it from tracking chain | 202 | * A free-running lane has ended; remove it from tracking chain |
203 | */ | 203 | */ |
204 | static bool tracking_remove( Lane* s) | 204 | static bool tracking_remove(Lane* s) |
205 | { | 205 | { |
206 | bool found{ false }; | 206 | bool found{ false }; |
207 | MUTEX_LOCK( &s->U->tracking_cs); | 207 | s->U->tracking_cs.lock(); |
208 | { | 208 | { |
209 | // Make sure (within the MUTEX) that we actually are in the chain | 209 | // Make sure (within the MUTEX) that we actually are in the chain |
210 | // still (at process exit they will remove us from chain and then | 210 | // still (at process exit they will remove us from chain and then |
@@ -228,7 +228,7 @@ static bool tracking_remove( Lane* s) | |||
228 | assert( found); | 228 | assert( found); |
229 | } | 229 | } |
230 | } | 230 | } |
231 | MUTEX_UNLOCK( &s->U->tracking_cs); | 231 | s->U->tracking_cs.unlock(); |
232 | return found; | 232 | return found; |
233 | } | 233 | } |
234 | 234 | ||
@@ -396,12 +396,12 @@ static int run_finalizers( lua_State* L, int lua_rc) | |||
396 | */ | 396 | */ |
397 | static void selfdestruct_add( Lane* s) | 397 | static void selfdestruct_add( Lane* s) |
398 | { | 398 | { |
399 | MUTEX_LOCK( &s->U->selfdestruct_cs); | 399 | s->U->selfdestruct_cs.lock(); |
400 | assert( s->selfdestruct_next == nullptr); | 400 | assert( s->selfdestruct_next == nullptr); |
401 | 401 | ||
402 | s->selfdestruct_next = s->U->selfdestruct_first; | 402 | s->selfdestruct_next = s->U->selfdestruct_first; |
403 | s->U->selfdestruct_first= s; | 403 | s->U->selfdestruct_first= s; |
404 | MUTEX_UNLOCK( &s->U->selfdestruct_cs); | 404 | s->U->selfdestruct_cs.unlock(); |
405 | } | 405 | } |
406 | 406 | ||
407 | /* | 407 | /* |
@@ -410,7 +410,7 @@ static void selfdestruct_add( Lane* s) | |||
410 | static bool selfdestruct_remove( Lane* s) | 410 | static bool selfdestruct_remove( Lane* s) |
411 | { | 411 | { |
412 | bool found{ false }; | 412 | bool found{ false }; |
413 | MUTEX_LOCK( &s->U->selfdestruct_cs); | 413 | s->U->selfdestruct_cs.lock(); |
414 | { | 414 | { |
415 | // Make sure (within the MUTEX) that we actually are in the chain | 415 | // Make sure (within the MUTEX) that we actually are in the chain |
416 | // still (at process exit they will remove us from chain and then | 416 | // still (at process exit they will remove us from chain and then |
@@ -436,7 +436,7 @@ static bool selfdestruct_remove( Lane* s) | |||
436 | assert( found); | 436 | assert( found); |
437 | } | 437 | } |
438 | } | 438 | } |
439 | MUTEX_UNLOCK( &s->U->selfdestruct_cs); | 439 | s->U->selfdestruct_cs.unlock(); |
440 | return found; | 440 | return found; |
441 | } | 441 | } |
442 | 442 | ||
@@ -451,7 +451,7 @@ static int selfdestruct_gc( lua_State* L) | |||
451 | { | 451 | { |
452 | // Signal _all_ still running threads to exit (including the timer thread) | 452 | // Signal _all_ still running threads to exit (including the timer thread) |
453 | // | 453 | // |
454 | MUTEX_LOCK( &U->selfdestruct_cs); | 454 | U->selfdestruct_cs.lock(); |
455 | { | 455 | { |
456 | Lane* s = U->selfdestruct_first; | 456 | Lane* s = U->selfdestruct_first; |
457 | while( s != SELFDESTRUCT_END) | 457 | while( s != SELFDESTRUCT_END) |
@@ -470,7 +470,7 @@ static int selfdestruct_gc( lua_State* L) | |||
470 | s = s->selfdestruct_next; | 470 | s = s->selfdestruct_next; |
471 | } | 471 | } |
472 | } | 472 | } |
473 | MUTEX_UNLOCK( &U->selfdestruct_cs); | 473 | U->selfdestruct_cs.unlock(); |
474 | 474 | ||
475 | // When noticing their cancel, the lanes will remove themselves from | 475 | // When noticing their cancel, the lanes will remove themselves from |
476 | // the selfdestruct chain. | 476 | // the selfdestruct chain. |
@@ -497,7 +497,7 @@ static int selfdestruct_gc( lua_State* L) | |||
497 | // count the number of cancelled thread that didn't have the time to act yet | 497 | // count the number of cancelled thread that didn't have the time to act yet |
498 | int n = 0; | 498 | int n = 0; |
499 | double t_now = 0.0; | 499 | double t_now = 0.0; |
500 | MUTEX_LOCK( &U->selfdestruct_cs); | 500 | U->selfdestruct_cs.lock(); |
501 | { | 501 | { |
502 | Lane* s = U->selfdestruct_first; | 502 | Lane* s = U->selfdestruct_first; |
503 | while( s != SELFDESTRUCT_END) | 503 | while( s != SELFDESTRUCT_END) |
@@ -507,7 +507,7 @@ static int selfdestruct_gc( lua_State* L) | |||
507 | s = s->selfdestruct_next; | 507 | s = s->selfdestruct_next; |
508 | } | 508 | } |
509 | } | 509 | } |
510 | MUTEX_UNLOCK( &U->selfdestruct_cs); | 510 | U->selfdestruct_cs.unlock(); |
511 | // if timeout elapsed, or we know all threads have acted, stop waiting | 511 | // if timeout elapsed, or we know all threads have acted, stop waiting |
512 | t_now = now_secs(); | 512 | t_now = now_secs(); |
513 | if( n == 0 || (t_now >= t_until)) | 513 | if( n == 0 || (t_now >= t_until)) |
@@ -535,7 +535,7 @@ static int selfdestruct_gc( lua_State* L) | |||
535 | // first thing we did was to raise the linda signals the threads were waiting on (if any) | 535 | // first thing we did was to raise the linda signals the threads were waiting on (if any) |
536 | // therefore, any well-behaved thread should be in CANCELLED state | 536 | // therefore, any well-behaved thread should be in CANCELLED state |
537 | // these are not running, and the state can be closed | 537 | // these are not running, and the state can be closed |
538 | MUTEX_LOCK( &U->selfdestruct_cs); | 538 | U->selfdestruct_cs.lock(); |
539 | { | 539 | { |
540 | Lane* s = U->selfdestruct_first; | 540 | Lane* s = U->selfdestruct_first; |
541 | while( s != SELFDESTRUCT_END) | 541 | while( s != SELFDESTRUCT_END) |
@@ -557,7 +557,7 @@ static int selfdestruct_gc( lua_State* L) | |||
557 | } | 557 | } |
558 | U->selfdestruct_first = SELFDESTRUCT_END; | 558 | U->selfdestruct_first = SELFDESTRUCT_END; |
559 | } | 559 | } |
560 | MUTEX_UNLOCK( &U->selfdestruct_cs); | 560 | U->selfdestruct_cs.unlock(); |
561 | 561 | ||
562 | DEBUGSPEW_CODE( fprintf( stderr, "Killed %d lane(s) at process end.\n", n)); | 562 | DEBUGSPEW_CODE( fprintf( stderr, "Killed %d lane(s) at process end.\n", n)); |
563 | } | 563 | } |
@@ -575,7 +575,8 @@ static int selfdestruct_gc( lua_State* L) | |||
575 | // no need to mutex-protect this as all threads in the universe are gone at that point | 575 | // no need to mutex-protect this as all threads in the universe are gone at that point |
576 | if( U->timer_deep != nullptr) // test ins case some early internal error prevented Lanes from creating the deep timer | 576 | if( U->timer_deep != nullptr) // test ins case some early internal error prevented Lanes from creating the deep timer |
577 | { | 577 | { |
578 | -- U->timer_deep->refcount; // should be 0 now | 578 | int const prev_ref_count{ U->timer_deep->m_refcount.fetch_sub(1, std::memory_order_relaxed) }; |
579 | ASSERT_L(prev_ref_count == 1); // this should be the last reference | ||
579 | free_deep_prelude( L, (DeepPrelude*) U->timer_deep); | 580 | free_deep_prelude( L, (DeepPrelude*) U->timer_deep); |
580 | U->timer_deep = nullptr; | 581 | U->timer_deep = nullptr; |
581 | } | 582 | } |
@@ -585,15 +586,8 @@ static int selfdestruct_gc( lua_State* L) | |||
585 | // remove the protected allocator, if any | 586 | // remove the protected allocator, if any |
586 | cleanup_allocator_function( U, L); | 587 | cleanup_allocator_function( U, L); |
587 | 588 | ||
588 | #if HAVE_LANE_TRACKING() | 589 | U->Universe::~Universe(); |
589 | MUTEX_FREE( &U->tracking_cs); | 590 | |
590 | #endif // HAVE_LANE_TRACKING() | ||
591 | // Linked chains handling | ||
592 | MUTEX_FREE( &U->selfdestruct_cs); | ||
593 | MUTEX_FREE( &U->require_cs); | ||
594 | // Locks for 'tools.c' inc/dec counters | ||
595 | MUTEX_FREE( &U->deep_lock); | ||
596 | MUTEX_FREE( &U->mtid_lock); | ||
597 | // universe is no longer available (nor necessary) | 591 | // universe is no longer available (nor necessary) |
598 | // we need to do this in case some deep userdata objects were created before Lanes was initialized, | 592 | // we need to do this in case some deep userdata objects were created before Lanes was initialized, |
599 | // as potentially they will be garbage collected after Lanes at application shutdown | 593 | // as potentially they will be garbage collected after Lanes at application shutdown |
@@ -950,10 +944,10 @@ static THREAD_RETURN_T THREAD_CALLCONV lane_main( void* vs) | |||
950 | // | 944 | // |
951 | lua_close( s->L); | 945 | lua_close( s->L); |
952 | 946 | ||
953 | MUTEX_LOCK( &s->U->selfdestruct_cs); | 947 | s->U->selfdestruct_cs.lock(); |
954 | // done with lua_close(), terminal shutdown sequence may proceed | 948 | // done with lua_close(), terminal shutdown sequence may proceed |
955 | -- s->U->selfdestructing_count; | 949 | -- s->U->selfdestructing_count; |
956 | MUTEX_UNLOCK( &s->U->selfdestruct_cs); | 950 | s->U->selfdestruct_cs.unlock(); |
957 | 951 | ||
958 | lane_cleanup( s); // s is freed at this point | 952 | lane_cleanup( s); // s is freed at this point |
959 | } | 953 | } |
@@ -1665,7 +1659,7 @@ LUAG_FUNC( threads) | |||
1665 | 1659 | ||
1666 | // List _all_ still running threads | 1660 | // List _all_ still running threads |
1667 | // | 1661 | // |
1668 | MUTEX_LOCK( &U->tracking_cs); | 1662 | U->tracking_cs.lock(); |
1669 | if( U->tracking_first && U->tracking_first != TRACKING_END) | 1663 | if( U->tracking_first && U->tracking_first != TRACKING_END) |
1670 | { | 1664 | { |
1671 | Lane* s = U->tracking_first; | 1665 | Lane* s = U->tracking_first; |
@@ -1683,7 +1677,7 @@ LUAG_FUNC( threads) | |||
1683 | s = s->tracking_next; | 1677 | s = s->tracking_next; |
1684 | } | 1678 | } |
1685 | } | 1679 | } |
1686 | MUTEX_UNLOCK( &U->tracking_cs); | 1680 | U->tracking_cs.unlock(); |
1687 | return lua_gettop( L) - top; // 0 or 1 | 1681 | return lua_gettop( L) - top; // 0 or 1 |
1688 | } | 1682 | } |
1689 | #endif // HAVE_LANE_TRACKING() | 1683 | #endif // HAVE_LANE_TRACKING() |
@@ -1863,12 +1857,12 @@ LUAG_FUNC( configure) | |||
1863 | #endif // THREADAPI == THREADAPI_PTHREAD | 1857 | #endif // THREADAPI == THREADAPI_PTHREAD |
1864 | 1858 | ||
1865 | STACK_GROW( L, 4); | 1859 | STACK_GROW( L, 4); |
1866 | STACK_CHECK_START_ABS( L, 1); // settings | 1860 | STACK_CHECK_START_ABS( L, 1); // settings |
1867 | 1861 | ||
1868 | DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "%p: lanes.configure() BEGIN\n" INDENT_END, L)); | 1862 | DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "%p: lanes.configure() BEGIN\n" INDENT_END, L)); |
1869 | DEBUGSPEW_CODE( if( U) ++ U->debugspew_indent_depth); | 1863 | DEBUGSPEW_CODE( if( U) ++ U->debugspew_indent_depth); |
1870 | 1864 | ||
1871 | if( U == nullptr) | 1865 | if(U == nullptr) |
1872 | { | 1866 | { |
1873 | U = universe_create( L); // settings universe | 1867 | U = universe_create( L); // settings universe |
1874 | DEBUGSPEW_CODE( ++ U->debugspew_indent_depth); | 1868 | DEBUGSPEW_CODE( ++ U->debugspew_indent_depth); |
@@ -1885,17 +1879,11 @@ LUAG_FUNC( configure) | |||
1885 | U->demoteFullUserdata = lua_toboolean( L, -1) ? true : false; | 1879 | U->demoteFullUserdata = lua_toboolean( L, -1) ? true : false; |
1886 | lua_pop( L, 1); // settings | 1880 | lua_pop( L, 1); // settings |
1887 | #if HAVE_LANE_TRACKING() | 1881 | #if HAVE_LANE_TRACKING() |
1888 | MUTEX_INIT( &U->tracking_cs); | ||
1889 | lua_getfield( L, 1, "track_lanes"); // settings track_lanes | 1882 | lua_getfield( L, 1, "track_lanes"); // settings track_lanes |
1890 | U->tracking_first = lua_toboolean( L, -1) ? TRACKING_END : nullptr; | 1883 | U->tracking_first = lua_toboolean( L, -1) ? TRACKING_END : nullptr; |
1891 | lua_pop( L, 1); // settings | 1884 | lua_pop( L, 1); // settings |
1892 | #endif // HAVE_LANE_TRACKING() | 1885 | #endif // HAVE_LANE_TRACKING() |
1893 | // Linked chains handling | 1886 | // Linked chains handling |
1894 | MUTEX_INIT( &U->selfdestruct_cs); | ||
1895 | MUTEX_RECURSIVE_INIT( &U->require_cs); | ||
1896 | // Locks for 'tools.c' inc/dec counters | ||
1897 | MUTEX_INIT( &U->deep_lock); | ||
1898 | MUTEX_INIT( &U->mtid_lock); | ||
1899 | U->selfdestruct_first = SELFDESTRUCT_END; | 1887 | U->selfdestruct_first = SELFDESTRUCT_END; |
1900 | initialize_allocator_function( U, L); | 1888 | initialize_allocator_function( U, L); |
1901 | initialize_on_state_create( U, L); | 1889 | initialize_on_state_create( U, L); |
@@ -1908,10 +1896,10 @@ LUAG_FUNC( configure) | |||
1908 | lua_call( L, 1, 1); // settings linda | 1896 | lua_call( L, 1, 1); // settings linda |
1909 | STACK_CHECK( L, 2); | 1897 | STACK_CHECK( L, 2); |
1910 | 1898 | ||
1911 | // Proxy userdata contents is only a 'DEEP_PRELUDE*' pointer | 1899 | // Proxy userdata contents is only a 'DeepPrelude*' pointer |
1912 | U->timer_deep = *(DeepPrelude**) lua_touserdata( L, -1); | 1900 | U->timer_deep = *(DeepPrelude**) lua_touserdata( L, -1); |
1913 | // increment refcount so that this linda remains alive as long as the universe exists. | 1901 | // increment refcount so that this linda remains alive as long as the universe exists. |
1914 | ++ U->timer_deep->refcount; | 1902 | U->timer_deep->m_refcount.fetch_add(1, std::memory_order_relaxed); |
1915 | lua_pop( L, 1); // settings | 1903 | lua_pop( L, 1); // settings |
1916 | } | 1904 | } |
1917 | STACK_CHECK( L, 1); | 1905 | STACK_CHECK( L, 1); |
@@ -1938,7 +1926,7 @@ LUAG_FUNC( configure) | |||
1938 | 1926 | ||
1939 | { | 1927 | { |
1940 | char const* errmsg; | 1928 | char const* errmsg; |
1941 | errmsg = push_deep_proxy( U, L, (DeepPrelude*) U->timer_deep, 0, eLM_LaneBody); // settings M timer_deep | 1929 | errmsg = push_deep_proxy(L, (DeepPrelude*) U->timer_deep, 0, eLM_LaneBody); // settings M timer_deep |
1942 | if( errmsg != nullptr) | 1930 | if( errmsg != nullptr) |
1943 | { | 1931 | { |
1944 | return luaL_error( L, errmsg); | 1932 | return luaL_error( L, errmsg); |
diff --git a/src/linda.cpp b/src/linda.cpp index a6025ce..f2e39a8 100644 --- a/src/linda.cpp +++ b/src/linda.cpp | |||
@@ -791,8 +791,8 @@ static void* linda_id( lua_State* L, DeepOp op_) | |||
791 | * One can use any memory allocation scheme. | 791 | * One can use any memory allocation scheme. |
792 | * just don't use L's allocF because we don't know which state will get the honor of GCing the linda | 792 | * just don't use L's allocF because we don't know which state will get the honor of GCing the linda |
793 | */ | 793 | */ |
794 | Universe* const U = universe_get(L); | ||
794 | { | 795 | { |
795 | Universe* const U = universe_get(L); | ||
796 | AllocatorDefinition* const allocD = &U->internal_allocator; | 796 | AllocatorDefinition* const allocD = &U->internal_allocator; |
797 | s = (struct s_Linda*) allocD->allocF(allocD->allocUD, nullptr, 0, sizeof(struct s_Linda) + name_len); // terminating 0 is already included | 797 | s = (struct s_Linda*) allocD->allocF(allocD->allocUD, nullptr, 0, sizeof(struct s_Linda) + name_len); // terminating 0 is already included |
798 | } | 798 | } |
@@ -801,7 +801,7 @@ static void* linda_id( lua_State* L, DeepOp op_) | |||
801 | s->prelude.DeepPrelude::DeepPrelude(); | 801 | s->prelude.DeepPrelude::DeepPrelude(); |
802 | SIGNAL_INIT( &s->read_happened); | 802 | SIGNAL_INIT( &s->read_happened); |
803 | SIGNAL_INIT( &s->write_happened); | 803 | SIGNAL_INIT( &s->write_happened); |
804 | s->U = universe_get( L); | 804 | s->U = U; |
805 | s->simulate_cancel = CancelRequest::None; | 805 | s->simulate_cancel = CancelRequest::None; |
806 | s->group = linda_group << KEEPER_MAGIC_SHIFT; | 806 | s->group = linda_group << KEEPER_MAGIC_SHIFT; |
807 | s->name[0] = 0; | 807 | s->name[0] = 0; |
@@ -828,9 +828,9 @@ static void* linda_id( lua_State* L, DeepOp op_) | |||
828 | // There aren't any lanes waiting on these lindas, since all proxies have been gc'ed. Right? | 828 | // There aren't any lanes waiting on these lindas, since all proxies have been gc'ed. Right? |
829 | SIGNAL_FREE( &linda->read_happened); | 829 | SIGNAL_FREE( &linda->read_happened); |
830 | SIGNAL_FREE( &linda->write_happened); | 830 | SIGNAL_FREE( &linda->write_happened); |
831 | linda->prelude.DeepPrelude::~DeepPrelude(); | ||
831 | { | 832 | { |
832 | Universe* const U = universe_get(L); | 833 | AllocatorDefinition* const allocD = &linda->U->internal_allocator; |
833 | AllocatorDefinition* const allocD = &U->internal_allocator; | ||
834 | (void) allocD->allocF(allocD->allocUD, linda, sizeof(struct s_Linda) + strlen(linda->name), 0); | 834 | (void) allocD->allocF(allocD->allocUD, linda, sizeof(struct s_Linda) + strlen(linda->name), 0); |
835 | } | 835 | } |
836 | return nullptr; | 836 | return nullptr; |
diff --git a/src/state.cpp b/src/state.cpp index aa6b38a..c66242c 100644 --- a/src/state.cpp +++ b/src/state.cpp | |||
@@ -72,11 +72,11 @@ static int luaG_new_require( lua_State* L) | |||
72 | 72 | ||
73 | // Using 'lua_pcall()' to catch errors; otherwise a failing 'require' would | 73 | // Using 'lua_pcall()' to catch errors; otherwise a failing 'require' would |
74 | // leave us locked, blocking any future 'require' calls from other lanes. | 74 | // leave us locked, blocking any future 'require' calls from other lanes. |
75 | 75 | ||
76 | MUTEX_LOCK( &U->require_cs); | 76 | U->require_cs.lock(); |
77 | // starting with Lua 5.4, require may return a second optional value, so we need LUA_MULTRET | 77 | // starting with Lua 5.4, require may return a second optional value, so we need LUA_MULTRET |
78 | rc = lua_pcall( L, args, LUA_MULTRET, 0 /*errfunc*/ ); // err|result(s) | 78 | rc = lua_pcall( L, args, LUA_MULTRET, 0 /*errfunc*/ ); // err|result(s) |
79 | MUTEX_UNLOCK( &U->require_cs); | 79 | U->require_cs.unlock(); |
80 | 80 | ||
81 | // the required module (or an error message) is left on the stack as returned value by original require function | 81 | // the required module (or an error message) is left on the stack as returned value by original require function |
82 | 82 | ||
diff --git a/src/tools.cpp b/src/tools.cpp index 1e38144..68846ba 100644 --- a/src/tools.cpp +++ b/src/tools.cpp | |||
@@ -174,9 +174,9 @@ static void* protected_lua_Alloc( void *ud, void *ptr, size_t osize, size_t nsiz | |||
174 | { | 174 | { |
175 | void* p; | 175 | void* p; |
176 | ProtectedAllocator* s = (ProtectedAllocator*) ud; | 176 | ProtectedAllocator* s = (ProtectedAllocator*) ud; |
177 | MUTEX_LOCK( &s->lock); | 177 | s->lock.lock(); |
178 | p = s->definition.allocF( s->definition.allocUD, ptr, osize, nsize); | 178 | p = s->definition.allocF( s->definition.allocUD, ptr, osize, nsize); |
179 | MUTEX_UNLOCK( &s->lock); | 179 | s->lock.unlock(); |
180 | return p; | 180 | return p; |
181 | } | 181 | } |
182 | 182 | ||
@@ -214,9 +214,7 @@ void initialize_allocator_function( Universe* U, lua_State* L) | |||
214 | } | 214 | } |
215 | else if( lua_type( L, -1) == LUA_TSTRING) // should be "protected" | 215 | else if( lua_type( L, -1) == LUA_TSTRING) // should be "protected" |
216 | { | 216 | { |
217 | // initialize all we need for the protected allocator | 217 | // set the original allocator to call from inside protection by the mutex |
218 | MUTEX_INIT( &U->protected_allocator.lock); // the mutex | ||
219 | // and the original allocator to call from inside protection by the mutex | ||
220 | U->protected_allocator.definition.allocF = lua_getallocf( L, &U->protected_allocator.definition.allocUD); | 218 | U->protected_allocator.definition.allocF = lua_getallocf( L, &U->protected_allocator.definition.allocUD); |
221 | // before a state is created, this function will be called to obtain the allocator | 219 | // before a state is created, this function will be called to obtain the allocator |
222 | U->provide_allocator = luaG_provide_protected_allocator; | 220 | U->provide_allocator = luaG_provide_protected_allocator; |
@@ -226,8 +224,6 @@ void initialize_allocator_function( Universe* U, lua_State* L) | |||
226 | } | 224 | } |
227 | else | 225 | else |
228 | { | 226 | { |
229 | // initialize the mutex even if we are not going to use it, because cleanup_allocator_function will deinitialize it | ||
230 | MUTEX_INIT( &U->protected_allocator.lock); | ||
231 | // just grab whatever allocator was provided to lua_newstate | 227 | // just grab whatever allocator was provided to lua_newstate |
232 | U->protected_allocator.definition.allocF = lua_getallocf( L, &U->protected_allocator.definition.allocUD); | 228 | U->protected_allocator.definition.allocF = lua_getallocf( L, &U->protected_allocator.definition.allocUD); |
233 | } | 229 | } |
@@ -258,8 +254,6 @@ void cleanup_allocator_function( Universe* U, lua_State* L) | |||
258 | { | 254 | { |
259 | // install the non-protected allocator | 255 | // install the non-protected allocator |
260 | lua_setallocf( L, U->protected_allocator.definition.allocF, U->protected_allocator.definition.allocUD); | 256 | lua_setallocf( L, U->protected_allocator.definition.allocF, U->protected_allocator.definition.allocUD); |
261 | // release the mutex | ||
262 | MUTEX_FREE( &U->protected_allocator.lock); | ||
263 | } | 257 | } |
264 | } | 258 | } |
265 | 259 | ||
@@ -645,15 +639,13 @@ static lua_Integer get_mt_id( Universe* U, lua_State* L, int i) | |||
645 | lua_pushvalue( L, i); // ... _R[REG_MTID] {mt} | 639 | lua_pushvalue( L, i); // ... _R[REG_MTID] {mt} |
646 | lua_rawget( L, -2); // ... _R[REG_MTID] mtk? | 640 | lua_rawget( L, -2); // ... _R[REG_MTID] mtk? |
647 | 641 | ||
648 | id = lua_tointeger( L, -1); // 0 for nil | 642 | id = lua_tointeger( L, -1); // 0 for nil |
649 | lua_pop( L, 1); // ... _R[REG_MTID] | 643 | lua_pop( L, 1); // ... _R[REG_MTID] |
650 | STACK_CHECK( L, 1); | 644 | STACK_CHECK( L, 1); |
651 | 645 | ||
652 | if( id == 0) | 646 | if( id == 0) |
653 | { | 647 | { |
654 | MUTEX_LOCK( &U->mtid_lock); | 648 | id = U->last_mt_id.fetch_add(1, std::memory_order_relaxed); |
655 | id = ++ U->last_mt_id; | ||
656 | MUTEX_UNLOCK( &U->mtid_lock); | ||
657 | 649 | ||
658 | /* Create two-way references: id_uint <-> table | 650 | /* Create two-way references: id_uint <-> table |
659 | */ | 651 | */ |
diff --git a/src/universe.cpp b/src/universe.cpp index 06c7313..4dd956d 100644 --- a/src/universe.cpp +++ b/src/universe.cpp | |||
@@ -43,11 +43,11 @@ static constexpr UniqueKey UNIVERSE_REGKEY{ 0x9f877b2cf078f17full }; | |||
43 | 43 | ||
44 | Universe* universe_create(lua_State* L) | 44 | Universe* universe_create(lua_State* L) |
45 | { | 45 | { |
46 | Universe* U = (Universe*) lua_newuserdatauv( L, sizeof(Universe), 0); // universe | 46 | Universe* const U = static_cast<Universe*>(lua_newuserdatauv(L, sizeof(Universe), 0)); // universe |
47 | memset( U, 0, sizeof( Universe)); | 47 | U->Universe::Universe(); |
48 | STACK_CHECK_START_REL(L, 1); | 48 | STACK_CHECK_START_REL(L, 1); |
49 | UNIVERSE_REGKEY.set_registry(L, [](lua_State* L) { lua_pushvalue(L, -2); }); // universe | 49 | UNIVERSE_REGKEY.set_registry(L, [](lua_State* L) { lua_pushvalue(L, -2); }); // universe |
50 | STACK_CHECK( L, 1); | 50 | STACK_CHECK(L, 1); |
51 | return U; | 51 | return U; |
52 | } | 52 | } |
53 | 53 | ||
@@ -64,12 +64,11 @@ void universe_store(lua_State* L, Universe* U) | |||
64 | 64 | ||
65 | Universe* universe_get(lua_State* L) | 65 | Universe* universe_get(lua_State* L) |
66 | { | 66 | { |
67 | Universe* universe; | 67 | STACK_GROW(L, 2); |
68 | STACK_GROW( L, 2); | ||
69 | STACK_CHECK_START_REL(L, 0); | 68 | STACK_CHECK_START_REL(L, 0); |
70 | UNIVERSE_REGKEY.query_registry(L); | 69 | UNIVERSE_REGKEY.query_registry(L); |
71 | universe = (Universe*) lua_touserdata( L, -1); // nullptr if nil | 70 | Universe* const universe = static_cast<Universe*>(lua_touserdata(L, -1)); // nullptr if nil |
72 | lua_pop( L, 1); | 71 | lua_pop(L, 1); |
73 | STACK_CHECK( L, 0); | 72 | STACK_CHECK(L, 0); |
74 | return universe; | 73 | return universe; |
75 | } | 74 | } |
diff --git a/src/universe.h b/src/universe.h index 34cef33..a6beb68 100644 --- a/src/universe.h +++ b/src/universe.h | |||
@@ -8,9 +8,10 @@ extern "C" { | |||
8 | } | 8 | } |
9 | #endif // __cplusplus | 9 | #endif // __cplusplus |
10 | 10 | ||
11 | #include "threading.h" | ||
12 | #include "macros_and_utils.h" | 11 | #include "macros_and_utils.h" |
13 | 12 | ||
13 | #include <mutex> | ||
14 | |||
14 | // forwards | 15 | // forwards |
15 | struct DeepPrelude; | 16 | struct DeepPrelude; |
16 | struct Keepers; | 17 | struct Keepers; |
@@ -28,15 +29,15 @@ struct Lane; | |||
28 | // everything we need to provide to lua_newstate() | 29 | // everything we need to provide to lua_newstate() |
29 | struct AllocatorDefinition | 30 | struct AllocatorDefinition |
30 | { | 31 | { |
31 | lua_Alloc allocF; | 32 | lua_Alloc allocF{ nullptr }; |
32 | void* allocUD; | 33 | void* allocUD{ nullptr }; |
33 | }; | 34 | }; |
34 | 35 | ||
35 | // mutex-protected allocator for use with Lua states that share a non-threadsafe allocator | 36 | // mutex-protected allocator for use with Lua states that share a non-threadsafe allocator |
36 | struct ProtectedAllocator | 37 | struct ProtectedAllocator |
37 | { | 38 | { |
38 | AllocatorDefinition definition; | 39 | AllocatorDefinition definition; |
39 | MUTEX_T lock; | 40 | std::mutex lock; |
40 | }; | 41 | }; |
41 | 42 | ||
42 | // ################################################################################################ | 43 | // ################################################################################################ |
@@ -47,15 +48,15 @@ struct ProtectedAllocator | |||
47 | struct Universe | 48 | struct Universe |
48 | { | 49 | { |
49 | // for verbose errors | 50 | // for verbose errors |
50 | bool verboseErrors; | 51 | bool verboseErrors{ false }; |
51 | 52 | ||
52 | bool demoteFullUserdata; | 53 | bool demoteFullUserdata{ false }; |
53 | 54 | ||
54 | // before a state is created, this function will be called to obtain the allocator | 55 | // before a state is created, this function will be called to obtain the allocator |
55 | lua_CFunction provide_allocator; | 56 | lua_CFunction provide_allocator{ nullptr }; |
56 | 57 | ||
57 | // after a state is created, this function will be called right after the bases libraries are loaded | 58 | // after a state is created, this function will be called right after the bases libraries are loaded |
58 | lua_CFunction on_state_create_func; | 59 | lua_CFunction on_state_create_func{ nullptr }; |
59 | 60 | ||
60 | // if allocator="protected" is found in the configuration settings, a wrapper allocator will protect all allocator calls with a mutex | 61 | // if allocator="protected" is found in the configuration settings, a wrapper allocator will protect all allocator calls with a mutex |
61 | // contains a mutex and the original allocator definition | 62 | // contains a mutex and the original allocator definition |
@@ -63,38 +64,34 @@ struct Universe | |||
63 | 64 | ||
64 | AllocatorDefinition internal_allocator; | 65 | AllocatorDefinition internal_allocator; |
65 | 66 | ||
66 | Keepers* keepers; | 67 | Keepers* keepers{ nullptr }; |
67 | 68 | ||
68 | // Initialized by 'init_once_LOCKED()': the deep userdata Linda object | 69 | // Initialized by 'init_once_LOCKED()': the deep userdata Linda object |
69 | // used for timers (each lane will get a proxy to this) | 70 | // used for timers (each lane will get a proxy to this) |
70 | volatile DeepPrelude* timer_deep; // = nullptr | 71 | volatile DeepPrelude* timer_deep{ nullptr }; // = nullptr |
71 | 72 | ||
72 | #if HAVE_LANE_TRACKING() | 73 | #if HAVE_LANE_TRACKING() |
73 | MUTEX_T tracking_cs; | 74 | std::mutex tracking_cs; |
74 | Lane* volatile tracking_first; // will change to TRACKING_END if we want to activate tracking | 75 | Lane* volatile tracking_first{ nullptr }; // will change to TRACKING_END if we want to activate tracking |
75 | #endif // HAVE_LANE_TRACKING() | 76 | #endif // HAVE_LANE_TRACKING() |
76 | 77 | ||
77 | MUTEX_T selfdestruct_cs; | 78 | std::mutex selfdestruct_cs; |
78 | 79 | ||
79 | // require() serialization | 80 | // require() serialization |
80 | MUTEX_T require_cs; | 81 | std::recursive_mutex require_cs; |
81 | |||
82 | // Lock for reference counter inc/dec locks (to be initialized by outside code) TODO: get rid of this and use atomics instead! | ||
83 | MUTEX_T deep_lock; | ||
84 | MUTEX_T mtid_lock; | ||
85 | 82 | ||
86 | lua_Integer last_mt_id; | 83 | std::atomic<lua_Integer> last_mt_id{ 0 }; |
87 | 84 | ||
88 | #if USE_DEBUG_SPEW() | 85 | #if USE_DEBUG_SPEW() |
89 | int debugspew_indent_depth; | 86 | int debugspew_indent_depth{ 0 }; |
90 | #endif // USE_DEBUG_SPEW() | 87 | #endif // USE_DEBUG_SPEW() |
91 | 88 | ||
92 | Lane* volatile selfdestruct_first; | 89 | Lane* volatile selfdestruct_first{ nullptr }; |
93 | // After a lane has removed itself from the chain, it still performs some processing. | 90 | // After a lane has removed itself from the chain, it still performs some processing. |
94 | // The terminal desinit sequence should wait for all such processing to terminate before force-killing threads | 91 | // The terminal desinit sequence should wait for all such processing to terminate before force-killing threads |
95 | int volatile selfdestructing_count; | 92 | int volatile selfdestructing_count{ 0 }; |
96 | }; | 93 | }; |
97 | 94 | ||
98 | Universe* universe_get( lua_State* L); | 95 | Universe* universe_get(lua_State* L); |
99 | Universe* universe_create( lua_State* L); | 96 | Universe* universe_create(lua_State* L); |
100 | void universe_store( lua_State* L, Universe* U); | 97 | void universe_store(lua_State* L, Universe* U); |