aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGES7
-rw-r--r--docs/index.html14
-rw-r--r--src/keeper.c2
-rw-r--r--src/lanes.c160
-rw-r--r--src/lanes.lua88
-rw-r--r--tests/cancel.lua30
-rw-r--r--tests/linda_perf.lua4
7 files changed, 178 insertions, 127 deletions
diff --git a/CHANGES b/CHANGES
index 6baa38e..329c53f 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,5 +1,12 @@
1CHANGES: 1CHANGES:
2 2
3CHANGE 98: BGe 13-Feb-14
4 * version 3.8.5
5 * linda:limit() returns lanes.cancel_error on a limited linda
6 * lanes.genlock() and lanes.genatomic() support cancelled lindas by returning lanes.cancel_error whenever appropriate
7 * fixed a possible Lua stack overflow when calling linda:dump()
8 * fixed cases where linda:send() and linda:receive() would not return lanes.cancel_error when they should
9
3CHANGE 97: BGe 10-Feb-14 10CHANGE 97: BGe 10-Feb-14
4 * version 3.8.4 11 * version 3.8.4
5 * new API linda:cancel("read"|"write"|"both"|"none") 12 * new API linda:cancel("read"|"write"|"both"|"none")
diff --git a/docs/index.html b/docs/index.html
index 1ad25a6..2468ad8 100644
--- a/docs/index.html
+++ b/docs/index.html
@@ -70,7 +70,7 @@
70 </p> 70 </p>
71 71
72 <p> 72 <p>
73 This document was revised on 10-Feb-14, and applies to version <tt>3.8.4</tt>. 73 This document was revised on 13-Feb-14, and applies to version <tt>3.8.5</tt>.
74 </p> 74 </p>
75 </font> 75 </font>
76 </center> 76 </center>
@@ -1039,7 +1039,7 @@
1039 1039
1040 [key, val [, ...]]|[lanes.cancel_error] = h:receive( timeout, h.batched, key, n_uint_min[, n_uint_max]) 1040 [key, val [, ...]]|[lanes.cancel_error] = h:receive( timeout, h.batched, key, n_uint_min[, n_uint_max])
1041 1041
1042 [true] = h:limit( key, n_uint) 1042 [true|lanes.cancel_error] = h:limit( key, n_uint)
1043</pre></td></tr></table> 1043</pre></td></tr></table>
1044 1044
1045<p> 1045<p>
@@ -1288,11 +1288,11 @@ events to a common Linda, but... :).</font>
1288</p> 1288</p>
1289 1289
1290<table border="1" bgcolor="#E0E0FF" cellpadding="10" style="width:50%"><tr><td><pre> 1290<table border="1" bgcolor="#E0E0FF" cellpadding="10" style="width:50%"><tr><td><pre>
1291 lock_func = lanes.genlock( linda_h, key [,N_uint=1]) 1291 lock_func|lanes.cancel_error = lanes.genlock( linda_h, key [,N_uint=1])
1292 1292
1293 bool = lock_func( M_uint [, "try"] ) -- acquire 1293 bool|lanes.cancel_error = lock_func( M_uint [, "try"] ) -- acquire
1294 .. 1294 ..
1295 bool = lock_func( -M_uint) -- release 1295 bool|lanes.cancel_error = lock_func( -M_uint) -- release
1296</pre></td></tr></table> 1296</pre></td></tr></table>
1297 1297
1298<p> 1298<p>
@@ -1314,9 +1314,9 @@ events to a common Linda, but... :).</font>
1314<p> 1314<p>
1315 1315
1316<table border="1" bgcolor="#E0E0FF" cellpadding="10" style="width:50%"><tr><td><pre> 1316<table border="1" bgcolor="#E0E0FF" cellpadding="10" style="width:50%"><tr><td><pre>
1317 atomic_func = lanes.genatomic( linda_h, key [,initial_num=0.0]) 1317 atomic_func|lanes.cancel_error = lanes.genatomic( linda_h, key [,initial_num=0.0])
1318 1318
1319 new_num = atomic_func( [diff_num=+1.0]) 1319 new_num|lanes.cancel_error = atomic_func( [diff_num=+1.0])
1320</pre></td></tr></table> 1320</pre></td></tr></table>
1321 1321
1322<p> 1322<p>
diff --git a/src/keeper.c b/src/keeper.c
index 1a696aa..c22bfed 100644
--- a/src/keeper.c
+++ b/src/keeper.c
@@ -190,6 +190,7 @@ int keeper_push_linda_storage( lua_State* L, void* ptr)
190 struct s_Keeper* K = keeper_acquire( ptr); 190 struct s_Keeper* K = keeper_acquire( ptr);
191 lua_State* KL = K ? K->L : NULL; 191 lua_State* KL = K ? K->L : NULL;
192 if( KL == NULL) return 0; 192 if( KL == NULL) return 0;
193 STACK_GROW( KL, 4);
193 STACK_CHECK( KL); 194 STACK_CHECK( KL);
194 lua_pushlightuserdata( KL, fifos_key); // fifos_key 195 lua_pushlightuserdata( KL, fifos_key); // fifos_key
195 lua_rawget( KL, LUA_REGISTRYINDEX); // fifos 196 lua_rawget( KL, LUA_REGISTRYINDEX); // fifos
@@ -204,6 +205,7 @@ int keeper_push_linda_storage( lua_State* L, void* ptr)
204 } 205 }
205 // move data from keeper to destination state KEEPER MAIN 206 // move data from keeper to destination state KEEPER MAIN
206 lua_pushnil( KL); // storage nil 207 lua_pushnil( KL); // storage nil
208 STACK_GROW( L, 5);
207 STACK_CHECK( L); 209 STACK_CHECK( L);
208 lua_newtable( L); // out 210 lua_newtable( L); // out
209 while( lua_next( KL, -2)) // storage key fifo 211 while( lua_next( KL, -2)) // storage key fifo
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 {
diff --git a/src/lanes.lua b/src/lanes.lua
index 1286099..86dbe47 100644
--- a/src/lanes.lua
+++ b/src/lanes.lua
@@ -585,13 +585,25 @@ end
585 585
586end -- settings.with_timers 586end -- settings.with_timers
587 587
588-- avoid pulling the whole core module as upvalue when cancel_error is enough
589local cancel_error = assert( core.cancel_error)
590
588---=== Lock & atomic generators ===--- 591---=== Lock & atomic generators ===---
589 592
590-- These functions are just surface sugar, but make solutions easier to read. 593-- These functions are just surface sugar, but make solutions easier to read.
591-- Not many applications should even need explicit locks or atomic counters. 594-- Not many applications should even need explicit locks or atomic counters.
592 595
593-- 596--
594-- lock_f= lanes.genlock( linda_h, key [,N_uint=1] ) 597-- [true [, ...]= trues(uint)
598--
599local function trues( n)
600 if n > 0 then
601 return true, trues( n - 1)
602 end
603end
604
605--
606-- lock_f = lanes.genlock( linda_h, key [,N_uint=1] )
595-- 607--
596-- = lock_f( +M ) -- acquire M 608-- = lock_f( +M ) -- acquire M
597-- ...locked... 609-- ...locked...
@@ -602,16 +614,10 @@ end -- settings.with_timers
602-- 614--
603-- PUBLIC LANES API 615-- PUBLIC LANES API
604local genlock = function( linda, key, N) 616local genlock = function( linda, key, N)
605 linda:set( key) -- clears existing data 617 -- clear existing data and set the limit
606 linda:limit( key, N) 618 N = N or 1
607 619 if linda:set( key) == cancel_error or linda:limit( key, N) == cancel_error then
608 -- 620 return cancel_error
609 -- [true [, ...]= trues(uint)
610 --
611 local function trues( n)
612 if n > 0 then
613 return true, trues( n - 1)
614 end
615 end 621 end
616 622
617 -- use an optimized version for case N == 1 623 -- use an optimized version for case N == 1
@@ -623,7 +629,8 @@ local genlock = function( linda, key, N)
623 return linda:send( timeout, key, true) -- suspends until been able to push them 629 return linda:send( timeout, key, true) -- suspends until been able to push them
624 else 630 else
625 local k = linda:receive( nil, key) 631 local k = linda:receive( nil, key)
626 return k and true or false 632 -- propagate cancel_error if we got it, else return true or false
633 return k and ((k ~= cancel_error) and true or k) or false
627 end 634 end
628 end 635 end
629 or 636 or
@@ -634,34 +641,45 @@ local genlock = function( linda, key, N)
634 return linda:send( timeout, key, trues(M)) -- suspends until been able to push them 641 return linda:send( timeout, key, trues(M)) -- suspends until been able to push them
635 else 642 else
636 local k = linda:receive( nil, linda.batched, key, -M) 643 local k = linda:receive( nil, linda.batched, key, -M)
637 return k and true or false 644 -- propagate cancel_error if we got it, else return true or false
645 return k and ((k ~= cancel_error) and true or k) or false
638 end 646 end
639 end 647 end
640end 648end
641 649
642 650
643-- 651 --
644-- atomic_f= lanes.genatomic( linda_h, key [,initial_num=0.0] ) 652 -- atomic_f = lanes.genatomic( linda_h, key [,initial_num=0.0])
645-- 653 --
646-- int= atomic_f( [diff_num=1.0] ) 654 -- int|cancel_error = atomic_f( [diff_num = 1.0])
647-- 655 --
648-- Returns an access function that allows atomic increment/decrement of the 656 -- Returns an access function that allows atomic increment/decrement of the
649-- number in 'key'. 657 -- number in 'key'.
650-- 658 --
651-- PUBLIC LANES API 659 -- PUBLIC LANES API
652local function genatomic( linda, key, initial_val ) 660 local genatomic = function( linda, key, initial_val)
653 linda:limit(key,2) -- value [,true] 661 -- clears existing data (also queue). the slot may contain the stored value, and an additional boolean value
654 linda:set(key,initial_val or 0.0) -- clears existing data (also queue) 662 if linda:limit( key, 2) == cancel_error or linda:set( key, initial_val or 0.0) == cancel_error then
655 663 return cancel_error
656 return 664 end
657 function(diff) 665
658 -- 'nil' allows 'key' to be numeric 666 return function( diff)
659 linda:send( nil, key, true ) -- suspends until our 'true' is in 667 -- 'nil' allows 'key' to be numeric
660 local val= linda:get(key) + (diff or 1.0) 668 -- suspends until our 'true' is in
661 linda:set( key, val ) -- releases the lock, by emptying queue 669 if linda:send( nil, key, true) == cancel_error then
662 return val 670 return cancel_error
663 end 671 end
664end 672 local val = linda:get( key)
673 if val ~= cancel_error then
674 val = val + (diff or 1.0)
675 -- set() releases the lock by emptying queue
676 if linda:set( key, val) == cancel_error then
677 val = cancel_error
678 end
679 end
680 return val
681 end
682 end
665 683
666 -- activate full interface 684 -- activate full interface
667 lanes.require = core.require 685 lanes.require = core.require
diff --git a/tests/cancel.lua b/tests/cancel.lua
index a5f1dab..6429487 100644
--- a/tests/cancel.lua
+++ b/tests/cancel.lua
@@ -2,6 +2,33 @@ local lanes = require "lanes" .configure{ with_timers = false}
2 2
3local linda = lanes.linda() 3local linda = lanes.linda()
4 4
5--####################################################################
6print "\n\n####################################################################\nbegin genlock & genatomic cancel test\n"
7
8-- get a lock and a atomic operator
9local lock = lanes.genlock( linda, "lock", 1)
10local atomic = lanes.genatomic( linda, "atomic")
11
12-- check that cancelled lindas give cancel_error as they should
13linda:cancel()
14assert( linda:get( "empty") == lanes.cancel_error)
15assert( lanes.genlock( linda, "any", 1) == lanes.cancel_error)
16assert( lanes.genatomic( linda, "any") == lanes.cancel_error)
17
18-- check that lock and atomic functions return cancel_error if the linda was cancelled
19assert( lock( 1) == lanes.cancel_error)
20assert( lock( -1) == lanes.cancel_error)
21assert( atomic( 1) == lanes.cancel_error)
22
23-- reset the linda so that the other tests work
24linda:cancel( "none")
25linda:limit( "lock", -1)
26linda:set( "lock")
27linda:limit( "atomic", -1)
28linda:set( "atomic")
29
30--####################################################################
31
5local laneBody = function( timeout_) 32local laneBody = function( timeout_)
6 set_finalizer( function( err, stk) 33 set_finalizer( function( err, stk)
7 if err == lanes.cancel_error then 34 if err == lanes.cancel_error then
@@ -105,4 +132,7 @@ linda:cancel( "both")
105print "wait 5s" 132print "wait 5s"
106linda:receive( 5, "yeah") 133linda:receive( 5, "yeah")
107 134
135--####################################################################
136
108print "\ndone" 137print "\ndone"
138
diff --git a/tests/linda_perf.lua b/tests/linda_perf.lua
index 1d92c8e..1a44d07 100644
--- a/tests/linda_perf.lua
+++ b/tests/linda_perf.lua
@@ -31,8 +31,8 @@ local batched = function( l, loop, batch)
31 print( val) 31 print( val)
32end 32end
33 33
34local lane_eater_gen = lanes.gen( "*", eater) 34local lane_eater_gen = lanes.gen( "*", {priority = 3}, eater)
35local lane_batched_gen = lanes.gen( "*", batched) 35local lane_batched_gen = lanes.gen( "*", {priority = 3}, batched)
36 36
37-- main thread writes data while a lane reads it 37-- main thread writes data while a lane reads it
38local function ziva( preloop, loop, batch) 38local function ziva( preloop, loop, batch)