diff options
author | Benoit Germain <bnt period germain arrobase gmail period com> | 2014-02-13 16:09:15 +0100 |
---|---|---|
committer | Benoit Germain <bnt period germain arrobase gmail period com> | 2014-02-13 16:09:15 +0100 |
commit | 32ad991eb8c590472607d61e9a831d2ca9db05c5 (patch) | |
tree | 1e3920223e81a5970241f9687db9129d7ec7bb2e /src/lanes.c | |
parent | c38429579de57d338e0a1c14a7ed7b4aa90e059a (diff) | |
download | lanes-32ad991eb8c590472607d61e9a831d2ca9db05c5.tar.gz lanes-32ad991eb8c590472607d61e9a831d2ca9db05c5.tar.bz2 lanes-32ad991eb8c590472607d61e9a831d2ca9db05c5.zip |
more fixes/tweaks about cancelled lindas
* bumped version to 3.8.5
* linda:limit() returns lanes.cancel_error on a limited linda
* lanes.genlock() and lanes.genatomic() support cancelled lindas by
returning lanes.cancel_error whenever appropriate
* fixed a possible Lua stack overflow when calling linda:dump()
* fixed cases where linda:send() and linda:receive() would not return
lanes.cancel_error when they should
Diffstat (limited to 'src/lanes.c')
-rw-r--r-- | src/lanes.c | 160 |
1 files changed, 77 insertions, 83 deletions
diff --git a/src/lanes.c b/src/lanes.c index cf88171..dbb0a82 100644 --- a/src/lanes.c +++ b/src/lanes.c | |||
@@ -52,7 +52,7 @@ | |||
52 | * ... | 52 | * ... |
53 | */ | 53 | */ |
54 | 54 | ||
55 | char const* VERSION = "3.8.4"; | 55 | char const* VERSION = "3.8.5"; |
56 | 56 | ||
57 | /* | 57 | /* |
58 | =============================================================================== | 58 | =============================================================================== |
@@ -424,13 +424,17 @@ struct s_Linda | |||
424 | 424 | ||
425 | static void linda_id( lua_State*, char const * const which); | 425 | static void linda_id( lua_State*, char const * const which); |
426 | 426 | ||
427 | #define lua_toLinda(L,n) ((struct s_Linda *)luaG_todeep( L, linda_id, n )) | 427 | static inline struct s_Linda* lua_toLinda( lua_State* L, int idx_) |
428 | 428 | { | |
429 | struct s_Linda* linda = luaG_todeep( L, linda_id, idx_); | ||
430 | luaL_argcheck( L, linda != NULL, idx_, "expecting a linda object"); | ||
431 | return linda; | ||
432 | } | ||
429 | 433 | ||
430 | static void check_key_types( lua_State*L, int _start, int _end) | 434 | static void check_key_types( lua_State* L, int start_, int end_) |
431 | { | 435 | { |
432 | int i; | 436 | int i; |
433 | for( i = _start; i <= _end; ++ i) | 437 | for( i = start_; i <= end_; ++ i) |
434 | { | 438 | { |
435 | int t = lua_type( L, i); | 439 | int t = lua_type( L, i); |
436 | if( t == LUA_TBOOLEAN || t == LUA_TNUMBER || t == LUA_TSTRING || t == LUA_TLIGHTUSERDATA) | 440 | if( t == LUA_TBOOLEAN || t == LUA_TNUMBER || t == LUA_TSTRING || t == LUA_TLIGHTUSERDATA) |
@@ -459,8 +463,6 @@ LUAG_FUNC( linda_send) | |||
459 | time_d timeout = -1.0; | 463 | time_d timeout = -1.0; |
460 | uint_t key_i = 2; // index of first key, if timeout not there | 464 | uint_t key_i = 2; // index of first key, if timeout not there |
461 | 465 | ||
462 | luaL_argcheck( L, linda, 1, "expected a linda object!"); | ||
463 | |||
464 | if( lua_type( L, 2) == LUA_TNUMBER) // we don't want to use lua_isnumber() because of autocoercion | 466 | if( lua_type( L, 2) == LUA_TNUMBER) // we don't want to use lua_isnumber() because of autocoercion |
465 | { | 467 | { |
466 | timeout = SIGNAL_TIMEOUT_PREPARE( lua_tonumber( L,2)); | 468 | timeout = SIGNAL_TIMEOUT_PREPARE( lua_tonumber( L,2)); |
@@ -485,12 +487,26 @@ LUAG_FUNC( linda_send) | |||
485 | 487 | ||
486 | STACK_GROW( L, 1); | 488 | STACK_GROW( L, 1); |
487 | { | 489 | { |
490 | bool_t try_again = TRUE; | ||
491 | struct s_lane* const s = get_lane_from_registry( L); | ||
488 | struct s_Keeper* K = keeper_acquire( linda); | 492 | struct s_Keeper* K = keeper_acquire( linda); |
489 | lua_State* KL = K ? K->L : NULL; // need to do this for 'STACK_CHECK' | 493 | lua_State* KL = K ? K->L : NULL; // need to do this for 'STACK_CHECK' |
490 | if( KL == NULL) return 0; | 494 | if( KL == NULL) return 0; |
491 | STACK_CHECK( KL); | 495 | STACK_CHECK( KL); |
492 | for( ;;) | 496 | for( ;;) |
493 | { | 497 | { |
498 | if( s != NULL) | ||
499 | { | ||
500 | cancel = s->cancel_request; | ||
501 | } | ||
502 | cancel = (cancel != CANCEL_NONE) ? cancel : linda->simulate_cancel; | ||
503 | // if user wants to cancel, or looped because of a timeout, the call returns without sending anything | ||
504 | if( !try_again || cancel != CANCEL_NONE) | ||
505 | { | ||
506 | pushed = 0; | ||
507 | break; | ||
508 | } | ||
509 | |||
494 | STACK_MID( KL, 0); | 510 | STACK_MID( KL, 0); |
495 | pushed = keeper_call( KL, KEEPER_API( send), L, linda, key_i); | 511 | pushed = keeper_call( KL, KEEPER_API( send), L, linda, key_i); |
496 | if( pushed < 0) | 512 | if( pushed < 0) |
@@ -506,28 +522,19 @@ LUAG_FUNC( linda_send) | |||
506 | if( ret) | 522 | if( ret) |
507 | { | 523 | { |
508 | // Wake up ALL waiting threads | 524 | // Wake up ALL waiting threads |
509 | // | ||
510 | SIGNAL_ALL( &linda->write_happened); | 525 | SIGNAL_ALL( &linda->write_happened); |
511 | break; | 526 | break; |
512 | } | 527 | } |
528 | |||
529 | // instant timout to bypass the | ||
513 | if( timeout == 0.0) | 530 | if( timeout == 0.0) |
514 | { | 531 | { |
515 | break; /* no wait; instant timeout */ | 532 | break; /* no wait; instant timeout */ |
516 | } | 533 | } |
517 | /* limit faced; push until timeout */ | ||
518 | 534 | ||
535 | // storage limit hit, wait until timeout or signalled that we should try again | ||
519 | { | 536 | { |
520 | enum e_status prev_status = ERROR_ST; // prevent 'might be used uninitialized' warnings | 537 | enum e_status prev_status = ERROR_ST; // prevent 'might be used uninitialized' warnings |
521 | struct s_lane* const s = get_lane_from_registry( L); | ||
522 | if( s != NULL) | ||
523 | { | ||
524 | cancel = s->cancel_request; | ||
525 | } | ||
526 | cancel = (cancel != CANCEL_NONE) ? cancel : linda->simulate_cancel; | ||
527 | if( cancel != CANCEL_NONE) // if user wants to cancel, the call returns without sending anything | ||
528 | { | ||
529 | break; | ||
530 | } | ||
531 | if( s != NULL) | 538 | if( s != NULL) |
532 | { | 539 | { |
533 | // change status of lane to "waiting" | 540 | // change status of lane to "waiting" |
@@ -537,22 +544,12 @@ LUAG_FUNC( linda_send) | |||
537 | ASSERT_L( s->waiting_on == NULL); | 544 | ASSERT_L( s->waiting_on == NULL); |
538 | s->waiting_on = &linda->read_happened; | 545 | s->waiting_on = &linda->read_happened; |
539 | } | 546 | } |
547 | // could not send because no room: wait until some data was read before trying again, or until timeout is reached | ||
548 | try_again = SIGNAL_WAIT( &linda->read_happened, &K->lock_, timeout); | ||
549 | if( s != NULL) | ||
540 | { | 550 | { |
541 | // could not send because no room: wait until some data was read before trying again, or until timeout is reached | 551 | s->waiting_on = NULL; |
542 | bool_t const signalled = SIGNAL_WAIT( &linda->read_happened, &K->lock_, timeout); | 552 | s->status = prev_status; |
543 | if( s != NULL) | ||
544 | { | ||
545 | s->waiting_on = NULL; | ||
546 | s->status = prev_status; | ||
547 | // if a cancel request is pending, be sure to handle it as soon as possible | ||
548 | cancel = s->cancel_request; | ||
549 | } | ||
550 | cancel = (cancel != CANCEL_NONE) ? cancel : linda->simulate_cancel; | ||
551 | if( !signalled || cancel != CANCEL_NONE) | ||
552 | { | ||
553 | // waiting returned after a timeout, or pending cancel: we are done | ||
554 | break; | ||
555 | } | ||
556 | } | 553 | } |
557 | } | 554 | } |
558 | } | 555 | } |
@@ -569,7 +566,7 @@ LUAG_FUNC( linda_send) | |||
569 | switch( cancel) | 566 | switch( cancel) |
570 | { | 567 | { |
571 | case CANCEL_SOFT: | 568 | case CANCEL_SOFT: |
572 | // if user wants to soft-cancel, the call returns CANCEL_ERROR | 569 | // if user wants to soft-cancel, the call returns lanes.cancel_error |
573 | lua_pushlightuserdata( L, CANCEL_ERROR); | 570 | lua_pushlightuserdata( L, CANCEL_ERROR); |
574 | return 1; | 571 | return 1; |
575 | 572 | ||
@@ -606,8 +603,6 @@ LUAG_FUNC( linda_receive) | |||
606 | time_d timeout = -1.0; | 603 | time_d timeout = -1.0; |
607 | uint_t key_i = 2; | 604 | uint_t key_i = 2; |
608 | 605 | ||
609 | luaL_argcheck( L, linda, 1, "expected a linda object!"); | ||
610 | |||
611 | if( lua_type( L, 2) == LUA_TNUMBER) // we don't want to use lua_isnumber() because of autocoercion | 606 | if( lua_type( L, 2) == LUA_TNUMBER) // we don't want to use lua_isnumber() because of autocoercion |
612 | { | 607 | { |
613 | timeout = SIGNAL_TIMEOUT_PREPARE( lua_tonumber( L, 2)); | 608 | timeout = SIGNAL_TIMEOUT_PREPARE( lua_tonumber( L, 2)); |
@@ -655,10 +650,24 @@ LUAG_FUNC( linda_receive) | |||
655 | } | 650 | } |
656 | 651 | ||
657 | { | 652 | { |
653 | bool_t try_again = TRUE; | ||
654 | struct s_lane* const s = get_lane_from_registry( L); | ||
658 | struct s_Keeper* K = keeper_acquire( linda); | 655 | struct s_Keeper* K = keeper_acquire( linda); |
659 | if( K == NULL) return 0; | 656 | if( K == NULL) return 0; |
660 | for( ;;) | 657 | for( ;;) |
661 | { | 658 | { |
659 | if( s != NULL) | ||
660 | { | ||
661 | cancel = s->cancel_request; | ||
662 | } | ||
663 | cancel = (cancel != CANCEL_NONE) ? cancel : linda->simulate_cancel; | ||
664 | // if user wants to cancel, or looped because of a timeout, the call returns without sending anything | ||
665 | if( !try_again || cancel != CANCEL_NONE) | ||
666 | { | ||
667 | pushed = 0; | ||
668 | break; | ||
669 | } | ||
670 | |||
662 | // all arguments of receive() but the first are passed to the keeper's receive function | 671 | // all arguments of receive() but the first are passed to the keeper's receive function |
663 | pushed = keeper_call( K->L, keeper_receive, L, linda, key_i); | 672 | pushed = keeper_call( K->L, keeper_receive, L, linda, key_i); |
664 | if( pushed < 0) | 673 | if( pushed < 0) |
@@ -674,26 +683,16 @@ LUAG_FUNC( linda_receive) | |||
674 | // | 683 | // |
675 | SIGNAL_ALL( &linda->read_happened); | 684 | SIGNAL_ALL( &linda->read_happened); |
676 | break; | 685 | break; |
677 | |||
678 | } | 686 | } |
687 | |||
679 | if( timeout == 0.0) | 688 | if( timeout == 0.0) |
680 | { | 689 | { |
681 | break; /* instant timeout */ | 690 | break; /* instant timeout */ |
682 | } | 691 | } |
683 | /* nothing received; wait until timeout */ | ||
684 | 692 | ||
693 | // nothing received, wait until timeout or signalled that we should try again | ||
685 | { | 694 | { |
686 | enum e_status prev_status = ERROR_ST; // prevent 'might be used uninitialized' warnings | 695 | enum e_status prev_status = ERROR_ST; // prevent 'might be used uninitialized' warnings |
687 | struct s_lane* const s = get_lane_from_registry( L); | ||
688 | if( s != NULL) | ||
689 | { | ||
690 | cancel = s->cancel_request; | ||
691 | } | ||
692 | cancel = (cancel != CANCEL_NONE) ? cancel : linda->simulate_cancel; | ||
693 | if( cancel != CANCEL_NONE) // if user wants to cancel, the call returns without providing anything | ||
694 | { | ||
695 | break; | ||
696 | } | ||
697 | if( s != NULL) | 696 | if( s != NULL) |
698 | { | 697 | { |
699 | // change status of lane to "waiting" | 698 | // change status of lane to "waiting" |
@@ -703,22 +702,12 @@ LUAG_FUNC( linda_receive) | |||
703 | ASSERT_L( s->waiting_on == NULL); | 702 | ASSERT_L( s->waiting_on == NULL); |
704 | s->waiting_on = &linda->write_happened; | 703 | s->waiting_on = &linda->write_happened; |
705 | } | 704 | } |
705 | // not enough data to read: wakeup when data was sent, or when timeout is reached | ||
706 | try_again = SIGNAL_WAIT( &linda->write_happened, &K->lock_, timeout); | ||
707 | if( s != NULL) | ||
706 | { | 708 | { |
707 | // not enough data to read: wakeup when data was sent, or when timeout is reached | 709 | s->waiting_on = NULL; |
708 | bool_t const signalled = SIGNAL_WAIT( &linda->write_happened, &K->lock_, timeout); | 710 | s->status = prev_status; |
709 | if( s != NULL) | ||
710 | { | ||
711 | s->waiting_on = NULL; | ||
712 | s->status = prev_status; | ||
713 | // if a cancel request is pending, be sure to handle it as soon as possible | ||
714 | cancel = s->cancel_request; | ||
715 | } | ||
716 | cancel = (cancel != CANCEL_NONE) ? cancel : linda->simulate_cancel; | ||
717 | if( !signalled || cancel != CANCEL_NONE) | ||
718 | { | ||
719 | // waiting returned after a timeout, or pending cancel: we are done | ||
720 | break; | ||
721 | } | ||
722 | } | 711 | } |
723 | } | 712 | } |
724 | } | 713 | } |
@@ -761,7 +750,6 @@ LUAG_FUNC( linda_set) | |||
761 | struct s_Linda* const linda = lua_toLinda( L, 1); | 750 | struct s_Linda* const linda = lua_toLinda( L, 1); |
762 | int pushed; | 751 | int pushed; |
763 | bool_t has_value = lua_gettop( L) > 2; | 752 | bool_t has_value = lua_gettop( L) > 2; |
764 | luaL_argcheck( L, linda, 1, "expected a linda object!"); | ||
765 | 753 | ||
766 | // make sure the key is of a valid type (throws an error if not the case) | 754 | // make sure the key is of a valid type (throws an error if not the case) |
767 | check_key_types( L, 2, 2); | 755 | check_key_types( L, 2, 2); |
@@ -819,7 +807,6 @@ LUAG_FUNC( linda_count) | |||
819 | struct s_Linda* linda = lua_toLinda( L, 1); | 807 | struct s_Linda* linda = lua_toLinda( L, 1); |
820 | int pushed; | 808 | int pushed; |
821 | 809 | ||
822 | luaL_argcheck( L, linda, 1, "expected a linda object!"); | ||
823 | // make sure the keys are of a valid type | 810 | // make sure the keys are of a valid type |
824 | check_key_types( L, 2, lua_gettop( L)); | 811 | check_key_types( L, 2, lua_gettop( L)); |
825 | 812 | ||
@@ -848,7 +835,6 @@ LUAG_FUNC( linda_get) | |||
848 | int pushed; | 835 | int pushed; |
849 | int count = luaL_optint( L, 3, 1); | 836 | int count = luaL_optint( L, 3, 1); |
850 | luaL_argcheck( L, count >= 1, 3, "count should be >= 1"); | 837 | luaL_argcheck( L, count >= 1, 3, "count should be >= 1"); |
851 | luaL_argcheck( L, linda, 1, "expected a linda object"); | ||
852 | luaL_argcheck( L, lua_gettop( L) <= 3, 4, "too many arguments"); | 838 | luaL_argcheck( L, lua_gettop( L) <= 3, 4, "too many arguments"); |
853 | 839 | ||
854 | // make sure the key is of a valid type (throws an error if not the case) | 840 | // make sure the key is of a valid type (throws an error if not the case) |
@@ -897,7 +883,6 @@ LUAG_FUNC( linda_limit) | |||
897 | bool_t wake_writers = FALSE; | 883 | bool_t wake_writers = FALSE; |
898 | 884 | ||
899 | // make sure we got 3 arguments: the linda, a key and a limit | 885 | // make sure we got 3 arguments: the linda, a key and a limit |
900 | luaL_argcheck( L, linda, 1, "expected a linda object!"); | ||
901 | luaL_argcheck( L, lua_gettop( L) == 3, 2, "wrong number of arguments"); | 886 | luaL_argcheck( L, lua_gettop( L) == 3, 2, "wrong number of arguments"); |
902 | // make sure we got a numeric limit | 887 | // make sure we got a numeric limit |
903 | luaL_checknumber( L, 3); | 888 | luaL_checknumber( L, 3); |
@@ -907,12 +892,22 @@ LUAG_FUNC( linda_limit) | |||
907 | { | 892 | { |
908 | struct s_Keeper* K = keeper_acquire( linda); | 893 | struct s_Keeper* K = keeper_acquire( linda); |
909 | if( K == NULL) return 0; | 894 | if( K == NULL) return 0; |
910 | pushed = keeper_call( K->L, KEEPER_API( limit), L, linda, 2); | 895 | |
911 | ASSERT_L( pushed == 0 || pushed == 1); // no error, optional boolean value saying if we should wake blocked writer threads | 896 | if( linda->simulate_cancel == CANCEL_NONE) |
912 | if( pushed == 1) | 897 | { |
898 | pushed = keeper_call( K->L, KEEPER_API( limit), L, linda, 2); | ||
899 | ASSERT_L( pushed == 0 || pushed == 1); // no error, optional boolean value saying if we should wake blocked writer threads | ||
900 | if( pushed == 1) | ||
901 | { | ||
902 | ASSERT_L( lua_type( L, -1) == LUA_TBOOLEAN && lua_toboolean( L, -1) == 1); | ||
903 | SIGNAL_ALL( &linda->read_happened); // To be done from within the 'K' locking area | ||
904 | } | ||
905 | } | ||
906 | else // linda is cancelled | ||
913 | { | 907 | { |
914 | ASSERT_L( lua_type( L, -1) == LUA_TBOOLEAN && lua_toboolean( L, -1) == 1); | 908 | // do nothing and return lanes.cancel_error |
915 | SIGNAL_ALL( &linda->read_happened); // To be done from within the 'K' locking area | 909 | lua_pushlightuserdata( L, CANCEL_ERROR); |
910 | pushed = 1; | ||
916 | } | 911 | } |
917 | keeper_release( K); | 912 | keeper_release( K); |
918 | } | 913 | } |
@@ -929,12 +924,11 @@ LUAG_FUNC( linda_limit) | |||
929 | LUAG_FUNC( linda_cancel) | 924 | LUAG_FUNC( linda_cancel) |
930 | { | 925 | { |
931 | struct s_Linda* linda = lua_toLinda( L, 1); | 926 | struct s_Linda* linda = lua_toLinda( L, 1); |
932 | char const* who = luaL_checkstring( L, 2); | 927 | char const* who = luaL_optstring( L, 2, "both"); |
933 | struct s_Keeper* K; | 928 | struct s_Keeper* K; |
934 | 929 | ||
935 | // make sure we got 3 arguments: the linda, a key and a limit | 930 | // make sure we got 3 arguments: the linda, a key and a limit |
936 | luaL_argcheck( L, linda, 1, "expected a linda object!"); | 931 | luaL_argcheck( L, lua_gettop( L) <= 2, 2, "wrong number of arguments"); |
937 | luaL_argcheck( L, lua_gettop( L) == 2, 2, "wrong number of arguments"); | ||
938 | 932 | ||
939 | // signalling must be done from inside the K locking area | 933 | // signalling must be done from inside the K locking area |
940 | K = keeper_acquire( linda); | 934 | K = keeper_acquire( linda); |
@@ -984,11 +978,11 @@ LUAG_FUNC( linda_cancel) | |||
984 | * different userdata and won't be known to be essentially the same deep one | 978 | * different userdata and won't be known to be essentially the same deep one |
985 | * without this. | 979 | * without this. |
986 | */ | 980 | */ |
987 | LUAG_FUNC( linda_deep ) { | 981 | LUAG_FUNC( linda_deep) |
988 | struct s_Linda *linda= lua_toLinda( L, 1 ); | 982 | { |
989 | luaL_argcheck( L, linda, 1, "expected a linda object!"); | 983 | struct s_Linda* linda= lua_toLinda( L, 1); |
990 | lua_pushlightuserdata( L, linda ); // just the address | 984 | lua_pushlightuserdata( L, linda); // just the address |
991 | return 1; | 985 | return 1; |
992 | } | 986 | } |
993 | 987 | ||
994 | 988 | ||
@@ -1002,10 +996,10 @@ LUAG_FUNC( linda_deep ) { | |||
1002 | 996 | ||
1003 | static int linda_tostring( lua_State* L, int idx_, bool_t opt_) | 997 | static int linda_tostring( lua_State* L, int idx_, bool_t opt_) |
1004 | { | 998 | { |
1005 | struct s_Linda* linda = lua_toLinda( L, idx_); | 999 | struct s_Linda* linda = luaG_todeep( L, linda_id, idx_); |
1006 | if( !opt_) | 1000 | if( !opt_) |
1007 | { | 1001 | { |
1008 | luaL_argcheck( L, linda, idx_, "expected a linda object!"); | 1002 | luaL_argcheck( L, linda, idx_, "expecting a linda object"); |
1009 | } | 1003 | } |
1010 | if( linda != NULL) | 1004 | if( linda != NULL) |
1011 | { | 1005 | { |