diff options
Diffstat (limited to 'src/lanes.cpp')
-rw-r--r-- | src/lanes.cpp | 88 |
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) | ||
103 | static void tracking_add(Lane* lane_); | ||
104 | |||
105 | Lane::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 | //--- | 252 | Lane::~Lane() |
232 | // low-level cleanup | ||
233 | |||
234 | static 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); |