aboutsummaryrefslogtreecommitdiff
path: root/src/lanes.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lanes.c')
-rw-r--r--src/lanes.c203
1 files changed, 2 insertions, 201 deletions
diff --git a/src/lanes.c b/src/lanes.c
index 8762766..cbac6da 100644
--- a/src/lanes.c
+++ b/src/lanes.c
@@ -1,6 +1,6 @@
1/* 1/*
2 * LANES.C Copyright (c) 2007-08, Asko Kauppi 2 * LANES.C Copyright (c) 2007-08, Asko Kauppi
3 * Copyright (C) 2009-17, Benoit Germain 3 * Copyright (C) 2009-19, Benoit Germain
4 * 4 *
5 * Multithreading in Lua. 5 * Multithreading in Lua.
6 * 6 *
@@ -56,7 +56,7 @@
56=============================================================================== 56===============================================================================
57 57
58Copyright (C) 2007-10 Asko Kauppi <akauppi@gmail.com> 58Copyright (C) 2007-10 Asko Kauppi <akauppi@gmail.com>
59 2011-17 Benoit Germain <bnt.germain@gmail.com> 59 2011-19 Benoit Germain <bnt.germain@gmail.com>
60 60
61Permission is hereby granted, free of charge, to any person obtaining a copy 61Permission is hereby granted, free of charge, to any person obtaining a copy
62of this software and associated documentation files (the "Software"), to deal 62of this software and associated documentation files (the "Software"), to deal
@@ -124,33 +124,6 @@ static void securize_debug_threadname( lua_State* L, Lane* s)
124 STACK_END( L, 0); 124 STACK_END( L, 0);
125} 125}
126 126
127/*
128* Check if the thread in question ('L') has been signalled for cancel.
129*
130* Called by cancellation hooks and/or pending Linda operations (because then
131* the check won't affect performance).
132*
133* Returns TRUE if any locks are to be exited, and 'cancel_error()' called,
134* to make execution of the lane end.
135*/
136static inline enum e_cancel_request cancel_test( lua_State* L)
137{
138 Lane* const s = get_lane_from_registry( L);
139 // 's' is NULL for the original main state (and no-one can cancel that)
140 return s ? s->cancel_request : CANCEL_NONE;
141}
142
143static void cancel_hook( lua_State* L, lua_Debug* ar)
144{
145 (void)ar;
146 DEBUGSPEW_CODE( fprintf( stderr, "cancel_hook\n"));
147 if( cancel_test( L) != CANCEL_NONE)
148 {
149 cancel_error( L);
150 }
151}
152
153
154#if ERROR_FULL_STACK 127#if ERROR_FULL_STACK
155static int lane_error( lua_State* L); 128static int lane_error( lua_State* L);
156// crc64/we of string "STACKTRACE_REGKEY" generated at http://www.nitrxgen.net/hashgen/ 129// crc64/we of string "STACKTRACE_REGKEY" generated at http://www.nitrxgen.net/hashgen/
@@ -404,115 +377,6 @@ static int run_finalizers( lua_State* L, int lua_rc)
404 * ############################################################################################### 377 * ###############################################################################################
405 */ 378 */
406 379
407//---
408// = thread_cancel( lane_ud [,timeout_secs=0.0] [,force_kill_bool=false] )
409//
410// The originator thread asking us specifically to cancel the other thread.
411//
412// 'timeout': <0: wait forever, until the lane is finished
413// 0.0: just signal it to cancel, no time waited
414// >0: time to wait for the lane to detect cancellation
415//
416// 'force_kill': if true, and lane does not detect cancellation within timeout,
417// it is forcefully killed. Using this with 0.0 timeout means just kill
418// (unless the lane is already finished).
419//
420// Returns: true if the lane was already finished (DONE/ERROR_ST/CANCELLED) or if we
421// managed to cancel it.
422// false if the cancellation timed out, or a kill was needed.
423//
424
425typedef enum
426{
427 CR_Timeout,
428 CR_Cancelled,
429 CR_Killed
430} cancel_result;
431
432static cancel_result thread_cancel_soft( lua_State* L, Lane* s, bool_t wake_lindas_)
433{
434 s->cancel_request = CANCEL_SOFT; // it's now signaled to stop
435 // negative timeout: we don't want to truly abort the lane, we just want it to react to cancel_test() on its own
436 if( wake_lindas_) // wake the thread so that execution returns from any pending linda operation if desired
437 {
438 SIGNAL_T *waiting_on = s->waiting_on;
439 if( s->status == WAITING && waiting_on != NULL)
440 {
441 SIGNAL_ALL( waiting_on);
442 }
443 }
444 // say we succeeded though
445 return CR_Cancelled;
446}
447
448static cancel_result thread_cancel_hard( lua_State* L, Lane* s, double secs_, bool_t force_, double waitkill_timeout_)
449{
450 cancel_result result;
451
452 s->cancel_request = CANCEL_HARD; // it's now signaled to stop
453 {
454 SIGNAL_T *waiting_on = s->waiting_on;
455 if( s->status == WAITING && waiting_on != NULL)
456 {
457 SIGNAL_ALL( waiting_on);
458 }
459 }
460
461 result = THREAD_WAIT( &s->thread, secs_, &s->done_signal, &s->done_lock, &s->status) ? CR_Cancelled : CR_Timeout;
462
463 if( (result == CR_Timeout) && force_)
464 {
465 // Killing is asynchronous; we _will_ wait for it to be done at
466 // GC, to make sure the data structure can be released (alternative
467 // would be use of "cancellation cleanup handlers" that at least
468 // PThread seems to have).
469 //
470 THREAD_KILL( &s->thread);
471#if THREADAPI == THREADAPI_PTHREAD
472 // pthread: make sure the thread is really stopped!
473 // note that this may block forever if the lane doesn't call a cancellation point and pthread doesn't honor PTHREAD_CANCEL_ASYNCHRONOUS
474 result = THREAD_WAIT( &s->thread, waitkill_timeout_, &s->done_signal, &s->done_lock, &s->status);
475 if( result == CR_Timeout)
476 {
477 return luaL_error( L, "force-killed lane failed to terminate within %f second%s", waitkill_timeout_, waitkill_timeout_ > 1 ? "s" : "");
478 }
479#else
480 (void) waitkill_timeout_; // unused
481 (void) L; // unused
482#endif // THREADAPI == THREADAPI_PTHREAD
483 s->mstatus = KILLED; // mark 'gc' to wait for it
484 // note that s->status value must remain to whatever it was at the time of the kill
485 // because we need to know if we can lua_close() the Lua State or not.
486 result = CR_Killed;
487 }
488 return result;
489}
490
491static cancel_result thread_cancel( lua_State* L, Lane* s, double secs_, bool_t force_, double waitkill_timeout_)
492{
493 // remember that lanes are not transferable: only one thread can cancel a lane, so no multithreading issue here
494 // We can read 's->status' without locks, but not wait for it (if Posix no PTHREAD_TIMEDJOIN)
495 if( s->mstatus == KILLED)
496 {
497 return CR_Killed;
498 }
499
500 if( s->status >= DONE)
501 {
502 // say "ok" by default, including when lane is already done
503 return CR_Cancelled;
504 }
505
506 // signal the linda the wake up the thread so that it can react to the cancel query
507 // let us hope we never land here with a pointer on a linda that has been destroyed...
508 if( secs_ < 0.0)
509 {
510 return thread_cancel_soft( L, s, force_);
511 }
512
513 return thread_cancel_hard( L, s, secs_, force_, waitkill_timeout_);
514}
515
516// 380//
517// Protects modifying the selfdestruct chain 381// Protects modifying the selfdestruct chain
518 382
@@ -734,19 +598,6 @@ static int selfdestruct_gc( lua_State* L)
734 598
735 599
736//--- 600//---
737// bool = cancel_test()
738//
739// Available inside the global namespace of lanes
740// returns a boolean saying if a cancel request is pending
741//
742LUAG_FUNC( cancel_test)
743{
744 enum e_cancel_request test = cancel_test( L);
745 lua_pushboolean( L, test != CANCEL_NONE);
746 return 1;
747}
748
749//---
750// = _single( [cores_uint=1] ) 601// = _single( [cores_uint=1] )
751// 602//
752// Limits the process to use only 'cores' CPU cores. To be used for performance 603// Limits the process to use only 'cores' CPU cores. To be used for performance
@@ -1527,56 +1378,6 @@ LUAG_FUNC( thread_gc)
1527 return 0; 1378 return 0;
1528} 1379}
1529 1380
1530// lane_h:cancel( [timeout] [, force [, forcekill_timeout]])
1531LUAG_FUNC( thread_cancel)
1532{
1533 Lane* s = lua_toLane( L, 1);
1534 double secs = 0.0;
1535 int force_i = 2;
1536 int forcekill_timeout_i = 3;
1537
1538 if( lua_isnumber( L, 2))
1539 {
1540 secs = lua_tonumber( L, 2);
1541 if( secs < 0.0 && lua_gettop( L) > 3)
1542 {
1543 return luaL_error( L, "can't force_kill a soft cancel");
1544 }
1545 // negative timeout and force flag means we want to wake linda-waiting threads
1546 ++ force_i;
1547 ++ forcekill_timeout_i;
1548 }
1549 else if( lua_isnil( L, 2))
1550 {
1551 ++ force_i;
1552 ++ forcekill_timeout_i;
1553 }
1554
1555 {
1556 bool_t force = lua_toboolean( L, force_i); // FALSE if nothing there
1557 double forcekill_timeout = luaL_optnumber( L, forcekill_timeout_i, 0.0);
1558
1559 switch( thread_cancel( L, s, secs, force, forcekill_timeout))
1560 {
1561 case CR_Timeout:
1562 lua_pushboolean( L, 0);
1563 lua_pushstring( L, "timeout");
1564 return 2;
1565
1566 case CR_Cancelled:
1567 lua_pushboolean( L, 1);
1568 return 1;
1569
1570 case CR_Killed:
1571 lua_pushboolean( L, 0);
1572 lua_pushstring( L, "killed");
1573 return 2;
1574 }
1575 }
1576 // should never happen, only here to prevent the compiler from complaining of "not all control paths returning a value"
1577 return 0;
1578}
1579
1580//--- 1381//---
1581// str= thread_status( lane ) 1382// str= thread_status( lane )
1582// 1383//