From 0373f863a9dbabbbe3e9aa74bea3e4b778f3a0cd Mon Sep 17 00:00:00 2001 From: Benoit Germain Date: Tue, 10 Jul 2012 21:43:32 +0200 Subject: one more step toward 5.2 compatibility * lua51-lanes renamed lanes.core * keeper state microcode is no longer embedded inside lanes.core, but located and loaded with package.loaders[2] * changed rockspec build type from "make" to "builtin" --- src/Makefile | 37 ++----- src/keeper.c | 27 +++-- src/keeper.lua | 302 --------------------------------------------------- src/lanes-keeper.lua | 302 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/lanes.c | 10 +- src/lanes.lua | 4 +- 6 files changed, 334 insertions(+), 348 deletions(-) delete mode 100644 src/keeper.lua create mode 100644 src/lanes-keeper.lua (limited to 'src') diff --git a/src/Makefile b/src/Makefile index 03f5558..a16acce 100644 --- a/src/Makefile +++ b/src/Makefile @@ -1,8 +1,8 @@ # # Lanes/src/Makefile # -# make [LUA=... LUAC=...] Manual build -# make LUAROCKS=1 CFLAGS=... LIBFLAG=... LUA=... LUAC=... LuaRocks automated build +# make [LUA=...] Manual build +# make LUAROCKS=1 CFLAGS=... LIBFLAG=... LUA=... LuaRocks automated build # MODULE=lanes @@ -19,11 +19,10 @@ OPT_FLAGS=-O2 # -O0 -g LUA=lua -LUAC=luac -_SO=.so +_SO=so ifeq "$(findstring MINGW32,$(shell uname -s))" "MINGW32" - _SO=.dll + _SO=dll endif ifeq "$(LUAROCKS)" "" @@ -116,32 +115,21 @@ ifeq "$(shell uname -s)" "BSD" LIBS += -lpthread endif +MODULE_DIR=$(MODULE) + #--- -all: lua51-$(MODULE)$(_SO) +all: $(MODULE)/core.$(_SO) %.o: %.c *.h Makefile # Note: Don't put $(LUA_LIBS) ahead of $^; MSYS will not like that (I think) # -lua51-$(MODULE)$(_SO): $(OBJ) +$(MODULE_DIR)/core.$(_SO): $(OBJ) + mkdir -p $(MODULE_DIR) $(CC) $(LIBFLAG) $^ $(LIBS) $(LUA_LIBS) -o $@ clean: - -rm -rf lua51-$(MODULE)$(_SO) *.lch *.o *.tmp *.map - -lanes.o: keeper.lch - -# Note: 'luac -o -' could be used on systems other than Windows (where pipes -# are binary). We need to support MinGW as well, so a temporary file. -# -# mode 1: embed bytecode version -#%.lch: %.lua -# $(LUAC) -o $@.tmp $< -# $(LUA) ../tools/bin2c.lua $@.tmp -o $@ -# -rm $@.tmp -# mode 2: embed text version (LuaJIT2-compatible) -%.lch: %.lua - $(LUA) ../tools/bin2c.lua $< -o $@ + -rm -rf $(MODULE)/core.$(_SO) *.o *.map #--- # NSLU2 "slug" Linux ARM @@ -166,10 +154,9 @@ win32: $(WIN32_LUA51)/include/lua.h $(MAKE) build CC=$(MINGW_GCC) \ LUA_FLAGS=-I$(WIN32_LUA51)/include \ LUA_LIBS="-L$(WIN32_LUA51) -llua51" \ - _SO=.dll \ + _SO=dll \ SO_FLAGS=-shared \ - LUA=lua51 \ - LUAC=luac51 + LUA=lua51 $(WIN32_LUA51)/include/lua.h: @echo "Usage: make win32 WIN32_LUA51=" diff --git a/src/keeper.c b/src/keeper.c index 6f5bd95..2404520 100644 --- a/src/keeper.c +++ b/src/keeper.c @@ -63,12 +63,6 @@ static struct s_Keeper *GKeepers = NULL; static int GNbKeepers = 0; -/* -* Lua code for the keeper states (baked in) -*/ -static char const keeper_chunk[]= -#include "keeper.lch" - /* * Initialize keeper states * @@ -95,26 +89,31 @@ char const* init_keepers( int const _nbKeepers, lua_CFunction _on_state_create) if (!K) return "out of memory"; + STACK_CHECK( K) // to see VM name in Decoda debugger lua_pushliteral( K, "Keeper #"); lua_pushinteger( K, i + 1); lua_concat( K, 2); lua_setglobal( K, "decoda_name"); - // Read in the preloaded chunk (and run it) - // - if( luaL_loadbuffer( K, keeper_chunk, sizeof(keeper_chunk), "@keeper.lua")) - return "luaL_loadbuffer() failed"; // LUA_ERRMEM - - if( lua_pcall( K, 0 /*args*/, 0 /*results*/, 0 /*errfunc*/)) + // use package.loaders[2] to find keeper microcode + lua_getfield( K, LUA_GLOBALSINDEX, "package"); // package + lua_getfield( K, -1, "loaders"); // package package.loaders + lua_rawgeti( K, -1, 2); // package package.loaders package.loaders[2] + lua_pushliteral( K, "lanes-keeper"); // package package.loaders package.loaders[2] "lanes-keeper" + STACK_MID( K, 4); + // first pcall loads lanes-keeper.lua, second one runs the chunk + if( lua_pcall( K, 1 /*args*/, 1 /*results*/, 0 /*errfunc*/) || lua_pcall( K, 0 /*args*/, 0 /*results*/, 0 /*errfunc*/)) { // LUA_ERRRUN / LUA_ERRMEM / LUA_ERRERR // char const* err = lua_tostring( K, -1); assert( err); return err; - } - + } // package package.loaders + STACK_MID( K, 2); + lua_pop( K, 2); + STACK_END( K, 0) MUTEX_INIT( &GKeepers[i].lock_); GKeepers[i].L = K; //GKeepers[i].count = 0; diff --git a/src/keeper.lua b/src/keeper.lua deleted file mode 100644 index 1f17599..0000000 --- a/src/keeper.lua +++ /dev/null @@ -1,302 +0,0 @@ --- --- KEEPER.LUA --- --- Keeper state logic --- --- This code is read in for each "keeper state", which are the hidden, inter- --- mediate data stores used by Lanes inter-state communication objects. --- --- Author: Asko Kauppi --- ---[[ -=============================================================================== - -Copyright (C) 2008-10 Asko Kauppi - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. - -=============================================================================== -]]-- - --- We only need to have base and table libraries (and io for debugging) --- -local table_concat = assert( table.concat) -local table_insert = assert( table.insert) -local table_remove = assert( table.remove) -local select, unpack = assert( select), assert( unpack) - ---[[ -local function WR(...) - if io then - io.stderr:write( table_concat({...},'\t').."\n" ) - end -end - -local function DEBUG(title,ud,key) - assert( title and ud and key ) - - local data,_= tables(ud) - - local s= tostring(data[key]) - for _,v in ipairs( data[key] or {} ) do - s= s..", "..tostring(v) - end - WR( "*** "..title.." ("..tostring(key).."): ", s ) -end ---]] - ------ --- FIFO for a key --- - -local fifo_new = function() - return { first = 1, count = 0} -end - -local fifo_push = function( fifo, ...) - local first, count, added = fifo.first, fifo.count, select( '#', ...) - local start = first + count - 1 - for i = 1, added do - fifo[start + i] = select( i, ...) - end - fifo.count = count + added -end - -local fifo_peek = function( fifo, count) - if count <= fifo.count then - local first = fifo.first - local last = first + count - 1 - return unpack( fifo, first, last) - end -end - -local fifo_pop = function( fifo, count) - local first = fifo.first - local last = first + count - 1 - local out = { unpack( fifo, first, last)} - for i = first, last do - fifo[i] = nil - end - fifo.first = first + count - fifo.count = fifo.count - count - return unpack( out) -end - - ------ --- Actual data store --- --- { [linda_deep_ud]= { key= { val [, ... ] } [, ...] } --- ... --- } --- -local _data= {} - ------ --- Length limits (if any) for queues --- --- 0: don't queue values at all; ':send()' waits if the slot is not vacant --- N: allow N values to be queued (slot itself + N-1); wait if full --- nil: no limits, '_data' may grow endlessly --- -local _limits= {} - ------ --- data_tbl, limits_tbl = tables( linda_deep_ud ) --- --- Gives appropriate tables for a certain Linda (creates them if needed) --- -local function tables( ud ) - -- tables are created either all or nothing - -- - if not _data[ud] then - _data[ud]= {} - _limits[ud]= {} - end - return _data[ud], _limits[ud] -end - ------ --- bool= send( linda_deep_ud, key, ...) --- --- Send new data (1..N) to 'key' slot. This send is atomic; all the values --- end up one after each other (this is why having possibility for sending --- multiple values in one call is deemed important). --- --- If the queue has a limit, values are sent only if all of them fit in. --- --- Returns: 'true' if all the values were placed --- 'false' if sending would exceed the queue limit (wait & retry) --- -function send( ud, key, ...) - - local data, limits = tables( ud) - - local n = select( '#', ...) - - -- Initialize queue for all keys that have been used with ':send()' - -- - if data[key] == nil then - data[key] = fifo_new() - end - local fifo = data[key] - - local len = fifo.count - local m = limits[key] - - if m and len+n > m then - return false -- would exceed the limit; try again later - end - - fifo_push( fifo, ...) - return true -end - - ------ --- [val, key]= receive( linda_deep_ud, key [, ...] ) --- --- Read any of the given keys, consuming the data found. Keys are read in --- order. --- -function receive( ud, ...) - - local data = tables( ud) - - for i = 1, select( '#', ...) do - local key = select( i, ...) - local fifo = data[key] - if fifo and fifo.count > 0 then - local val = fifo_pop( fifo, 1) - if val ~= nil then - return val, key - end - end - end -end - - ------ --- [val1, ... valCOUNT]= receive_batched( linda_deep_ud, key , min_COUNT, max_COUNT) --- --- Read a single key, consuming the data found. --- -receive_batched = function( ud, key, min_count, max_count) - if min_count > 0 then - local fifo = tables( ud)[key] - if fifo then - local fifo_count = fifo.count - if fifo_count >= min_count then - max_count = max_count or min_count - max_count = (max_count > fifo_count) and fifo_count or max_count - return fifo_pop( fifo, max_count) - end - end - end -end - - ------ --- = limit( linda_deep_ud, key, uint ) --- -function limit( ud, key, n) - - local _, limits = tables( ud) - - limits[key] = n -end - - ------ --- void= set( linda_deep_ud, key, [val] ) --- -function set( ud, key, val) - - local data, _ = tables( ud) - - -- Setting a key to 'nil' really clears it; only queing uses sentinels. - -- - if val ~= nil then - local fifo = fifo_new() - fifo_push( fifo, val) - data[key] = fifo - else - data[key] = nil - end -end - - ------ --- [val]= get( linda_deep_ud, key ) --- -function get( ud, key) - local data, _ = tables( ud) - local fifo = data[key] - return fifo and fifo_peek( fifo, 1) -end - - ------ --- [val]= count( linda_deep_ud, ...) --- --- 3 modes of operation --- linda:count() -> returns a table of key/count pairs --- linda:count(key) returns the number of items waiting in the key --- linda:count(key,...) -> returns a table telling, for each key, the number of items -function count( ud, ...) - local data, _ = tables( ud) - local n = select( '#', ...) - if n == 0 then - local out - for key, _ in pairs( data) do - local fifo = data[key] - local count = fifo and fifo.count or 0 - out = out or {} - out[key] = count - found = true - end - return out - elseif n == 1 then - local key = ... - local fifo = data[key] - return fifo and fifo.count or nil - else -- more than 1 key - local out - for i = 1, n do - local key = select( i, ...) - local fifo = data[key] - local count = fifo and fifo.count or nil - out = out or {} - out[key] = count - end - return out - end -end - - ------ --- void= clear( linda_deep_ud) --- --- Clear the data structures used for a Linda (at its destructor) --- -function clear( ud) - - _data[ud]= nil - _limits[ud]= nil -end diff --git a/src/lanes-keeper.lua b/src/lanes-keeper.lua new file mode 100644 index 0000000..1f17599 --- /dev/null +++ b/src/lanes-keeper.lua @@ -0,0 +1,302 @@ +-- +-- KEEPER.LUA +-- +-- Keeper state logic +-- +-- This code is read in for each "keeper state", which are the hidden, inter- +-- mediate data stores used by Lanes inter-state communication objects. +-- +-- Author: Asko Kauppi +-- +--[[ +=============================================================================== + +Copyright (C) 2008-10 Asko Kauppi + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +=============================================================================== +]]-- + +-- We only need to have base and table libraries (and io for debugging) +-- +local table_concat = assert( table.concat) +local table_insert = assert( table.insert) +local table_remove = assert( table.remove) +local select, unpack = assert( select), assert( unpack) + +--[[ +local function WR(...) + if io then + io.stderr:write( table_concat({...},'\t').."\n" ) + end +end + +local function DEBUG(title,ud,key) + assert( title and ud and key ) + + local data,_= tables(ud) + + local s= tostring(data[key]) + for _,v in ipairs( data[key] or {} ) do + s= s..", "..tostring(v) + end + WR( "*** "..title.." ("..tostring(key).."): ", s ) +end +--]] + +----- +-- FIFO for a key +-- + +local fifo_new = function() + return { first = 1, count = 0} +end + +local fifo_push = function( fifo, ...) + local first, count, added = fifo.first, fifo.count, select( '#', ...) + local start = first + count - 1 + for i = 1, added do + fifo[start + i] = select( i, ...) + end + fifo.count = count + added +end + +local fifo_peek = function( fifo, count) + if count <= fifo.count then + local first = fifo.first + local last = first + count - 1 + return unpack( fifo, first, last) + end +end + +local fifo_pop = function( fifo, count) + local first = fifo.first + local last = first + count - 1 + local out = { unpack( fifo, first, last)} + for i = first, last do + fifo[i] = nil + end + fifo.first = first + count + fifo.count = fifo.count - count + return unpack( out) +end + + +----- +-- Actual data store +-- +-- { [linda_deep_ud]= { key= { val [, ... ] } [, ...] } +-- ... +-- } +-- +local _data= {} + +----- +-- Length limits (if any) for queues +-- +-- 0: don't queue values at all; ':send()' waits if the slot is not vacant +-- N: allow N values to be queued (slot itself + N-1); wait if full +-- nil: no limits, '_data' may grow endlessly +-- +local _limits= {} + +----- +-- data_tbl, limits_tbl = tables( linda_deep_ud ) +-- +-- Gives appropriate tables for a certain Linda (creates them if needed) +-- +local function tables( ud ) + -- tables are created either all or nothing + -- + if not _data[ud] then + _data[ud]= {} + _limits[ud]= {} + end + return _data[ud], _limits[ud] +end + +----- +-- bool= send( linda_deep_ud, key, ...) +-- +-- Send new data (1..N) to 'key' slot. This send is atomic; all the values +-- end up one after each other (this is why having possibility for sending +-- multiple values in one call is deemed important). +-- +-- If the queue has a limit, values are sent only if all of them fit in. +-- +-- Returns: 'true' if all the values were placed +-- 'false' if sending would exceed the queue limit (wait & retry) +-- +function send( ud, key, ...) + + local data, limits = tables( ud) + + local n = select( '#', ...) + + -- Initialize queue for all keys that have been used with ':send()' + -- + if data[key] == nil then + data[key] = fifo_new() + end + local fifo = data[key] + + local len = fifo.count + local m = limits[key] + + if m and len+n > m then + return false -- would exceed the limit; try again later + end + + fifo_push( fifo, ...) + return true +end + + +----- +-- [val, key]= receive( linda_deep_ud, key [, ...] ) +-- +-- Read any of the given keys, consuming the data found. Keys are read in +-- order. +-- +function receive( ud, ...) + + local data = tables( ud) + + for i = 1, select( '#', ...) do + local key = select( i, ...) + local fifo = data[key] + if fifo and fifo.count > 0 then + local val = fifo_pop( fifo, 1) + if val ~= nil then + return val, key + end + end + end +end + + +----- +-- [val1, ... valCOUNT]= receive_batched( linda_deep_ud, key , min_COUNT, max_COUNT) +-- +-- Read a single key, consuming the data found. +-- +receive_batched = function( ud, key, min_count, max_count) + if min_count > 0 then + local fifo = tables( ud)[key] + if fifo then + local fifo_count = fifo.count + if fifo_count >= min_count then + max_count = max_count or min_count + max_count = (max_count > fifo_count) and fifo_count or max_count + return fifo_pop( fifo, max_count) + end + end + end +end + + +----- +-- = limit( linda_deep_ud, key, uint ) +-- +function limit( ud, key, n) + + local _, limits = tables( ud) + + limits[key] = n +end + + +----- +-- void= set( linda_deep_ud, key, [val] ) +-- +function set( ud, key, val) + + local data, _ = tables( ud) + + -- Setting a key to 'nil' really clears it; only queing uses sentinels. + -- + if val ~= nil then + local fifo = fifo_new() + fifo_push( fifo, val) + data[key] = fifo + else + data[key] = nil + end +end + + +----- +-- [val]= get( linda_deep_ud, key ) +-- +function get( ud, key) + local data, _ = tables( ud) + local fifo = data[key] + return fifo and fifo_peek( fifo, 1) +end + + +----- +-- [val]= count( linda_deep_ud, ...) +-- +-- 3 modes of operation +-- linda:count() -> returns a table of key/count pairs +-- linda:count(key) returns the number of items waiting in the key +-- linda:count(key,...) -> returns a table telling, for each key, the number of items +function count( ud, ...) + local data, _ = tables( ud) + local n = select( '#', ...) + if n == 0 then + local out + for key, _ in pairs( data) do + local fifo = data[key] + local count = fifo and fifo.count or 0 + out = out or {} + out[key] = count + found = true + end + return out + elseif n == 1 then + local key = ... + local fifo = data[key] + return fifo and fifo.count or nil + else -- more than 1 key + local out + for i = 1, n do + local key = select( i, ...) + local fifo = data[key] + local count = fifo and fifo.count or nil + out = out or {} + out[key] = count + end + return out + end +end + + +----- +-- void= clear( linda_deep_ud) +-- +-- Clear the data structures used for a Linda (at its destructor) +-- +function clear( ud) + + _data[ud]= nil + _limits[ud]= nil +end diff --git a/src/lanes.c b/src/lanes.c index 3e906c0..300c924 100644 --- a/src/lanes.c +++ b/src/lanes.c @@ -51,7 +51,7 @@ * ... */ -char const* VERSION = "3.1.4"; +char const* VERSION = "3.1.5"; /* =============================================================================== @@ -868,7 +868,7 @@ static void linda_id( lua_State *L, char const * const which) // in other words, forever. lua_pushnil( L); // other idfuncs must push a string naming the module they come from - //lua_pushliteral( L, "lua51-lanes"); + //lua_pushliteral( L, "lanes.core"); } } @@ -1697,11 +1697,11 @@ LUAG_FUNC( thread_new ) // modules to require in the target lane *before* the function is transfered! - //start by requiring lua51-lanes, since it is a bit special + //start by requiring lanes.core, since it is a bit special // it is not fatal if 'require' isn't loaded, just ignore (may cause function transfer errors later on if the lane pulls the lanes module itself) STACK_CHECK(L) STACK_CHECK(L2) - lua_pushliteral( L, "lua51-lanes"); + lua_pushliteral( L, "lanes.core"); require_one_module( L, L2, FALSE); lua_pop( L, 1); STACK_END(L2,0) @@ -2510,7 +2510,7 @@ int #if (defined PLATFORM_WIN32) || (defined PLATFORM_POCKETPC) __declspec(dllexport) #endif // (defined PLATFORM_WIN32) || (defined PLATFORM_POCKETPC) -luaopen_lanes( lua_State *L ) +luaopen_lanes_core( lua_State *L ) { // Create main module interface table // we only have 1 closure, which must be called to configure Lanes diff --git a/src/lanes.lua b/src/lanes.lua index bd66e6c..8cd3737 100644 --- a/src/lanes.lua +++ b/src/lanes.lua @@ -55,10 +55,10 @@ if _params.on_state_create and (type( _params.on_state_create) ~= "function") th error( "Bad on_state_create: " .. tostring( _params.on_state_create), 2) end -local mm = require "lua51-lanes" +local mm = require "lanes.core" assert( type(mm)=="table" ) --- configure() is available only the first time lua51-lanes is required process-wide, and we *must* call it to have the other functions in the interface +-- configure() is available only the first time lanes.core is required process-wide, and we *must* call it to have the other functions in the interface if mm.configure then mm.configure( _params.nb_keepers, _params.on_state_create) end local thread_new = assert(mm.thread_new) -- cgit v1.2.3-55-g6feb