diff options
Diffstat (limited to 'src/keeper.c')
-rw-r--r-- | src/keeper.c | 199 |
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 | */ | ||
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 | } | ||