aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGES6
-rw-r--r--docs/index.html8
-rw-r--r--src/keeper.c8
-rw-r--r--src/keeper.h2
-rw-r--r--src/lanes.c32
5 files changed, 42 insertions, 14 deletions
diff --git a/CHANGES b/CHANGES
index e3d88f7..0352c9e 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,5 +1,11 @@
1CHANGES: 1CHANGES:
2 2
3CHANGE 105: BGe 27-Feb-14
4 * Bumped version to 3.9.3
5 * new exposed variable linda.null that exposes the internal NIL_SENTINEL marker
6 * linda:send() interprets send key linda.null as authorization to silently send a single nil when not provided with anything to send
7 (useful when sending results of a function that can return nothing)
8
3CHANGE 104: BGe 25-Feb-14 9CHANGE 104: BGe 25-Feb-14
4 * Bumped version to 3.9.2 10 * Bumped version to 3.9.2
5 * Internal rework: the whole Lanes engine now works "per universe" to allow concurrent Lanes execution in more than one embedded master state 11 * Internal rework: the whole Lanes engine now works "per universe" to allow concurrent Lanes execution in more than one embedded master state
diff --git a/docs/index.html b/docs/index.html
index 6337647..c4a6441 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 26-Feb-14, and applies to version <tt>3.9.2</tt>. 73 This document was revised on 27-Feb-14, and applies to version <tt>3.9.3</tt>.
74 </p> 74 </p>
75 </font> 75 </font>
76 </center> 76 </center>
@@ -1038,7 +1038,7 @@
1038<table border="1" bgcolor="#E0E0FF" cellpadding="10" style="width:50%"><tr><td><pre> 1038<table border="1" bgcolor="#E0E0FF" cellpadding="10" style="width:50%"><tr><td><pre>
1039 h = lanes.linda( [opt_name, [opt_group]]) 1039 h = lanes.linda( [opt_name, [opt_group]])
1040 1040
1041 [true|lanes.cancel_error] = h:send( [timeout_secs,] key, ...) 1041 [true|lanes.cancel_error] = h:send( [timeout_secs,] [h.null,] key, ...)
1042 1042
1043 [key, val]|[lanes.cancel_error] = h:receive( [timeout_secs,] key [, ...]) 1043 [key, val]|[lanes.cancel_error] = h:receive( [timeout_secs,] key [, ...])
1044 1044
@@ -1071,6 +1071,10 @@
1071 <tt>send()</tt> returns <tt>true</tt> if the sending succeeded, and <tt>false</tt> if the queue limit was met, and the queue did not empty enough during the given timeout. 1071 <tt>send()</tt> returns <tt>true</tt> if the sending succeeded, and <tt>false</tt> if the queue limit was met, and the queue did not empty enough during the given timeout.
1072 <br/> 1072 <br/>
1073 (Since version 3.7.8) <tt>send()</tt> returns <tt>lanes.cancel_error</tt> if interrupted by a soft cancel request. 1073 (Since version 3.7.8) <tt>send()</tt> returns <tt>lanes.cancel_error</tt> if interrupted by a soft cancel request.
1074 <br/>
1075 If no data is provided after the key, <tt>send()</tt> raises an error. Since version 3.9.3, if provided with <tt>linda.null</tt> before the actual key and there is no data to send, <tt>send()</tt> sends a single <tt>nil</tt>.
1076 <br/>
1077 Also, if <tt>linda.null</tt> is sent as data in a linda, it will be read as a <tt>nil</tt>.
1074</p> 1078</p>
1075 1079
1076<p> 1080<p>
diff --git a/src/keeper.c b/src/keeper.c
index 9e5317b..7362ca6 100644
--- a/src/keeper.c
+++ b/src/keeper.c
@@ -756,23 +756,19 @@ void keeper_release( struct s_Keeper* K)
756void keeper_toggle_nil_sentinels( lua_State* L, int val_i_, enum eLookupMode mode_) 756void keeper_toggle_nil_sentinels( lua_State* L, int val_i_, enum eLookupMode mode_)
757{ 757{
758 int i, n = lua_gettop( L); 758 int i, n = lua_gettop( L);
759 /* We could use an empty table in 'keeper.lua' as the sentinel, but maybe
760 * checking for a lightuserdata is faster. (any unique value will do -> take the address of some global symbol of ours)
761 */
762 void* nil_sentinel = (void*) keeper_toggle_nil_sentinels;
763 for( i = val_i_; i <= n; ++ i) 759 for( i = val_i_; i <= n; ++ i)
764 { 760 {
765 if( mode_ == eLM_ToKeeper) 761 if( mode_ == eLM_ToKeeper)
766 { 762 {
767 if( lua_isnil( L, i)) 763 if( lua_isnil( L, i))
768 { 764 {
769 lua_pushlightuserdata( L, nil_sentinel); 765 lua_pushlightuserdata( L, NIL_SENTINEL);
770 lua_replace( L, i); 766 lua_replace( L, i);
771 } 767 }
772 } 768 }
773 else 769 else
774 { 770 {
775 if( lua_touserdata( L, i) == nil_sentinel) 771 if( lua_touserdata( L, i) == NIL_SENTINEL)
776 { 772 {
777 lua_pushnil( L); 773 lua_pushnil( L);
778 lua_replace( L, i); 774 lua_replace( L, i);
diff --git a/src/keeper.h b/src/keeper.h
index 450f64d..6ca4ad4 100644
--- a/src/keeper.h
+++ b/src/keeper.h
@@ -23,6 +23,8 @@ void keeper_release( struct s_Keeper* K);
23void keeper_toggle_nil_sentinels( lua_State* L, int _val_i, enum eLookupMode const mode_); 23void keeper_toggle_nil_sentinels( lua_State* L, int _val_i, enum eLookupMode const mode_);
24int keeper_push_linda_storage( struct s_Universe* U, lua_State* L, void* ptr, unsigned long magic_); 24int keeper_push_linda_storage( struct s_Universe* U, lua_State* L, void* ptr, unsigned long magic_);
25 25
26#define NIL_SENTINEL ((void*)keeper_toggle_nil_sentinels)
27
26typedef lua_CFunction keeper_api_t; 28typedef lua_CFunction keeper_api_t;
27#define KEEPER_API( _op) keepercall_ ## _op 29#define KEEPER_API( _op) keepercall_ ## _op
28#define PUSH_KEEPER_FUNC lua_pushcfunction 30#define PUSH_KEEPER_FUNC lua_pushcfunction
diff --git a/src/lanes.c b/src/lanes.c
index bca8b74..4130b24 100644
--- a/src/lanes.c
+++ b/src/lanes.c
@@ -52,7 +52,7 @@
52 * ... 52 * ...
53 */ 53 */
54 54
55char const* VERSION = "3.9.2"; 55char const* VERSION = "3.9.3";
56 56
57/* 57/*
58=============================================================================== 58===============================================================================
@@ -442,7 +442,7 @@ static void check_key_types( lua_State* L, int start_, int end_)
442} 442}
443 443
444/* 444/*
445* bool= linda_send( linda_ud, [timeout_secs=-1,] key_num|str|bool|lightuserdata, ... ) 445* bool= linda_send( linda_ud, [timeout_secs=-1,] [linda.null,] key_num|str|bool|lightuserdata, ... )
446* 446*
447* Send one or more values to a Linda. If there is a limit, all values must fit. 447* Send one or more values to a Linda. If there is a limit, all values must fit.
448* 448*
@@ -458,10 +458,11 @@ LUAG_FUNC( linda_send)
458 int pushed; 458 int pushed;
459 time_d timeout = -1.0; 459 time_d timeout = -1.0;
460 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
461 void* as_nil_sentinel; // if not NULL, send() will silently send a single nil if nothing is provided
461 462
462 if( lua_type( L, 2) == LUA_TNUMBER) // we don't want to use lua_isnumber() because of autocoercion 463 if( lua_type( L, 2) == LUA_TNUMBER) // we don't want to use lua_isnumber() because of autocoercion
463 { 464 {
464 timeout = SIGNAL_TIMEOUT_PREPARE( lua_tonumber( L,2)); 465 timeout = SIGNAL_TIMEOUT_PREPARE( lua_tonumber( L, 2));
465 ++ key_i; 466 ++ key_i;
466 } 467 }
467 else if( lua_isnil( L, 2)) // alternate explicit "no timeout" by passing nil before the key 468 else if( lua_isnil( L, 2)) // alternate explicit "no timeout" by passing nil before the key
@@ -469,19 +470,35 @@ LUAG_FUNC( linda_send)
469 ++ key_i; 470 ++ key_i;
470 } 471 }
471 472
472 // make sure the keys are of a valid type 473 as_nil_sentinel = lua_touserdata( L, key_i);
474 if( as_nil_sentinel == NIL_SENTINEL)
475 {
476 // the real key to send data to is after the NIL_SENTINEL marker
477 ++ key_i;
478 }
479
480 // make sure the key is of a valid type
473 check_key_types( L, key_i, key_i); 481 check_key_types( L, key_i, key_i);
474 482
483 STACK_GROW( L, 1);
484
475 // make sure there is something to send 485 // make sure there is something to send
476 if( (uint_t)lua_gettop( L) == key_i) 486 if( (uint_t)lua_gettop( L) == key_i)
477 { 487 {
478 return luaL_error( L, "no data to send"); 488 if( as_nil_sentinel == NIL_SENTINEL)
489 {
490 // send a single nil if nothing is provided
491 lua_pushlightuserdata( L, NIL_SENTINEL);
492 }
493 else
494 {
495 return luaL_error( L, "no data to send");
496 }
479 } 497 }
480 498
481 // convert nils to some special non-nil sentinel in sent values 499 // convert nils to some special non-nil sentinel in sent values
482 keeper_toggle_nil_sentinels( L, key_i + 1, eLM_ToKeeper); 500 keeper_toggle_nil_sentinels( L, key_i + 1, eLM_ToKeeper);
483 501
484 STACK_GROW( L, 1);
485 { 502 {
486 bool_t try_again = TRUE; 503 bool_t try_again = TRUE;
487 struct s_lane* const s = get_lane_from_registry( L); 504 struct s_lane* const s = get_lane_from_registry( L);
@@ -1210,6 +1227,9 @@ static void* linda_id( lua_State* L, enum eDeepOp op_)
1210 lua_pushliteral( L, BATCH_SENTINEL); 1227 lua_pushliteral( L, BATCH_SENTINEL);
1211 lua_setfield(L, -2, "batched"); 1228 lua_setfield(L, -2, "batched");
1212 1229
1230 lua_pushlightuserdata( L, NIL_SENTINEL);
1231 lua_setfield(L, -2, "null");
1232
1213 STACK_END( L, 1); 1233 STACK_END( L, 1);
1214 return NULL; 1234 return NULL;
1215 } 1235 }