diff options
author | Benoit Germain <bnt.germain@gmail.com> | 2012-08-22 21:36:37 +0200 |
---|---|---|
committer | Benoit Germain <bnt.germain@gmail.com> | 2012-08-22 21:36:37 +0200 |
commit | f0b1c6d629464c0a59ac78382d86f434e74c2162 (patch) | |
tree | e6788f8e7c0e859cd5f8d9254a922e187d9e7938 | |
parent | a9075ff6cf43e99cee994f5e77d0e1e54cb8dbac (diff) | |
download | lanes-3.2.0.tar.gz lanes-3.2.0.tar.bz2 lanes-3.2.0.zip |
lanes version 3.2.0v3.2.0
* keeper internals implemented in C instead of Lua for better performances
* fixed arguments checks in linda:limit() and linda:set()
-rw-r--r-- | ABOUT | 2 | ||||
-rw-r--r-- | CHANGES | 4 | ||||
-rw-r--r-- | COPYRIGHT | 2 | ||||
-rw-r--r-- | Makefile | 3 | ||||
-rw-r--r-- | docs/index.html | 6 | ||||
-rw-r--r-- | src/keeper.c | 390 | ||||
-rw-r--r-- | src/keeper.h | 25 | ||||
-rw-r--r-- | src/lanes-keeper.lua | 2 | ||||
-rw-r--r-- | src/lanes.c | 31 |
9 files changed, 437 insertions, 28 deletions
@@ -3,7 +3,7 @@ Lua Lanes | |||
3 | --------- | 3 | --------- |
4 | 4 | ||
5 | Lanes is a lightweight, native, lazy evaluating multithreading library for | 5 | Lanes is a lightweight, native, lazy evaluating multithreading library for |
6 | Lua 5.1. It allows efficient use of multicore processors in Lua, by passing | 6 | Lua 5.1 and Lua 5.2. It allows efficient use of multicore processors in Lua, by passing |
7 | function calls into separate OS threads, and separate Lua states. | 7 | function calls into separate OS threads, and separate Lua states. |
8 | 8 | ||
9 | No locking of the threads is needed, only launching and waiting for (with an | 9 | No locking of the threads is needed, only launching and waiting for (with an |
@@ -1,5 +1,9 @@ | |||
1 | CHANGES: | 1 | CHANGES: |
2 | 2 | ||
3 | CHANGE 45: BGe 21-Aug-2012 | ||
4 | * keeper internals implemented in C instead of Lua for better performances | ||
5 | * fixed arguments checks in linda:limit() and linda:set() | ||
6 | |||
3 | CHANGE 44: BGe 13-Aug-2012 | 7 | CHANGE 44: BGe 13-Aug-2012 |
4 | * lanes code updated to build against Lua 5.1 and Lua 5.2 | 8 | * lanes code updated to build against Lua 5.1 and Lua 5.2 |
5 | * removed the search for MSVCR80.DLL when building for MinGW32 since it no longer seems to be necessary | 9 | * removed the search for MSVCR80.DLL when building for MinGW32 since it no longer seems to be necessary |
@@ -7,7 +7,7 @@ For details and rationale, see http://www.lua.org/license.html | |||
7 | =============================================================================== | 7 | =============================================================================== |
8 | 8 | ||
9 | Copyright (C) 2007-11 Asko Kauppi, <akauppi@gmail.com> | 9 | Copyright (C) 2007-11 Asko Kauppi, <akauppi@gmail.com> |
10 | Copyright (C) 2010-11 Benoit Germain, <bnt.germain@gmail.com> | 10 | Copyright (C) 2010-12 Benoit Germain, <bnt.germain@gmail.com> |
11 | 11 | ||
12 | Permission is hereby granted, free of charge, to any person obtaining a copy | 12 | Permission is hereby granted, free of charge, to any person obtaining a copy |
13 | of this software and associated documentation files (the "Software"), to deal | 13 | of this software and associated documentation files (the "Software"), to deal |
@@ -197,11 +197,10 @@ LUA_SHAREDIR=$(DESTDIR)/share/lua/5.1 | |||
197 | # | 197 | # |
198 | # AKa 17-Oct: changed to use 'install -m 644' and 'cp -p' | 198 | # AKa 17-Oct: changed to use 'install -m 644' and 'cp -p' |
199 | # | 199 | # |
200 | install: $(_TARGET_SO) src/lanes.lua src/lanes-keeper.lua | 200 | install: $(_TARGET_SO) src/lanes.lua |
201 | mkdir -p $(LUA_LIBDIR) $(LUA_LIBDIR)/lanes $(LUA_SHAREDIR) | 201 | mkdir -p $(LUA_LIBDIR) $(LUA_LIBDIR)/lanes $(LUA_SHAREDIR) |
202 | install -m 644 $(_TARGET_SO) $(LUA_LIBDIR)/lanes | 202 | install -m 644 $(_TARGET_SO) $(LUA_LIBDIR)/lanes |
203 | cp -p src/lanes.lua $(LUA_SHAREDIR) | 203 | cp -p src/lanes.lua $(LUA_SHAREDIR) |
204 | cp -p src/lanes-keeper.lua $(LUA_SHAREDIR) | ||
205 | 204 | ||
206 | 205 | ||
207 | #--- Packaging --- | 206 | #--- Packaging --- |
diff --git a/docs/index.html b/docs/index.html index 4e37fe6..84ae5c0 100644 --- a/docs/index.html +++ b/docs/index.html | |||
@@ -56,7 +56,7 @@ | |||
56 | 56 | ||
57 | <p><br/><font size="-1"><i>Copyright © 2007-12 Asko Kauppi, Benoit Germain. All rights reserved.</i> | 57 | <p><br/><font size="-1"><i>Copyright © 2007-12 Asko Kauppi, Benoit Germain. All rights reserved.</i> |
58 | <br>Lua Lanes is published under the same <A HREF="http://en.wikipedia.org/wiki/MIT_License">MIT license</A> as Lua 5.1 and 5.2. | 58 | <br>Lua Lanes is published under the same <A HREF="http://en.wikipedia.org/wiki/MIT_License">MIT license</A> as Lua 5.1 and 5.2. |
59 | </p><p>This document was revised on 13-Aug-12, and applies to version 3.1.6 | 59 | </p><p>This document was revised on 21-Aug-12, and applies to version 3.2.0 |
60 | </font></p> | 60 | </font></p> |
61 | 61 | ||
62 | </center> | 62 | </center> |
@@ -147,7 +147,7 @@ | |||
147 | details and limitations. | 147 | details and limitations. |
148 | </p> | 148 | </p> |
149 | 149 | ||
150 | <p>To install Lanes, all you need are the <tt>lanes.lua</tt> <tt>lanes-keeper.lua</tt> and <tt>lanes/core.so|dll</tt> | 150 | <p>To install Lanes, all you need are the <tt>lanes.lua</tt> and <tt>lanes/core.so|dll</tt> |
151 | files to be reachable by Lua (see LUA_PATH, LUA_CPATH). | 151 | files to be reachable by Lua (see LUA_PATH, LUA_CPATH). |
152 | 152 | ||
153 | Or use <A HREF="http://www.luarocks.org" TARGET="_blank">Lua Rocks</A> package management. | 153 | Or use <A HREF="http://www.luarocks.org" TARGET="_blank">Lua Rocks</A> package management. |
@@ -1070,7 +1070,7 @@ Here are some things one should consider, if best performance is vital: | |||
1070 | <li>Lindas are hashed to a fixed number of "keeper states", which are a locking entity. | 1070 | <li>Lindas are hashed to a fixed number of "keeper states", which are a locking entity. |
1071 | If you are using a lot of Linda objects, | 1071 | If you are using a lot of Linda objects, |
1072 | it may be useful to try having more of these keeper states. By default, | 1072 | it may be useful to try having more of these keeper states. By default, |
1073 | only one is used (see <tt>KEEPER_STATES_N</tt>), but this is an implementation detail. | 1073 | only one is used (see <tt>lanes.configure()</tt>). |
1074 | </li> | 1074 | </li> |
1075 | </ul> | 1075 | </ul> |
1076 | </p> | 1076 | </p> |
diff --git a/src/keeper.c b/src/keeper.c index 444a98e..86c69e2 100644 --- a/src/keeper.c +++ b/src/keeper.c | |||
@@ -14,7 +14,7 @@ | |||
14 | --[[ | 14 | --[[ |
15 | =============================================================================== | 15 | =============================================================================== |
16 | 16 | ||
17 | Copyright (C) 2011 Benoit Germain <bnt.germain@gmail.com> | 17 | Copyright (C) 2011-2012 Benoit Germain <bnt.germain@gmail.com> |
18 | 18 | ||
19 | Permission is hereby granted, free of charge, to any person obtaining a copy | 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 | 20 | of this software and associated documentation files (the "Software"), to deal |
@@ -50,6 +50,374 @@ | |||
50 | #include "tools.h" | 50 | #include "tools.h" |
51 | #include "keeper.h" | 51 | #include "keeper.h" |
52 | 52 | ||
53 | #if KEEPER_MODEL == KEEPER_MODEL_C | ||
54 | //################################################################################### | ||
55 | // Keeper implementation | ||
56 | //################################################################################### | ||
57 | |||
58 | typedef struct | ||
59 | { | ||
60 | int first; | ||
61 | int count; | ||
62 | int limit; | ||
63 | } keeper_fifo; | ||
64 | |||
65 | // replaces the fifo ud by its uservalue on the stack | ||
66 | static keeper_fifo* prepare_fifo_access( lua_State* L, int idx) | ||
67 | { | ||
68 | keeper_fifo* fifo = (keeper_fifo*) lua_touserdata( L, idx); | ||
69 | if( fifo) | ||
70 | { | ||
71 | idx = lua_absindex( L, idx); | ||
72 | STACK_GROW( L, 1); | ||
73 | // we can replace the fifo userdata in the stack without fear of it being GCed, there are other references around | ||
74 | lua_getuservalue( L, idx); | ||
75 | lua_replace( L, idx); | ||
76 | } | ||
77 | return fifo; | ||
78 | } | ||
79 | |||
80 | // in: nothing | ||
81 | // out: { first = 1, count = 0, limit = -1} | ||
82 | static void fifo_new( lua_State* L) | ||
83 | { | ||
84 | keeper_fifo* fifo; | ||
85 | STACK_GROW( L, 2); | ||
86 | fifo = (keeper_fifo*) lua_newuserdata( L, sizeof( keeper_fifo)); | ||
87 | fifo->first = 1; | ||
88 | fifo->count = 0; | ||
89 | fifo->limit = -1; | ||
90 | lua_newtable( L); | ||
91 | lua_setuservalue( L, -2); | ||
92 | } | ||
93 | |||
94 | // in: expect fifo ... on top of the stack | ||
95 | // out: nothing, removes all pushed values on the stack | ||
96 | static void fifo_push( lua_State* L, keeper_fifo* fifo, int _count) | ||
97 | { | ||
98 | int idx = lua_gettop( L) - _count; | ||
99 | int start = fifo->first + fifo->count - 1; | ||
100 | int i; | ||
101 | // pop all additional arguments, storing them in the fifo | ||
102 | for( i = _count; i >= 1; -- i) | ||
103 | { | ||
104 | // store in the fifo the value at the top of the stack at the specified index, popping it from the stack | ||
105 | lua_rawseti( L, idx, start + i); | ||
106 | } | ||
107 | fifo->count += _count; | ||
108 | } | ||
109 | |||
110 | // in: fifo | ||
111 | // out: ...|nothing | ||
112 | // expects exactly 1 value on the stack! | ||
113 | // currently only called with a count of 1, but this may change in the future | ||
114 | // function assumes that there is enough data in the fifo to satisfy the request | ||
115 | static void fifo_peek( lua_State* L, keeper_fifo* fifo, int _count) | ||
116 | { | ||
117 | int i; | ||
118 | STACK_GROW( L, _count); | ||
119 | for( i = 0; i < _count; ++ i) | ||
120 | { | ||
121 | lua_rawgeti( L, 1, fifo->first + i); | ||
122 | } | ||
123 | } | ||
124 | |||
125 | // in: fifo | ||
126 | // out: pushes as many items as required on the stack (function assumes they exist in sufficient number) | ||
127 | static void fifo_pop( lua_State* L, keeper_fifo* fifo, int _count) | ||
128 | { | ||
129 | int fifo_idx = lua_gettop( L); // ... fifo | ||
130 | int i; | ||
131 | // each iteration pushes a value on the stack! | ||
132 | STACK_GROW( L, _count + 1); | ||
133 | for( i = 0; i < _count; ++ i) | ||
134 | { | ||
135 | int at = fifo->first + i; | ||
136 | lua_rawgeti( L, fifo_idx, at); // ... fifo val | ||
137 | lua_pushnil( L); // ... fifo val nil | ||
138 | lua_rawseti( L, fifo_idx, at); // ... fifo val | ||
139 | } | ||
140 | fifo->first += _count; | ||
141 | fifo->count -= _count; | ||
142 | } | ||
143 | |||
144 | // in: linda_ud expected at *absolute* stack slot idx | ||
145 | // out: fifos[ud] | ||
146 | static void* const fifos_key = (void*) prepare_fifo_access; | ||
147 | static void push_table( lua_State* L, int idx) | ||
148 | { | ||
149 | STACK_GROW( L, 4); | ||
150 | STACK_CHECK( L) | ||
151 | idx = lua_absindex( L, idx); | ||
152 | lua_pushlightuserdata( L, fifos_key); // ud fifos_key | ||
153 | lua_rawget( L, LUA_REGISTRYINDEX); // ud fifos | ||
154 | lua_pushvalue( L, idx); // ud fifos ud | ||
155 | lua_rawget( L, -2); // ud fifos fifos[ud] | ||
156 | STACK_MID( L, 2); | ||
157 | if( lua_isnil( L, -1)) | ||
158 | { | ||
159 | lua_pop( L, 1); // ud fifos | ||
160 | // add a new fifos table for this linda | ||
161 | lua_newtable( L); // ud fifos fifos[ud] | ||
162 | lua_pushvalue( L, idx); // ud fifos fifos[ud] ud | ||
163 | lua_pushvalue( L, -2); // ud fifos fifos[ud] ud fifos[ud] | ||
164 | lua_rawset( L, -4); // ud fifos fifos[ud] | ||
165 | } | ||
166 | lua_remove( L, -2); // ud fifos[ud] | ||
167 | STACK_END( L, 1); | ||
168 | } | ||
169 | |||
170 | // in: linda_ud | ||
171 | int keepercall_clear( lua_State* L) | ||
172 | { | ||
173 | STACK_GROW( L, 3); | ||
174 | lua_pushlightuserdata( L, fifos_key); // ud fifos_key | ||
175 | lua_rawget( L, LUA_REGISTRYINDEX); // ud fifos | ||
176 | lua_pushvalue( L, 1); // ud fifos ud | ||
177 | lua_pushnil( L); // ud fifos ud nil | ||
178 | lua_rawset( L, -3); // ud fifos | ||
179 | lua_pop( L, 1); // ud | ||
180 | return 0; | ||
181 | } | ||
182 | |||
183 | |||
184 | // in: linda_ud, key, ... | ||
185 | // out: true|false | ||
186 | int keepercall_send( lua_State* L) | ||
187 | { | ||
188 | keeper_fifo* fifo; | ||
189 | int n = lua_gettop( L) - 2; | ||
190 | push_table( L, 1); // ud key ... fifos | ||
191 | // get the fifo associated to this key in this linda, create it if it doesn't exist | ||
192 | lua_pushvalue( L, 2); // ud key ... fifos key | ||
193 | lua_rawget( L, -2); // ud key ... fifos fifo | ||
194 | if( lua_isnil( L, -1)) | ||
195 | { | ||
196 | lua_pop( L, 1); // ud key ... fifos | ||
197 | fifo_new( L); // ud key ... fifos fifo | ||
198 | lua_pushvalue( L, 2); // ud key ... fifos fifo key | ||
199 | lua_pushvalue( L, -2); // ud key ... fifos fifo key fifo | ||
200 | lua_rawset( L, -4); // ud key ... fifos fifo | ||
201 | } | ||
202 | lua_remove( L, -2); // ud key ... fifo | ||
203 | fifo = (keeper_fifo*) lua_touserdata( L, -1); | ||
204 | if( fifo->limit >= 0 && fifo->count + n > fifo->limit) | ||
205 | { | ||
206 | lua_settop( L, 0); // | ||
207 | lua_pushboolean( L, 0); // false | ||
208 | } | ||
209 | else | ||
210 | { | ||
211 | fifo = prepare_fifo_access( L, -1); | ||
212 | lua_replace( L, 2); // ud fifo ... | ||
213 | fifo_push( L, fifo, n); // ud fifo | ||
214 | lua_settop( L, 0); // | ||
215 | lua_pushboolean( L, 1); // true | ||
216 | } | ||
217 | return 1; | ||
218 | } | ||
219 | |||
220 | // in: linda_ud, key [, key]? | ||
221 | // out: (val, key) or nothing | ||
222 | int keepercall_receive( lua_State* L) | ||
223 | { | ||
224 | int top = lua_gettop( L); | ||
225 | int i; | ||
226 | keeper_fifo* fifo; | ||
227 | push_table( L, 1); // ud keys fifos | ||
228 | lua_replace( L, 1); // fifos keys | ||
229 | for( i = 2; i <= top; ++ i) | ||
230 | { | ||
231 | lua_pushvalue( L, i); // fifos keys key[i] | ||
232 | lua_rawget( L, 1); // fifos keys fifo | ||
233 | fifo = prepare_fifo_access( L, -1); // fifos keys fifo | ||
234 | if( fifo && fifo->count > 0) | ||
235 | { | ||
236 | fifo_pop( L, fifo, 1); // fifos keys fifo val | ||
237 | if( !lua_isnil( L, -1)) | ||
238 | { | ||
239 | lua_replace( L, 1); // val keys fifo | ||
240 | if( i != 2) | ||
241 | { | ||
242 | lua_pushvalue( L, i); // val keys fifo key[i] | ||
243 | lua_replace( L, 2); // val key keys fifo | ||
244 | } | ||
245 | lua_settop( L, 2); // val key | ||
246 | return 2; | ||
247 | } | ||
248 | } | ||
249 | lua_settop( L, top); // data keys | ||
250 | } | ||
251 | // nothing to receive | ||
252 | return 0; | ||
253 | } | ||
254 | |||
255 | //in: linda_ud key mincount [maxcount] | ||
256 | int keepercall_receive_batched( lua_State* L) | ||
257 | { | ||
258 | int const min_count = (int) lua_tointeger( L, 3); | ||
259 | if( min_count > 0) | ||
260 | { | ||
261 | keeper_fifo* fifo; | ||
262 | int const max_count = (int) luaL_optinteger( L, 4, min_count); | ||
263 | lua_settop( L, 2); // ud key | ||
264 | push_table( L, 1); // ud key fifos | ||
265 | lua_replace( L, 1); // fifos key | ||
266 | lua_rawget( L, -2); // fifos fifo | ||
267 | lua_remove( L, 1); // fifo | ||
268 | fifo = prepare_fifo_access( L, 1); // fifo | ||
269 | if( fifo && fifo->count >= min_count) | ||
270 | { | ||
271 | fifo_pop( L, fifo, min( max_count, fifo->count)); // fifo ... | ||
272 | } | ||
273 | return lua_gettop( L) - 1; | ||
274 | } | ||
275 | else | ||
276 | { | ||
277 | return 0; | ||
278 | } | ||
279 | } | ||
280 | |||
281 | // in: linda_ud key n | ||
282 | // out: nothing | ||
283 | int keepercall_limit( lua_State* L) | ||
284 | { | ||
285 | keeper_fifo* fifo; | ||
286 | int limit = (int) lua_tointeger( L, 3); | ||
287 | push_table( L, 1); // ud key n fifos | ||
288 | lua_replace( L, 1); // fifos key n | ||
289 | lua_pop( L, 1); // fifos key | ||
290 | lua_pushvalue( L, -1); // fifos key key | ||
291 | lua_rawget( L, -3); // fifos key fifo | ||
292 | fifo = (keeper_fifo*) lua_touserdata( L, -1); | ||
293 | if( !fifo) | ||
294 | { | ||
295 | lua_pop( L, 1); // fifos key | ||
296 | fifo_new( L); // fifos key fifo | ||
297 | fifo = (keeper_fifo*) lua_touserdata( L, -1); | ||
298 | lua_rawset( L, -3); // fifos | ||
299 | } | ||
300 | fifo->limit = limit; | ||
301 | return 0; | ||
302 | } | ||
303 | |||
304 | //in: linda_ud key [val] | ||
305 | int keepercall_set( lua_State* L) | ||
306 | { | ||
307 | // make sure we have a value on the stack | ||
308 | if( lua_gettop( L) == 2) | ||
309 | { | ||
310 | lua_pushnil( L); | ||
311 | } | ||
312 | push_table( L, 1); // ud key val fifos | ||
313 | lua_replace( L, 1); // fifos key val | ||
314 | if( !lua_isnil( L, 3)) // replace contents stored at the specified key? | ||
315 | { | ||
316 | keeper_fifo* fifo; | ||
317 | fifo_new( L); // fifos key val fifo | ||
318 | lua_pushvalue( L, 2); // fifos key val fifo key | ||
319 | lua_pushvalue( L, -2); // fifos key val fifo key fifo | ||
320 | lua_rawset( L, 1); // fifos key val fifo | ||
321 | fifo = prepare_fifo_access( L, -1); | ||
322 | lua_insert( L, -2); // fifos key fifo val | ||
323 | fifo_push( L, fifo, 1); // fifos key fifo | ||
324 | } | ||
325 | else | ||
326 | { | ||
327 | // val == nil => stack contents: fifos key nil => remove the fifo associated with the current key | ||
328 | lua_rawset( L, 1); // fifos | ||
329 | } | ||
330 | return 0; | ||
331 | } | ||
332 | |||
333 | // in: linda_ud key | ||
334 | int keepercall_get( lua_State* L) | ||
335 | { | ||
336 | keeper_fifo* fifo; | ||
337 | push_table( L, 1); // ud key fifos | ||
338 | lua_replace( L, 1); // fifos key | ||
339 | lua_rawget( L, 1); // fifos fifo | ||
340 | fifo = prepare_fifo_access( L, -1); // fifos fifo | ||
341 | if( fifo && fifo->count > 0) | ||
342 | { | ||
343 | lua_remove( L, 1); // fifo | ||
344 | // read one value off the fifo | ||
345 | fifo_peek( L, fifo, 1); // fifo ... | ||
346 | return 1; | ||
347 | } | ||
348 | // no fifo was ever registered for this key, or it is empty | ||
349 | return 0; | ||
350 | } | ||
351 | |||
352 | // in: linda_ud [, key [, ...]] | ||
353 | int keepercall_count( lua_State* L) | ||
354 | { | ||
355 | int top; | ||
356 | push_table( L, 1); // ud keys fifos | ||
357 | switch( lua_gettop( L)) | ||
358 | { | ||
359 | // no key is specified: return a table giving the count of all known keys | ||
360 | case 2: // ud fifos | ||
361 | lua_newtable( L); // ud fifos out | ||
362 | lua_replace( L, 1); // out fifos | ||
363 | lua_pushnil( L); // out fifos nil | ||
364 | while( lua_next( L, 2)) // out fifos key fifo | ||
365 | { | ||
366 | keeper_fifo* fifo = prepare_fifo_access( L, -1); // out fifos key fifo | ||
367 | lua_pop( L, 1); // out fifos key | ||
368 | lua_pushvalue( L, -1); // out fifos key key | ||
369 | lua_pushinteger( L, fifo->count); // out fifos key key count | ||
370 | lua_rawset( L, -5); // out fifos key | ||
371 | } | ||
372 | lua_pop( L, 1); // out | ||
373 | break; | ||
374 | |||
375 | // 1 key is specified: return its count | ||
376 | case 3: // ud key fifos | ||
377 | { | ||
378 | keeper_fifo* fifo; | ||
379 | lua_replace( L, 1); // fifos key | ||
380 | lua_rawget( L, -2); // fifos fifo | ||
381 | fifo = prepare_fifo_access( L, -1); // fifos fifo | ||
382 | lua_pushinteger( L, fifo->count); // fifos fifo count | ||
383 | lua_replace( L, -3); // count fifo | ||
384 | lua_pop( L, 1); // count | ||
385 | } | ||
386 | break; | ||
387 | |||
388 | // a variable number of keys is specified: return a table of their counts | ||
389 | default: // ud keys fifos | ||
390 | lua_newtable( L); // ud keys fifos out | ||
391 | lua_replace( L, 1); // out keys fifos | ||
392 | // shifts all keys up in the stack. potentially slow if there are a lot of them, but then it should be bearable | ||
393 | lua_insert( L, 2); // out fifos keys | ||
394 | while( (top = lua_gettop( L)) > 2) | ||
395 | { | ||
396 | keeper_fifo* fifo; | ||
397 | lua_pushvalue( L, -1); // out fifos keys key | ||
398 | lua_rawget( L, 2); // out fifos keys fifo | ||
399 | fifo = prepare_fifo_access( L, -1); // out fifos keys fifo | ||
400 | lua_pop( L, 1); // out fifos keys | ||
401 | if( fifo) | ||
402 | { | ||
403 | lua_pushinteger( L, fifo->count); // out fifos keys count | ||
404 | lua_rawset( L, 1); // out fifos keys | ||
405 | } | ||
406 | else | ||
407 | { | ||
408 | lua_pop( L, 1); // out fifos keys | ||
409 | } | ||
410 | } | ||
411 | lua_pop( L, 1); // out | ||
412 | } | ||
413 | return 1; | ||
414 | } | ||
415 | #endif // KEEPER_MODEL == KEEPER_MODEL_C | ||
416 | |||
417 | //################################################################################### | ||
418 | // Keeper API, accessed from linda methods | ||
419 | //################################################################################### | ||
420 | |||
53 | /*---=== Keeper states ===--- | 421 | /*---=== Keeper states ===--- |
54 | */ | 422 | */ |
55 | 423 | ||
@@ -115,6 +483,14 @@ char const* init_keepers( int const _nbKeepers, lua_CFunction _on_state_create) | |||
115 | lua_concat( K, 2); | 483 | lua_concat( K, 2); |
116 | lua_setglobal( K, "decoda_name"); | 484 | lua_setglobal( K, "decoda_name"); |
117 | 485 | ||
486 | #if KEEPER_MODEL == KEEPER_MODEL_C | ||
487 | // create the fifos table in the keeper state | ||
488 | lua_pushlightuserdata( K, fifos_key); | ||
489 | lua_newtable( K); | ||
490 | lua_rawset( K, LUA_REGISTRYINDEX); | ||
491 | #endif // KEEPER_MODEL == KEEPER_MODEL_C | ||
492 | |||
493 | #if KEEPER_MODEL == KEEPER_MODEL_LUA | ||
118 | // use package.loaders[2] to find keeper microcode | 494 | // use package.loaders[2] to find keeper microcode |
119 | lua_getglobal( K, "package"); // package | 495 | lua_getglobal( K, "package"); // package |
120 | lua_getfield( K, -1, "loaders"); // package package.loaders | 496 | lua_getfield( K, -1, "loaders"); // package package.loaders |
@@ -132,6 +508,7 @@ char const* init_keepers( int const _nbKeepers, lua_CFunction _on_state_create) | |||
132 | } // package package.loaders | 508 | } // package package.loaders |
133 | STACK_MID( K, 2); | 509 | STACK_MID( K, 2); |
134 | lua_pop( K, 2); | 510 | lua_pop( K, 2); |
511 | #endif // KEEPER_MODEL == KEEPER_MODEL_LUA | ||
135 | STACK_END( K, 0) | 512 | STACK_END( K, 0) |
136 | MUTEX_INIT( &GKeepers[i].lock_); | 513 | MUTEX_INIT( &GKeepers[i].lock_); |
137 | GKeepers[i].L = K; | 514 | GKeepers[i].L = K; |
@@ -207,7 +584,7 @@ struct s_Keeper *keeper_acquire( const void *ptr) | |||
207 | * | 584 | * |
208 | * Pointers are often aligned by 8 or so - ignore the low order bits | 585 | * Pointers are often aligned by 8 or so - ignore the low order bits |
209 | */ | 586 | */ |
210 | unsigned int i= ((unsigned long)(ptr) >> 3) % GNbKeepers; | 587 | unsigned int i= ((uintptr_t)(ptr) >> 3) % GNbKeepers; |
211 | struct s_Keeper *K= &GKeepers[i]; | 588 | struct s_Keeper *K= &GKeepers[i]; |
212 | 589 | ||
213 | MUTEX_LOCK( &K->lock_); | 590 | MUTEX_LOCK( &K->lock_); |
@@ -259,16 +636,15 @@ void keeper_toggle_nil_sentinels( lua_State *L, int _val_i, int _nil_to_sentinel | |||
259 | * | 636 | * |
260 | * Returns: number of return values (pushed to 'L') or -1 in case of error | 637 | * Returns: number of return values (pushed to 'L') or -1 in case of error |
261 | */ | 638 | */ |
262 | int keeper_call( lua_State *K, char const *func_name, lua_State *L, void *linda, uint_t starting_index) | 639 | int keeper_call( lua_State *K, keeper_api_t _func, lua_State *L, void *linda, uint_t starting_index) |
263 | { | 640 | { |
264 | int const args = starting_index ? (lua_gettop(L) - starting_index +1) : 0; | 641 | int const args = starting_index ? (lua_gettop( L) - starting_index + 1) : 0; |
265 | int const Ktos = lua_gettop(K); | 642 | int const Ktos = lua_gettop( K); |
266 | int retvals = -1; | 643 | int retvals = -1; |
267 | 644 | ||
268 | STACK_GROW( K, 2); | 645 | STACK_GROW( K, 2); |
269 | 646 | ||
270 | lua_getglobal( K, func_name); | 647 | PUSH_KEEPER_FUNC( K, _func); |
271 | ASSERT_L( lua_isfunction(K, -1)); | ||
272 | 648 | ||
273 | lua_pushlightuserdata( K, linda); | 649 | lua_pushlightuserdata( K, linda); |
274 | 650 | ||
diff --git a/src/keeper.h b/src/keeper.h index 6c4c6f9..a0ea8c5 100644 --- a/src/keeper.h +++ b/src/keeper.h | |||
@@ -13,7 +13,30 @@ void populate_keepers( lua_State *L); | |||
13 | struct s_Keeper *keeper_acquire( const void *ptr); | 13 | struct s_Keeper *keeper_acquire( const void *ptr); |
14 | void keeper_release( struct s_Keeper *K); | 14 | void keeper_release( struct s_Keeper *K); |
15 | void keeper_toggle_nil_sentinels( lua_State *L, int _val_i, int _nil_to_sentinel); | 15 | void keeper_toggle_nil_sentinels( lua_State *L, int _val_i, int _nil_to_sentinel); |
16 | int keeper_call( lua_State *K, char const *func_name, lua_State *L, void *linda, uint_t starting_index); | ||
17 | 16 | ||
17 | #define KEEPER_MODEL_LUA 1 | ||
18 | #define KEEPER_MODEL_C 2 | ||
19 | #define KEEPER_MODEL KEEPER_MODEL_C | ||
20 | |||
21 | #if KEEPER_MODEL == KEEPER_MODEL_LUA | ||
22 | typedef char const* keeper_api_t; | ||
23 | #define KEEPER_API( _op) #_op | ||
24 | #define PUSH_KEEPER_FUNC( K, _api) lua_getglobal( K, _api) | ||
25 | #elif KEEPER_MODEL == KEEPER_MODEL_C | ||
26 | typedef lua_CFunction keeper_api_t; | ||
27 | #define KEEPER_API( _op) keepercall_ ## _op | ||
28 | #define PUSH_KEEPER_FUNC lua_pushcfunction | ||
29 | // lua_Cfunctions to run inside a keeper state (formerly implemented in Lua) | ||
30 | int keepercall_clear( lua_State* L); | ||
31 | int keepercall_send( lua_State* L); | ||
32 | int keepercall_receive( lua_State* L); | ||
33 | int keepercall_receive_batched( lua_State* L); | ||
34 | int keepercall_limit( lua_State* L); | ||
35 | int keepercall_get( lua_State* L); | ||
36 | int keepercall_set( lua_State* L); | ||
37 | int keepercall_count( lua_State* L); | ||
38 | #endif // KEEPER_MODEL | ||
39 | |||
40 | int keeper_call( lua_State *K, keeper_api_t _func, lua_State *L, void *linda, uint_t starting_index); | ||
18 | 41 | ||
19 | #endif // __keeper_h__ \ No newline at end of file | 42 | #endif // __keeper_h__ \ No newline at end of file |
diff --git a/src/lanes-keeper.lua b/src/lanes-keeper.lua index 1f17599..b07d6a9 100644 --- a/src/lanes-keeper.lua +++ b/src/lanes-keeper.lua | |||
@@ -2,6 +2,8 @@ | |||
2 | -- KEEPER.LUA | 2 | -- KEEPER.LUA |
3 | -- | 3 | -- |
4 | -- Keeper state logic | 4 | -- Keeper state logic |
5 | -- DEPRECATED BY THE EQUIVALENT C IMPLEMENTATION, KEPT FOR REFERENCE ONLY | ||
6 | -- SHOULD NOT BE PART OF THE INSTALLATION ANYMORE | ||
5 | -- | 7 | -- |
6 | -- This code is read in for each "keeper state", which are the hidden, inter- | 8 | -- This code is read in for each "keeper state", which are the hidden, inter- |
7 | -- mediate data stores used by Lanes inter-state communication objects. | 9 | -- mediate data stores used by Lanes inter-state communication objects. |
diff --git a/src/lanes.c b/src/lanes.c index 8f5768f..9f455b2 100644 --- a/src/lanes.c +++ b/src/lanes.c | |||
@@ -51,7 +51,7 @@ | |||
51 | * ... | 51 | * ... |
52 | */ | 52 | */ |
53 | 53 | ||
54 | char const* VERSION = "3.1.6"; | 54 | char const* VERSION = "3.2.0"; |
55 | 55 | ||
56 | /* | 56 | /* |
57 | =============================================================================== | 57 | =============================================================================== |
@@ -309,7 +309,7 @@ LUAG_FUNC( linda_send) | |||
309 | for( ;;) | 309 | for( ;;) |
310 | { | 310 | { |
311 | STACK_MID(KL, 0) | 311 | STACK_MID(KL, 0) |
312 | pushed = keeper_call( KL, "send", L, linda, key_i); | 312 | pushed = keeper_call( KL, KEEPER_API( send), L, linda, key_i); |
313 | if( pushed < 0) | 313 | if( pushed < 0) |
314 | { | 314 | { |
315 | break; | 315 | break; |
@@ -410,7 +410,7 @@ LUAG_FUNC( linda_receive) | |||
410 | struct s_Linda *linda = lua_toLinda( L, 1); | 410 | struct s_Linda *linda = lua_toLinda( L, 1); |
411 | int pushed, expected_pushed_min, expected_pushed_max; | 411 | int pushed, expected_pushed_min, expected_pushed_max; |
412 | bool_t cancel = FALSE; | 412 | bool_t cancel = FALSE; |
413 | char *keeper_receive; | 413 | keeper_api_t keeper_receive; |
414 | 414 | ||
415 | time_d timeout = -1.0; | 415 | time_d timeout = -1.0; |
416 | uint_t key_i = 2; | 416 | uint_t key_i = 2; |
@@ -440,7 +440,7 @@ LUAG_FUNC( linda_receive) | |||
440 | // make sure the keys are of a valid type | 440 | // make sure the keys are of a valid type |
441 | check_key_types( L, key_i, key_i); | 441 | check_key_types( L, key_i, key_i); |
442 | // receive multiple values from a single slot | 442 | // receive multiple values from a single slot |
443 | keeper_receive = "receive_batched"; | 443 | keeper_receive = KEEPER_API( receive_batched); |
444 | // we expect a user-defined amount of return value | 444 | // we expect a user-defined amount of return value |
445 | expected_pushed_min = (int)luaL_checkinteger( L, key_i + 1); | 445 | expected_pushed_min = (int)luaL_checkinteger( L, key_i + 1); |
446 | expected_pushed_max = (int)luaL_optinteger( L, key_i + 2, expected_pushed_min); | 446 | expected_pushed_max = (int)luaL_optinteger( L, key_i + 2, expected_pushed_min); |
@@ -454,7 +454,7 @@ LUAG_FUNC( linda_receive) | |||
454 | // make sure the keys are of a valid type | 454 | // make sure the keys are of a valid type |
455 | check_key_types( L, key_i, lua_gettop( L)); | 455 | check_key_types( L, key_i, lua_gettop( L)); |
456 | // receive a single value, checking multiple slots | 456 | // receive a single value, checking multiple slots |
457 | keeper_receive = "receive"; | 457 | keeper_receive = KEEPER_API( receive); |
458 | // we expect a single (value, key) pair of returned values | 458 | // we expect a single (value, key) pair of returned values |
459 | expected_pushed_min = expected_pushed_max = 2; | 459 | expected_pushed_min = expected_pushed_max = 2; |
460 | } | 460 | } |
@@ -558,6 +558,7 @@ LUAG_FUNC( linda_set) | |||
558 | struct s_Linda *linda = lua_toLinda( L, 1); | 558 | struct s_Linda *linda = lua_toLinda( L, 1); |
559 | bool_t has_value = !lua_isnil( L, 3); | 559 | bool_t has_value = !lua_isnil( L, 3); |
560 | luaL_argcheck( L, linda, 1, "expected a linda object!"); | 560 | luaL_argcheck( L, linda, 1, "expected a linda object!"); |
561 | luaL_argcheck( L, lua_gettop( L) <= 3, 4, "too many arguments"); | ||
561 | 562 | ||
562 | // make sure the key is of a valid type | 563 | // make sure the key is of a valid type |
563 | check_key_types( L, 2, 2); | 564 | check_key_types( L, 2, 2); |
@@ -566,7 +567,7 @@ LUAG_FUNC( linda_set) | |||
566 | int pushed; | 567 | int pushed; |
567 | struct s_Keeper *K = keeper_acquire( linda); | 568 | struct s_Keeper *K = keeper_acquire( linda); |
568 | // no nil->sentinel toggling, we really clear the linda contents for the given key with a set() | 569 | // no nil->sentinel toggling, we really clear the linda contents for the given key with a set() |
569 | pushed = keeper_call( K->L, "set", L, linda, 2); | 570 | pushed = keeper_call( K->L, KEEPER_API( set), L, linda, 2); |
570 | if( pushed >= 0) // no error? | 571 | if( pushed >= 0) // no error? |
571 | { | 572 | { |
572 | ASSERT_L( pushed == 0); | 573 | ASSERT_L( pushed == 0); |
@@ -606,7 +607,7 @@ LUAG_FUNC( linda_count) | |||
606 | 607 | ||
607 | { | 608 | { |
608 | struct s_Keeper *K = keeper_acquire( linda); | 609 | struct s_Keeper *K = keeper_acquire( linda); |
609 | pushed = keeper_call( K->L, "count", L, linda, 2); | 610 | pushed = keeper_call( K->L, KEEPER_API( count), L, linda, 2); |
610 | keeper_release( K); | 611 | keeper_release( K); |
611 | if( pushed < 0) | 612 | if( pushed < 0) |
612 | { | 613 | { |
@@ -634,7 +635,7 @@ LUAG_FUNC( linda_get) | |||
634 | 635 | ||
635 | { | 636 | { |
636 | struct s_Keeper *K = keeper_acquire( linda); | 637 | struct s_Keeper *K = keeper_acquire( linda); |
637 | pushed = keeper_call( K->L, "get", L, linda, 2); | 638 | pushed = keeper_call( K->L, KEEPER_API( get), L, linda, 2); |
638 | ASSERT_L( pushed==0 || pushed==1 ); | 639 | ASSERT_L( pushed==0 || pushed==1 ); |
639 | if( pushed > 0) | 640 | if( pushed > 0) |
640 | { | 641 | { |
@@ -659,15 +660,19 @@ LUAG_FUNC( linda_get) | |||
659 | */ | 660 | */ |
660 | LUAG_FUNC( linda_limit) | 661 | LUAG_FUNC( linda_limit) |
661 | { | 662 | { |
662 | struct s_Linda *linda= lua_toLinda( L, 1 ); | 663 | struct s_Linda* linda= lua_toLinda( L, 1 ); |
663 | 664 | ||
664 | luaL_argcheck( L, linda, 1, "expected a linda object!"); | 665 | luaL_argcheck( L, linda, 1, "expected a linda object!"); |
666 | // make sure we got a key and a limit | ||
667 | luaL_argcheck( L, lua_gettop( L) == 3, 2, "wrong number of arguments"); | ||
668 | // make sure we got a numeric limit | ||
669 | luaL_checknumber( L, 3); | ||
665 | // make sure the key is of a valid type | 670 | // make sure the key is of a valid type |
666 | check_key_types( L, 2, 2); | 671 | check_key_types( L, 2, 2); |
667 | 672 | ||
668 | { | 673 | { |
669 | struct s_Keeper *K = keeper_acquire( linda); | 674 | struct s_Keeper* K = keeper_acquire( linda); |
670 | int pushed = keeper_call( K->L, "limit", L, linda, 2); | 675 | int pushed = keeper_call( K->L, KEEPER_API( limit), L, linda, 2); |
671 | ASSERT_L( pushed <= 0); // either error or no return values | 676 | ASSERT_L( pushed <= 0); // either error or no return values |
672 | keeper_release( K); | 677 | keeper_release( K); |
673 | // must trigger error after keeper state has been released | 678 | // must trigger error after keeper state has been released |
@@ -825,8 +830,8 @@ static void linda_id( lua_State *L, char const * const which) | |||
825 | K= keeper_acquire(s); | 830 | K= keeper_acquire(s); |
826 | if( K && K->L) // can be NULL if this happens during main state shutdown (lanes is GC'ed -> no keepers -> no need to cleanup) | 831 | if( K && K->L) // can be NULL if this happens during main state shutdown (lanes is GC'ed -> no keepers -> no need to cleanup) |
827 | { | 832 | { |
828 | keeper_call( K->L, "clear", L, s, 0 ); | 833 | keeper_call( K->L, KEEPER_API( clear), L, s, 0 ); |
829 | keeper_release(K); | 834 | keeper_release( K); |
830 | } | 835 | } |
831 | 836 | ||
832 | /* There aren't any lanes waiting on these lindas, since all proxies | 837 | /* There aren't any lanes waiting on these lindas, since all proxies |