aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/deep.cpp79
-rw-r--r--src/deep.h10
-rw-r--r--src/lanes.cpp70
-rw-r--r--src/linda.cpp8
-rw-r--r--src/state.cpp6
-rw-r--r--src/tools.cpp18
-rw-r--r--src/universe.cpp15
-rw-r--r--src/universe.h47
8 files changed, 112 insertions, 141 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
144void free_deep_prelude( lua_State* L, DeepPrelude* prelude_) 144void 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 */
205char const* push_deep_proxy( Universe* U, lua_State* L, DeepPrelude* prelude, int nuv_, LookupMode mode_) 204char 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*/
379int luaG_newdeepuserdata( lua_State* L, luaG_IdFunction* idfunc, int nuv_) 373int 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 {
diff --git a/src/deep.h b/src/deep.h
index 5322525..878fa63 100644
--- a/src/deep.h
+++ b/src/deep.h
@@ -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
20struct Universe; 22struct 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
42static constexpr UniqueKey DEEP_VERSION{ 0xB4B0119C10642B29ull }; 44static 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
45struct DeepPrelude 47struct 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
54char const* push_deep_proxy( Universe* U, lua_State* L, DeepPrelude* prelude, int nuv_, LookupMode mode_); 56char const* push_deep_proxy(lua_State* L, DeepPrelude* prelude, int nuv_, LookupMode mode_);
55void free_deep_prelude( lua_State* L, DeepPrelude* prelude_); 57void free_deep_prelude( lua_State* L, DeepPrelude* prelude_);
56 58
57LANES_API int luaG_newdeepuserdata( lua_State* L, luaG_IdFunction* idfunc, int nuv_); 59LANES_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 */
188static void tracking_add( Lane* s) 188static 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 */
204static bool tracking_remove( Lane* s) 204static 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 */
397static void selfdestruct_add( Lane* s) 397static 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)
410static bool selfdestruct_remove( Lane* s) 410static 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
44Universe* universe_create(lua_State* L) 44Universe* 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
65Universe* universe_get(lua_State* L) 65Universe* 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
15struct DeepPrelude; 16struct DeepPrelude;
16struct Keepers; 17struct 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()
29struct AllocatorDefinition 30struct 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
36struct ProtectedAllocator 37struct 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
47struct Universe 48struct 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
98Universe* universe_get( lua_State* L); 95Universe* universe_get(lua_State* L);
99Universe* universe_create( lua_State* L); 96Universe* universe_create(lua_State* L);
100void universe_store( lua_State* L, Universe* U); 97void universe_store(lua_State* L, Universe* U);