diff options
| author | Benoit Germain <bnt period germain arrobase gmail period com> | 2014-01-16 14:17:23 +0100 |
|---|---|---|
| committer | Benoit Germain <bnt period germain arrobase gmail period com> | 2014-01-16 14:17:23 +0100 |
| commit | 1843a0add00186eee129b0b0a2ee605866acbb61 (patch) | |
| tree | 5de8d13e1b8495836f898c17790adf571f05365c /src | |
| parent | baaea3cebf9d787f76557b68f18a012dc6adbbbc (diff) | |
| download | lanes-1843a0add00186eee129b0b0a2ee605866acbb61.tar.gz lanes-1843a0add00186eee129b0b0a2ee605866acbb61.tar.bz2 lanes-1843a0add00186eee129b0b0a2ee605866acbb61.zip | |
Cancellation improvements and some fixes
* bumped version to 3.7.8
* lane:cancel() now accepts a boolean second argument when soft
cancelling (negative timeout) to wake the thread if necessary
* if a blocked linda send() or receive() call is interrupted by a
cancellation request, it returns CANCEL_ERROR so that this case can be
differentiated from a simple timeout
* fixed WIN32 THREAD_CREATE() wrong _beginthreadex() error detection
* fatal WIN32 threading errors retrieve and output the error description
string with FormatMessage()
* fixed missing lanes.set_singlethreaded
* fixed perftest.lua
* added test/cancel.lua
Diffstat (limited to 'src')
| -rw-r--r-- | src/lanes.c | 214 | ||||
| -rw-r--r-- | src/lanes.lua | 2 | ||||
| -rw-r--r-- | src/threading.c | 14 |
3 files changed, 125 insertions, 105 deletions
diff --git a/src/lanes.c b/src/lanes.c index ef44d90..cad8fb1 100644 --- a/src/lanes.c +++ b/src/lanes.c | |||
| @@ -52,7 +52,7 @@ | |||
| 52 | * ... | 52 | * ... |
| 53 | */ | 53 | */ |
| 54 | 54 | ||
| 55 | char const* VERSION = "3.7.7"; | 55 | char const* VERSION = "3.7.8"; |
| 56 | 56 | ||
| 57 | /* | 57 | /* |
| 58 | =============================================================================== | 58 | =============================================================================== |
| @@ -189,11 +189,59 @@ struct s_lane | |||
| 189 | // For tracking only | 189 | // For tracking only |
| 190 | }; | 190 | }; |
| 191 | 191 | ||
| 192 | static enum e_cancel_request cancel_test( lua_State* L); | 192 | // To allow free-running threads (longer lifespan than the handle's) |
| 193 | static void cancel_error( lua_State*L ); | 193 | // 'struct s_lane' are malloc/free'd and the handle only carries a pointer. |
| 194 | // This is not deep userdata since the handle's not portable among lanes. | ||
| 195 | // | ||
| 196 | #define lua_toLane( L, i) (*((struct s_lane**) lua_touserdata( L, i))) | ||
| 197 | |||
| 198 | #define CANCEL_TEST_KEY ((void*)get_lane) // used as registry key | ||
| 199 | static inline struct s_lane* get_lane( lua_State* L) | ||
| 200 | { | ||
| 201 | struct s_lane* s; | ||
| 202 | STACK_GROW( L, 1); | ||
| 203 | STACK_CHECK( L); | ||
| 204 | lua_pushlightuserdata( L, CANCEL_TEST_KEY); | ||
| 205 | lua_rawget( L, LUA_REGISTRYINDEX); | ||
| 206 | s = lua_touserdata( L, -1); // lightuserdata (true 's_lane' pointer) / nil | ||
| 207 | lua_pop( L, 1); | ||
| 208 | STACK_END( L, 0); | ||
| 209 | return s; | ||
| 210 | } | ||
| 211 | |||
| 212 | /* | ||
| 213 | * Check if the thread in question ('L') has been signalled for cancel. | ||
| 214 | * | ||
| 215 | * Called by cancellation hooks and/or pending Linda operations (because then | ||
| 216 | * the check won't affect performance). | ||
| 217 | * | ||
| 218 | * Returns TRUE if any locks are to be exited, and 'cancel_error()' called, | ||
| 219 | * to make execution of the lane end. | ||
| 220 | */ | ||
| 221 | static inline enum e_cancel_request cancel_test( lua_State* L) | ||
| 222 | { | ||
| 223 | struct s_lane* const s = get_lane( L); | ||
| 224 | // 's' is NULL for the original main state (and no-one can cancel that) | ||
| 225 | return s ? s->cancel_request : CANCEL_NONE; | ||
| 226 | } | ||
| 194 | 227 | ||
| 195 | #define CANCEL_TEST_KEY ((void*)cancel_test) // used as registry key | ||
| 196 | #define CANCEL_ERROR ((void*)cancel_error) // 'cancel_error' sentinel | 228 | #define CANCEL_ERROR ((void*)cancel_error) // 'cancel_error' sentinel |
| 229 | static int cancel_error( lua_State* L) | ||
| 230 | { | ||
| 231 | STACK_GROW( L, 1); | ||
| 232 | lua_pushlightuserdata( L, CANCEL_ERROR); // special error value | ||
| 233 | return lua_error( L); // doesn't return | ||
| 234 | } | ||
| 235 | |||
| 236 | static void cancel_hook( lua_State* L, lua_Debug* ar) | ||
| 237 | { | ||
| 238 | (void)ar; | ||
| 239 | if( cancel_test( L) != CANCEL_NONE) | ||
| 240 | { | ||
| 241 | cancel_error( L); | ||
| 242 | } | ||
| 243 | } | ||
| 244 | |||
| 197 | 245 | ||
| 198 | #if ERROR_FULL_STACK | 246 | #if ERROR_FULL_STACK |
| 199 | static int lane_error( lua_State* L); | 247 | static int lane_error( lua_State* L); |
| @@ -383,6 +431,7 @@ static void check_key_types( lua_State*L, int _start, int _end) | |||
| 383 | * | 431 | * |
| 384 | * Returns: 'true' if the value was queued | 432 | * Returns: 'true' if the value was queued |
| 385 | * 'false' for timeout (only happens when the queue size is limited) | 433 | * 'false' for timeout (only happens when the queue size is limited) |
| 434 | * nil, CANCEL_ERROR if cancelled | ||
| 386 | */ | 435 | */ |
| 387 | LUAG_FUNC( linda_send) | 436 | LUAG_FUNC( linda_send) |
| 388 | { | 437 | { |
| @@ -417,7 +466,7 @@ LUAG_FUNC( linda_send) | |||
| 417 | // convert nils to some special non-nil sentinel in sent values | 466 | // convert nils to some special non-nil sentinel in sent values |
| 418 | keeper_toggle_nil_sentinels( L, key_i + 1, 1); | 467 | keeper_toggle_nil_sentinels( L, key_i + 1, 1); |
| 419 | 468 | ||
| 420 | STACK_GROW(L, 1); | 469 | STACK_GROW( L, 1); |
| 421 | { | 470 | { |
| 422 | struct s_Keeper* K = keeper_acquire( linda); | 471 | struct s_Keeper* K = keeper_acquire( linda); |
| 423 | lua_State* KL = K ? K->L : NULL; // need to do this for 'STACK_CHECK' | 472 | lua_State* KL = K ? K->L : NULL; // need to do this for 'STACK_CHECK' |
| @@ -451,26 +500,17 @@ LUAG_FUNC( linda_send) | |||
| 451 | } | 500 | } |
| 452 | /* limit faced; push until timeout */ | 501 | /* limit faced; push until timeout */ |
| 453 | 502 | ||
| 454 | cancel = cancel_test( L); // testing here causes no delays | ||
| 455 | if( cancel != CANCEL_NONE) // if user wants to cancel, the call returns without sending anything | ||
| 456 | { | 503 | { |
| 457 | break; | ||
| 458 | } | ||
| 459 | |||
| 460 | // change status of lane to "waiting" | ||
| 461 | { | ||
| 462 | struct s_lane* s; | ||
| 463 | enum e_status prev_status = ERROR_ST; // prevent 'might be used uninitialized' warnings | 504 | enum e_status prev_status = ERROR_ST; // prevent 'might be used uninitialized' warnings |
| 464 | STACK_GROW( L, 1); | 505 | struct s_lane* const s = get_lane( L); |
| 465 | |||
| 466 | STACK_CHECK( L); | ||
| 467 | lua_pushlightuserdata( L, CANCEL_TEST_KEY); | ||
| 468 | lua_rawget( L, LUA_REGISTRYINDEX); | ||
| 469 | s = lua_touserdata( L, -1); // lightuserdata (true 's_lane' pointer) or nil if in the main Lua state | ||
| 470 | lua_pop( L, 1); | ||
| 471 | STACK_END( L, 0); | ||
| 472 | if( s != NULL) | 506 | if( s != NULL) |
| 473 | { | 507 | { |
| 508 | cancel = s->cancel_request; // testing here causes no delays | ||
| 509 | if( cancel != CANCEL_NONE) // if user wants to cancel, the call returns without sending anything | ||
| 510 | { | ||
| 511 | break; | ||
| 512 | } | ||
| 513 | // change status of lane to "waiting" | ||
| 474 | prev_status = s->status; // RUNNING, most likely | 514 | prev_status = s->status; // RUNNING, most likely |
| 475 | ASSERT_L( prev_status == RUNNING); // but check, just in case | 515 | ASSERT_L( prev_status == RUNNING); // but check, just in case |
| 476 | s->status = WAITING; | 516 | s->status = WAITING; |
| @@ -484,6 +524,8 @@ LUAG_FUNC( linda_send) | |||
| 484 | { | 524 | { |
| 485 | s->waiting_on = NULL; | 525 | s->waiting_on = NULL; |
| 486 | s->status = prev_status; | 526 | s->status = prev_status; |
| 527 | // if woken by a cancel request, be sure to handle it properly | ||
| 528 | cancel = s->cancel_request; | ||
| 487 | } | 529 | } |
| 488 | break; | 530 | break; |
| 489 | } | 531 | } |
| @@ -504,12 +546,21 @@ LUAG_FUNC( linda_send) | |||
| 504 | return luaL_error( L, "tried to copy unsupported types"); | 546 | return luaL_error( L, "tried to copy unsupported types"); |
| 505 | } | 547 | } |
| 506 | 548 | ||
| 507 | // raise an error interrupting execution only in case of hard cancel | 549 | switch( cancel) |
| 508 | if( cancel == CANCEL_HARD) | 550 | { |
| 509 | cancel_error( L); | 551 | case CANCEL_SOFT: |
| 552 | // if user wants to soft-cancel, the call returns CANCEL_ERROR | ||
| 553 | lua_pushlightuserdata( L, CANCEL_ERROR); | ||
| 554 | return 1; | ||
| 510 | 555 | ||
| 511 | lua_pushboolean( L, ret); | 556 | case CANCEL_HARD: |
| 512 | return 1; | 557 | // raise an error interrupting execution only in case of hard cancel |
| 558 | return cancel_error( L); // raises an error and doesn't return | ||
| 559 | |||
| 560 | default: | ||
| 561 | lua_pushboolean( L, ret); // true (success) or false (timeout) | ||
| 562 | return 1; | ||
| 563 | } | ||
| 513 | } | 564 | } |
| 514 | 565 | ||
| 515 | 566 | ||
| @@ -611,26 +662,17 @@ LUAG_FUNC( linda_receive) | |||
| 611 | } | 662 | } |
| 612 | /* nothing received; wait until timeout */ | 663 | /* nothing received; wait until timeout */ |
| 613 | 664 | ||
| 614 | cancel = cancel_test( L); // testing here causes no delays | ||
| 615 | if( cancel != CANCEL_NONE) // if user wants to cancel, the call returns without providing anything | ||
| 616 | { | 665 | { |
| 617 | break; | ||
| 618 | } | ||
| 619 | |||
| 620 | // change status of lane to "waiting" | ||
| 621 | { | ||
| 622 | struct s_lane* s; | ||
| 623 | enum e_status prev_status = ERROR_ST; // prevent 'might be used uninitialized' warnings | 666 | enum e_status prev_status = ERROR_ST; // prevent 'might be used uninitialized' warnings |
| 624 | STACK_GROW( L, 1); | 667 | struct s_lane* const s = get_lane( L); |
| 625 | |||
| 626 | STACK_CHECK( L); | ||
| 627 | lua_pushlightuserdata( L, CANCEL_TEST_KEY); | ||
| 628 | lua_rawget( L, LUA_REGISTRYINDEX); | ||
| 629 | s = lua_touserdata( L, -1); // lightuserdata (true 's_lane' pointer) or nil if in the main Lua state | ||
| 630 | lua_pop( L, 1); | ||
| 631 | STACK_END( L, 0); | ||
| 632 | if( s != NULL) | 668 | if( s != NULL) |
| 633 | { | 669 | { |
| 670 | cancel = s->cancel_request; // testing here causes no delays | ||
| 671 | if( cancel != CANCEL_NONE) // if user wants to cancel, the call returns without providing anything | ||
| 672 | { | ||
| 673 | break; | ||
| 674 | } | ||
| 675 | // change status of lane to "waiting" | ||
| 634 | prev_status = s->status; // RUNNING, most likely | 676 | prev_status = s->status; // RUNNING, most likely |
| 635 | ASSERT_L( prev_status == RUNNING); // but check, just in case | 677 | ASSERT_L( prev_status == RUNNING); // but check, just in case |
| 636 | s->status = WAITING; | 678 | s->status = WAITING; |
| @@ -644,6 +686,8 @@ LUAG_FUNC( linda_receive) | |||
| 644 | { | 686 | { |
| 645 | s->waiting_on = NULL; | 687 | s->waiting_on = NULL; |
| 646 | s->status = prev_status; | 688 | s->status = prev_status; |
| 689 | // if woken by a cancel request, be sure to handle it properly | ||
| 690 | cancel = s->cancel_request; | ||
| 647 | } | 691 | } |
| 648 | break; | 692 | break; |
| 649 | } | 693 | } |
| @@ -663,11 +707,20 @@ LUAG_FUNC( linda_receive) | |||
| 663 | return luaL_error( L, "tried to copy unsupported types"); | 707 | return luaL_error( L, "tried to copy unsupported types"); |
| 664 | } | 708 | } |
| 665 | 709 | ||
| 666 | // raise an error interrupting execution only in case of hard cancel | 710 | switch( cancel) |
| 667 | if( cancel == CANCEL_HARD) | 711 | { |
| 668 | cancel_error( L); | 712 | case CANCEL_SOFT: |
| 713 | // if user wants to soft-cancel, the call returns CANCEL_ERROR | ||
| 714 | lua_pushlightuserdata( L, CANCEL_ERROR); | ||
| 715 | return 1; | ||
| 669 | 716 | ||
| 670 | return pushed; | 717 | case CANCEL_HARD: |
| 718 | // raise an error interrupting execution only in case of hard cancel | ||
| 719 | return cancel_error( L); // raises an error and doesn't return | ||
| 720 | |||
| 721 | default: | ||
| 722 | return pushed; | ||
| 723 | } | ||
| 671 | } | 724 | } |
| 672 | 725 | ||
| 673 | 726 | ||
| @@ -1225,6 +1278,14 @@ static cancel_result thread_cancel( lua_State* L, struct s_lane* s, double secs, | |||
| 1225 | { | 1278 | { |
| 1226 | s->cancel_request = CANCEL_SOFT; // it's now signaled to stop | 1279 | s->cancel_request = CANCEL_SOFT; // it's now signaled to stop |
| 1227 | // negative timeout: we don't want to truly abort the lane, we just want it to react to cancel_test() on its own | 1280 | // negative timeout: we don't want to truly abort the lane, we just want it to react to cancel_test() on its own |
| 1281 | if( force) // wake the thread so that execution returns from any pending linda operation if desired | ||
| 1282 | { | ||
| 1283 | SIGNAL_T *waiting_on = s->waiting_on; | ||
| 1284 | if( s->status == WAITING && waiting_on != NULL) | ||
| 1285 | { | ||
| 1286 | SIGNAL_ALL( waiting_on); | ||
| 1287 | } | ||
| 1288 | } | ||
| 1228 | // say we succeeded though | 1289 | // say we succeeded though |
| 1229 | result = CR_Cancelled; | 1290 | result = CR_Cancelled; |
| 1230 | } | 1291 | } |
| @@ -1509,54 +1570,6 @@ static int selfdestruct_gc( lua_State* L) | |||
| 1509 | } | 1570 | } |
| 1510 | 1571 | ||
| 1511 | 1572 | ||
| 1512 | // To allow free-running threads (longer lifespan than the handle's) | ||
| 1513 | // 'struct s_lane' are malloc/free'd and the handle only carries a pointer. | ||
| 1514 | // This is not deep userdata since the handle's not portable among lanes. | ||
| 1515 | // | ||
| 1516 | #define lua_toLane(L,i) (* ((struct s_lane**) lua_touserdata(L,i))) | ||
| 1517 | |||
| 1518 | |||
| 1519 | /* | ||
| 1520 | * Check if the thread in question ('L') has been signalled for cancel. | ||
| 1521 | * | ||
| 1522 | * Called by cancellation hooks and/or pending Linda operations (because then | ||
| 1523 | * the check won't affect performance). | ||
| 1524 | * | ||
| 1525 | * Returns TRUE if any locks are to be exited, and 'cancel_error()' called, | ||
| 1526 | * to make execution of the lane end. | ||
| 1527 | */ | ||
| 1528 | static enum e_cancel_request cancel_test( lua_State* L) | ||
| 1529 | { | ||
| 1530 | struct s_lane* s; | ||
| 1531 | |||
| 1532 | STACK_GROW( L, 1); | ||
| 1533 | |||
| 1534 | STACK_CHECK( L); | ||
| 1535 | lua_pushlightuserdata( L, CANCEL_TEST_KEY); | ||
| 1536 | lua_rawget( L, LUA_REGISTRYINDEX); | ||
| 1537 | s = lua_touserdata( L, -1); // lightuserdata (true 's_lane' pointer) / nil | ||
| 1538 | lua_pop( L, 1); | ||
| 1539 | STACK_END( L, 0); | ||
| 1540 | |||
| 1541 | // 's' is NULL for the original main state (no-one can cancel that) | ||
| 1542 | // | ||
| 1543 | return s ? s->cancel_request : CANCEL_NONE; | ||
| 1544 | } | ||
| 1545 | |||
| 1546 | static void cancel_error( lua_State*L ) { | ||
| 1547 | STACK_GROW(L,1); | ||
| 1548 | lua_pushlightuserdata( L, CANCEL_ERROR ); // special error value | ||
| 1549 | lua_error(L); // no return | ||
| 1550 | } | ||
| 1551 | |||
| 1552 | static void cancel_hook( lua_State*L, lua_Debug *ar ) | ||
| 1553 | { | ||
| 1554 | (void)ar; | ||
| 1555 | if( cancel_test( L) != CANCEL_NONE) | ||
| 1556 | cancel_error( L); | ||
| 1557 | } | ||
| 1558 | |||
| 1559 | |||
| 1560 | //--- | 1573 | //--- |
| 1561 | // bool = cancel_test() | 1574 | // bool = cancel_test() |
| 1562 | // | 1575 | // |
| @@ -2294,7 +2307,7 @@ LUAG_FUNC( thread_gc) | |||
| 2294 | return 0; | 2307 | return 0; |
| 2295 | } | 2308 | } |
| 2296 | 2309 | ||
| 2297 | // lane_h:cancel( [timeout,] force[, forcekill_timeout]) | 2310 | // lane_h:cancel( [timeout] [, force [, forcekill_timeout]]) |
| 2298 | LUAG_FUNC( thread_cancel) | 2311 | LUAG_FUNC( thread_cancel) |
| 2299 | { | 2312 | { |
| 2300 | if( lua_gettop( L) < 1 || lua_type( L, 1) != LUA_TUSERDATA) | 2313 | if( lua_gettop( L) < 1 || lua_type( L, 1) != LUA_TUSERDATA) |
| @@ -2311,10 +2324,11 @@ LUAG_FUNC( thread_cancel) | |||
| 2311 | if( lua_isnumber( L, 2)) | 2324 | if( lua_isnumber( L, 2)) |
| 2312 | { | 2325 | { |
| 2313 | secs = lua_tonumber( L, 2); | 2326 | secs = lua_tonumber( L, 2); |
| 2314 | if( secs < 0.0 && lua_gettop( L) > 2) | 2327 | if( secs < 0.0 && lua_gettop( L) > 3) |
| 2315 | { | 2328 | { |
| 2316 | return luaL_error( L, "can't force a soft cancel"); | 2329 | return luaL_error( L, "can't force_kill a soft cancel"); |
| 2317 | } | 2330 | } |
| 2331 | // negative timeout and force flag means we want to wake linda-waiting threads | ||
| 2318 | ++ force_i; | 2332 | ++ force_i; |
| 2319 | ++ forcekill_timeout_i; | 2333 | ++ forcekill_timeout_i; |
| 2320 | } | 2334 | } |
| @@ -2330,16 +2344,16 @@ LUAG_FUNC( thread_cancel) | |||
| 2330 | 2344 | ||
| 2331 | switch( thread_cancel( L, s, secs, force, forcekill_timeout)) | 2345 | switch( thread_cancel( L, s, secs, force, forcekill_timeout)) |
| 2332 | { | 2346 | { |
| 2333 | case CR_Timeout: | 2347 | case CR_Timeout: |
| 2334 | lua_pushboolean( L, 0); | 2348 | lua_pushboolean( L, 0); |
| 2335 | lua_pushstring( L, "timeout"); | 2349 | lua_pushstring( L, "timeout"); |
| 2336 | return 2; | 2350 | return 2; |
| 2337 | 2351 | ||
| 2338 | case CR_Cancelled: | 2352 | case CR_Cancelled: |
| 2339 | lua_pushboolean( L, 1); | 2353 | lua_pushboolean( L, 1); |
| 2340 | return 1; | 2354 | return 1; |
| 2341 | 2355 | ||
| 2342 | case CR_Killed: | 2356 | case CR_Killed: |
| 2343 | lua_pushboolean( L, 0); | 2357 | lua_pushboolean( L, 0); |
| 2344 | lua_pushstring( L, "killed"); | 2358 | lua_pushstring( L, "killed"); |
| 2345 | return 2; | 2359 | return 2; |
diff --git a/src/lanes.lua b/src/lanes.lua index 0c544bb..e7b9715 100644 --- a/src/lanes.lua +++ b/src/lanes.lua | |||
| @@ -128,7 +128,6 @@ lanes.configure = function( settings_) | |||
| 128 | end | 128 | end |
| 129 | local settings = core.configure and core.configure( params_checker( settings_)) or core.settings | 129 | local settings = core.configure and core.configure( params_checker( settings_)) or core.settings |
| 130 | local thread_new = assert( core.thread_new) | 130 | local thread_new = assert( core.thread_new) |
| 131 | local set_singlethreaded = assert( core.set_singlethreaded) | ||
| 132 | local max_prio = assert( core.max_prio) | 131 | local max_prio = assert( core.max_prio) |
| 133 | 132 | ||
| 134 | lanes.ABOUT = | 133 | lanes.ABOUT = |
| @@ -664,6 +663,7 @@ end | |||
| 664 | lanes.linda = core.linda | 663 | lanes.linda = core.linda |
| 665 | lanes.cancel_error = core.cancel_error | 664 | lanes.cancel_error = core.cancel_error |
| 666 | lanes.nameof = core.nameof | 665 | lanes.nameof = core.nameof |
| 666 | lanes.set_singlethreaded = core.set_singlethreaded | ||
| 667 | lanes.threads = core.threads or function() error "lane tracking is not available" end -- core.threads isn't registered if settings.track_lanes is false | 667 | lanes.threads = core.threads or function() error "lane tracking is not available" end -- core.threads isn't registered if settings.track_lanes is false |
| 668 | lanes.set_thread_priority = core.set_thread_priority | 668 | lanes.set_thread_priority = core.set_thread_priority |
| 669 | lanes.timer = timer | 669 | lanes.timer = timer |
diff --git a/src/threading.c b/src/threading.c index 3014136..5a3e64b 100644 --- a/src/threading.c +++ b/src/threading.c | |||
| @@ -87,11 +87,13 @@ THE SOFTWARE. | |||
| 87 | #if defined( PLATFORM_XBOX) || defined( PLATFORM_WIN32) || defined( PLATFORM_POCKETPC) | 87 | #if defined( PLATFORM_XBOX) || defined( PLATFORM_WIN32) || defined( PLATFORM_POCKETPC) |
| 88 | static void FAIL( char const* funcname, int rc) | 88 | static void FAIL( char const* funcname, int rc) |
| 89 | { | 89 | { |
| 90 | fprintf( stderr, "%s() failed! (%d)\n", funcname, rc ); | 90 | char buf[256]; |
| 91 | FormatMessageA( FORMAT_MESSAGE_FROM_SYSTEM, NULL, rc, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), buf, 256, NULL); | ||
| 92 | fprintf( stderr, "%s() failed! [GetLastError() -> %d] '%s'", funcname, rc, buf); | ||
| 91 | #ifdef _MSC_VER | 93 | #ifdef _MSC_VER |
| 92 | __debugbreak(); // give a chance to the debugger! | 94 | __debugbreak(); // give a chance to the debugger! |
| 93 | #endif // _MSC_VER | 95 | #endif // _MSC_VER |
| 94 | abort(); | 96 | abort(); |
| 95 | } | 97 | } |
| 96 | #endif // win32 build | 98 | #endif // win32 build |
| 97 | 99 | ||
| @@ -296,11 +298,15 @@ void THREAD_CREATE( THREAD_T* ref, THREAD_RETURN_T (__stdcall *func)( void*), vo | |||
| 296 | NULL // thread id (not used) | 298 | NULL // thread id (not used) |
| 297 | ); | 299 | ); |
| 298 | 300 | ||
| 299 | if( h == INVALID_HANDLE_VALUE) | 301 | if( h == NULL) // _beginthreadex returns 0L on failure instead of -1L (like _beginthread) |
| 302 | { | ||
| 300 | FAIL( "CreateThread", GetLastError()); | 303 | FAIL( "CreateThread", GetLastError()); |
| 304 | } | ||
| 301 | 305 | ||
| 302 | if (!SetThreadPriority( h, gs_prio_remap[prio + 3])) | 306 | if (!SetThreadPriority( h, gs_prio_remap[prio + 3])) |
| 307 | { | ||
| 303 | FAIL( "SetThreadPriority", GetLastError()); | 308 | FAIL( "SetThreadPriority", GetLastError()); |
| 309 | } | ||
| 304 | 310 | ||
| 305 | *ref = h; | 311 | *ref = h; |
| 306 | } | 312 | } |
