diff options
| author | Benoit Germain <bnt.germain@gmail.com> | 2011-02-18 20:33:43 +0100 |
|---|---|---|
| committer | Benoit Germain <bnt.germain@gmail.com> | 2011-02-18 20:33:43 +0100 |
| commit | 1760eafa1d2ebce8f07e11414a53d4a251af5b8e (patch) | |
| tree | 18f2fcd400bb35528212930c4e61be04be31bea0 /src | |
| parent | ab233d0c9a1edc34836e2249c1eb6d714f1066b5 (diff) | |
| download | lanes-1760eafa1d2ebce8f07e11414a53d4a251af5b8e.tar.gz lanes-1760eafa1d2ebce8f07e11414a53d4a251af5b8e.tar.bz2 lanes-1760eafa1d2ebce8f07e11414a53d4a251af5b8e.zip | |
* 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
Diffstat (limited to 'src')
| -rw-r--r-- | src/Makefile | 12 | ||||
| -rw-r--r-- | src/keeper.c | 199 | ||||
| -rw-r--r-- | src/keeper.h | 18 | ||||
| -rw-r--r-- | src/keeper.lua | 28 | ||||
| -rw-r--r-- | src/lanes.c | 215 | ||||
| -rw-r--r-- | src/tools.c | 69 | ||||
| -rw-r--r-- | src/tools.h | 3 |
7 files changed, 313 insertions, 231 deletions
diff --git a/src/Makefile b/src/Makefile index a17e9cd..df65926 100644 --- a/src/Makefile +++ b/src/Makefile | |||
| @@ -7,7 +7,7 @@ | |||
| 7 | 7 | ||
| 8 | MODULE=lanes | 8 | MODULE=lanes |
| 9 | 9 | ||
| 10 | SRC=lanes.c threading.c tools.c | 10 | SRC=lanes.c threading.c tools.c keeper.c |
| 11 | 11 | ||
| 12 | OBJ=$(SRC:.c=.o) | 12 | OBJ=$(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 | */ | ||
| 69 | static 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 | */ | ||
| 74 | static bool_t nil_sentinel = 0; | ||
| 75 | |||
| 76 | /* | ||
| 77 | * Lua code for the keeper states (baked in) | ||
| 78 | */ | ||
| 79 | static 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 | */ | ||
| 91 | const 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 | |||
| 131 | struct 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 | |||
| 147 | void 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 | */ | ||
| 162 | int 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 | |||
| 190 | void 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 | |||
| 4 | struct s_Keeper | ||
| 5 | { | ||
| 6 | MUTEX_T lock_; | ||
| 7 | lua_State *L; | ||
| 8 | //int count; | ||
| 9 | }; | ||
| 10 | |||
| 11 | const char *init_keepers(void); | ||
| 12 | struct s_Keeper *keeper_acquire( const void *ptr); | ||
| 13 | void keeper_release( struct s_Keeper *K); | ||
| 14 | int keeper_call( lua_State *K, char const *func_name, lua_State *L, void *linda, uint_t starting_index); | ||
| 15 | void 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 ) | |||
| 43 | local table_remove= assert( table.remove ) | 43 | local table_remove= assert( table.remove ) |
| 44 | local table_concat= assert( table.concat ) | 44 | local table_concat= assert( table.concat ) |
| 45 | 45 | ||
| 46 | --[[ | ||
| 46 | local function WR(...) | 47 | local 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 |
| 50 | end | 51 | end |
| 51 | 52 | ||
| 53 | local 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 ) | ||
| 63 | end | ||
| 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] |
| 93 | end | 107 | end |
| 94 | 108 | ||
| 95 | |||
| 96 | local 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 ) | ||
| 106 | end | ||
| 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 | */ | ||
| 135 | static 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 | |||
| 260 | static 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 | // | ||
| 269 | static 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 | */ | ||
| 299 | static | ||
| 300 | void 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 | */ | ||
| 333 | struct 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 | */ | ||
| 343 | static 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 | */ | ||
| 354 | static 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 | |||
| 390 | static 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 | |||
| 406 | static 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 | */ | ||
| 421 | static 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 | |||
| 1285 | MUTEX_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 | // | ||
| 1294 | static 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 | */ | ||
| 1326 | void 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); | |||
| 72 | extern MUTEX_T deep_lock; | 72 | extern MUTEX_T deep_lock; |
| 73 | extern MUTEX_T mtid_lock; | 73 | extern MUTEX_T mtid_lock; |
| 74 | 74 | ||
| 75 | void serialize_require( lua_State *L); | ||
| 76 | extern MUTEX_T require_cs; | ||
| 77 | |||
| 75 | #endif | 78 | #endif |
| 76 | // TOOLS_H | 79 | // TOOLS_H |
