aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGES6
-rw-r--r--docs/index.html48
-rw-r--r--src/lanes.c405
-rw-r--r--tests/cancel.lua19
4 files changed, 302 insertions, 176 deletions
diff --git a/CHANGES b/CHANGES
index 45bd142..6baa38e 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,5 +1,11 @@
1CHANGES: 1CHANGES:
2 2
3CHANGE 97: BGe 10-Feb-14
4 * version 3.8.4
5 * new API linda:cancel("read"|"write"|"both"|"none")
6 * all linda operations return lanes.cancel_error on a cancelled linda
7 * raised an internal string length so that longer linda names are fully output before truncation applies when doing tostring( linda)
8
3CHANGE 96: BGe 24-Jan-14 9CHANGE 96: BGe 24-Jan-14
4 * another Lua stack overflow fix when sending complex function through lindas or as lane body 10 * another Lua stack overflow fix when sending complex function through lindas or as lane body
5 11
diff --git a/docs/index.html b/docs/index.html
index f639f18..1ad25a6 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 22-Jan-14, and applies to version <tt>3.8.3</tt>. 73 This document was revised on 10-Feb-14, and applies to version <tt>3.8.4</tt>.
74 </p> 74 </p>
75 </font> 75 </font>
76 </center> 76 </center>
@@ -902,10 +902,12 @@
902<p> 902<p>
903 <tt>cancel()</tt> sends a cancellation request to the lane.<br/> 903 <tt>cancel()</tt> sends a cancellation request to the lane.<br/>
904 First argument is a timeout, that defaults to 0 if not specified. (Starting with version 3.6.3) signification of the following arguments differ depending on whether the timeout is negative or not. 904 First argument is a timeout, that defaults to 0 if not specified. (Starting with version 3.6.3) signification of the following arguments differ depending on whether the timeout is negative or not.
905 <br/> 905</p>
906<p>
906 If <tt>timeout_secs</tt> is negative (aka "soft cancel"), cancellation will only cause <tt>cancel_test()</tt> to return <tt>true</tt>, so that the lane can cleanup manually (the actual value is irrelevant). 907 If <tt>timeout_secs</tt> is negative (aka "soft cancel"), cancellation will only cause <tt>cancel_test()</tt> to return <tt>true</tt>, so that the lane can cleanup manually (the actual value is irrelevant).
907 If <tt>wake_bool</tt> is <tt>true</tt>, the lane is also signalled so that execution returns from any pending linda operation. 908 If <tt>wake_bool</tt> is <tt>true</tt>, the lane is also signalled so that execution returns from any pending linda operation. Linda operations detecting the cancellation request return <tt>lanes.cancel_error</tt>.
908 <br/> 909</p>
910<p>
909 If <tt>timeout_secs</tt> is positive (aka "hard cancel"), waits for the request to be processed, or a timeout to occur. Linda operations detecting the cancellation request will raise a special cancellation error (meaning they won't return in that case). 911 If <tt>timeout_secs</tt> is positive (aka "hard cancel"), waits for the request to be processed, or a timeout to occur. Linda operations detecting the cancellation request will raise a special cancellation error (meaning they won't return in that case).
910 If <tt>force_kill_bool</tt> is <tt>true</tt>, <tt>forcekill_timeout</tt> can be set to tell how long lanes will wait for the OS thread to terminate before raising an error. Windows threads always terminate immediately, but it might not always be the case with some pthread implementations. 912 If <tt>force_kill_bool</tt> is <tt>true</tt>, <tt>forcekill_timeout</tt> can be set to tell how long lanes will wait for the OS thread to terminate before raising an error. Windows threads always terminate immediately, but it might not always be the case with some pthread implementations.
911 Returns <tt>true</tt> if soft cancelling, or the lane was already done (in <tt>"done"</tt>, <tt>"error"</tt> or <tt>"cancelled"</tt> status), or the cancellation was fruitful within <tt>timeout_secs</tt> timeout period. 913 Returns <tt>true</tt> if soft cancelling, or the lane was already done (in <tt>"done"</tt>, <tt>"error"</tt> or <tt>"cancelled"</tt> status), or the cancellation was fruitful within <tt>timeout_secs</tt> timeout period.
@@ -1007,7 +1009,7 @@
1007 print( "timed out") 1009 print( "timed out")
1008 break 1010 break
1009 end 1011 end
1010 print( "received: " .. val) 1012 print( tostring( linda) .. " received: " .. val)
1011 end 1013 end
1012</pre></td></tr></table> 1014</pre></td></tr></table>
1013 1015
@@ -1024,27 +1026,28 @@
1024 <li><tt>receive</tt> can wait for multiple keys at once.</li> 1026 <li><tt>receive</tt> can wait for multiple keys at once.</li>
1025 <li><tt>receive</tt> has a batched mode to consume more than one value from a single key, as in <tt>linda:receive( 1.0, linda.batched, "key", 3, 6).</tt></li> 1027 <li><tt>receive</tt> has a batched mode to consume more than one value from a single key, as in <tt>linda:receive( 1.0, linda.batched, "key", 3, 6).</tt></li>
1026 <li>individual keys' queue length can be limited, balancing speed differences in a producer/consumer scenario (making <tt>:send</tt> wait).</li> 1028 <li>individual keys' queue length can be limited, balancing speed differences in a producer/consumer scenario (making <tt>:send</tt> wait).</li>
1029 <li><tt>tostring( linda)</tt> returns a string of the form <tt>"Linda: &lt;opt_name&gt;"</tt></li>
1027 </ul> 1030 </ul>
1028</p> 1031</p>
1029 1032
1030<table border="1" bgcolor="#E0E0FF" cellpadding="10" style="width:50%"><tr><td><pre> 1033<table border="1" bgcolor="#E0E0FF" cellpadding="10" style="width:50%"><tr><td><pre>
1031 h = lanes.linda( [opt_name]) 1034 h = lanes.linda( [opt_name])
1032 1035
1033 bool|cancel_error = h:send( [timeout_secs,] key, ...) 1036 [true|lanes.cancel_error] = h:send( [timeout_secs,] key, ...)
1034 1037
1035 [key, val]|[cancel_error] = h:receive( [timeout_secs,] key [, ...]) 1038 [key, val]|[lanes.cancel_error] = h:receive( [timeout_secs,] key [, ...])
1036 1039
1037 [key, val [, ...]]|[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])
1038 1041
1039 [true] = h:limit( key, n_uint) 1042 [true] = h:limit( key, n_uint)
1040</pre></td></tr></table> 1043</pre></td></tr></table>
1041 1044
1042<p> 1045<p>
1043 The <tt>send</tt> and <tt>receive</tt> methods use Linda keys as FIFO stacks (first in, first out). Timeouts are given in seconds (millisecond accuracy). If using numbers as the first Linda key, one must explicitly give <tt>nil</tt> as the timeout parameter to avoid ambiguities. 1046 The <tt>send()</tt> and <tt>receive()</tt> methods use Linda keys as FIFO stacks (first in, first out). Timeouts are given in seconds (millisecond accuracy). If using numbers as the first Linda key, one must explicitly give <tt>nil</tt> as the timeout parameter to avoid ambiguities.
1044</p> 1047</p>
1045 1048
1046<p> 1049<p>
1047 By default, stack sizes are unlimited but limits can be enforced using the <tt>limit</tt> method. This can be useful to balance execution speeds in a producer/consumer scenario. Any negative value removes the limit. 1050 By default, stack sizes are unlimited but limits can be enforced using the <tt>limit()</tt> method. This can be useful to balance execution speeds in a producer/consumer scenario. Any negative value removes the limit.
1048 <br/> 1051 <br/>
1049 A limit of 0 is allowed to block everything. 1052 A limit of 0 is allowed to block everything.
1050 <br/> 1053 <br/>
@@ -1083,9 +1086,9 @@
1083</p> 1086</p>
1084 1087
1085<table border="1" bgcolor="#E0E0FF" cellpadding="10" style="width:50%"><tr><td><pre> 1088<table border="1" bgcolor="#E0E0FF" cellpadding="10" style="width:50%"><tr><td><pre>
1086 [bool] = linda_h:set( key [, val [, ...]]) 1089 bool|lanes.cancel_error = linda_h:set( key [, val [, ...]])
1087 1090
1088 [val [, ...]] = linda_h:get( key [, count = 1]) 1091 [[val [, ...]]|lanes.cancel_error] = linda_h:get( key [, count = 1])
1089</pre></td></tr></table> 1092</pre></td></tr></table>
1090 1093
1091<p> 1094<p>
@@ -1099,9 +1102,9 @@
1099</p> 1102</p>
1100 1103
1101<p> 1104<p>
1102 <tt>set()</tt> signals the linda for write if a value is stored. 1105 <tt>set()</tt> signals the linda for write if a value is stored. If nothing special happens, <tt>set() </tt>returns nothing.
1103 <br/> 1106 <br/>
1104 (Since version 3.7.7) if the key was full but the new data count of the key after <tt>set()</tt> is below its limit, <tt>set()</tt> returns <tt>true</tt> and the linda is also signaled for read so that send()-blocked threads are awakened. 1107 Since version 3.7.7, if the key was full but the new data count of the key after <tt>set()</tt> is below its limit, <tt>set()</tt> returns <tt>true</tt> and the linda is also signaled for read so that <tt>send()</tt>-blocked threads are awakened.
1105</p> 1108</p>
1106 1109
1107<p> 1110<p>
@@ -1110,6 +1113,10 @@
1110 Also, <tt>get()</tt> can read several values at once. If the key contains no data, <tt>get()</tt> returns no value. This can be used to separate the case when reading stored <tt>nil</tt> values. 1113 Also, <tt>get()</tt> can read several values at once. If the key contains no data, <tt>get()</tt> returns no value. This can be used to separate the case when reading stored <tt>nil</tt> values.
1111</p> 1114</p>
1112 1115
1116<p>
1117 Since version 3.8.4, trying to send or receive data through a cancelled linda does nothing and returns <tt>lanes.cancel_error</tt>.
1118</p>
1119
1113<table border="1" bgcolor="#E0E0FF" cellpadding="10" style="width:50%"><tr><td><pre> 1120<table border="1" bgcolor="#E0E0FF" cellpadding="10" style="width:50%"><tr><td><pre>
1114 [val] = linda_h:count( [key[,...]]) 1121 [val] = linda_h:count( [key[,...]])
1115</pre></td></tr></table> 1122</pre></td></tr></table>
@@ -1134,6 +1141,19 @@
1134 Returns a table describing the full contents of a linda, or <tt>nil</tt> if the linda wasn't used yet. 1141 Returns a table describing the full contents of a linda, or <tt>nil</tt> if the linda wasn't used yet.
1135</p> 1142</p>
1136 1143
1144<table border="1" bgcolor="#E0E0FF" cellpadding="10" style="width:50%"><tr><td><pre>
1145 void = linda_h:cancel("read"|"write"|"both"|"none")
1146</pre></td></tr></table>
1147
1148<p>
1149 (Starting with version 3.8.4) Signals the linda so that lanes waiting for read, write, or both, wake up.
1150 All linda operations (including <tt>get()</tt> and <tt>set()</tt>) will return <tt>lanes.cancel_error</tt> as when the calling lane is <a href="#cancelling">soft-cancelled</a> as long as the linda is marked as cancelled.
1151 <br/>
1152 <tt>"none"</tt> reset the linda's cancel status, but doesn't signal it.
1153 <br/>
1154 If not void, the lane's cancel status overrides the linda's cancel status.
1155</p>
1156
1137<h3>Granularity of using Lindas</h3> 1157<h3>Granularity of using Lindas</h3>
1138 1158
1139<p> 1159<p>
diff --git a/src/lanes.c b/src/lanes.c
index 64c144c..cf88171 100644
--- a/src/lanes.c
+++ b/src/lanes.c
@@ -52,7 +52,7 @@
52 * ... 52 * ...
53 */ 53 */
54 54
55char const* VERSION = "3.8.3"; 55char const* VERSION = "3.8.4";
56 56
57/* 57/*
58=============================================================================== 58===============================================================================
@@ -147,7 +147,7 @@ struct s_lane
147 // M: sets to PENDING (before launching) 147 // M: sets to PENDING (before launching)
148 // S: updates -> RUNNING/WAITING -> DONE/ERROR_ST/CANCELLED 148 // S: updates -> RUNNING/WAITING -> DONE/ERROR_ST/CANCELLED
149 149
150 SIGNAL_T * volatile waiting_on; 150 SIGNAL_T* volatile waiting_on;
151 // 151 //
152 // When status is WAITING, points on the linda's signal the thread waits on, else NULL 152 // When status is WAITING, points on the linda's signal the thread waits on, else NULL
153 153
@@ -414,10 +414,12 @@ static void lane_cleanup( struct s_lane* s)
414* Actual data is kept within a keeper state, which is hashed by the 's_Linda' 414* Actual data is kept within a keeper state, which is hashed by the 's_Linda'
415* pointer (which is same to all userdatas pointing to it). 415* pointer (which is same to all userdatas pointing to it).
416*/ 416*/
417struct s_Linda { 417struct s_Linda
418 SIGNAL_T read_happened; 418{
419 SIGNAL_T write_happened; 419 SIGNAL_T read_happened;
420 char name[1]; 420 SIGNAL_T write_happened;
421 enum e_cancel_request simulate_cancel;
422 char name[1];
421}; 423};
422 424
423static void linda_id( lua_State*, char const * const which); 425static void linda_id( lua_State*, char const * const which);
@@ -450,11 +452,11 @@ static void check_key_types( lua_State*L, int _start, int _end)
450*/ 452*/
451LUAG_FUNC( linda_send) 453LUAG_FUNC( linda_send)
452{ 454{
453 struct s_Linda *linda = lua_toLinda( L, 1); 455 struct s_Linda* linda = lua_toLinda( L, 1);
454 bool_t ret; 456 bool_t ret;
455 enum e_cancel_request cancel = CANCEL_NONE; 457 enum e_cancel_request cancel = CANCEL_NONE;
456 int pushed; 458 int pushed;
457 time_d timeout= -1.0; 459 time_d timeout = -1.0;
458 uint_t key_i = 2; // index of first key, if timeout not there 460 uint_t key_i = 2; // index of first key, if timeout not there
459 461
460 luaL_argcheck( L, linda, 1, "expected a linda object!"); 462 luaL_argcheck( L, linda, 1, "expected a linda object!");
@@ -507,7 +509,6 @@ LUAG_FUNC( linda_send)
507 // 509 //
508 SIGNAL_ALL( &linda->write_happened); 510 SIGNAL_ALL( &linda->write_happened);
509 break; 511 break;
510
511 } 512 }
512 if( timeout == 0.0) 513 if( timeout == 0.0)
513 { 514 {
@@ -520,11 +521,15 @@ LUAG_FUNC( linda_send)
520 struct s_lane* const s = get_lane_from_registry( L); 521 struct s_lane* const s = get_lane_from_registry( L);
521 if( s != NULL) 522 if( s != NULL)
522 { 523 {
523 cancel = s->cancel_request; // testing here causes no delays 524 cancel = s->cancel_request;
524 if( cancel != CANCEL_NONE) // if user wants to cancel, the call returns without sending anything 525 }
525 { 526 cancel = (cancel != CANCEL_NONE) ? cancel : linda->simulate_cancel;
526 break; 527 if( cancel != CANCEL_NONE) // if user wants to cancel, the call returns without sending anything
527 } 528 {
529 break;
530 }
531 if( s != NULL)
532 {
528 // change status of lane to "waiting" 533 // change status of lane to "waiting"
529 prev_status = s->status; // RUNNING, most likely 534 prev_status = s->status; // RUNNING, most likely
530 ASSERT_L( prev_status == RUNNING); // but check, just in case 535 ASSERT_L( prev_status == RUNNING); // but check, just in case
@@ -532,22 +537,22 @@ LUAG_FUNC( linda_send)
532 ASSERT_L( s->waiting_on == NULL); 537 ASSERT_L( s->waiting_on == NULL);
533 s->waiting_on = &linda->read_happened; 538 s->waiting_on = &linda->read_happened;
534 } 539 }
535 // could not send because no room: wait until some data was read before trying again, or until timeout is reached
536 if( !SIGNAL_WAIT( &linda->read_happened, &K->lock_, timeout))
537 { 540 {
541 // could not send because no room: wait until some data was read before trying again, or until timeout is reached
542 bool_t const signalled = SIGNAL_WAIT( &linda->read_happened, &K->lock_, timeout);
538 if( s != NULL) 543 if( s != NULL)
539 { 544 {
540 s->waiting_on = NULL; 545 s->waiting_on = NULL;
541 s->status = prev_status; 546 s->status = prev_status;
542 // if woken by a cancel request, be sure to handle it properly 547 // if a cancel request is pending, be sure to handle it as soon as possible
543 cancel = s->cancel_request; 548 cancel = s->cancel_request;
544 } 549 }
545 break; 550 cancel = (cancel != CANCEL_NONE) ? cancel : linda->simulate_cancel;
546 } 551 if( !signalled || cancel != CANCEL_NONE)
547 if( s != NULL) 552 {
548 { 553 // waiting returned after a timeout, or pending cancel: we are done
549 s->waiting_on = NULL; 554 break;
550 s->status = prev_status; 555 }
551 } 556 }
552 } 557 }
553 } 558 }
@@ -593,7 +598,7 @@ LUAG_FUNC( linda_send)
593#define BATCH_SENTINEL "270e6c9d-280f-4983-8fee-a7ecdda01475" 598#define BATCH_SENTINEL "270e6c9d-280f-4983-8fee-a7ecdda01475"
594LUAG_FUNC( linda_receive) 599LUAG_FUNC( linda_receive)
595{ 600{
596 struct s_Linda *linda = lua_toLinda( L, 1); 601 struct s_Linda* linda = lua_toLinda( L, 1);
597 int pushed, expected_pushed_min, expected_pushed_max; 602 int pushed, expected_pushed_min, expected_pushed_max;
598 enum e_cancel_request cancel = CANCEL_NONE; 603 enum e_cancel_request cancel = CANCEL_NONE;
599 keeper_api_t keeper_receive; 604 keeper_api_t keeper_receive;
@@ -650,7 +655,7 @@ LUAG_FUNC( linda_receive)
650 } 655 }
651 656
652 { 657 {
653 struct s_Keeper *K = keeper_acquire( linda); 658 struct s_Keeper* K = keeper_acquire( linda);
654 if( K == NULL) return 0; 659 if( K == NULL) return 0;
655 for( ;;) 660 for( ;;)
656 { 661 {
@@ -682,11 +687,15 @@ LUAG_FUNC( linda_receive)
682 struct s_lane* const s = get_lane_from_registry( L); 687 struct s_lane* const s = get_lane_from_registry( L);
683 if( s != NULL) 688 if( s != NULL)
684 { 689 {
685 cancel = s->cancel_request; // testing here causes no delays 690 cancel = s->cancel_request;
686 if( cancel != CANCEL_NONE) // if user wants to cancel, the call returns without providing anything 691 }
687 { 692 cancel = (cancel != CANCEL_NONE) ? cancel : linda->simulate_cancel;
688 break; 693 if( cancel != CANCEL_NONE) // if user wants to cancel, the call returns without providing anything
689 } 694 {
695 break;
696 }
697 if( s != NULL)
698 {
690 // change status of lane to "waiting" 699 // change status of lane to "waiting"
691 prev_status = s->status; // RUNNING, most likely 700 prev_status = s->status; // RUNNING, most likely
692 ASSERT_L( prev_status == RUNNING); // but check, just in case 701 ASSERT_L( prev_status == RUNNING); // but check, just in case
@@ -694,22 +703,22 @@ LUAG_FUNC( linda_receive)
694 ASSERT_L( s->waiting_on == NULL); 703 ASSERT_L( s->waiting_on == NULL);
695 s->waiting_on = &linda->write_happened; 704 s->waiting_on = &linda->write_happened;
696 } 705 }
697 // not enough data to read: wakeup when data was sent, or when timeout is reached
698 if( !SIGNAL_WAIT( &linda->write_happened, &K->lock_, timeout))
699 { 706 {
707 // not enough data to read: wakeup when data was sent, or when timeout is reached
708 bool_t const signalled = SIGNAL_WAIT( &linda->write_happened, &K->lock_, timeout);
700 if( s != NULL) 709 if( s != NULL)
701 { 710 {
702 s->waiting_on = NULL; 711 s->waiting_on = NULL;
703 s->status = prev_status; 712 s->status = prev_status;
704 // if woken by a cancel request, be sure to handle it properly 713 // if a cancel request is pending, be sure to handle it as soon as possible
705 cancel = s->cancel_request; 714 cancel = s->cancel_request;
706 } 715 }
707 break; 716 cancel = (cancel != CANCEL_NONE) ? cancel : linda->simulate_cancel;
708 } 717 if( !signalled || cancel != CANCEL_NONE)
709 if( s != NULL) 718 {
710 { 719 // waiting returned after a timeout, or pending cancel: we are done
711 s->waiting_on = NULL; 720 break;
712 s->status = prev_status; 721 }
713 } 722 }
714 } 723 }
715 } 724 }
@@ -740,7 +749,7 @@ LUAG_FUNC( linda_receive)
740 749
741 750
742/* 751/*
743* [true] = linda_set( linda_ud, key_num|str|bool|lightuserdata [, value [, ...]]) 752* [true|lanes.cancel_error] = linda_set( linda_ud, key_num|str|bool|lightuserdata [, value [, ...]])
744* 753*
745* Set one or more value to Linda. 754* Set one or more value to Linda.
746* TODO: what do we do if we set to non-nil and limit is 0? 755* TODO: what do we do if we set to non-nil and limit is 0?
@@ -760,28 +769,38 @@ LUAG_FUNC( linda_set)
760 { 769 {
761 struct s_Keeper* K = keeper_acquire( linda); 770 struct s_Keeper* K = keeper_acquire( linda);
762 if( K == NULL) return 0; 771 if( K == NULL) return 0;
763 if( has_value)
764 {
765 // convert nils to some special non-nil sentinel in sent values
766 keeper_toggle_nil_sentinels( L, 3, eLM_ToKeeper);
767 }
768 pushed = keeper_call( K->L, KEEPER_API( set), L, linda, 2);
769 if( pushed >= 0) // no error?
770 {
771 ASSERT_L( pushed == 0 || pushed == 1);
772 772
773 if( linda->simulate_cancel == CANCEL_NONE)
774 {
773 if( has_value) 775 if( has_value)
774 { 776 {
775 // we put some data in the slot, tell readers that they should wake 777 // convert nils to some special non-nil sentinel in sent values
776 SIGNAL_ALL( &linda->write_happened); // To be done from within the 'K' locking area 778 keeper_toggle_nil_sentinels( L, 3, eLM_ToKeeper);
777 } 779 }
778 if( pushed == 1) 780 pushed = keeper_call( K->L, KEEPER_API( set), L, linda, 2);
781 if( pushed >= 0) // no error?
779 { 782 {
780 // the key was full, but it is no longer the case, tell writers they should wake 783 ASSERT_L( pushed == 0 || pushed == 1);
781 ASSERT_L( lua_type( L, -1) == LUA_TBOOLEAN && lua_toboolean( L, -1) == 1); 784
782 SIGNAL_ALL( &linda->read_happened); // To be done from within the 'K' locking area 785 if( has_value)
786 {
787 // we put some data in the slot, tell readers that they should wake
788 SIGNAL_ALL( &linda->write_happened); // To be done from within the 'K' locking area
789 }
790 if( pushed == 1)
791 {
792 // the key was full, but it is no longer the case, tell writers they should wake
793 ASSERT_L( lua_type( L, -1) == LUA_TBOOLEAN && lua_toboolean( L, -1) == 1);
794 SIGNAL_ALL( &linda->read_happened); // To be done from within the 'K' locking area
795 }
783 } 796 }
784 } 797 }
798 else // linda is cancelled
799 {
800 // do nothing and return lanes.cancel_error
801 lua_pushlightuserdata( L, CANCEL_ERROR);
802 pushed = 1;
803 }
785 keeper_release( K); 804 keeper_release( K);
786 } 805 }
787 806
@@ -837,10 +856,20 @@ LUAG_FUNC( linda_get)
837 { 856 {
838 struct s_Keeper* K = keeper_acquire( linda); 857 struct s_Keeper* K = keeper_acquire( linda);
839 if( K == NULL) return 0; 858 if( K == NULL) return 0;
840 pushed = keeper_call( K->L, KEEPER_API( get), L, linda, 2); 859
841 if( pushed > 0) 860 if( linda->simulate_cancel == CANCEL_NONE)
861 {
862 pushed = keeper_call( K->L, KEEPER_API( get), L, linda, 2);
863 if( pushed > 0)
864 {
865 keeper_toggle_nil_sentinels( L, lua_gettop( L) - pushed, eLM_FromKeeper);
866 }
867 }
868 else // linda is cancelled
842 { 869 {
843 keeper_toggle_nil_sentinels( L, lua_gettop( L) - pushed, eLM_FromKeeper); 870 // do nothing and return lanes.cancel_error
871 lua_pushlightuserdata( L, CANCEL_ERROR);
872 pushed = 1;
844 } 873 }
845 keeper_release( K); 874 keeper_release( K);
846 // must trigger error after keeper state has been released 875 // must trigger error after keeper state has been released
@@ -893,6 +922,59 @@ LUAG_FUNC( linda_limit)
893 922
894 923
895/* 924/*
925* (void) = linda_cancel( linda_ud, "read"|"write"|"both"|"none")
926*
927* Signal linda so that waiting threads wake up as if their own lane was cancelled
928*/
929LUAG_FUNC( linda_cancel)
930{
931 struct s_Linda* linda = lua_toLinda( L, 1);
932 char const* who = luaL_checkstring( L, 2);
933 struct s_Keeper* K;
934
935 // make sure we got 3 arguments: the linda, a key and a limit
936 luaL_argcheck( L, linda, 1, "expected a linda object!");
937 luaL_argcheck( L, lua_gettop( L) == 2, 2, "wrong number of arguments");
938
939 // signalling must be done from inside the K locking area
940 K = keeper_acquire( linda);
941 if( K == NULL) return 0;
942
943 linda->simulate_cancel = CANCEL_SOFT;
944 if( strcmp( who, "both") == 0) // tell everyone writers to wake up
945 {
946 SIGNAL_ALL( &linda->write_happened);
947 SIGNAL_ALL( &linda->read_happened);
948 }
949 else if( strcmp( who, "none") == 0) // reset flag
950 {
951 linda->simulate_cancel = CANCEL_NONE;
952 }
953 else if( strcmp( who, "read") == 0) // tell blocked readers to wake up
954 {
955 SIGNAL_ALL( &linda->write_happened);
956 }
957 else if( strcmp( who, "write") == 0) // tell blocked writers to wake up
958 {
959 SIGNAL_ALL( &linda->read_happened);
960 }
961 else
962 {
963 // error ...
964 linda = NULL;
965 }
966 keeper_release( K);
967
968 // ... but we must raise it outside the lock
969 if( !linda)
970 {
971 return luaL_error( L, "unknown wake hint '%s'", who);
972 }
973 return 0;
974}
975
976
977/*
896* lightuserdata= linda_deep( linda_ud ) 978* lightuserdata= linda_deep( linda_ud )
897* 979*
898* Return the 'deep' userdata pointer, identifying the Linda. 980* Return the 'deep' userdata pointer, identifying the Linda.
@@ -918,16 +1000,16 @@ LUAG_FUNC( linda_deep ) {
918* Useful for concatenation or debugging purposes 1000* Useful for concatenation or debugging purposes
919*/ 1001*/
920 1002
921static int linda_tostring( lua_State* L, int _idx, bool_t _opt) 1003static int linda_tostring( lua_State* L, int idx_, bool_t opt_)
922{ 1004{
923 struct s_Linda* linda = lua_toLinda( L, _idx); 1005 struct s_Linda* linda = lua_toLinda( L, idx_);
924 if( !_opt) 1006 if( !opt_)
925 { 1007 {
926 luaL_argcheck( L, linda, _idx, "expected a linda object!"); 1008 luaL_argcheck( L, linda, idx_, "expected a linda object!");
927 } 1009 }
928 if( linda != NULL) 1010 if( linda != NULL)
929 { 1011 {
930 char text[32]; 1012 char text[128];
931 int len; 1013 int len;
932 if( linda->name[0]) 1014 if( linda->name[0])
933 len = sprintf( text, "Linda: %.*s", (int)sizeof(text) - 8, linda->name); 1015 len = sprintf( text, "Linda: %.*s", (int)sizeof(text) - 8, linda->name);
@@ -1008,120 +1090,123 @@ LUAG_FUNC( linda_dump)
1008* For any other strings, the ID function must not react at all. This allows 1090* For any other strings, the ID function must not react at all. This allows
1009* future extensions of the system. 1091* future extensions of the system.
1010*/ 1092*/
1011static void linda_id( lua_State*L, char const * const which) 1093static void linda_id( lua_State* L, char const* const which)
1012{ 1094{
1013 if (strcmp( which, "new" )==0) 1095 if( strcmp( which, "new" ) == 0)
1014 { 1096 {
1015 struct s_Linda *s; 1097 struct s_Linda* s;
1016 size_t name_len = 0; 1098 size_t name_len = 0;
1017 char const* linda_name = NULL; 1099 char const* linda_name = NULL;
1018 int const top = lua_gettop( L); 1100 int const top = lua_gettop( L);
1019 1101
1020 if( top > 0 && lua_type( L, top) == LUA_TSTRING) 1102 if( top > 0 && lua_type( L, top) == LUA_TSTRING)
1021 { 1103 {
1022 linda_name = lua_tostring( L, top); 1104 linda_name = lua_tostring( L, top);
1023 name_len = strlen( linda_name); 1105 name_len = strlen( linda_name);
1024 } 1106 }
1025 1107
1026 /* The deep data is allocated separately of Lua stack; we might no 1108 /* The deep data is allocated separately of Lua stack; we might no
1027 * longer be around when last reference to it is being released. 1109 * longer be around when last reference to it is being released.
1028 * One can use any memory allocation scheme. 1110 * One can use any memory allocation scheme.
1029 */ 1111 */
1030 s= (struct s_Linda *) malloc( sizeof(struct s_Linda) + name_len); // terminating 0 is already included 1112 s = (struct s_Linda*) malloc( sizeof(struct s_Linda) + name_len); // terminating 0 is already included
1031 ASSERT_L(s); 1113 ASSERT_L( s);
1032 1114
1033 SIGNAL_INIT( &s->read_happened ); 1115 SIGNAL_INIT( &s->read_happened);
1034 SIGNAL_INIT( &s->write_happened ); 1116 SIGNAL_INIT( &s->write_happened);
1035 s->name[0] = 0; 1117 s->simulate_cancel = CANCEL_NONE;
1036 memcpy( s->name, linda_name, name_len ? name_len + 1 : 0); 1118 s->name[0] = 0;
1119 memcpy( s->name, linda_name, name_len ? name_len + 1 : 0);
1037 1120
1038 lua_pushlightuserdata( L, s ); 1121 lua_pushlightuserdata( L, s);
1039 } 1122 }
1040 else if( strcmp( which, "delete" ) == 0) 1123 else if( strcmp( which, "delete") == 0)
1041 { 1124 {
1042 struct s_Keeper* K; 1125 struct s_Keeper* K;
1043 struct s_Linda* l= lua_touserdata( L, 1); 1126 struct s_Linda* l = lua_touserdata( L, 1);
1044 ASSERT_L( l); 1127 ASSERT_L( l);
1045
1046 /* Clean associated structures in the keeper state.
1047 */
1048 K = keeper_acquire( l);
1049 if( K && K->L) // can be NULL if this happens during main state shutdown (lanes is GC'ed -> no keepers -> no need to cleanup)
1050 {
1051 keeper_call( K->L, KEEPER_API( clear), L, l, 0);
1052 }
1053 keeper_release( K);
1054
1055 /* There aren't any lanes waiting on these lindas, since all proxies
1056 * have been gc'ed. Right?
1057 */
1058 SIGNAL_FREE( &l->read_happened);
1059 SIGNAL_FREE( &l->write_happened);
1060 free( l);
1061 }
1062 else if (strcmp( which, "metatable" )==0)
1063 {
1064 1128
1065 STACK_CHECK( L); 1129 /* Clean associated structures in the keeper state.
1066 lua_newtable(L); 1130 */
1067 // metatable is its own index 1131 K = keeper_acquire( l);
1068 lua_pushvalue( L, -1); 1132 if( K && K->L) // can be NULL if this happens during main state shutdown (lanes is GC'ed -> no keepers -> no need to cleanup)
1069 lua_setfield( L, -2, "__index"); 1133 {
1134 keeper_call( K->L, KEEPER_API( clear), L, l, 0);
1135 }
1136 keeper_release( K);
1070 1137
1071 // protect metatable from external access 1138 /* There aren't any lanes waiting on these lindas, since all proxies
1072 lua_pushliteral( L, "Linda"); 1139 * have been gc'ed. Right?
1073 lua_setfield( L, -2, "__metatable"); 1140 */
1141 SIGNAL_FREE( &l->read_happened);
1142 SIGNAL_FREE( &l->write_happened);
1143 free( l);
1144 }
1145 else if( strcmp( which, "metatable" ) == 0)
1146 {
1074 1147
1075 lua_pushcfunction( L, LG_linda_tostring); 1148 STACK_CHECK( L);
1076 lua_setfield( L, -2, "__tostring"); 1149 lua_newtable( L);
1150 // metatable is its own index
1151 lua_pushvalue( L, -1);
1152 lua_setfield( L, -2, "__index");
1077 1153
1078 // Decoda __towatch support 1154 // protect metatable from external access
1079 lua_pushcfunction( L, LG_linda_dump); 1155 lua_pushliteral( L, "Linda");
1080 lua_setfield( L, -2, "__towatch"); 1156 lua_setfield( L, -2, "__metatable");
1081 1157
1082 lua_pushcfunction( L, LG_linda_concat); 1158 lua_pushcfunction( L, LG_linda_tostring);
1083 lua_setfield( L, -2, "__concat"); 1159 lua_setfield( L, -2, "__tostring");
1084 1160
1085 // 1161 // Decoda __towatch support
1086 // [-1]: linda metatable 1162 lua_pushcfunction( L, LG_linda_dump);
1087 lua_pushcfunction( L, LG_linda_send ); 1163 lua_setfield( L, -2, "__towatch");
1088 lua_setfield( L, -2, "send" );
1089 1164
1090 lua_pushcfunction( L, LG_linda_receive ); 1165 lua_pushcfunction( L, LG_linda_concat);
1091 lua_setfield( L, -2, "receive" ); 1166 lua_setfield( L, -2, "__concat");
1092 1167
1093 lua_pushcfunction( L, LG_linda_limit ); 1168 // [-1]: linda metatable
1094 lua_setfield( L, -2, "limit" ); 1169 lua_pushcfunction( L, LG_linda_send);
1170 lua_setfield( L, -2, "send");
1095 1171
1096 lua_pushcfunction( L, LG_linda_set ); 1172 lua_pushcfunction( L, LG_linda_receive);
1097 lua_setfield( L, -2, "set" ); 1173 lua_setfield( L, -2, "receive");
1098
1099 lua_pushcfunction( L, LG_linda_count );
1100 lua_setfield( L, -2, "count" );
1101
1102 lua_pushcfunction( L, LG_linda_get );
1103 lua_setfield( L, -2, "get" );
1104 1174
1105 lua_pushcfunction( L, LG_linda_deep ); 1175 lua_pushcfunction( L, LG_linda_limit);
1106 lua_setfield( L, -2, "deep" ); 1176 lua_setfield( L, -2, "limit");
1107 1177
1108 lua_pushcfunction( L, LG_linda_dump); 1178 lua_pushcfunction( L, LG_linda_set);
1109 lua_setfield( L, -2, "dump" ); 1179 lua_setfield( L, -2, "set");
1110
1111 lua_pushliteral( L, BATCH_SENTINEL);
1112 lua_setfield(L, -2, "batched");
1113 1180
1114 STACK_END( L, 1); 1181 lua_pushcfunction( L, LG_linda_count);
1115 } 1182 lua_setfield( L, -2, "count");
1116 else if( strcmp( which, "module") == 0) 1183
1117 { 1184 lua_pushcfunction( L, LG_linda_get);
1118 // linda is a special case because we know lanes must be loaded from the main lua state 1185 lua_setfield( L, -2, "get");
1119 // to be able to ever get here, so we know it will remain loaded as long a the main state is around 1186
1120 // in other words, forever. 1187 lua_pushcfunction( L, LG_linda_cancel);
1121 lua_pushnil( L); 1188 lua_setfield( L, -2, "cancel");
1122 // other idfuncs must push a string naming the module they come from 1189
1123 //lua_pushliteral( L, "lanes.core"); 1190 lua_pushcfunction( L, LG_linda_deep);
1124 } 1191 lua_setfield( L, -2, "deep");
1192
1193 lua_pushcfunction( L, LG_linda_dump);
1194 lua_setfield( L, -2, "dump");
1195
1196 lua_pushliteral( L, BATCH_SENTINEL);
1197 lua_setfield(L, -2, "batched");
1198
1199 STACK_END( L, 1);
1200 }
1201 else if( strcmp( which, "module") == 0)
1202 {
1203 // linda is a special case because we know lanes must be loaded from the main lua state
1204 // to be able to ever get here, so we know it will remain loaded as long a the main state is around
1205 // in other words, forever.
1206 lua_pushnil( L);
1207 // other idfuncs must push a string naming the module they come from
1208 //lua_pushliteral( L, "lanes.core");
1209 }
1125} 1210}
1126 1211
1127/* 1212/*
diff --git a/tests/cancel.lua b/tests/cancel.lua
index 0aab341..a5f1dab 100644
--- a/tests/cancel.lua
+++ b/tests/cancel.lua
@@ -83,11 +83,26 @@ h = lanes.gen("*", laneBody)()
83print "wait 3s" 83print "wait 3s"
84linda:receive( 3, "yeah") 84linda:receive( 3, "yeah")
85 85
86-- hard cancel and wait 10s: the lane will be interrupted from inside its current linda:receive() and won't return from it 86-- hard cancel: the lane will be interrupted from inside its current linda:receive() and won't return from it
87print "hard cancel (always awakens)" 87print "hard cancel (always awakens)"
88h:cancel() 88h:cancel()
89 89
90print "wait 5s" 90print "wait 5s"
91linda:receive( 5, "yeah") 91linda:receive( 5, "yeah")
92 92
93print "\ndone" \ No newline at end of file 93--####################################################################
94print "\n\n####################################################################\nbegin linda cancel test\n"
95h = lanes.gen("*", laneBody)()
96
97-- wait 3s before cancelling the lane
98print "wait 3s"
99linda:receive( 3, "yeah")
100
101-- linda cancel: the lane will be interrupted from inside its current linda:receive() and won't return from it
102print "linda cancel (always awakens the lane)"
103linda:cancel( "both")
104
105print "wait 5s"
106linda:receive( 5, "yeah")
107
108print "\ndone"