From 437759ddf0ce7e6dc5ed4944e033ef04674de430 Mon Sep 17 00:00:00 2001 From: Benoit Germain Date: Thu, 27 Feb 2014 18:32:00 +0100 Subject: linda:send() improvements * Bumped version to 3.9.3 * new exposed variable linda.null that exposes the internal NIL_SENTINEL marker * linda:send() interprets send key linda.null as authorization to silently send a single nil when not provided with anything to send (useful when sending results of a function that can return nothing) --- CHANGES | 6 ++++++ docs/index.html | 8 ++++++-- src/keeper.c | 8 ++------ src/keeper.h | 2 ++ src/lanes.c | 32 ++++++++++++++++++++++++++------ 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 @@ CHANGES: +CHANGE 105: BGe 27-Feb-14 + * Bumped version to 3.9.3 + * new exposed variable linda.null that exposes the internal NIL_SENTINEL marker + * linda:send() interprets send key linda.null as authorization to silently send a single nil when not provided with anything to send + (useful when sending results of a function that can return nothing) + CHANGE 104: BGe 25-Feb-14 * Bumped version to 3.9.2 * 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 @@

- This document was revised on 26-Feb-14, and applies to version 3.9.2. + This document was revised on 27-Feb-14, and applies to version 3.9.3.

@@ -1038,7 +1038,7 @@
 	h = lanes.linda( [opt_name, [opt_group]])
 
-	[true|lanes.cancel_error] = h:send( [timeout_secs,] key, ...)
+	[true|lanes.cancel_error] = h:send( [timeout_secs,] [h.null,] key, ...)
 
 	[key, val]|[lanes.cancel_error] = h:receive( [timeout_secs,] key [, ...])
 
@@ -1071,6 +1071,10 @@
 	send() returns true if the sending succeeded, and false if the queue limit was met, and the queue did not empty enough during the given timeout.
 	
(Since version 3.7.8) send() returns lanes.cancel_error if interrupted by a soft cancel request. +
+ If no data is provided after the key, send() raises an error. Since version 3.9.3, if provided with linda.null before the actual key and there is no data to send, send() sends a single nil. +
+ Also, if linda.null is sent as data in a linda, it will be read as a nil.

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) void keeper_toggle_nil_sentinels( lua_State* L, int val_i_, enum eLookupMode mode_) { int i, n = lua_gettop( L); - /* We could use an empty table in 'keeper.lua' as the sentinel, but maybe - * checking for a lightuserdata is faster. (any unique value will do -> take the address of some global symbol of ours) - */ - void* nil_sentinel = (void*) keeper_toggle_nil_sentinels; for( i = val_i_; i <= n; ++ i) { if( mode_ == eLM_ToKeeper) { if( lua_isnil( L, i)) { - lua_pushlightuserdata( L, nil_sentinel); + lua_pushlightuserdata( L, NIL_SENTINEL); lua_replace( L, i); } } else { - if( lua_touserdata( L, i) == nil_sentinel) + if( lua_touserdata( L, i) == NIL_SENTINEL) { lua_pushnil( L); 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); void keeper_toggle_nil_sentinels( lua_State* L, int _val_i, enum eLookupMode const mode_); int keeper_push_linda_storage( struct s_Universe* U, lua_State* L, void* ptr, unsigned long magic_); +#define NIL_SENTINEL ((void*)keeper_toggle_nil_sentinels) + typedef lua_CFunction keeper_api_t; #define KEEPER_API( _op) keepercall_ ## _op #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 @@ * ... */ -char const* VERSION = "3.9.2"; +char const* VERSION = "3.9.3"; /* =============================================================================== @@ -442,7 +442,7 @@ static void check_key_types( lua_State* L, int start_, int end_) } /* -* bool= linda_send( linda_ud, [timeout_secs=-1,] key_num|str|bool|lightuserdata, ... ) +* bool= linda_send( linda_ud, [timeout_secs=-1,] [linda.null,] key_num|str|bool|lightuserdata, ... ) * * Send one or more values to a Linda. If there is a limit, all values must fit. * @@ -458,10 +458,11 @@ LUAG_FUNC( linda_send) int pushed; time_d timeout = -1.0; uint_t key_i = 2; // index of first key, if timeout not there + void* as_nil_sentinel; // if not NULL, send() will silently send a single nil if nothing is provided if( lua_type( L, 2) == LUA_TNUMBER) // we don't want to use lua_isnumber() because of autocoercion { - timeout = SIGNAL_TIMEOUT_PREPARE( lua_tonumber( L,2)); + timeout = SIGNAL_TIMEOUT_PREPARE( lua_tonumber( L, 2)); ++ key_i; } else if( lua_isnil( L, 2)) // alternate explicit "no timeout" by passing nil before the key @@ -469,19 +470,35 @@ LUAG_FUNC( linda_send) ++ key_i; } - // make sure the keys are of a valid type + as_nil_sentinel = lua_touserdata( L, key_i); + if( as_nil_sentinel == NIL_SENTINEL) + { + // the real key to send data to is after the NIL_SENTINEL marker + ++ key_i; + } + + // make sure the key is of a valid type check_key_types( L, key_i, key_i); + STACK_GROW( L, 1); + // make sure there is something to send if( (uint_t)lua_gettop( L) == key_i) { - return luaL_error( L, "no data to send"); + if( as_nil_sentinel == NIL_SENTINEL) + { + // send a single nil if nothing is provided + lua_pushlightuserdata( L, NIL_SENTINEL); + } + else + { + return luaL_error( L, "no data to send"); + } } // convert nils to some special non-nil sentinel in sent values keeper_toggle_nil_sentinels( L, key_i + 1, eLM_ToKeeper); - STACK_GROW( L, 1); { bool_t try_again = TRUE; struct s_lane* const s = get_lane_from_registry( L); @@ -1210,6 +1227,9 @@ static void* linda_id( lua_State* L, enum eDeepOp op_) lua_pushliteral( L, BATCH_SENTINEL); lua_setfield(L, -2, "batched"); + lua_pushlightuserdata( L, NIL_SENTINEL); + lua_setfield(L, -2, "null"); + STACK_END( L, 1); return NULL; } -- cgit v1.2.3-55-g6feb