From cf9b09ff352611fb8cee3679127f3655cbe73ae7 Mon Sep 17 00:00:00 2001 From: Benoit Germain Date: Mon, 20 Jan 2014 10:51:11 +0100 Subject: get()/set() improvements * bumped version to 3.8.0 * linda:set() accepts multiple values to set in the specified slot * linda:get() accepts an optional count to peek several values at once * nil values are now converted just as in send()/receive() --- src/keeper.c | 102 +++++++++++++++++++++++++++++++--------------------------- src/keeper.h | 2 +- src/lanes.c | 44 +++++++++++++------------ src/lanes.lua | 2 +- 4 files changed, 80 insertions(+), 70 deletions(-) (limited to 'src') diff --git a/src/keeper.c b/src/keeper.c index 6d5ecbf..b0db8b4 100644 --- a/src/keeper.c +++ b/src/keeper.c @@ -115,11 +115,11 @@ static void fifo_push( lua_State* L, keeper_fifo* fifo, int _count) // expects exactly 1 value on the stack! // currently only called with a count of 1, but this may change in the future // function assumes that there is enough data in the fifo to satisfy the request -static void fifo_peek( lua_State* L, keeper_fifo* fifo, int _count) +static void fifo_peek( lua_State* L, keeper_fifo* fifo, int count_) { int i; - STACK_GROW( L, _count); - for( i = 0; i < _count; ++ i) + STACK_GROW( L, count_); + for( i = 0; i < count_; ++ i) { lua_rawgeti( L, 1, fifo->first + i); } @@ -384,54 +384,21 @@ int keepercall_limit( lua_State* L) return lua_gettop( L); } -//in: linda_ud key [val] +//in: linda_ud key [[val] ...] //out: true or nil int keepercall_set( lua_State* L) { bool_t should_wake_writers = FALSE; STACK_GROW( L, 6); - // make sure we have a value on the stack - if( lua_gettop( L) == 2) // ud key val? - { - lua_pushnil( L); // ud key nil - } // retrieve fifos associated with the linda - push_table( L, 1); // ud key val fifos - lua_replace( L, 1); // fifos key val + push_table( L, 1); // ud key [val [, ...]] fifos + lua_replace( L, 1); // fifos key [val [, ...]] - if( !lua_isnil( L, 3)) // set/replace contents stored at the specified key? + // make sure we have a value on the stack + if( lua_gettop( L) == 2) // fifos key { keeper_fifo* fifo; - lua_pushvalue( L, -2); // fifos key val key - lua_rawget( L, 1); // fifos key val fifo|nil - fifo = (keeper_fifo*) lua_touserdata( L, -1); - if( fifo == NULL) // can be NULL if we store a value at a new key - { // fifos key val nil - lua_pop( L, 1); // fifos key val - fifo_new( L); // fifos key val fifo - lua_pushvalue( L, 2); // fifos key val fifo key - lua_pushvalue( L, -2); // fifos key val fifo key fifo - lua_rawset( L, 1); // fifos key val fifo - } - else // the fifo exists, we just want to update its contents - { // fifos key val fifo - // we create room if the fifo was full but it is no longer the case - should_wake_writers = (fifo->limit > 0) && (fifo->count >= fifo->limit); - // empty the fifo for the specified key: replace uservalue with a virgin table, reset counters, but leave limit unchanged! - lua_newtable( L); // fifos key val fifo {} - lua_setuservalue( L, -2); // fifos key val fifo - fifo->first = 1; - fifo->count = 0; - } - fifo = prepare_fifo_access( L, -1); - lua_insert( L, -2); // fifos key fifo val - fifo_push( L, fifo, 1); // fifos key fifo - } - else // val == nil: we clear the key contents - { // fifos key nil - keeper_fifo* fifo; - lua_pop( L, 1); // fifos key lua_pushvalue( L, -1); // fifos key key lua_rawget( L, 1); // fifos key fifo|nil // empty the fifo for the specified key: replace uservalue with a virgin table, reset counters, but leave limit unchanged! @@ -456,13 +423,51 @@ int keepercall_set( lua_State* L) } } } + else // set/replace contents stored at the specified key? + { + int count = lua_gettop( L) - 2; // number of items we want to store + keeper_fifo* fifo; // fifos key [val [, ...]] + lua_pushvalue( L, 2); // fifos key [val [, ...]] key + lua_rawget( L, 1); // fifos key [val [, ...]] fifo|nil + fifo = (keeper_fifo*) lua_touserdata( L, -1); + if( fifo == NULL) // can be NULL if we store a value at a new key + { // fifos key [val [, ...]] nil + // no need to wake writers in that case, because a writer can't wait on an inexistent key + lua_pop( L, 1); // fifos key [val [, ...]] + fifo_new( L); // fifos key [val [, ...]] fifo + lua_pushvalue( L, 2); // fifos key [val [, ...]] fifo key + lua_pushvalue( L, -2); // fifos key [val [, ...]] fifo key fifo + lua_rawset( L, 1); // fifos key [val [, ...]] fifo + } + else // the fifo exists, we just want to update its contents + { // fifos key [val [, ...]] fifo + // we create room if the fifo was full but it is no longer the case + should_wake_writers = (fifo->limit > 0) && (fifo->count >= fifo->limit) && (count < fifo->limit); + // empty the fifo for the specified key: replace uservalue with a virgin table, reset counters, but leave limit unchanged! + lua_newtable( L); // fifos key [val [, ...]] fifo {} + lua_setuservalue( L, -2); // fifos key [val [, ...]] fifo + fifo->first = 1; + fifo->count = 0; + } + fifo = prepare_fifo_access( L, -1); + // move the fifo below the values we want to store + lua_insert( L, 3); // fifos key fifo [val [, ...]] + fifo_push( L, fifo, count); // fifos key fifo + } return should_wake_writers ? (lua_pushboolean( L, 1), 1) : 0; } -// in: linda_ud key +// in: linda_ud key [count] +// out: at most values int keepercall_get( lua_State* L) { keeper_fifo* fifo; + int count = 1; + if( lua_gettop( L) == 3) // ud key count + { + count = lua_tointeger( L, 3); + lua_pop( L, 1); // ud key + } push_table( L, 1); // ud key fifos lua_replace( L, 1); // fifos key lua_rawget( L, 1); // fifos fifo @@ -470,9 +475,10 @@ int keepercall_get( lua_State* L) if( fifo != NULL && fifo->count > 0) { lua_remove( L, 1); // fifo - // read one value off the fifo - fifo_peek( L, fifo, 1); // fifo ... - return 1; + count = __min( count, fifo->count); + // read value off the fifo + fifo_peek( L, fifo, count); // fifo ... + return count; } // no fifo was ever registered for this key, or it is empty return 0; @@ -682,16 +688,16 @@ void keeper_release( struct s_Keeper* K) if( K) MUTEX_UNLOCK( &K->lock_); } -void keeper_toggle_nil_sentinels( lua_State* L, int _val_i, int _nil_to_sentinel) +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 of ours) */ void* nil_sentinel = &GNbKeepers; - for( i = _val_i; i <= n; ++ i) + for( i = val_i_; i <= n; ++ i) { - if( _nil_to_sentinel) + if( mode_ == eLM_ToKeeper) { if( lua_isnil( L, i)) { diff --git a/src/keeper.h b/src/keeper.h index 2ef443d..c0fd5d0 100644 --- a/src/keeper.h +++ b/src/keeper.h @@ -20,7 +20,7 @@ void close_keepers( void); struct s_Keeper *keeper_acquire( const void *ptr); void keeper_release( struct s_Keeper *K); -void keeper_toggle_nil_sentinels( lua_State *L, int _val_i, int _nil_to_sentinel); +void keeper_toggle_nil_sentinels( lua_State *L, int _val_i, enum eLookupMode const mode_); int keeper_push_linda_storage( lua_State* L, void* ptr); typedef lua_CFunction keeper_api_t; diff --git a/src/lanes.c b/src/lanes.c index cad8fb1..f62c39f 100644 --- a/src/lanes.c +++ b/src/lanes.c @@ -52,7 +52,7 @@ * ... */ -char const* VERSION = "3.7.8"; +char const* VERSION = "3.8.0"; /* =============================================================================== @@ -464,7 +464,7 @@ LUAG_FUNC( linda_send) } // convert nils to some special non-nil sentinel in sent values - keeper_toggle_nil_sentinels( L, key_i + 1, 1); + keeper_toggle_nil_sentinels( L, key_i + 1, eLM_ToKeeper); STACK_GROW( L, 1); { @@ -649,7 +649,7 @@ LUAG_FUNC( linda_receive) { ASSERT_L( pushed >= expected_pushed_min && pushed <= expected_pushed_max); // replace sentinels with real nils - keeper_toggle_nil_sentinels( L, lua_gettop( L) - pushed, 0); + keeper_toggle_nil_sentinels( L, lua_gettop( L) - pushed, eLM_FromKeeper); // To be done from within the 'K' locking area // SIGNAL_ALL( &linda->read_happened); @@ -725,28 +725,31 @@ LUAG_FUNC( linda_receive) /* -* [true] = linda_set( linda_ud, key_num|str|bool|lightuserdata [,value] ) +* [true] = linda_set( linda_ud, key_num|str|bool|lightuserdata [, value [, ...]]) * -* Set a value to Linda. +* Set one or more value to Linda. * TODO: what do we do if we set to non-nil and limit is 0? * -* Existing slot value is replaced, and possible queue entries removed. +* Existing slot value is replaced, and possible queued entries removed. */ LUAG_FUNC( linda_set) { - struct s_Linda *linda = lua_toLinda( L, 1); + struct s_Linda* const linda = lua_toLinda( L, 1); int pushed; - bool_t has_value = !lua_isnil( L, 3); + bool_t has_value = lua_gettop( L) > 2; luaL_argcheck( L, linda, 1, "expected a linda object!"); - luaL_argcheck( L, lua_gettop( L) <= 3, 4, "too many arguments"); - // make sure the key is of a valid type + // make sure the key is of a valid type (throws an error if not the case) check_key_types( L, 2, 2); { struct s_Keeper* K = keeper_acquire( linda); if( K == NULL) return 0; - // no nil->sentinel toggling, we really clear the linda contents for the given key with a set() + if( has_value) + { + // convert nils to some special non-nil sentinel in sent values + keeper_toggle_nil_sentinels( L, 3, eLM_ToKeeper); + } pushed = keeper_call( K->L, KEEPER_API( set), L, linda, 2); if( pushed >= 0) // no error? { @@ -801,31 +804,32 @@ LUAG_FUNC( linda_count) /* -* [val]= linda_get( linda_ud, key_num|str|bool|lightuserdata ) +* [val [, ...]] = linda_get( linda_ud, key_num|str|bool|lightuserdata [, count = 1]) * -* Get a value from Linda. -* TODO: add support to get multiple values? +* Get one or more values from Linda. */ LUAG_FUNC( linda_get) { - struct s_Linda *linda= lua_toLinda( L, 1); + struct s_Linda* const linda = lua_toLinda( L, 1); int pushed; + int count = luaL_optint( L, 3, 1); + luaL_argcheck( L, count >= 1, 3, "count should be >= 1"); + luaL_argcheck( L, linda, 1, "expected a linda object"); + luaL_argcheck( L, lua_gettop( L) <= 3, 4, "too many arguments"); - luaL_argcheck( L, linda, 1, "expected a linda object!"); - // make sure the key is of a valid type + // make sure the key is of a valid type (throws an error if not the case) check_key_types( L, 2, 2); - { struct s_Keeper* K = keeper_acquire( linda); if( K == NULL) return 0; pushed = keeper_call( K->L, KEEPER_API( get), L, linda, 2); - ASSERT_L( pushed == 0 || pushed == 1); if( pushed > 0) { - keeper_toggle_nil_sentinels( L, lua_gettop( L) - pushed, 0); + keeper_toggle_nil_sentinels( L, lua_gettop( L) - pushed, eLM_FromKeeper); } keeper_release( K); // must trigger error after keeper state has been released + // (an error can be raised if we attempt to read an unregistered function) if( pushed < 0) { return luaL_error( L, "tried to copy unsupported types"); diff --git a/src/lanes.lua b/src/lanes.lua index e7b9715..9a0287d 100644 --- a/src/lanes.lua +++ b/src/lanes.lua @@ -596,8 +596,8 @@ end -- settings.with_timers -- -- PUBLIC LANES API local genlock = function( linda, key, N) + linda:set( key) -- clears existing data linda:limit( key, N) - linda:set( key, nil) -- clears existing data -- -- [true [, ...]= trues(uint) -- cgit v1.2.3-55-g6feb