diff options
author | Benoit Germain <b n t DOT g e r m a i n AT g m a i l DOT c o m> | 2019-04-22 17:17:03 +0200 |
---|---|---|
committer | Benoit Germain <b n t DOT g e r m a i n AT g m a i l DOT c o m> | 2019-04-22 17:17:03 +0200 |
commit | 32f8cdfc73ed90dcf88ffcf4bfc1a3e4d5a69e6c (patch) | |
tree | 9f348cc5cf26f37b8801aaccd0e1d2647e4a3675 /src | |
parent | b735db9ef342973deb628129fc04f0d295616164 (diff) | |
download | lanes-32f8cdfc73ed90dcf88ffcf4bfc1a3e4d5a69e6c.tar.gz lanes-32f8cdfc73ed90dcf88ffcf4bfc1a3e4d5a69e6c.tar.bz2 lanes-32f8cdfc73ed90dcf88ffcf4bfc1a3e4d5a69e6c.zip |
Moved cancellation code in separate files
Diffstat (limited to 'src')
-rw-r--r-- | src/cancel.c | 252 | ||||
-rw-r--r-- | src/cancel.h | 57 | ||||
-rw-r--r-- | src/lanes.c | 203 | ||||
-rw-r--r-- | src/lanes_private.h | 24 | ||||
-rw-r--r-- | src/macros_and_utils.h | 2 | ||||
-rw-r--r-- | src/tools.c | 4 | ||||
-rw-r--r-- | src/tools.h | 2 |
7 files changed, 316 insertions, 228 deletions
diff --git a/src/cancel.c b/src/cancel.c new file mode 100644 index 0000000..11e100d --- /dev/null +++ b/src/cancel.c | |||
@@ -0,0 +1,252 @@ | |||
1 | /* | ||
2 | -- | ||
3 | -- CANCEL.C | ||
4 | -- | ||
5 | -- Lane cancellation support | ||
6 | -- | ||
7 | -- Author: Benoit Germain <bnt.germain@gmail.com> | ||
8 | -- | ||
9 | --[[ | ||
10 | =============================================================================== | ||
11 | |||
12 | Copyright (C) 2011-2019 Benoit Germain <bnt.germain@gmail.com> | ||
13 | |||
14 | Permission is hereby granted, free of charge, to any person obtaining a copy | ||
15 | of this software and associated documentation files (the "Software"), to deal | ||
16 | in the Software without restriction, including without limitation the rights | ||
17 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
18 | copies of the Software, and to permit persons to whom the Software is | ||
19 | furnished to do so, subject to the following conditions: | ||
20 | |||
21 | The above copyright notice and this permission notice shall be included in | ||
22 | all copies or substantial portions of the Software. | ||
23 | |||
24 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
25 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
26 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
27 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
28 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
29 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
30 | THE SOFTWARE. | ||
31 | |||
32 | =============================================================================== | ||
33 | ]]-- | ||
34 | */ | ||
35 | |||
36 | #include <assert.h> | ||
37 | |||
38 | #include "threading.h" | ||
39 | #include "cancel.h" | ||
40 | #include "tools.h" | ||
41 | #include "lanes_private.h" | ||
42 | |||
43 | // ################################################################################################ | ||
44 | // ################################################################################################ | ||
45 | |||
46 | /* | ||
47 | * Check if the thread in question ('L') has been signalled for cancel. | ||
48 | * | ||
49 | * Called by cancellation hooks and/or pending Linda operations (because then | ||
50 | * the check won't affect performance). | ||
51 | * | ||
52 | * Returns TRUE if any locks are to be exited, and 'cancel_error()' called, | ||
53 | * to make execution of the lane end. | ||
54 | */ | ||
55 | static inline enum e_cancel_request cancel_test( lua_State* L) | ||
56 | { | ||
57 | Lane* const s = get_lane_from_registry( L); | ||
58 | // 's' is NULL for the original main state (and no-one can cancel that) | ||
59 | return s ? s->cancel_request : CANCEL_NONE; | ||
60 | } | ||
61 | |||
62 | // ################################################################################################ | ||
63 | |||
64 | //--- | ||
65 | // bool = cancel_test() | ||
66 | // | ||
67 | // Available inside the global namespace of lanes | ||
68 | // returns a boolean saying if a cancel request is pending | ||
69 | // | ||
70 | LUAG_FUNC( cancel_test) | ||
71 | { | ||
72 | enum e_cancel_request test = cancel_test( L); | ||
73 | lua_pushboolean( L, test != CANCEL_NONE); | ||
74 | return 1; | ||
75 | } | ||
76 | |||
77 | // ################################################################################################ | ||
78 | // ################################################################################################ | ||
79 | |||
80 | void cancel_hook( lua_State* L, lua_Debug* ar) | ||
81 | { | ||
82 | (void)ar; | ||
83 | DEBUGSPEW_CODE( fprintf( stderr, "cancel_hook\n")); | ||
84 | if( cancel_test( L) != CANCEL_NONE) | ||
85 | { | ||
86 | cancel_error( L); | ||
87 | } | ||
88 | } | ||
89 | |||
90 | // ################################################################################################ | ||
91 | // ################################################################################################ | ||
92 | |||
93 | //--- | ||
94 | // = thread_cancel( lane_ud [,timeout_secs=0.0] [,force_kill_bool=false] ) | ||
95 | // | ||
96 | // The originator thread asking us specifically to cancel the other thread. | ||
97 | // | ||
98 | // 'timeout': <0: wait forever, until the lane is finished | ||
99 | // 0.0: just signal it to cancel, no time waited | ||
100 | // >0: time to wait for the lane to detect cancellation | ||
101 | // | ||
102 | // 'force_kill': if true, and lane does not detect cancellation within timeout, | ||
103 | // it is forcefully killed. Using this with 0.0 timeout means just kill | ||
104 | // (unless the lane is already finished). | ||
105 | // | ||
106 | // Returns: true if the lane was already finished (DONE/ERROR_ST/CANCELLED) or if we | ||
107 | // managed to cancel it. | ||
108 | // false if the cancellation timed out, or a kill was needed. | ||
109 | // | ||
110 | |||
111 | // ################################################################################################ | ||
112 | |||
113 | static cancel_result thread_cancel_soft( Lane* s, bool_t wake_lindas_) | ||
114 | { | ||
115 | s->cancel_request = CANCEL_SOFT; // it's now signaled to stop | ||
116 | // negative timeout: we don't want to truly abort the lane, we just want it to react to cancel_test() on its own | ||
117 | if( wake_lindas_) // wake the thread so that execution returns from any pending linda operation if desired | ||
118 | { | ||
119 | SIGNAL_T *waiting_on = s->waiting_on; | ||
120 | if( s->status == WAITING && waiting_on != NULL) | ||
121 | { | ||
122 | SIGNAL_ALL( waiting_on); | ||
123 | } | ||
124 | } | ||
125 | // say we succeeded though | ||
126 | return CR_Cancelled; | ||
127 | } | ||
128 | |||
129 | // ################################################################################################ | ||
130 | |||
131 | static cancel_result thread_cancel_hard( lua_State* L, Lane* s, double secs_, bool_t force_, double waitkill_timeout_) | ||
132 | { | ||
133 | cancel_result result; | ||
134 | |||
135 | s->cancel_request = CANCEL_HARD; // it's now signaled to stop | ||
136 | { | ||
137 | SIGNAL_T *waiting_on = s->waiting_on; | ||
138 | if( s->status == WAITING && waiting_on != NULL) | ||
139 | { | ||
140 | SIGNAL_ALL( waiting_on); | ||
141 | } | ||
142 | } | ||
143 | |||
144 | result = THREAD_WAIT( &s->thread, secs_, &s->done_signal, &s->done_lock, &s->status) ? CR_Cancelled : CR_Timeout; | ||
145 | |||
146 | if( (result == CR_Timeout) && force_) | ||
147 | { | ||
148 | // Killing is asynchronous; we _will_ wait for it to be done at | ||
149 | // GC, to make sure the data structure can be released (alternative | ||
150 | // would be use of "cancellation cleanup handlers" that at least | ||
151 | // PThread seems to have). | ||
152 | // | ||
153 | THREAD_KILL( &s->thread); | ||
154 | #if THREADAPI == THREADAPI_PTHREAD | ||
155 | // pthread: make sure the thread is really stopped! | ||
156 | // note that this may block forever if the lane doesn't call a cancellation point and pthread doesn't honor PTHREAD_CANCEL_ASYNCHRONOUS | ||
157 | result = THREAD_WAIT( &s->thread, waitkill_timeout_, &s->done_signal, &s->done_lock, &s->status); | ||
158 | if( result == CR_Timeout) | ||
159 | { | ||
160 | return luaL_error( L, "force-killed lane failed to terminate within %f second%s", waitkill_timeout_, waitkill_timeout_ > 1 ? "s" : ""); | ||
161 | } | ||
162 | #else | ||
163 | (void) waitkill_timeout_; // unused | ||
164 | (void) L; // unused | ||
165 | #endif // THREADAPI == THREADAPI_PTHREAD | ||
166 | s->mstatus = KILLED; // mark 'gc' to wait for it | ||
167 | // note that s->status value must remain to whatever it was at the time of the kill | ||
168 | // because we need to know if we can lua_close() the Lua State or not. | ||
169 | result = CR_Killed; | ||
170 | } | ||
171 | return result; | ||
172 | } | ||
173 | |||
174 | // ################################################################################################ | ||
175 | |||
176 | cancel_result thread_cancel( lua_State* L, Lane* s, double secs_, bool_t force_, double waitkill_timeout_) | ||
177 | { | ||
178 | // remember that lanes are not transferable: only one thread can cancel a lane, so no multithreading issue here | ||
179 | // We can read 's->status' without locks, but not wait for it (if Posix no PTHREAD_TIMEDJOIN) | ||
180 | if( s->mstatus == KILLED) | ||
181 | { | ||
182 | return CR_Killed; | ||
183 | } | ||
184 | |||
185 | if( s->status >= DONE) | ||
186 | { | ||
187 | // say "ok" by default, including when lane is already done | ||
188 | return CR_Cancelled; | ||
189 | } | ||
190 | |||
191 | // signal the linda the wake up the thread so that it can react to the cancel query | ||
192 | // let us hope we never land here with a pointer on a linda that has been destroyed... | ||
193 | if( secs_ < 0.0) | ||
194 | { | ||
195 | return thread_cancel_soft( s, force_); | ||
196 | } | ||
197 | |||
198 | return thread_cancel_hard( L, s, secs_, force_, waitkill_timeout_); | ||
199 | } | ||
200 | |||
201 | // ################################################################################################ | ||
202 | // ################################################################################################ | ||
203 | |||
204 | // lane_h:cancel( [timeout] [, force [, forcekill_timeout]]) | ||
205 | LUAG_FUNC( thread_cancel) | ||
206 | { | ||
207 | Lane* s = lua_toLane( L, 1); | ||
208 | double secs = 0.0; | ||
209 | int force_i = 2; | ||
210 | int forcekill_timeout_i = 3; | ||
211 | |||
212 | if( lua_isnumber( L, 2)) | ||
213 | { | ||
214 | secs = lua_tonumber( L, 2); | ||
215 | if( secs < 0.0 && lua_gettop( L) > 3) | ||
216 | { | ||
217 | return luaL_error( L, "can't force_kill a soft cancel"); | ||
218 | } | ||
219 | // negative timeout and force flag means we want to wake linda-waiting threads | ||
220 | ++ force_i; | ||
221 | ++ forcekill_timeout_i; | ||
222 | } | ||
223 | else if( lua_isnil( L, 2)) | ||
224 | { | ||
225 | ++ force_i; | ||
226 | ++ forcekill_timeout_i; | ||
227 | } | ||
228 | |||
229 | { | ||
230 | bool_t force = lua_toboolean( L, force_i); // FALSE if nothing there | ||
231 | double forcekill_timeout = luaL_optnumber( L, forcekill_timeout_i, 0.0); | ||
232 | |||
233 | switch( thread_cancel( L, s, secs, force, forcekill_timeout)) | ||
234 | { | ||
235 | case CR_Timeout: | ||
236 | lua_pushboolean( L, 0); | ||
237 | lua_pushstring( L, "timeout"); | ||
238 | return 2; | ||
239 | |||
240 | case CR_Cancelled: | ||
241 | lua_pushboolean( L, 1); | ||
242 | return 1; | ||
243 | |||
244 | case CR_Killed: | ||
245 | lua_pushboolean( L, 0); | ||
246 | lua_pushstring( L, "killed"); | ||
247 | return 2; | ||
248 | } | ||
249 | } | ||
250 | // should never happen, only here to prevent the compiler from complaining of "not all control paths returning a value" | ||
251 | return 0; | ||
252 | } | ||
diff --git a/src/cancel.h b/src/cancel.h new file mode 100644 index 0000000..3112809 --- /dev/null +++ b/src/cancel.h | |||
@@ -0,0 +1,57 @@ | |||
1 | #if !defined( __LANES_CANCEL_H__) | ||
2 | #define __LANES_CANCEL_H__ 1 | ||
3 | |||
4 | #include "lua.h" | ||
5 | #include "lualib.h" | ||
6 | #include "lauxlib.h" | ||
7 | |||
8 | #include "uniquekey.h" | ||
9 | #include "macros_and_utils.h" | ||
10 | |||
11 | // ################################################################################################ | ||
12 | |||
13 | typedef struct s_Lane Lane; // forward | ||
14 | |||
15 | /* | ||
16 | * Lane cancellation request modes | ||
17 | */ | ||
18 | enum e_cancel_request | ||
19 | { | ||
20 | CANCEL_NONE, // no pending cancel request | ||
21 | CANCEL_SOFT, // user wants the lane to cancel itself manually on cancel_test() | ||
22 | CANCEL_HARD // user wants the lane to be interrupted (meaning code won't return from those functions) from inside linda:send/receive calls | ||
23 | }; | ||
24 | |||
25 | typedef enum | ||
26 | { | ||
27 | CR_Timeout, | ||
28 | CR_Cancelled, | ||
29 | CR_Killed | ||
30 | } cancel_result; | ||
31 | |||
32 | // crc64/we of string "CANCEL_ERROR" generated at http://www.nitrxgen.net/hashgen/ | ||
33 | static DECLARE_CONST_UNIQUE_KEY(CANCEL_ERROR, 0xe97d41626cc97577); // 'cancel_error' sentinel | ||
34 | |||
35 | // crc64/we of string "CANCEL_TEST_KEY" generated at http://www.nitrxgen.net/hashgen/ | ||
36 | static DECLARE_CONST_UNIQUE_KEY(CANCEL_TEST_KEY, 0xe66f5960c57d133a); // used as registry key | ||
37 | |||
38 | void cancel_hook( lua_State* L, lua_Debug* ar); | ||
39 | |||
40 | cancel_result thread_cancel( lua_State* L, Lane* s, double secs_, bool_t force_, double waitkill_timeout_); | ||
41 | |||
42 | static inline int cancel_error( lua_State* L) | ||
43 | { | ||
44 | STACK_GROW( L, 1); | ||
45 | push_unique_key( L, CANCEL_ERROR); // special error value | ||
46 | return lua_error( L); // doesn't return | ||
47 | } | ||
48 | |||
49 | // ################################################################################################ | ||
50 | // ################################################################################################ | ||
51 | |||
52 | LUAG_FUNC( cancel_test); | ||
53 | LUAG_FUNC( thread_cancel); | ||
54 | |||
55 | // ################################################################################################ | ||
56 | |||
57 | #endif // __LANES_CANCEL_H__ | ||
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 | ||
58 | Copyright (C) 2007-10 Asko Kauppi <akauppi@gmail.com> | 58 | Copyright (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 | ||
61 | Permission is hereby granted, free of charge, to any person obtaining a copy | 61 | Permission is hereby granted, free of charge, to any person obtaining a copy |
62 | of this software and associated documentation files (the "Software"), to deal | 62 | of 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 | */ | ||
136 | static 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 | |||
143 | static 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 |
155 | static int lane_error( lua_State* L); | 128 | static 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 | |||
425 | typedef enum | ||
426 | { | ||
427 | CR_Timeout, | ||
428 | CR_Cancelled, | ||
429 | CR_Killed | ||
430 | } cancel_result; | ||
431 | |||
432 | static 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 | |||
448 | static 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 | |||
491 | static 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 | // | ||
742 | LUAG_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]]) | ||
1531 | LUAG_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 | // |
diff --git a/src/lanes_private.h b/src/lanes_private.h index 16c178d..ac05129 100644 --- a/src/lanes_private.h +++ b/src/lanes_private.h | |||
@@ -2,16 +2,7 @@ | |||
2 | #define __lanes_private_h__ 1 | 2 | #define __lanes_private_h__ 1 |
3 | 3 | ||
4 | #include "uniquekey.h" | 4 | #include "uniquekey.h" |
5 | 5 | #include "cancel.h" | |
6 | /* | ||
7 | * Lane cancellation request modes | ||
8 | */ | ||
9 | enum e_cancel_request | ||
10 | { | ||
11 | CANCEL_NONE, // no pending cancel request | ||
12 | CANCEL_SOFT, // user wants the lane to cancel itself manually on cancel_test() | ||
13 | CANCEL_HARD // user wants the lane to be interrupted (meaning code won't return from those functions) from inside linda:send/receive calls | ||
14 | }; | ||
15 | 6 | ||
16 | // NOTE: values to be changed by either thread, during execution, without | 7 | // NOTE: values to be changed by either thread, during execution, without |
17 | // locking, are marked "volatile" | 8 | // locking, are marked "volatile" |
@@ -86,12 +77,6 @@ typedef struct s_Lane Lane; | |||
86 | // | 77 | // |
87 | #define lua_toLane( L, i) (*((Lane**) luaL_checkudata( L, i, "Lane"))) | 78 | #define lua_toLane( L, i) (*((Lane**) luaL_checkudata( L, i, "Lane"))) |
88 | 79 | ||
89 | // crc64/we of string "CANCEL_ERROR" generated at http://www.nitrxgen.net/hashgen/ | ||
90 | static DECLARE_CONST_UNIQUE_KEY(CANCEL_ERROR, 0xe97d41626cc97577); // 'cancel_error' sentinel | ||
91 | |||
92 | // crc64/we of string "CANCEL_TEST_KEY" generated at http://www.nitrxgen.net/hashgen/ | ||
93 | static DECLARE_CONST_UNIQUE_KEY(CANCEL_TEST_KEY, 0xe66f5960c57d133a); // used as registry key | ||
94 | |||
95 | static inline Lane* get_lane_from_registry( lua_State* L) | 80 | static inline Lane* get_lane_from_registry( lua_State* L) |
96 | { | 81 | { |
97 | Lane* s; | 82 | Lane* s; |
@@ -104,11 +89,4 @@ static inline Lane* get_lane_from_registry( lua_State* L) | |||
104 | return s; | 89 | return s; |
105 | } | 90 | } |
106 | 91 | ||
107 | static inline int cancel_error( lua_State* L) | ||
108 | { | ||
109 | STACK_GROW( L, 1); | ||
110 | push_unique_key( L, CANCEL_ERROR); // special error value | ||
111 | return lua_error( L); // doesn't return | ||
112 | } | ||
113 | |||
114 | #endif // __lanes_private_h__ \ No newline at end of file | 92 | #endif // __lanes_private_h__ \ No newline at end of file |
diff --git a/src/macros_and_utils.h b/src/macros_and_utils.h index 4b0b9d3..ae3a6c9 100644 --- a/src/macros_and_utils.h +++ b/src/macros_and_utils.h | |||
@@ -97,4 +97,6 @@ extern char const* debugspew_indent; | |||
97 | lua_rawget( L, LUA_REGISTRYINDEX); \ | 97 | lua_rawget( L, LUA_REGISTRYINDEX); \ |
98 | } | 98 | } |
99 | 99 | ||
100 | #define LUAG_FUNC( func_name) int LG_##func_name( lua_State* L) | ||
101 | |||
100 | #endif // MACROS_AND_UTILS_H | 102 | #endif // MACROS_AND_UTILS_H |
diff --git a/src/tools.c b/src/tools.c index 48e904c..02d51ae 100644 --- a/src/tools.c +++ b/src/tools.c | |||
@@ -1736,7 +1736,7 @@ static void inter_copy_keyvaluepair( Universe* U, lua_State* L2, uint_t L2_cache | |||
1736 | } | 1736 | } |
1737 | } | 1737 | } |
1738 | 1738 | ||
1739 | bool_t copyclone( Universe* U, lua_State* L2, uint_t L2_cache_i, lua_State* L, uint_t i, enum e_vt vt, LookupMode mode_, char const* upName_) | 1739 | static bool_t copyclone( Universe* U, lua_State* L2, uint_t L2_cache_i, lua_State* L, uint_t i, LookupMode mode_, char const* upName_) |
1740 | { | 1740 | { |
1741 | STACK_CHECK( L, 0); | 1741 | STACK_CHECK( L, 0); |
1742 | STACK_CHECK( L2, 0); | 1742 | STACK_CHECK( L2, 0); |
@@ -1849,7 +1849,7 @@ static bool_t inter_copy_userdata( Universe* U, lua_State* L2, uint_t L2_cache_i | |||
1849 | STACK_MID( L, 0); | 1849 | STACK_MID( L, 0); |
1850 | STACK_MID( L2, 0); | 1850 | STACK_MID( L2, 0); |
1851 | 1851 | ||
1852 | if( copyclone( U, L2, L2_cache_i, L, i, vt, mode_, upName_)) | 1852 | if( copyclone( U, L2, L2_cache_i, L, i, mode_, upName_)) |
1853 | { | 1853 | { |
1854 | STACK_MID( L, 0); | 1854 | STACK_MID( L, 0); |
1855 | STACK_MID( L2, 1); | 1855 | STACK_MID( L2, 1); |
diff --git a/src/tools.h b/src/tools.h index 71460c3..8a8ad7b 100644 --- a/src/tools.h +++ b/src/tools.h | |||
@@ -13,8 +13,6 @@ typedef struct s_Universe Universe; | |||
13 | 13 | ||
14 | // ################################################################################################ | 14 | // ################################################################################################ |
15 | 15 | ||
16 | #define LUAG_FUNC( func_name) int LG_##func_name( lua_State* L) | ||
17 | |||
18 | #define luaG_optunsigned(L,i,d) ((uint_t) luaL_optinteger(L,i,d)) | 16 | #define luaG_optunsigned(L,i,d) ((uint_t) luaL_optinteger(L,i,d)) |
19 | #define luaG_tounsigned(L,i) ((uint_t) lua_tointeger(L,i)) | 17 | #define luaG_tounsigned(L,i) ((uint_t) lua_tointeger(L,i)) |
20 | 18 | ||