aboutsummaryrefslogtreecommitdiff
path: root/src/lanes.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lanes.c')
-rw-r--r--src/lanes.c215
1 files changed, 2 insertions, 213 deletions
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