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
|