aboutsummaryrefslogtreecommitdiff
path: root/src/lanes.c
diff options
context:
space:
mode:
authorBenoit Germain <bnt period germain arrobase gmail period com>2014-02-13 16:09:15 +0100
committerBenoit Germain <bnt period germain arrobase gmail period com>2014-02-13 16:09:15 +0100
commit32ad991eb8c590472607d61e9a831d2ca9db05c5 (patch)
tree1e3920223e81a5970241f9687db9129d7ec7bb2e /src/lanes.c
parentc38429579de57d338e0a1c14a7ed7b4aa90e059a (diff)
downloadlanes-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.c160
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
55char const* VERSION = "3.8.4"; 55char const* VERSION = "3.8.5";
56 56
57/* 57/*
58=============================================================================== 58===============================================================================
@@ -424,13 +424,17 @@ struct s_Linda
424 424
425static void linda_id( lua_State*, char const * const which); 425static 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 )) 427static 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
430static void check_key_types( lua_State*L, int _start, int _end) 434static 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)
929LUAG_FUNC( linda_cancel) 924LUAG_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*/
987LUAG_FUNC( linda_deep ) { 981LUAG_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
1003static int linda_tostring( lua_State* L, int idx_, bool_t opt_) 997static 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 {