From f0b1c6d629464c0a59ac78382d86f434e74c2162 Mon Sep 17 00:00:00 2001 From: Benoit Germain Date: Wed, 22 Aug 2012 21:36:37 +0200 Subject: lanes version 3.2.0 * keeper internals implemented in C instead of Lua for better performances * fixed arguments checks in linda:limit() and linda:set() --- src/keeper.c | 390 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 383 insertions(+), 7 deletions(-) (limited to 'src/keeper.c') diff --git a/src/keeper.c b/src/keeper.c index 444a98e..86c69e2 100644 --- a/src/keeper.c +++ b/src/keeper.c @@ -14,7 +14,7 @@ --[[ =============================================================================== - Copyright (C) 2011 Benoit Germain + Copyright (C) 2011-2012 Benoit Germain Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -50,6 +50,374 @@ #include "tools.h" #include "keeper.h" +#if KEEPER_MODEL == KEEPER_MODEL_C +//################################################################################### +// Keeper implementation +//################################################################################### + +typedef struct +{ + int first; + int count; + int limit; +} keeper_fifo; + +// replaces the fifo ud by its uservalue on the stack +static keeper_fifo* prepare_fifo_access( lua_State* L, int idx) +{ + keeper_fifo* fifo = (keeper_fifo*) lua_touserdata( L, idx); + if( fifo) + { + idx = lua_absindex( L, idx); + STACK_GROW( L, 1); + // we can replace the fifo userdata in the stack without fear of it being GCed, there are other references around + lua_getuservalue( L, idx); + lua_replace( L, idx); + } + return fifo; +} + +// in: nothing +// out: { first = 1, count = 0, limit = -1} +static void fifo_new( lua_State* L) +{ + keeper_fifo* fifo; + STACK_GROW( L, 2); + fifo = (keeper_fifo*) lua_newuserdata( L, sizeof( keeper_fifo)); + fifo->first = 1; + fifo->count = 0; + fifo->limit = -1; + lua_newtable( L); + lua_setuservalue( L, -2); +} + +// in: expect fifo ... on top of the stack +// out: nothing, removes all pushed values on the stack +static void fifo_push( lua_State* L, keeper_fifo* fifo, int _count) +{ + int idx = lua_gettop( L) - _count; + int start = fifo->first + fifo->count - 1; + int i; + // pop all additional arguments, storing them in the fifo + for( i = _count; i >= 1; -- i) + { + // store in the fifo the value at the top of the stack at the specified index, popping it from the stack + lua_rawseti( L, idx, start + i); + } + fifo->count += _count; +} + +// in: fifo +// out: ...|nothing +// 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) +{ + int i; + STACK_GROW( L, _count); + for( i = 0; i < _count; ++ i) + { + lua_rawgeti( L, 1, fifo->first + i); + } +} + +// in: fifo +// out: pushes as many items as required on the stack (function assumes they exist in sufficient number) +static void fifo_pop( lua_State* L, keeper_fifo* fifo, int _count) +{ + int fifo_idx = lua_gettop( L); // ... fifo + int i; + // each iteration pushes a value on the stack! + STACK_GROW( L, _count + 1); + for( i = 0; i < _count; ++ i) + { + int at = fifo->first + i; + lua_rawgeti( L, fifo_idx, at); // ... fifo val + lua_pushnil( L); // ... fifo val nil + lua_rawseti( L, fifo_idx, at); // ... fifo val + } + fifo->first += _count; + fifo->count -= _count; +} + +// in: linda_ud expected at *absolute* stack slot idx +// out: fifos[ud] +static void* const fifos_key = (void*) prepare_fifo_access; +static void push_table( lua_State* L, int idx) +{ + STACK_GROW( L, 4); + STACK_CHECK( L) + idx = lua_absindex( L, idx); + lua_pushlightuserdata( L, fifos_key); // ud fifos_key + lua_rawget( L, LUA_REGISTRYINDEX); // ud fifos + lua_pushvalue( L, idx); // ud fifos ud + lua_rawget( L, -2); // ud fifos fifos[ud] + STACK_MID( L, 2); + if( lua_isnil( L, -1)) + { + lua_pop( L, 1); // ud fifos + // add a new fifos table for this linda + lua_newtable( L); // ud fifos fifos[ud] + lua_pushvalue( L, idx); // ud fifos fifos[ud] ud + lua_pushvalue( L, -2); // ud fifos fifos[ud] ud fifos[ud] + lua_rawset( L, -4); // ud fifos fifos[ud] + } + lua_remove( L, -2); // ud fifos[ud] + STACK_END( L, 1); +} + +// in: linda_ud +int keepercall_clear( lua_State* L) +{ + STACK_GROW( L, 3); + lua_pushlightuserdata( L, fifos_key); // ud fifos_key + lua_rawget( L, LUA_REGISTRYINDEX); // ud fifos + lua_pushvalue( L, 1); // ud fifos ud + lua_pushnil( L); // ud fifos ud nil + lua_rawset( L, -3); // ud fifos + lua_pop( L, 1); // ud + return 0; +} + + +// in: linda_ud, key, ... +// out: true|false +int keepercall_send( lua_State* L) +{ + keeper_fifo* fifo; + int n = lua_gettop( L) - 2; + push_table( L, 1); // ud key ... fifos + // get the fifo associated to this key in this linda, create it if it doesn't exist + lua_pushvalue( L, 2); // ud key ... fifos key + lua_rawget( L, -2); // ud key ... fifos fifo + if( lua_isnil( L, -1)) + { + lua_pop( L, 1); // ud key ... fifos + fifo_new( L); // ud key ... fifos fifo + lua_pushvalue( L, 2); // ud key ... fifos fifo key + lua_pushvalue( L, -2); // ud key ... fifos fifo key fifo + lua_rawset( L, -4); // ud key ... fifos fifo + } + lua_remove( L, -2); // ud key ... fifo + fifo = (keeper_fifo*) lua_touserdata( L, -1); + if( fifo->limit >= 0 && fifo->count + n > fifo->limit) + { + lua_settop( L, 0); // + lua_pushboolean( L, 0); // false + } + else + { + fifo = prepare_fifo_access( L, -1); + lua_replace( L, 2); // ud fifo ... + fifo_push( L, fifo, n); // ud fifo + lua_settop( L, 0); // + lua_pushboolean( L, 1); // true + } + return 1; +} + +// in: linda_ud, key [, key]? +// out: (val, key) or nothing +int keepercall_receive( lua_State* L) +{ + int top = lua_gettop( L); + int i; + keeper_fifo* fifo; + push_table( L, 1); // ud keys fifos + lua_replace( L, 1); // fifos keys + for( i = 2; i <= top; ++ i) + { + lua_pushvalue( L, i); // fifos keys key[i] + lua_rawget( L, 1); // fifos keys fifo + fifo = prepare_fifo_access( L, -1); // fifos keys fifo + if( fifo && fifo->count > 0) + { + fifo_pop( L, fifo, 1); // fifos keys fifo val + if( !lua_isnil( L, -1)) + { + lua_replace( L, 1); // val keys fifo + if( i != 2) + { + lua_pushvalue( L, i); // val keys fifo key[i] + lua_replace( L, 2); // val key keys fifo + } + lua_settop( L, 2); // val key + return 2; + } + } + lua_settop( L, top); // data keys + } + // nothing to receive + return 0; +} + +//in: linda_ud key mincount [maxcount] +int keepercall_receive_batched( lua_State* L) +{ + int const min_count = (int) lua_tointeger( L, 3); + if( min_count > 0) + { + keeper_fifo* fifo; + int const max_count = (int) luaL_optinteger( L, 4, min_count); + lua_settop( L, 2); // ud key + push_table( L, 1); // ud key fifos + lua_replace( L, 1); // fifos key + lua_rawget( L, -2); // fifos fifo + lua_remove( L, 1); // fifo + fifo = prepare_fifo_access( L, 1); // fifo + if( fifo && fifo->count >= min_count) + { + fifo_pop( L, fifo, min( max_count, fifo->count)); // fifo ... + } + return lua_gettop( L) - 1; + } + else + { + return 0; + } +} + +// in: linda_ud key n +// out: nothing +int keepercall_limit( lua_State* L) +{ + keeper_fifo* fifo; + int limit = (int) lua_tointeger( L, 3); + push_table( L, 1); // ud key n fifos + lua_replace( L, 1); // fifos key n + lua_pop( L, 1); // fifos key + lua_pushvalue( L, -1); // fifos key key + lua_rawget( L, -3); // fifos key fifo + fifo = (keeper_fifo*) lua_touserdata( L, -1); + if( !fifo) + { + lua_pop( L, 1); // fifos key + fifo_new( L); // fifos key fifo + fifo = (keeper_fifo*) lua_touserdata( L, -1); + lua_rawset( L, -3); // fifos + } + fifo->limit = limit; + return 0; +} + +//in: linda_ud key [val] +int keepercall_set( lua_State* L) +{ + // make sure we have a value on the stack + if( lua_gettop( L) == 2) + { + lua_pushnil( L); + } + push_table( L, 1); // ud key val fifos + lua_replace( L, 1); // fifos key val + if( !lua_isnil( L, 3)) // replace contents stored at the specified key? + { + keeper_fifo* fifo; + 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 + 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 => stack contents: fifos key nil => remove the fifo associated with the current key + lua_rawset( L, 1); // fifos + } + return 0; +} + +// in: linda_ud key +int keepercall_get( lua_State* L) +{ + keeper_fifo* fifo; + push_table( L, 1); // ud key fifos + lua_replace( L, 1); // fifos key + lua_rawget( L, 1); // fifos fifo + fifo = prepare_fifo_access( L, -1); // fifos fifo + if( fifo && fifo->count > 0) + { + lua_remove( L, 1); // fifo + // read one value off the fifo + fifo_peek( L, fifo, 1); // fifo ... + return 1; + } + // no fifo was ever registered for this key, or it is empty + return 0; +} + +// in: linda_ud [, key [, ...]] +int keepercall_count( lua_State* L) +{ + int top; + push_table( L, 1); // ud keys fifos + switch( lua_gettop( L)) + { + // no key is specified: return a table giving the count of all known keys + case 2: // ud fifos + lua_newtable( L); // ud fifos out + lua_replace( L, 1); // out fifos + lua_pushnil( L); // out fifos nil + while( lua_next( L, 2)) // out fifos key fifo + { + keeper_fifo* fifo = prepare_fifo_access( L, -1); // out fifos key fifo + lua_pop( L, 1); // out fifos key + lua_pushvalue( L, -1); // out fifos key key + lua_pushinteger( L, fifo->count); // out fifos key key count + lua_rawset( L, -5); // out fifos key + } + lua_pop( L, 1); // out + break; + + // 1 key is specified: return its count + case 3: // ud key fifos + { + keeper_fifo* fifo; + lua_replace( L, 1); // fifos key + lua_rawget( L, -2); // fifos fifo + fifo = prepare_fifo_access( L, -1); // fifos fifo + lua_pushinteger( L, fifo->count); // fifos fifo count + lua_replace( L, -3); // count fifo + lua_pop( L, 1); // count + } + break; + + // a variable number of keys is specified: return a table of their counts + default: // ud keys fifos + lua_newtable( L); // ud keys fifos out + lua_replace( L, 1); // out keys fifos + // shifts all keys up in the stack. potentially slow if there are a lot of them, but then it should be bearable + lua_insert( L, 2); // out fifos keys + while( (top = lua_gettop( L)) > 2) + { + keeper_fifo* fifo; + lua_pushvalue( L, -1); // out fifos keys key + lua_rawget( L, 2); // out fifos keys fifo + fifo = prepare_fifo_access( L, -1); // out fifos keys fifo + lua_pop( L, 1); // out fifos keys + if( fifo) + { + lua_pushinteger( L, fifo->count); // out fifos keys count + lua_rawset( L, 1); // out fifos keys + } + else + { + lua_pop( L, 1); // out fifos keys + } + } + lua_pop( L, 1); // out + } + return 1; +} +#endif // KEEPER_MODEL == KEEPER_MODEL_C + +//################################################################################### +// Keeper API, accessed from linda methods +//################################################################################### + /*---=== Keeper states ===--- */ @@ -115,6 +483,14 @@ char const* init_keepers( int const _nbKeepers, lua_CFunction _on_state_create) lua_concat( K, 2); lua_setglobal( K, "decoda_name"); +#if KEEPER_MODEL == KEEPER_MODEL_C + // create the fifos table in the keeper state + lua_pushlightuserdata( K, fifos_key); + lua_newtable( K); + lua_rawset( K, LUA_REGISTRYINDEX); +#endif // KEEPER_MODEL == KEEPER_MODEL_C + +#if KEEPER_MODEL == KEEPER_MODEL_LUA // use package.loaders[2] to find keeper microcode lua_getglobal( K, "package"); // package lua_getfield( K, -1, "loaders"); // package package.loaders @@ -132,6 +508,7 @@ char const* init_keepers( int const _nbKeepers, lua_CFunction _on_state_create) } // package package.loaders STACK_MID( K, 2); lua_pop( K, 2); +#endif // KEEPER_MODEL == KEEPER_MODEL_LUA STACK_END( K, 0) MUTEX_INIT( &GKeepers[i].lock_); GKeepers[i].L = K; @@ -207,7 +584,7 @@ struct s_Keeper *keeper_acquire( const void *ptr) * * Pointers are often aligned by 8 or so - ignore the low order bits */ - unsigned int i= ((unsigned long)(ptr) >> 3) % GNbKeepers; + unsigned int i= ((uintptr_t)(ptr) >> 3) % GNbKeepers; struct s_Keeper *K= &GKeepers[i]; MUTEX_LOCK( &K->lock_); @@ -259,16 +636,15 @@ void keeper_toggle_nil_sentinels( lua_State *L, int _val_i, int _nil_to_sentinel * * Returns: number of return values (pushed to 'L') or -1 in case of error */ -int keeper_call( lua_State *K, char const *func_name, lua_State *L, void *linda, uint_t starting_index) +int keeper_call( lua_State *K, keeper_api_t _func, lua_State *L, void *linda, uint_t starting_index) { - int const args = starting_index ? (lua_gettop(L) - starting_index +1) : 0; - int const Ktos = lua_gettop(K); + int const args = starting_index ? (lua_gettop( L) - starting_index + 1) : 0; + int const Ktos = lua_gettop( K); int retvals = -1; STACK_GROW( K, 2); - lua_getglobal( K, func_name); - ASSERT_L( lua_isfunction(K, -1)); + PUSH_KEEPER_FUNC( K, _func); lua_pushlightuserdata( K, linda); -- cgit v1.2.3-55-g6feb