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" --- CHANGES | 5 + Makefile | 36 +++--- docs/index.html | 4 +- lanes-3.1.4.rockspec | 91 ---------------- src/Makefile | 37 ++----- src/keeper.c | 27 +++-- src/keeper.lua | 302 --------------------------------------------------- src/lanes-keeper.lua | 302 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/lanes.c | 10 +- src/lanes.lua | 4 +- tools/bin2c.lua | 131 ---------------------- 11 files changed, 360 insertions(+), 589 deletions(-) delete mode 100644 lanes-3.1.4.rockspec delete mode 100644 src/keeper.lua create mode 100644 src/lanes-keeper.lua delete mode 100644 tools/bin2c.lua diff --git a/CHANGES b/CHANGES index 95e0e70..6bcc061 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,11 @@ CHANGES: +CHANGE 41: BGe 07-Jul-2012 + * 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" + CHANGE 40: BGe 26-Jun-2012 * when a transfered function is not found in source, guess its name to help the user find out what's wrong * new function lanes.nameof() diff --git a/Makefile b/Makefile index 3f1f0e1..c5c41b1 100644 --- a/Makefile +++ b/Makefile @@ -17,39 +17,40 @@ MODULE = lanes N=1000 -_SO=.so -_TARGET_SO=src/lua51-lanes.so +_TARGET_DIR=src/lanes TIME=time ifeq "$(findstring MINGW32,$(shell uname -s))" "MINGW32" # MinGW MSYS on XP # - LUA=lua.exe - LUAC=luac.exe - _SO=.dll - _TARGET_SO=./lua51-lanes.dll + _SO=dll + _LUAEXT=.exe TIME=timeit.exe else - # Autodetect LUA & LUAC - # - LUA=$(word 1,$(shell which lua5.1) $(shell which lua51) lua) - LUAC=$(word 1,$(shell which luac5.1) $(shell which luac51) luac) + _SO=so + _LUAEXT= endif -_PREFIX=LUA_CPATH="./src/?$(_SO)" LUA_PATH="./src/?.lua;./tests/?.lua" +# Autodetect LUA +# +LUA=$(word 1,$(shell which lua5.1$(_LUAEXT)) $(shell which lua51$(_LUAEXT)) lua$(_LUAEXT)) + +_TARGET_SO=$(_TARGET_DIR)/core.$(_SO) + +_PREFIX=LUA_CPATH="./src/?.$(_SO)" LUA_PATH="./src/?.lua;./tests/?.lua" #--- all: $(_TARGET_SO) $(_TARGET_SO): src/*.lua src/*.c src/*.h - cd src && $(MAKE) LUA=$(LUA) LUAC=$(LUAC) + cd src && $(MAKE) LUA=$(LUA) clean: cd src && $(MAKE) clean debug: $(MAKE) clean - cd src && $(MAKE) LUA=$(LUA) LUAC=$(LUAC) OPT_FLAGS="-O0 -g" + cd src && $(MAKE) LUA=$(LUA) OPT_FLAGS="-O0 -g" @echo "" @echo "** Now, try 'make repetitive' or something and if it crashes, 'gdb $(LUA) ...core file...'" @echo " Then 'bt' for a backtrace." @@ -65,7 +66,7 @@ gdb: #--- LuaRocks automated build --- # rock: - cd src && $(MAKE) LUAROCKS=1 CFLAGS="$(CFLAGS)" LIBFLAG="$(LIBFLAG)" LUA=$(LUA) LUAC=$(LUAC) + cd src && $(MAKE) LUAROCKS=1 CFLAGS="$(CFLAGS)" LIBFLAG="$(LIBFLAG)" LUA=$(LUA) #--- Testing --- @@ -196,10 +197,11 @@ LUA_SHAREDIR=$(DESTDIR)/share/lua/5.1 # # AKa 17-Oct: changed to use 'install -m 644' and 'cp -p' # -install: $(_TARGET_SO) src/lanes.lua - mkdir -p $(LUA_LIBDIR) $(LUA_SHAREDIR) - install -m 644 $(_TARGET_SO) $(LUA_LIBDIR) +install: $(_TARGET_SO) src/lanes.lua src/lanes-keeper.lua + mkdir -p $(LUA_LIBDIR) $(LUA_LIBDIR)/lanes $(LUA_SHAREDIR) + install -m 644 $(_TARGET_SO) $(LUA_LIBDIR)/lanes cp -p src/lanes.lua $(LUA_SHAREDIR) + cp -p src/lanes-keeper.lua $(LUA_SHAREDIR) #--- Packaging --- diff --git a/docs/index.html b/docs/index.html index 2d1c78e..7cb4f40 100644 --- a/docs/index.html +++ b/docs/index.html @@ -56,7 +56,7 @@


Copyright © 2007-12 Asko Kauppi, Benoit Germain. All rights reserved.
Lua Lanes is published under the same MIT license as Lua 5.1. -

This document was revised on 26-Jun-12, and applies to version 3.1.4 +

This document was revised on 09-Jul-12, and applies to version 3.1.5

@@ -145,7 +145,7 @@ details and limitations.

-

To install Lanes, all you need are the lanes.lua and lua51-lanes.so|dll +

To install Lanes, all you need are the lanes.lua lanes-keeper.lua and lanes/core.so|dll files to be reachable by Lua (see LUA_PATH, LUA_CPATH). Or use Lua Rocks package management. diff --git a/lanes-3.1.4.rockspec b/lanes-3.1.4.rockspec deleted file mode 100644 index 64206fa..0000000 --- a/lanes-3.1.4.rockspec +++ /dev/null @@ -1,91 +0,0 @@ --- --- Lanes rockspec --- --- Ref: --- --- - -package = "Lanes" - -version = "3.1.4-1" - -source= { - url= "git://github.com/LuaLanes/lanes.git", - branch= "v3.1.4" -} - -description = { - summary= "Multithreading support for Lua", - detailed= [[ - Lua Lanes is a portable, message passing multithreading library - providing the possibility to run multiple Lua states in parallel. - ]], - license= "MIT/X11", - homepage="http://kotisivu.dnainternet.net/askok/lanes/", - maintainer="Benoit Germain " -} - --- Q: What is the difference of "windows" and "win32"? Seems there is none; --- so should we list either one or both? --- -supported_platforms= { "win32", - "macosx", - "linux", - "freebsd", -- TBD: not tested - "msys", -- TBD: not supported by LuaRocks 1.0 (or is it?) -} - -dependencies= { - "lua = 5.1", -} - --- --- Non-Win32: build using the Makefile --- Win32: build using 'make-vc.cmd' and "manual" copy of products --- --- TBD: How is MSYS treated? We'd like (really) it to use the Makefile. --- It should be a target like "cygwin", not defining "windows". --- "windows" should actually guarantee Visual C++ as the compiler. --- --- Q: Does "win32" guarantee we have Visual C++ 2005/2008 command line tools? --- --- Note: Cannot use the simple "module" build type, because we need to precompile --- 'src/keeper.lua' -> keeper.lch and bake it into lanes.c. --- -build = { - - -- Win32 (Visual C++) uses 'make-vc.cmd' for building - -- - platforms= { - windows= { - type= "command", - build_command= "make-vc.cmd", - install= { - lua = { "src/lanes.lua" }, - lib = { "lua51-lanes.dll" } - } - } - }, - - -- Other platforms use the Makefile - -- - -- LuaRocks defines CFLAGS, LIBFLAG and LUA_INCDIR for 'make rock', - -- defines LIBDIR, LUADIR for 'make install' - -- - -- Ref: - -- - type = "make", - - build_target = "rock", - build_variables= { - CFLAGS= "$(CFLAGS) -I$(LUA_INCDIR)", - LIBFLAG= "$(LIBFLAG)", - }, - - install_target = "install", - install_variables= { - LUA_LIBDIR= "$(LIBDIR)", - LUA_SHAREDIR= "$(LUADIR)", - } -} - 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) diff --git a/tools/bin2c.lua b/tools/bin2c.lua deleted file mode 100644 index 352d18e..0000000 --- a/tools/bin2c.lua +++ /dev/null @@ -1,131 +0,0 @@ --- --- BIN2C.LUA [filename] [-o output.lch] --- --- Convert files to byte arrays for automatic loading with 'lua_dobuffer'. --- --- Based on 'etc/bin2c.c' of Lua 5.0.1 sources by: --- Luiz Henrique de Figueiredo (lhf@tecgraf.puc-rio.br) --- --- Changes: --- --- 12-Dec-07/AKa: changed the output to have just the "{ ... }" part; others --- (variable name) can be explicitly given before the '#include' --- 16-Nov-07/AKa: taken into luaSub --- 16-Mar-04/AKa: added 'glua_wrap()' support --- xx-Jan-04/AKa: subdirectory names are not included in debug info --- - -local function USAGE() - io.stderr:write "lua bin2c.lua [filename] [-o output.lch]" - os.exit(-1) -end - -local out_f -- file to output to (stdout if nil) - -local function OUT( ... ) - (out_f or io.stdout): write( ... ); -- ; actually needed by Lua - (out_f or io.stdout): write "\n" -end - -local HEAD= "{ " -local START= ' ' -local FILL= '%3d,' -local STOP= "" -local TAIL= "};\n" - --- -local function dump( f ) - -- - OUT [[ -/* bin2c.lua generated code -- DO NOT EDIT - * - * To use from C source: - * char my_chunk[]= - * #include "my.lch" - */]] - - local str= HEAD..'\n'..START - local len= 0 - - while true do - for n=1,20 do - local c= f:read(1) - if c then - str= str..string.format( FILL, string.byte(c) ) - len= len+1 - else - OUT( str..STOP.. string.format( TAIL, len ) ) - return -- the end - end - end - OUT(str..STOP) - str= START - end -end - --- -local function fdump( fn ) - -- - local f= io.open( fn, "rb" ) -- must open as binary - - if not f then - error( "bin2c: cannot open "..fn ) - else - dump( f ) - f:close() - end -end - --- -local function main( argv ) - -- - local fn= argv.o - if fn then - local f,err= io.open( fn, "w" ) - assert( f, "Unable to write '"..fn.."': "..(err or "") ) - - out_f= f - end - - if argv[2] then - USAGE() - elseif argv[1] then - fdump( argv[1] ) - else -- use stdin (no params) - if os.getenv("WINDIR") then - error "using stdin not allowed on Win32!" -- it wouldn't be binary - end - dump(io.stdin) - end - - if out_f then - out_f:close() - end -end - --- -local argv= {} -local valid_flags= { o=1 } -- lookup: 0=no value, 1=value - --- Need to use while since '-o' advances 'i' by 2 --- -local args= select('#',...) -local i=1 - -while i<=args do - local v= select(i,...) - local flag= string.match( v, "^%-(.+)" ) - - if flag then - if not valid_flags[flag] then - error( "Unknown flag: -"..flag ) - end - argv[flag]= (i+1<=args) and select(i+1,...) or true - i= i+1 - else - table.insert( argv, v ) -- [1..N] - end - i= i+1 -end - -return main(argv) -- cgit v1.2.3-55-g6feb