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