aboutsummaryrefslogtreecommitdiff
path: root/src/lanes.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/lanes.cpp')
-rw-r--r--src/lanes.cpp88
1 files changed, 42 insertions, 46 deletions
diff --git a/src/lanes.cpp b/src/lanes.cpp
index 327c2df..079b880 100644
--- a/src/lanes.cpp
+++ b/src/lanes.cpp
@@ -99,6 +99,27 @@ THE SOFTWARE.
99# include <sys/types.h> 99# include <sys/types.h>
100#endif 100#endif
101 101
102// forwarding (will do things better later)
103static void tracking_add(Lane* lane_);
104
105Lane::Lane(Universe* U_, lua_State* L_)
106: U{ U_ }
107, L{ L_ }
108{
109#if THREADWAIT_METHOD == THREADWAIT_CONDVAR
110 MUTEX_INIT(&done_lock);
111 SIGNAL_INIT(&done_signal);
112#endif // THREADWAIT_METHOD == THREADWAIT_CONDVAR
113
114#if HAVE_LANE_TRACKING()
115 if (U->tracking_first)
116 {
117 tracking_add(this);
118 }
119#endif // HAVE_LANE_TRACKING()
120}
121
122
102/* Do you want full call stacks, or just the line where the error happened? 123/* Do you want full call stacks, or just the line where the error happened?
103* 124*
104* TBD: The full stack feature does not seem to work (try 'make error'). 125* TBD: The full stack feature does not seem to work (try 'make error').
@@ -228,27 +249,22 @@ static bool tracking_remove(Lane* lane_)
228 249
229// ################################################################################################# 250// #################################################################################################
230 251
231//--- 252Lane::~Lane()
232// low-level cleanup
233
234static void lane_cleanup(Lane* lane_)
235{ 253{
236 // Clean up after a (finished) thread 254 // Clean up after a (finished) thread
237 // 255 //
238#if THREADWAIT_METHOD == THREADWAIT_CONDVAR 256#if THREADWAIT_METHOD == THREADWAIT_CONDVAR
239 SIGNAL_FREE(&lane_->done_signal); 257 SIGNAL_FREE(&done_signal);
240 MUTEX_FREE(&lane_->done_lock); 258 MUTEX_FREE(&done_lock);
241#endif // THREADWAIT_METHOD == THREADWAIT_CONDVAR 259#endif // THREADWAIT_METHOD == THREADWAIT_CONDVAR
242 260
243#if HAVE_LANE_TRACKING() 261#if HAVE_LANE_TRACKING()
244 if (lane_->U->tracking_first != nullptr) 262 if (U->tracking_first != nullptr)
245 { 263 {
246 // Lane was cleaned up, no need to handle at process termination 264 // Lane was cleaned up, no need to handle at process termination
247 tracking_remove(lane_); 265 tracking_remove(this);
248 } 266 }
249#endif // HAVE_LANE_TRACKING() 267#endif // HAVE_LANE_TRACKING()
250
251 lane_->U->internal_allocator.free(lane_, sizeof(Lane));
252} 268}
253 269
254/* 270/*
@@ -536,7 +552,7 @@ static int selfdestruct_gc( lua_State* L)
536#endif // THREADAPI == THREADAPI_PTHREAD 552#endif // THREADAPI == THREADAPI_PTHREAD
537 } 553 }
538 // NO lua_close() in this case because we don't know where execution of the state was interrupted 554 // NO lua_close() in this case because we don't know where execution of the state was interrupted
539 lane_cleanup(lane); 555 delete lane;
540 lane = next_s; 556 lane = next_s;
541 ++n; 557 ++n;
542 } 558 }
@@ -565,7 +581,7 @@ static int selfdestruct_gc( lua_State* L)
565 U->timer_deep = nullptr; 581 U->timer_deep = nullptr;
566 } 582 }
567 583
568 close_keepers( U); 584 close_keepers(U);
569 585
570 // remove the protected allocator, if any 586 // remove the protected allocator, if any
571 U->protected_allocator.removeFrom(L); 587 U->protected_allocator.removeFrom(L);
@@ -919,7 +935,7 @@ static THREAD_RETURN_T THREAD_CALLCONV lane_main(void* vs)
919 // STACK_DUMP(L); 935 // STACK_DUMP(L);
920 // Call finalizers, if the script has set them up. 936 // Call finalizers, if the script has set them up.
921 // 937 //
922 int rc2 = run_finalizers(L, rc); 938 int rc2{ run_finalizers(L, rc) };
923 DEBUGSPEW_CODE(fprintf(stderr, INDENT_BEGIN "Lane %p finalizer: %s\n" INDENT_END, L, get_errcode_name(rc2))); 939 DEBUGSPEW_CODE(fprintf(stderr, INDENT_BEGIN "Lane %p finalizer: %s\n" INDENT_END, L, get_errcode_name(rc2)));
924 if (rc2 != LUA_OK) // Error within a finalizer! 940 if (rc2 != LUA_OK) // Error within a finalizer!
925 { 941 {
@@ -938,7 +954,7 @@ static THREAD_RETURN_T THREAD_CALLCONV lane_main(void* vs)
938 --lane->U->selfdestructing_count; 954 --lane->U->selfdestructing_count;
939 lane->U->selfdestruct_cs.unlock(); 955 lane->U->selfdestruct_cs.unlock();
940 956
941 lane_cleanup(lane); // s is freed at this point 957 delete lane;
942 } 958 }
943 else 959 else
944 { 960 {
@@ -1207,35 +1223,14 @@ LUAG_FUNC( lane_new)
1207 STACK_CHECK( L2, 1 + nargs); 1223 STACK_CHECK( L2, 1 + nargs);
1208 1224
1209 // 'lane' is allocated from heap, not Lua, since its life span may surpass the handle's (if free running thread) 1225 // 'lane' is allocated from heap, not Lua, since its life span may surpass the handle's (if free running thread)
1210 // 1226 Lane* const lane{ new (U) Lane{ U, L2 } };
1211 // a Lane full userdata needs a single uservalue
1212 Lane** const ud{ lua_newuserdatauv<Lane*>(L, 1) }; // func libs priority globals package required gc_cb lane
1213 Lane* const lane{ *ud = static_cast<Lane*>(U->internal_allocator.alloc(sizeof(Lane))) }; // don't forget to store the pointer in the userdata!
1214 if (lane == nullptr) 1227 if (lane == nullptr)
1215 { 1228 {
1216 return luaL_error(L, "could not create lane: out of memory"); 1229 return luaL_error(L, "could not create lane: out of memory");
1217 } 1230 }
1218 1231 // a Lane full userdata needs a single uservalue
1219 lane->L = L2; 1232 Lane** const ud{ lua_newuserdatauv<Lane*>(L, 1) }; // func libs priority globals package required gc_cb lane
1220 lane->U = U; 1233 *ud = lane; // don't forget to store the pointer in the userdata!
1221 lane->status = PENDING;
1222 lane->waiting_on = nullptr;
1223 lane->debug_name = "<unnamed>";
1224 lane->cancel_request = CancelRequest::None;
1225
1226#if THREADWAIT_METHOD == THREADWAIT_CONDVAR
1227 MUTEX_INIT(&lane->done_lock);
1228 SIGNAL_INIT(&lane->done_signal);
1229#endif // THREADWAIT_METHOD == THREADWAIT_CONDVAR
1230 lane->mstatus = ThreadStatus::Normal;
1231 lane->selfdestruct_next = nullptr;
1232#if HAVE_LANE_TRACKING()
1233 lane->tracking_next = nullptr;
1234 if (lane->U->tracking_first)
1235 {
1236 tracking_add(lane);
1237 }
1238#endif // HAVE_LANE_TRACKING()
1239 1234
1240 // Set metatable for the userdata 1235 // Set metatable for the userdata
1241 // 1236 //
@@ -1245,7 +1240,7 @@ LUAG_FUNC( lane_new)
1245 1240
1246 // Create uservalue for the userdata 1241 // Create uservalue for the userdata
1247 // (this is where lane body return values will be stored when the handle is indexed by a numeric key) 1242 // (this is where lane body return values will be stored when the handle is indexed by a numeric key)
1248 lua_newtable( L); // func libs cancelstep priority globals package required gc_cb lane uv 1243 lua_newtable(L); // func libs cancelstep priority globals package required gc_cb lane uv
1249 1244
1250 // Store the gc_cb callback in the uservalue 1245 // Store the gc_cb callback in the uservalue
1251 if (gc_cb_idx > 0) 1246 if (gc_cb_idx > 0)
@@ -1263,6 +1258,7 @@ LUAG_FUNC( lane_new)
1263 STACK_CHECK(L, 1); 1258 STACK_CHECK(L, 1);
1264 STACK_CHECK( L2, 1 + nargs); 1259 STACK_CHECK( L2, 1 + nargs);
1265 1260
1261 // TODO: launch thread earlier, sync with a std::latch to parallelize OS thread warmup and L2 preparation
1266 DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "lane_new: launching thread\n" INDENT_END)); 1262 DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "lane_new: launching thread\n" INDENT_END));
1267 THREAD_CREATE(&lane->thread, lane_main, lane, priority); 1263 THREAD_CREATE(&lane->thread, lane_main, lane, priority);
1268 1264
@@ -1306,7 +1302,7 @@ LUAG_FUNC(thread_gc)
1306 1302
1307 // We can read 'lane->status' without locks, but not wait for it 1303 // We can read 'lane->status' without locks, but not wait for it
1308 // test Killed state first, as it doesn't need to enter the selfdestruct chain 1304 // test Killed state first, as it doesn't need to enter the selfdestruct chain
1309 if (lane->mstatus == ThreadStatus::Killed) 1305 if (lane->mstatus == Lane::Killed)
1310 { 1306 {
1311 // Make sure a kill has proceeded, before cleaning up the data structure. 1307 // Make sure a kill has proceeded, before cleaning up the data structure.
1312 // 1308 //
@@ -1350,7 +1346,7 @@ LUAG_FUNC(thread_gc)
1350 } 1346 }
1351 1347
1352 // Clean up after a (finished) thread 1348 // Clean up after a (finished) thread
1353 lane_cleanup(lane); 1349 delete lane;
1354 1350
1355 // do this after lane cleanup in case the callback triggers an error 1351 // do this after lane cleanup in case the callback triggers an error
1356 if (have_gc_cb) 1352 if (have_gc_cb)
@@ -1377,7 +1373,7 @@ static char const * thread_status_string(Lane* lane_)
1377{ 1373{
1378 enum e_status const st{ lane_->status }; // read just once (volatile) 1374 enum e_status const st{ lane_->status }; // read just once (volatile)
1379 char const* str = 1375 char const* str =
1380 (lane_->mstatus == ThreadStatus::Killed) ? "killed" : // new to v3.3.0! 1376 (lane_->mstatus == Lane::Killed) ? "killed" : // new to v3.3.0!
1381 (st == PENDING) ? "pending" : 1377 (st == PENDING) ? "pending" :
1382 (st == RUNNING) ? "running" : // like in 'co.status()' 1378 (st == RUNNING) ? "running" : // like in 'co.status()'
1383 (st == WAITING) ? "waiting" : 1379 (st == WAITING) ? "waiting" :
@@ -1413,7 +1409,6 @@ LUAG_FUNC(thread_join)
1413 Lane* const lane{ lua_toLane(L, 1) }; 1409 Lane* const lane{ lua_toLane(L, 1) };
1414 lua_Number const wait_secs{ luaL_optnumber(L, 2, -1.0) }; 1410 lua_Number const wait_secs{ luaL_optnumber(L, 2, -1.0) };
1415 lua_State* const L2{ lane->L }; 1411 lua_State* const L2{ lane->L };
1416 int ret;
1417 bool const done{ THREAD_ISNULL(lane->thread) || THREAD_WAIT(&lane->thread, wait_secs, &lane->done_signal, &lane->done_lock, &lane->status) }; 1412 bool const done{ THREAD_ISNULL(lane->thread) || THREAD_WAIT(&lane->thread, wait_secs, &lane->done_signal, &lane->done_lock, &lane->status) };
1418 if (!done || !L2) 1413 if (!done || !L2)
1419 { 1414 {
@@ -1426,7 +1421,8 @@ LUAG_FUNC(thread_join)
1426 STACK_CHECK_START_REL(L, 0); 1421 STACK_CHECK_START_REL(L, 0);
1427 // Thread is DONE/ERROR_ST/CANCELLED; all ours now 1422 // Thread is DONE/ERROR_ST/CANCELLED; all ours now
1428 1423
1429 if (lane->mstatus == ThreadStatus::Killed) // OS thread was killed if thread_cancel was forced 1424 int ret{ 0 };
1425 if (lane->mstatus == Lane::Killed) // OS thread was killed if thread_cancel was forced
1430 { 1426 {
1431 // in that case, even if the thread was killed while DONE/ERROR_ST/CANCELLED, ignore regular return values 1427 // in that case, even if the thread was killed while DONE/ERROR_ST/CANCELLED, ignore regular return values
1432 STACK_GROW(L, 2); 1428 STACK_GROW(L, 2);
@@ -1536,7 +1532,7 @@ LUAG_FUNC(thread_index)
1536 switch (lane->status) 1532 switch (lane->status)
1537 { 1533 {
1538 default: 1534 default:
1539 if (lane->mstatus != ThreadStatus::Killed) 1535 if (lane->mstatus != Lane::Killed)
1540 { 1536 {
1541 // this is an internal error, we probably never get here 1537 // this is an internal error, we probably never get here
1542 lua_settop(L, 0); 1538 lua_settop(L, 0);