aboutsummaryrefslogtreecommitdiff
path: root/src/keeper.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/keeper.c')
-rw-r--r--src/keeper.c199
1 files changed, 199 insertions, 0 deletions
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}