aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGES4
-rw-r--r--CMakeLists.txt8
-rw-r--r--docs/index.html27
-rw-r--r--make-vc.cmd6
-rw-r--r--src/Makefile12
-rw-r--r--src/keeper.c199
-rw-r--r--src/keeper.h18
-rw-r--r--src/keeper.lua28
-rw-r--r--src/lanes.c215
-rw-r--r--src/tools.c69
-rw-r--r--src/tools.h3
11 files changed, 347 insertions, 242 deletions
diff --git a/CHANGES b/CHANGES
index 1e84397..1850415 100644
--- a/CHANGES
+++ b/CHANGES
@@ -3,6 +3,10 @@ CHANGES:
3 3
4CHANGE X: 4CHANGE X:
5 5
6CHANGE 28 BGe 18-Feb-2011
7 - moved keeper-related code in a separate source file
8 - keeper.lua is now embedded in text form instead of bytecode to improve LuaJIT2-compatibility
9
6CHANGE 27 BGe 17-Feb-2011 10CHANGE 27 BGe 17-Feb-2011
7 - we know Lanes is loaded in the master state, so we don't force it 11 - we know Lanes is loaded in the master state, so we don't force it
8 to be required in every lane too when a linda deep userdata is copied 12 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)
25ENDIF(CYGWIN) 25ENDIF(CYGWIN)
26 26
27#2DO - use provided bin2c 27#2DO - use provided bin2c
28# Compile Lua bytecode to C 28# Embed keeper.lua in text form in C (embedding bytecode is not LuaJIT2-compatible)
29ADD_CUSTOM_COMMAND(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/keeper.lch 29ADD_CUSTOM_COMMAND(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/keeper.lch
30 DEPENDS src/keeper.lua 30 DEPENDS src/keeper.lua
31 COMMAND "${LUAC}" "-o" "${CMAKE_CURRENT_BINARY_DIR}/keeper.lo"
32 "${CMAKE_CURRENT_SOURCE_DIR}/src/keeper.lua"
33 COMMAND "${LUA}" "${CMAKE_CURRENT_SOURCE_DIR}/tools/bin2c.lua" 31 COMMAND "${LUA}" "${CMAKE_CURRENT_SOURCE_DIR}/tools/bin2c.lua"
34 "${CMAKE_CURRENT_BINARY_DIR}/keeper.lo" 32 "${CMAKE_CURRENT_SOURCE_DIR}/src/keeper.lua"
35 "-o" "${CMAKE_CURRENT_BINARY_DIR}/keeper.lch") 33 "-o" "${CMAKE_CURRENT_BINARY_DIR}/keeper.lch")
36SET_SOURCE_FILES_PROPERTIES(src/lanes.c PROPERTIES OBJECT_DEPENDS 34SET_SOURCE_FILES_PROPERTIES(src/lanes.c PROPERTIES OBJECT_DEPENDS
37 ${CMAKE_CURRENT_BINARY_DIR}/keeper.lch) 35 ${CMAKE_CURRENT_BINARY_DIR}/keeper.lch)
@@ -40,7 +38,7 @@ INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR})
40 38
41# Build 39# Build
42INCLUDE_DIRECTORIES(src) 40INCLUDE_DIRECTORIES(src)
43ADD_LIBRARY(lua51-lanes MODULE src/lanes.c src/threading.c src/tools.c) 41ADD_LIBRARY(lua51-lanes MODULE src/lanes.c src/threading.c src/tools.c src/keeper.c)
44 42
45IF(UNIX AND NOT CYGWIN) 43IF(UNIX AND NOT CYGWIN)
46 SET(LIBS pthread) 44 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.
799</p> 799</p>
800<ol> 800<ol>
801 <li>Provide an <i>identity function</i> for your userdata, in C. This function is 801 <li>Provide an <i>identity function</i> for your userdata, in C. This function is
802used for creation and deletion of your deep userdata (the shared resource), 802 used for creation and deletion of your deep userdata (the shared resource),
803and for making metatables for the state-specific proxies for accessing it. 803 and for making metatables for the state-specific proxies for accessing it. The
804 prototype is
805 <table border="1" bgcolor="#E0E0FF" cellpadding="10">
806 <tr>
807 <td>
808 <code>void idfunc( lua_State *L, char const * const which);</code>
809 </table>
810<tt>which</tt> can be one of:
811<ul>
812 <li>
813 <tt>"new"</tt>: requests the creation of a new object, whose pointer is pushed on the stack
814 as a light userdata.
815 </li>
816 <li>
817 <tt>"delete"</tt>: receives this same pointer on the stack, and should cleanup the object.</li>
818 <li>
819 <tt>"metatable"</tt>: should build a metatable for the object. Don't cache the metatable
820yourself, Lanes takes care of it ("metatable" should only be invoked once).</li>
821 <li>
822 <tt>"module"</tt>: is the name of the module that exports the idfunc,
823to be pushed on the stack as a string. It is necessary so that Lanes can require it in
824any Lane and keeper state that receives a userdata. This is to prevent crashes in situations
825where the module could be unloaded while the idfunc pointer is still held.</li>
826</ul>
804Take a look at <tt>linda_id</tt> in <tt>lanes.c</tt>. 827Take a look at <tt>linda_id</tt> in <tt>lanes.c</tt>.
805 </li> 828 </li>
806 <li>Instanciate your userdata using <tt>luaG_deep_userdata()</tt>, 829 <li>Instanciate your userdata using <tt>luaG_deep_userdata()</tt>,
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
114:LUA_LIB_OK 114:LUA_LIB_OK
115 115
116@REM 116@REM
117@REM Precompile src/.lua -> .lch 117@REM Embed src/keeper.lua -> .lch
118@REM 118@REM
119@REM Note: we cannot use piping in Windows since we need binary output. 119@REM Note: we cannot use piping in Windows since we need binary output.
120@REM 120@REM
121"%LUAC_EXE%" -o delme src/keeper.lua 121"%LUA_EXE%" tools/bin2c.lua -o src/keeper.lch src/keeper.lua
122"%LUA_EXE%" tools/bin2c.lua -o src/keeper.lch delme
123@del delme
124 122
125@if "%VCINSTALLDIR%"=="" goto ERR_NOVC 123@if "%VCINSTALLDIR%"=="" goto ERR_NOVC
126 124
diff --git a/src/Makefile b/src/Makefile
index a17e9cd..df65926 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -7,7 +7,7 @@
7 7
8MODULE=lanes 8MODULE=lanes
9 9
10SRC=lanes.c threading.c tools.c 10SRC=lanes.c threading.c tools.c keeper.c
11 11
12OBJ=$(SRC:.c=.o) 12OBJ=$(SRC:.c=.o)
13 13
@@ -134,10 +134,14 @@ lanes.o: keeper.lch
134# Note: 'luac -o -' could be used on systems other than Windows (where pipes 134# Note: 'luac -o -' could be used on systems other than Windows (where pipes
135# are binary). We need to support MinGW as well, so a temporary file. 135# are binary). We need to support MinGW as well, so a temporary file.
136# 136#
137# mode 1: embed bytecode version
138#%.lch: %.lua
139# $(LUAC) -o $@.tmp $<
140# $(LUA) ../tools/bin2c.lua $@.tmp -o $@
141# -rm $@.tmp
142# mode 2: embed text version (LuaJIT2-compatible)
137%.lch: %.lua 143%.lch: %.lua
138 $(LUAC) -o $@.tmp $< 144 $(LUA) ../tools/bin2c.lua $< -o $@
139 $(LUA) ../tools/bin2c.lua $@.tmp -o $@
140 -rm $@.tmp
141 145
142#--- 146#---
143# NSLU2 "slug" Linux ARM 147# 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 @@
1/*
2 --
3 -- KEEPER.C
4 --
5 -- Keeper state logic
6 --
7 -- This code is read in for each "keeper state", which are the hidden, inter-
8 -- mediate data stores used by Lanes inter-state communication objects.
9 --
10 -- Author: Benoit Germain <bnt.germain@gmail.com>
11 --
12 -- C implementation replacement of the original keeper.lua
13 --
14 --[[
15 ===============================================================================
16
17 Copyright (C) 2011 Benoit Germain <bnt.germain@gmail.com>
18
19 Permission is hereby granted, free of charge, to any person obtaining a copy
20 of this software and associated documentation files (the "Software"), to deal
21 in the Software without restriction, including without limitation the rights
22 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
23 copies of the Software, and to permit persons to whom the Software is
24 furnished to do so, subject to the following conditions:
25
26 The above copyright notice and this permission notice shall be included in
27 all copies or substantial portions of the Software.
28
29 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
30 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
31 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
32 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
33 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
34 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
35 THE SOFTWARE.
36
37 ===============================================================================
38 ]]--
39 */
40
41#include <string.h>
42#include <stdio.h>
43#include <stdlib.h>
44#include <ctype.h>
45
46#include "lua.h"
47#include "lauxlib.h"
48
49#include "threading.h"
50#include "tools.h"
51#include "keeper.h"
52
53/*---=== Keeper states ===---
54*/
55
56/* The selected number is not optimal; needs to be tested. Even using just
57* one keeper state may be good enough (depends on the number of Lindas used
58* in the applications).
59*/
60#define KEEPER_STATES_N 1 // 6
61
62/*
63* Pool of keeper states
64*
65* Access to keeper states is locked (only one OS thread at a time) so the
66* bigger the pool, the less chances of unnecessary waits. Lindas map to the
67* keepers randomly, by a hash.
68*/
69static struct s_Keeper GKeepers[KEEPER_STATES_N];
70
71/* We could use an empty table in 'keeper.lua' as the sentinel, but maybe
72* checking for a lightuserdata is faster.
73*/
74static bool_t nil_sentinel = 0;
75
76/*
77* Lua code for the keeper states (baked in)
78*/
79static char const keeper_chunk[]=
80#include "keeper.lch"
81
82/*
83* Initialize keeper states
84*
85* If there is a problem, return an error message (NULL for okay).
86*
87* Note: Any problems would be design flaws; the created Lua state is left
88* unclosed, because it does not really matter. In production code, this
89* function never fails.
90*/
91const char *init_keepers(void)
92{
93 unsigned int i;
94 for( i=0; i<KEEPER_STATES_N; i++ )
95 {
96
97 // Initialize Keeper states with bare minimum of libs (those required
98 // by 'keeper.lua')
99 //
100 lua_State *L= luaL_newstate();
101 if (!L)
102 return "out of memory";
103
104 luaG_openlibs( L, "io,table,package" ); // 'io' for debugging messages, package because we need to require modules exporting idfuncs
105 serialize_require( L);
106
107 lua_pushlightuserdata( L, &nil_sentinel );
108 lua_setglobal( L, "nil_sentinel" );
109
110 // Read in the preloaded chunk (and run it)
111 //
112 if (luaL_loadbuffer( L, keeper_chunk, sizeof(keeper_chunk), "=lanes_keeper" ))
113 return "luaL_loadbuffer() failed"; // LUA_ERRMEM
114
115 if (lua_pcall( L, 0 /*args*/, 0 /*results*/, 0 /*errfunc*/ ))
116 {
117 // LUA_ERRRUN / LUA_ERRMEM / LUA_ERRERR
118 //
119 const char *err= lua_tostring(L,-1);
120 assert(err);
121 return err;
122 }
123
124 MUTEX_INIT( &GKeepers[i].lock_ );
125 GKeepers[i].L= L;
126 //GKeepers[i].count = 0;
127 }
128 return NULL; // ok
129}
130
131struct s_Keeper *keeper_acquire( const void *ptr)
132{
133 /*
134 * Any hashing will do that maps pointers to 0..KEEPER_STATES_N-1
135 * consistently.
136 *
137 * Pointers are often aligned by 8 or so - ignore the low order bits
138 */
139 unsigned int i= ((unsigned long)(ptr) >> 3) % KEEPER_STATES_N;
140 struct s_Keeper *K= &GKeepers[i];
141
142 MUTEX_LOCK( &K->lock_);
143 //++ K->count;
144 return K;
145}
146
147void keeper_release( struct s_Keeper *K)
148{
149 //-- K->count;
150 MUTEX_UNLOCK( &K->lock_);
151}
152
153/*
154* Call a function ('func_name') in the keeper state, and pass on the returned
155* values to 'L'.
156*
157* 'linda': deep Linda pointer (used only as a unique table key, first parameter)
158* 'starting_index': first of the rest of parameters (none if 0)
159*
160* Returns: number of return values (pushed to 'L') or -1 in case of error
161*/
162int keeper_call( lua_State *K, char const *func_name, lua_State *L, void *linda, uint_t starting_index)
163{
164 int const args = starting_index ? (lua_gettop(L) - starting_index +1) : 0;
165 int const Ktos = lua_gettop(K);
166 int retvals = -1;
167
168 STACK_GROW( K, 2);
169
170 lua_getglobal( K, func_name);
171 ASSERT_L( lua_isfunction(K, -1));
172
173 lua_pushlightuserdata( K, linda);
174
175 if( (args == 0) || luaG_inter_copy( L, K, args) == 0) // L->K
176 {
177 lua_call( K, 1 + args, LUA_MULTRET);
178
179 retvals = lua_gettop( K) - Ktos;
180 if( (retvals > 0) && luaG_inter_move( K, L, retvals) != 0) // K->L
181 {
182 retvals = -1;
183 }
184 }
185 // whatever happens, restore the stack to where it was at the origin
186 lua_settop( K, Ktos);
187 return retvals;
188}
189
190void close_keepers(void)
191{
192 int i;
193 for(i=0;i<KEEPER_STATES_N;i++)
194 {
195 lua_close( GKeepers[i].L);
196 GKeepers[i].L = 0;
197 //assert( GKeepers[i].count == 0);
198 }
199}
diff --git a/src/keeper.h b/src/keeper.h
new file mode 100644
index 0000000..66d8d7e
--- /dev/null
+++ b/src/keeper.h
@@ -0,0 +1,18 @@
1#if !defined( __keeper_h__)
2#define __keeper_h__ 1
3
4struct s_Keeper
5{
6 MUTEX_T lock_;
7 lua_State *L;
8 //int count;
9};
10
11const char *init_keepers(void);
12struct s_Keeper *keeper_acquire( const void *ptr);
13void keeper_release( struct s_Keeper *K);
14int keeper_call( lua_State *K, char const *func_name, lua_State *L, void *linda, uint_t starting_index);
15void close_keepers(void);
16
17
18#endif // __keeper_h__ \ No newline at end of file
diff --git a/src/keeper.lua b/src/keeper.lua
index 9256a4b..2c38c0b 100644
--- a/src/keeper.lua
+++ b/src/keeper.lua
@@ -43,12 +43,26 @@ assert( nil_sentinel )
43local table_remove= assert( table.remove ) 43local table_remove= assert( table.remove )
44local table_concat= assert( table.concat ) 44local table_concat= assert( table.concat )
45 45
46--[[
46local function WR(...) 47local function WR(...)
47 if io then 48 if io then
48 io.stderr:write( table_concat({...},'\t').."\n" ) 49 io.stderr:write( table_concat({...},'\t').."\n" )
49 end 50 end
50end 51end
51 52
53local function DEBUG(title,ud,key)
54 assert( title and ud and key )
55
56 local data,incoming,_= tables(ud)
57
58 local s= tostring(data[key])
59 for _,v in ipairs( incoming[key] or {} ) do
60 s= s..", "..tostring(v)
61 end
62 WR( "*** "..title.." ("..tostring(key).."): ", s )
63end
64--]]
65
52----- 66-----
53-- Actual data store 67-- Actual data store
54-- 68--
@@ -92,20 +106,6 @@ local function tables( ud )
92 return _data[ud], _incoming[ud], _limits[ud] 106 return _data[ud], _incoming[ud], _limits[ud]
93end 107end
94 108
95
96local function DEBUG(title,ud,key)
97 assert( title and ud and key )
98
99 local data,incoming,_= tables(ud)
100
101 local s= tostring(data[key])
102 for _,v in ipairs( incoming[key] or {} ) do
103 s= s..", "..tostring(v)
104 end
105 WR( "*** "..title.." ("..tostring(key).."): ", s )
106end
107
108
109----- 109-----
110-- bool= send( linda_deep_ud, key, ... ) 110-- bool= send( linda_deep_ud, key, ... )
111-- 111--
diff --git a/src/lanes.c b/src/lanes.c
index 0a89959..a8aba71 100644
--- a/src/lanes.c
+++ b/src/lanes.c
@@ -102,6 +102,7 @@ THE SOFTWARE.
102 102
103#include "threading.h" 103#include "threading.h"
104#include "tools.h" 104#include "tools.h"
105#include "keeper.h"
105 106
106#if !((defined PLATFORM_WIN32) || (defined PLATFORM_POCKETPC)) 107#if !((defined PLATFORM_WIN32) || (defined PLATFORM_POCKETPC))
107# include <sys/time.h> 108# include <sys/time.h>
@@ -113,12 +114,6 @@ THE SOFTWARE.
113# include <sys/types.h> 114# include <sys/types.h>
114#endif 115#endif
115 116
116/* The selected number is not optimal; needs to be tested. Even using just
117* one keeper state may be good enough (depends on the number of Lindas used
118* in the applications).
119*/
120#define KEEPER_STATES_N 1 // 6
121
122/* Do you want full call stacks, or just the line where the error happened? 117/* Do you want full call stacks, or just the line where the error happened?
123* 118*
124* TBD: The full stack feature does not seem to work (try 'make error'). 119* TBD: The full stack feature does not seem to work (try 'make error').
@@ -129,12 +124,6 @@ THE SOFTWARE.
129# define STACK_TRACE_KEY ((void*)lane_error) // used as registry key 124# define STACK_TRACE_KEY ((void*)lane_error) // used as registry key
130#endif 125#endif
131 126
132/*
133* Lua code for the keeper states (baked in)
134*/
135static char keeper_chunk[]=
136#include "keeper.lch"
137
138// NOTE: values to be changed by either thread, during execution, without 127// NOTE: values to be changed by either thread, during execution, without
139// locking, are marked "volatile" 128// locking, are marked "volatile"
140// 129//
@@ -254,199 +243,6 @@ static bool_t push_registry_table( lua_State *L, void *key, bool_t create ) {
254} 243}
255 244
256 245
257/*---=== Serialize require ===---
258*/
259
260static MUTEX_T require_cs;
261
262//---
263// [val]= new_require( ... )
264//
265// Call 'old_require' but only one lane at a time.
266//
267// Upvalues: [1]: original 'require' function
268//
269static int new_require( lua_State *L ) {
270 int rc;
271 int args= lua_gettop(L);
272
273 STACK_GROW(L,1);
274 STACK_CHECK(L)
275
276 // Using 'lua_pcall()' to catch errors; otherwise a failing 'require' would
277 // leave us locked, blocking any future 'require' calls from other lanes.
278 //
279 MUTEX_LOCK( &require_cs );
280 {
281 lua_pushvalue( L, lua_upvalueindex(1) );
282 lua_insert( L, 1 );
283
284 rc= lua_pcall( L, args, 1 /*retvals*/, 0 /*errfunc*/ );
285 //
286 // LUA_ERRRUN / LUA_ERRMEM
287 }
288 MUTEX_UNLOCK( &require_cs );
289
290 if (rc) lua_error(L); // error message already at [-1]
291
292 STACK_END(L,0)
293 return 1;
294}
295
296/*
297* Serialize calls to 'require', if it exists
298*/
299static
300void serialize_require( lua_State *L ) {
301
302 STACK_GROW(L,1);
303 STACK_CHECK(L)
304
305 // Check 'require' is there; if not, do nothing
306 //
307 lua_getglobal( L, "require" );
308 if (lua_isfunction( L, -1 )) {
309 // [-1]: original 'require' function
310
311 lua_pushcclosure( L, new_require, 1 /*upvalues*/ );
312 lua_setglobal( L, "require" );
313
314 } else {
315 // [-1]: nil
316 lua_pop(L,1);
317 }
318
319 STACK_END(L,0)
320}
321
322
323/*---=== Keeper states ===---
324*/
325
326/*
327* Pool of keeper states
328*
329* Access to keeper states is locked (only one OS thread at a time) so the
330* bigger the pool, the less chances of unnecessary waits. Lindas map to the
331* keepers randomly, by a hash.
332*/
333struct s_Keeper
334{
335 MUTEX_T lock_;
336 lua_State *L;
337 //int count;
338} GKeepers[KEEPER_STATES_N];
339
340/* We could use an empty table in 'keeper.lua' as the sentinel, but maybe
341* checking for a lightuserdata is faster.
342*/
343static bool_t nil_sentinel;
344
345/*
346* Initialize keeper states
347*
348* If there is a problem, return an error message (NULL for okay).
349*
350* Note: Any problems would be design flaws; the created Lua state is left
351* unclosed, because it does not really matter. In production code, this
352* function never fails.
353*/
354static const char *init_keepers(void) {
355 unsigned int i;
356 for( i=0; i<KEEPER_STATES_N; i++ ) {
357
358 // Initialize Keeper states with bare minimum of libs (those required
359 // by 'keeper.lua')
360 //
361 lua_State *L= luaL_newstate();
362 if (!L) return "out of memory";
363
364 luaG_openlibs( L, "io,table,package" ); // 'io' for debugging messages, package because we need to require modules exporting idfuncs
365 serialize_require( L);
366
367 lua_pushlightuserdata( L, &nil_sentinel );
368 lua_setglobal( L, "nil_sentinel" );
369
370 // Read in the preloaded chunk (and run it)
371 //
372 if (luaL_loadbuffer( L, keeper_chunk, sizeof(keeper_chunk), "=lanes_keeper" ))
373 return "luaL_loadbuffer() failed"; // LUA_ERRMEM
374
375 if (lua_pcall( L, 0 /*args*/, 0 /*results*/, 0 /*errfunc*/ )) {
376 // LUA_ERRRUN / LUA_ERRMEM / LUA_ERRERR
377 //
378 const char *err= lua_tostring(L,-1);
379 assert(err);
380 return err;
381 }
382
383 MUTEX_INIT( &GKeepers[i].lock_ );
384 GKeepers[i].L= L;
385 //GKeepers[i].count = 0;
386 }
387 return NULL; // ok
388}
389
390static struct s_Keeper *keeper_acquire( const void *ptr)
391{
392 /*
393 * Any hashing will do that maps pointers to 0..KEEPER_STATES_N-1
394 * consistently.
395 *
396 * Pointers are often aligned by 8 or so - ignore the low order bits
397 */
398 unsigned int i= ((unsigned long)(ptr) >> 3) % KEEPER_STATES_N;
399 struct s_Keeper *K= &GKeepers[i];
400
401 MUTEX_LOCK( &K->lock_);
402 //++ K->count;
403 return K;
404}
405
406static void keeper_release( struct s_Keeper *K)
407{
408 //-- K->count;
409 MUTEX_UNLOCK( &K->lock_);
410}
411
412/*
413* Call a function ('func_name') in the keeper state, and pass on the returned
414* values to 'L'.
415*
416* 'linda': deep Linda pointer (used only as a unique table key, first parameter)
417* 'starting_index': first of the rest of parameters (none if 0)
418*
419* Returns: number of return values (pushed to 'L') or -1 in case of error
420*/
421static int keeper_call( lua_State *K, char const *func_name, lua_State *L, struct s_Linda *linda, uint_t starting_index)
422{
423 int const args = starting_index ? (lua_gettop(L) - starting_index +1) : 0;
424 int const Ktos = lua_gettop(K);
425 int retvals = -1;
426
427 STACK_GROW( K, 2);
428
429 lua_getglobal( K, func_name);
430 ASSERT_L( lua_isfunction(K, -1));
431
432 lua_pushlightuserdata( K, linda);
433
434 if( (args == 0) || luaG_inter_copy( L, K, args) == 0) // L->K
435 {
436 lua_call( K, 1 + args, LUA_MULTRET);
437
438 retvals = lua_gettop( K) - Ktos;
439 if( (retvals > 0) && luaG_inter_move( K, L, retvals) != 0) // K->L
440 {
441 retvals = -1;
442 }
443 }
444 // whatever happens, restore the stack to where it was at the origin
445 lua_settop( K, Ktos);
446 return retvals;
447}
448
449
450/*---=== Linda ===--- 246/*---=== Linda ===---
451*/ 247*/
452 248
@@ -1189,14 +985,7 @@ static void selfdestruct_atexit( void ) {
1189 DEBUGEXEC(fprintf( stderr, "Killed %d lane(s) at process end.\n", n )); 985 DEBUGEXEC(fprintf( stderr, "Killed %d lane(s) at process end.\n", n ));
1190#endif 986#endif
1191 } 987 }
1192 { 988 close_keepers();
1193 int i;
1194 for(i=0;i<KEEPER_STATES_N;i++){
1195 lua_close( GKeepers[i].L);
1196 GKeepers[i].L = 0;
1197 //assert( GKeepers[i].count == 0);
1198 }
1199 }
1200} 989}
1201 990
1202 991
diff --git a/src/tools.c b/src/tools.c
index 29959a8..d475fc0 100644
--- a/src/tools.c
+++ b/src/tools.c
@@ -1278,3 +1278,72 @@ int luaG_inter_move( lua_State* L, lua_State *L2, uint_t n )
1278 lua_pop( L, (int) n); 1278 lua_pop( L, (int) n);
1279 return ret; 1279 return ret;
1280} 1280}
1281
1282/*---=== Serialize require ===---
1283*/
1284
1285MUTEX_T require_cs;
1286
1287//---
1288// [val]= new_require( ... )
1289//
1290// Call 'old_require' but only one lane at a time.
1291//
1292// Upvalues: [1]: original 'require' function
1293//
1294static int new_require( lua_State *L )
1295{
1296 int rc;
1297 int args= lua_gettop(L);
1298
1299 STACK_GROW(L,1);
1300 STACK_CHECK(L)
1301
1302 // Using 'lua_pcall()' to catch errors; otherwise a failing 'require' would
1303 // leave us locked, blocking any future 'require' calls from other lanes.
1304 //
1305 MUTEX_LOCK( &require_cs);
1306 {
1307 lua_pushvalue( L, lua_upvalueindex(1) );
1308 lua_insert( L, 1 );
1309
1310 rc= lua_pcall( L, args, 1 /*retvals*/, 0 /*errfunc*/ );
1311 //
1312 // LUA_ERRRUN / LUA_ERRMEM
1313 }
1314 MUTEX_UNLOCK( &require_cs);
1315
1316 if (rc)
1317 lua_error(L); // error message already at [-1]
1318
1319 STACK_END(L,0)
1320 return 1;
1321}
1322
1323/*
1324* Serialize calls to 'require', if it exists
1325*/
1326void serialize_require( lua_State *L )
1327{
1328 STACK_GROW(L,1);
1329 STACK_CHECK(L)
1330
1331 // Check 'require' is there; if not, do nothing
1332 //
1333 lua_getglobal( L, "require" );
1334 if (lua_isfunction( L, -1 ))
1335 {
1336 // [-1]: original 'require' function
1337
1338 lua_pushcclosure( L, new_require, 1 /*upvalues*/ );
1339 lua_setglobal( L, "require" );
1340
1341 }
1342 else
1343 {
1344 // [-1]: nil
1345 lua_pop(L,1);
1346 }
1347
1348 STACK_END(L,0)
1349}
diff --git a/src/tools.h b/src/tools.h
index 0907df2..a080257 100644
--- a/src/tools.h
+++ b/src/tools.h
@@ -72,5 +72,8 @@ int luaG_inter_move( lua_State *L, lua_State *L2, uint_t n);
72extern MUTEX_T deep_lock; 72extern MUTEX_T deep_lock;
73extern MUTEX_T mtid_lock; 73extern MUTEX_T mtid_lock;
74 74
75void serialize_require( lua_State *L);
76extern MUTEX_T require_cs;
77
75#endif 78#endif
76 // TOOLS_H 79 // TOOLS_H