From 1760eafa1d2ebce8f07e11414a53d4a251af5b8e Mon Sep 17 00:00:00 2001
From: Benoit Germain
Date: Fri, 18 Feb 2011 20:33:43 +0100
Subject: * keeper.lua is now embedded in text form instead of bytecode to
improve LuaJIT2-compatibility (but this is not enough). * moved
keeper-related code in a separate source file
---
CHANGES | 4 ++
CMakeLists.txt | 8 +--
docs/index.html | 27 ++++++-
make-vc.cmd | 6 +-
src/Makefile | 12 ++--
src/keeper.c | 199 +++++++++++++++++++++++++++++++++++++++++++++++++++
src/keeper.h | 18 +++++
src/keeper.lua | 28 ++++----
src/lanes.c | 215 +-------------------------------------------------------
src/tools.c | 69 ++++++++++++++++++
src/tools.h | 3 +
11 files changed, 347 insertions(+), 242 deletions(-)
create mode 100644 src/keeper.c
create mode 100644 src/keeper.h
diff --git a/CHANGES b/CHANGES
index 1e84397..1850415 100644
--- a/CHANGES
+++ b/CHANGES
@@ -3,6 +3,10 @@ CHANGES:
CHANGE X:
+CHANGE 28 BGe 18-Feb-2011
+ - moved keeper-related code in a separate source file
+ - keeper.lua is now embedded in text form instead of bytecode to improve LuaJIT2-compatibility
+
CHANGE 27 BGe 17-Feb-2011
- we know Lanes is loaded in the master state, so we don't force it
to be required in every lane too when a linda deep userdata is copied
diff --git a/CMakeLists.txt b/CMakeLists.txt
index be6534c..31883fa 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -25,13 +25,11 @@ IF(CYGWIN)
ENDIF(CYGWIN)
#2DO - use provided bin2c
-# Compile Lua bytecode to C
+# Embed keeper.lua in text form in C (embedding bytecode is not LuaJIT2-compatible)
ADD_CUSTOM_COMMAND(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/keeper.lch
DEPENDS src/keeper.lua
- COMMAND "${LUAC}" "-o" "${CMAKE_CURRENT_BINARY_DIR}/keeper.lo"
- "${CMAKE_CURRENT_SOURCE_DIR}/src/keeper.lua"
COMMAND "${LUA}" "${CMAKE_CURRENT_SOURCE_DIR}/tools/bin2c.lua"
- "${CMAKE_CURRENT_BINARY_DIR}/keeper.lo"
+ "${CMAKE_CURRENT_SOURCE_DIR}/src/keeper.lua"
"-o" "${CMAKE_CURRENT_BINARY_DIR}/keeper.lch")
SET_SOURCE_FILES_PROPERTIES(src/lanes.c PROPERTIES OBJECT_DEPENDS
${CMAKE_CURRENT_BINARY_DIR}/keeper.lch)
@@ -40,7 +38,7 @@ INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR})
# Build
INCLUDE_DIRECTORIES(src)
-ADD_LIBRARY(lua51-lanes MODULE src/lanes.c src/threading.c src/tools.c)
+ADD_LIBRARY(lua51-lanes MODULE src/lanes.c src/threading.c src/tools.c src/keeper.c)
IF(UNIX AND NOT CYGWIN)
SET(LIBS pthread)
diff --git a/docs/index.html b/docs/index.html
index 03c91f7..a28dd41 100644
--- a/docs/index.html
+++ b/docs/index.html
@@ -799,8 +799,31 @@ can be used for custom userdata as well. Here's what to do.
- Provide an identity function for your userdata, in C. This function is
-used for creation and deletion of your deep userdata (the shared resource),
-and for making metatables for the state-specific proxies for accessing it.
+ used for creation and deletion of your deep userdata (the shared resource),
+ and for making metatables for the state-specific proxies for accessing it. The
+ prototype is
+
+
+
+ void idfunc( lua_State *L, char const * const which);
+ |
+which can be one of:
+
+ -
+ "new": requests the creation of a new object, whose pointer is pushed on the stack
+ as a light userdata.
+
+ -
+ "delete": receives this same pointer on the stack, and should cleanup the object.
+ -
+ "metatable": should build a metatable for the object. Don't cache the metatable
+yourself, Lanes takes care of it ("metatable" should only be invoked once).
+ -
+ "module": is the name of the module that exports the idfunc,
+to be pushed on the stack as a string. It is necessary so that Lanes can require it in
+any Lane and keeper state that receives a userdata. This is to prevent crashes in situations
+where the module could be unloaded while the idfunc pointer is still held.
+
Take a look at linda_id in lanes.c.
- Instanciate your userdata using luaG_deep_userdata(),
diff --git a/make-vc.cmd b/make-vc.cmd
index 2b4a7f6..7711a44 100644
--- a/make-vc.cmd
+++ b/make-vc.cmd
@@ -114,13 +114,11 @@ goto ERR_NOLUA
:LUA_LIB_OK
@REM
-@REM Precompile src/.lua -> .lch
+@REM Embed src/keeper.lua -> .lch
@REM
@REM Note: we cannot use piping in Windows since we need binary output.
@REM
-"%LUAC_EXE%" -o delme src/keeper.lua
-"%LUA_EXE%" tools/bin2c.lua -o src/keeper.lch delme
-@del delme
+"%LUA_EXE%" tools/bin2c.lua -o src/keeper.lch src/keeper.lua
@if "%VCINSTALLDIR%"=="" goto ERR_NOVC
diff --git a/src/Makefile b/src/Makefile
index a17e9cd..df65926 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -7,7 +7,7 @@
MODULE=lanes
-SRC=lanes.c threading.c tools.c
+SRC=lanes.c threading.c tools.c keeper.c
OBJ=$(SRC:.c=.o)
@@ -134,10 +134,14 @@ 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
- $(LUAC) -o $@.tmp $<
- $(LUA) ../tools/bin2c.lua $@.tmp -o $@
- -rm $@.tmp
+ $(LUA) ../tools/bin2c.lua $< -o $@
#---
# NSLU2 "slug" Linux ARM
diff --git a/src/keeper.c b/src/keeper.c
new file mode 100644
index 0000000..f19beed
--- /dev/null
+++ b/src/keeper.c
@@ -0,0 +1,199 @@
+/*
+ --
+ -- KEEPER.C
+ --
+ -- 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: Benoit Germain
+ --
+ -- C implementation replacement of the original keeper.lua
+ --
+ --[[
+ ===============================================================================
+
+ Copyright (C) 2011 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
+ 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.
+
+ ===============================================================================
+ ]]--
+ */
+
+#include
+#include
+#include
+#include
+
+#include "lua.h"
+#include "lauxlib.h"
+
+#include "threading.h"
+#include "tools.h"
+#include "keeper.h"
+
+/*---=== Keeper states ===---
+*/
+
+/* The selected number is not optimal; needs to be tested. Even using just
+* one keeper state may be good enough (depends on the number of Lindas used
+* in the applications).
+*/
+#define KEEPER_STATES_N 1 // 6
+
+/*
+* Pool of keeper states
+*
+* Access to keeper states is locked (only one OS thread at a time) so the
+* bigger the pool, the less chances of unnecessary waits. Lindas map to the
+* keepers randomly, by a hash.
+*/
+static struct s_Keeper GKeepers[KEEPER_STATES_N];
+
+/* We could use an empty table in 'keeper.lua' as the sentinel, but maybe
+* checking for a lightuserdata is faster.
+*/
+static bool_t nil_sentinel = 0;
+
+/*
+* Lua code for the keeper states (baked in)
+*/
+static char const keeper_chunk[]=
+#include "keeper.lch"
+
+/*
+* Initialize keeper states
+*
+* If there is a problem, return an error message (NULL for okay).
+*
+* Note: Any problems would be design flaws; the created Lua state is left
+* unclosed, because it does not really matter. In production code, this
+* function never fails.
+*/
+const char *init_keepers(void)
+{
+ unsigned int i;
+ for( i=0; i> 3) % KEEPER_STATES_N;
+ struct s_Keeper *K= &GKeepers[i];
+
+ MUTEX_LOCK( &K->lock_);
+ //++ K->count;
+ return K;
+}
+
+void keeper_release( struct s_Keeper *K)
+{
+ //-- K->count;
+ MUTEX_UNLOCK( &K->lock_);
+}
+
+/*
+* Call a function ('func_name') in the keeper state, and pass on the returned
+* values to 'L'.
+*
+* 'linda': deep Linda pointer (used only as a unique table key, first parameter)
+* 'starting_index': first of the rest of parameters (none if 0)
+*
+* 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 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));
+
+ lua_pushlightuserdata( K, linda);
+
+ if( (args == 0) || luaG_inter_copy( L, K, args) == 0) // L->K
+ {
+ lua_call( K, 1 + args, LUA_MULTRET);
+
+ retvals = lua_gettop( K) - Ktos;
+ if( (retvals > 0) && luaG_inter_move( K, L, retvals) != 0) // K->L
+ {
+ retvals = -1;
+ }
+ }
+ // whatever happens, restore the stack to where it was at the origin
+ lua_settop( K, Ktos);
+ return retvals;
+}
+
+void close_keepers(void)
+{
+ int i;
+ for(i=0;i
@@ -113,12 +114,6 @@ THE SOFTWARE.
# include
#endif
-/* The selected number is not optimal; needs to be tested. Even using just
-* one keeper state may be good enough (depends on the number of Lindas used
-* in the applications).
-*/
-#define KEEPER_STATES_N 1 // 6
-
/* Do you want full call stacks, or just the line where the error happened?
*
* TBD: The full stack feature does not seem to work (try 'make error').
@@ -129,12 +124,6 @@ THE SOFTWARE.
# define STACK_TRACE_KEY ((void*)lane_error) // used as registry key
#endif
-/*
-* Lua code for the keeper states (baked in)
-*/
-static char keeper_chunk[]=
-#include "keeper.lch"
-
// NOTE: values to be changed by either thread, during execution, without
// locking, are marked "volatile"
//
@@ -254,199 +243,6 @@ static bool_t push_registry_table( lua_State *L, void *key, bool_t create ) {
}
-/*---=== Serialize require ===---
-*/
-
-static MUTEX_T require_cs;
-
-//---
-// [val]= new_require( ... )
-//
-// Call 'old_require' but only one lane at a time.
-//
-// Upvalues: [1]: original 'require' function
-//
-static int new_require( lua_State *L ) {
- int rc;
- int args= lua_gettop(L);
-
- STACK_GROW(L,1);
- STACK_CHECK(L)
-
- // Using 'lua_pcall()' to catch errors; otherwise a failing 'require' would
- // leave us locked, blocking any future 'require' calls from other lanes.
- //
- MUTEX_LOCK( &require_cs );
- {
- lua_pushvalue( L, lua_upvalueindex(1) );
- lua_insert( L, 1 );
-
- rc= lua_pcall( L, args, 1 /*retvals*/, 0 /*errfunc*/ );
- //
- // LUA_ERRRUN / LUA_ERRMEM
- }
- MUTEX_UNLOCK( &require_cs );
-
- if (rc) lua_error(L); // error message already at [-1]
-
- STACK_END(L,0)
- return 1;
-}
-
-/*
-* Serialize calls to 'require', if it exists
-*/
-static
-void serialize_require( lua_State *L ) {
-
- STACK_GROW(L,1);
- STACK_CHECK(L)
-
- // Check 'require' is there; if not, do nothing
- //
- lua_getglobal( L, "require" );
- if (lua_isfunction( L, -1 )) {
- // [-1]: original 'require' function
-
- lua_pushcclosure( L, new_require, 1 /*upvalues*/ );
- lua_setglobal( L, "require" );
-
- } else {
- // [-1]: nil
- lua_pop(L,1);
- }
-
- STACK_END(L,0)
-}
-
-
-/*---=== Keeper states ===---
-*/
-
-/*
-* Pool of keeper states
-*
-* Access to keeper states is locked (only one OS thread at a time) so the
-* bigger the pool, the less chances of unnecessary waits. Lindas map to the
-* keepers randomly, by a hash.
-*/
-struct s_Keeper
-{
- MUTEX_T lock_;
- lua_State *L;
- //int count;
-} GKeepers[KEEPER_STATES_N];
-
-/* We could use an empty table in 'keeper.lua' as the sentinel, but maybe
-* checking for a lightuserdata is faster.
-*/
-static bool_t nil_sentinel;
-
-/*
-* Initialize keeper states
-*
-* If there is a problem, return an error message (NULL for okay).
-*
-* Note: Any problems would be design flaws; the created Lua state is left
-* unclosed, because it does not really matter. In production code, this
-* function never fails.
-*/
-static const char *init_keepers(void) {
- unsigned int i;
- for( i=0; i> 3) % KEEPER_STATES_N;
- struct s_Keeper *K= &GKeepers[i];
-
- MUTEX_LOCK( &K->lock_);
- //++ K->count;
- return K;
-}
-
-static void keeper_release( struct s_Keeper *K)
-{
- //-- K->count;
- MUTEX_UNLOCK( &K->lock_);
-}
-
-/*
-* Call a function ('func_name') in the keeper state, and pass on the returned
-* values to 'L'.
-*
-* 'linda': deep Linda pointer (used only as a unique table key, first parameter)
-* 'starting_index': first of the rest of parameters (none if 0)
-*
-* Returns: number of return values (pushed to 'L') or -1 in case of error
-*/
-static int keeper_call( lua_State *K, char const *func_name, lua_State *L, struct s_Linda *linda, uint_t starting_index)
-{
- 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));
-
- lua_pushlightuserdata( K, linda);
-
- if( (args == 0) || luaG_inter_copy( L, K, args) == 0) // L->K
- {
- lua_call( K, 1 + args, LUA_MULTRET);
-
- retvals = lua_gettop( K) - Ktos;
- if( (retvals > 0) && luaG_inter_move( K, L, retvals) != 0) // K->L
- {
- retvals = -1;
- }
- }
- // whatever happens, restore the stack to where it was at the origin
- lua_settop( K, Ktos);
- return retvals;
-}
-
-
/*---=== Linda ===---
*/
@@ -1189,14 +985,7 @@ static void selfdestruct_atexit( void ) {
DEBUGEXEC(fprintf( stderr, "Killed %d lane(s) at process end.\n", n ));
#endif
}
- {
- int i;
- for(i=0;i