aboutsummaryrefslogtreecommitdiff
path: root/src/linda.c
diff options
context:
space:
mode:
authorBenoit Germain <bnt.germain@gmail.com>2018-11-15 09:24:46 +0100
committerBenoit Germain <bnt.germain@gmail.com>2018-11-15 09:24:46 +0100
commitf087dfe25d093b1cb1665d12dc5a039f29f3af11 (patch)
tree14dbc119b902e8c2db22ed78ae4d7ed4e718790e /src/linda.c
parentb0bb224ce6c4bd769a3f1a868e832d9d38f6e63e (diff)
downloadlanes-f087dfe25d093b1cb1665d12dc5a039f29f3af11.tar.gz
lanes-f087dfe25d093b1cb1665d12dc5a039f29f3af11.tar.bz2
lanes-f087dfe25d093b1cb1665d12dc5a039f29f3af11.zip
split linda code in a separate file
Diffstat (limited to 'src/linda.c')
-rw-r--r--src/linda.c934
1 files changed, 934 insertions, 0 deletions
diff --git a/src/linda.c b/src/linda.c
new file mode 100644
index 0000000..98d2a8e
--- /dev/null
+++ b/src/linda.c
@@ -0,0 +1,934 @@
1/*
2 * LINDA.C Copyright (c) 2018, Benoit Germain
3 *
4 * Linda deep userdata.
5*/
6
7/*
8===============================================================================
9
10Copyright (C) 2018 benoit Germain <bnt.germain@gmail.com>
11
12Permission is hereby granted, free of charge, to any person obtaining a copy
13of this software and associated documentation files (the "Software"), to deal
14in the Software without restriction, including without limitation the rights
15to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
16copies of the Software, and to permit persons to whom the Software is
17furnished to do so, subject to the following conditions:
18
19The above copyright notice and this permission notice shall be included in
20all copies or substantial portions of the Software.
21
22THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
25AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
28THE SOFTWARE.
29
30===============================================================================
31*/
32
33#include <stdlib.h>
34
35#include "threading.h"
36#include "compat.h"
37#include "tools.h"
38#include "universe.h"
39#include "keeper.h"
40#include "deep.h"
41#include "lanes_private.h"
42
43/*
44* Actual data is kept within a keeper state, which is hashed by the 's_Linda'
45* pointer (which is same to all userdatas pointing to it).
46*/
47struct s_Linda
48{
49 SIGNAL_T read_happened;
50 SIGNAL_T write_happened;
51 Universe* U; // the universe this linda belongs to
52 ptrdiff_t group; // a group to control keeper allocation between lindas
53 enum e_cancel_request simulate_cancel;
54 char name[1];
55};
56#define LINDA_KEEPER_HASHSEED( linda) (linda->group ? linda->group : (ptrdiff_t)linda)
57
58static void* linda_id( lua_State*, DeepOp);
59
60static inline struct s_Linda* lua_toLinda( lua_State* L, int idx_)
61{
62 struct s_Linda* linda = (struct s_Linda*) luaG_todeep( L, linda_id, idx_);
63 luaL_argcheck( L, linda != NULL, idx_, "expecting a linda object");
64 return linda;
65}
66
67static void check_key_types( lua_State* L, int start_, int end_)
68{
69 int i;
70 for( i = start_; i <= end_; ++ i)
71 {
72 int t = lua_type( L, i);
73 if( t == LUA_TBOOLEAN || t == LUA_TNUMBER || t == LUA_TSTRING || t == LUA_TLIGHTUSERDATA)
74 {
75 continue;
76 }
77 (void) luaL_error( L, "argument #%d: invalid key type (not a boolean, string, number or light userdata)", i);
78 }
79}
80
81LUAG_FUNC( linda_protected_call)
82{
83 int rc = LUA_OK;
84 struct s_Linda* linda = lua_toLinda( L, 1);
85
86 // acquire the keeper
87 Keeper* K = keeper_acquire( linda->U->keepers, LINDA_KEEPER_HASHSEED(linda));
88 lua_State* KL = K ? K->L : NULL; // need to do this for 'STACK_CHECK'
89 if( KL == NULL) return 0;
90
91 // retrieve the actual function to be called and move it before the arguments
92 lua_pushvalue( L, lua_upvalueindex( 1));
93 lua_insert( L, 1);
94 // do a protected call
95 rc = lua_pcall( L, lua_gettop( L) - 1, LUA_MULTRET, 0);
96
97 // release the keeper
98 keeper_release( K);
99
100 // if there was an error, forward it
101 if( rc != LUA_OK)
102 {
103 return lua_error( L);
104 }
105 // return whatever the actual operation provided
106 return lua_gettop( L);
107}
108
109/*
110* bool= linda_send( linda_ud, [timeout_secs=-1,] [linda.null,] key_num|str|bool|lightuserdata, ... )
111*
112* Send one or more values to a Linda. If there is a limit, all values must fit.
113*
114* Returns: 'true' if the value was queued
115* 'false' for timeout (only happens when the queue size is limited)
116* nil, CANCEL_ERROR if cancelled
117*/
118LUAG_FUNC( linda_send)
119{
120 struct s_Linda* linda = lua_toLinda( L, 1);
121 bool_t ret = FALSE;
122 enum e_cancel_request cancel = CANCEL_NONE;
123 int pushed;
124 time_d timeout = -1.0;
125 uint_t key_i = 2; // index of first key, if timeout not there
126 bool_t as_nil_sentinel; // if not NULL, send() will silently send a single nil if nothing is provided
127
128 if( lua_type( L, 2) == LUA_TNUMBER) // we don't want to use lua_isnumber() because of autocoercion
129 {
130 timeout = SIGNAL_TIMEOUT_PREPARE( lua_tonumber( L, 2));
131 ++ key_i;
132 }
133 else if( lua_isnil( L, 2)) // alternate explicit "no timeout" by passing nil before the key
134 {
135 ++ key_i;
136 }
137
138 as_nil_sentinel = equal_unique_key( L, key_i, NIL_SENTINEL);
139 if( as_nil_sentinel)
140 {
141 // the real key to send data to is after the NIL_SENTINEL marker
142 ++ key_i;
143 }
144
145 // make sure the key is of a valid type
146 check_key_types( L, key_i, key_i);
147
148 STACK_GROW( L, 1);
149
150 // make sure there is something to send
151 if( (uint_t)lua_gettop( L) == key_i)
152 {
153 if( as_nil_sentinel)
154 {
155 // send a single nil if nothing is provided
156 push_unique_key( L, NIL_SENTINEL);
157 }
158 else
159 {
160 return luaL_error( L, "no data to send");
161 }
162 }
163
164 // convert nils to some special non-nil sentinel in sent values
165 keeper_toggle_nil_sentinels( L, key_i + 1, eLM_ToKeeper);
166
167 {
168 bool_t try_again = TRUE;
169 Lane* const s = get_lane_from_registry( L);
170 Keeper* K = which_keeper( linda->U->keepers, LINDA_KEEPER_HASHSEED( linda));
171 lua_State* KL = K ? K->L : NULL; // need to do this for 'STACK_CHECK'
172 if( KL == NULL) return 0;
173 STACK_CHECK( KL);
174 for( ;;)
175 {
176 if( s != NULL)
177 {
178 cancel = s->cancel_request;
179 }
180 cancel = (cancel != CANCEL_NONE) ? cancel : linda->simulate_cancel;
181 // if user wants to cancel, or looped because of a timeout, the call returns without sending anything
182 if( !try_again || cancel != CANCEL_NONE)
183 {
184 pushed = 0;
185 break;
186 }
187
188 STACK_MID( KL, 0);
189 pushed = keeper_call( linda->U, KL, KEEPER_API( send), L, linda, key_i);
190 if( pushed < 0)
191 {
192 break;
193 }
194 ASSERT_L( pushed == 1);
195
196 ret = lua_toboolean( L, -1);
197 lua_pop( L, 1);
198
199 if( ret)
200 {
201 // Wake up ALL waiting threads
202 SIGNAL_ALL( &linda->write_happened);
203 break;
204 }
205
206 // instant timout to bypass the wait syscall
207 if( timeout == 0.0)
208 {
209 break; /* no wait; instant timeout */
210 }
211
212 // storage limit hit, wait until timeout or signalled that we should try again
213 {
214 enum e_status prev_status = ERROR_ST; // prevent 'might be used uninitialized' warnings
215 if( s != NULL)
216 {
217 // change status of lane to "waiting"
218 prev_status = s->status; // RUNNING, most likely
219 ASSERT_L( prev_status == RUNNING); // but check, just in case
220 s->status = WAITING;
221 ASSERT_L( s->waiting_on == NULL);
222 s->waiting_on = &linda->read_happened;
223 }
224 // could not send because no room: wait until some data was read before trying again, or until timeout is reached
225 try_again = SIGNAL_WAIT( &linda->read_happened, &K->keeper_cs, timeout);
226 if( s != NULL)
227 {
228 s->waiting_on = NULL;
229 s->status = prev_status;
230 }
231 }
232 }
233 STACK_END( KL, 0);
234 }
235
236 if( pushed < 0)
237 {
238 return luaL_error( L, "tried to copy unsupported types");
239 }
240
241 switch( cancel)
242 {
243 case CANCEL_SOFT:
244 // if user wants to soft-cancel, the call returns lanes.cancel_error
245 push_unique_key( L, CANCEL_ERROR);
246 return 1;
247
248 case CANCEL_HARD:
249 // raise an error interrupting execution only in case of hard cancel
250 return cancel_error( L); // raises an error and doesn't return
251
252 default:
253 lua_pushboolean( L, ret); // true (success) or false (timeout)
254 return 1;
255 }
256}
257
258
259/*
260 * 2 modes of operation
261 * [val, key]= linda_receive( linda_ud, [timeout_secs_num=-1], key_num|str|bool|lightuserdata [, ...] )
262 * Consumes a single value from the Linda, in any key.
263 * Returns: received value (which is consumed from the slot), and the key which had it
264
265 * [val1, ... valCOUNT]= linda_receive( linda_ud, [timeout_secs_num=-1], linda.batched, key_num|str|bool|lightuserdata, min_COUNT[, max_COUNT])
266 * Consumes between min_COUNT and max_COUNT values from the linda, from a single key.
267 * returns the actual consumed values, or nil if there weren't enough values to consume
268 *
269 */
270#define BATCH_SENTINEL "270e6c9d-280f-4983-8fee-a7ecdda01475"
271LUAG_FUNC( linda_receive)
272{
273 struct s_Linda* linda = lua_toLinda( L, 1);
274 int pushed, expected_pushed_min, expected_pushed_max;
275 enum e_cancel_request cancel = CANCEL_NONE;
276 keeper_api_t keeper_receive;
277
278 time_d timeout = -1.0;
279 uint_t key_i = 2;
280
281 if( lua_type( L, 2) == LUA_TNUMBER) // we don't want to use lua_isnumber() because of autocoercion
282 {
283 timeout = SIGNAL_TIMEOUT_PREPARE( lua_tonumber( L, 2));
284 ++ key_i;
285 }
286 else if( lua_isnil( L, 2)) // alternate explicit "no timeout" by passing nil before the key
287 {
288 ++ key_i;
289 }
290
291 // are we in batched mode?
292 {
293 int is_batched;
294 lua_pushliteral( L, BATCH_SENTINEL);
295 is_batched = lua501_equal( L, key_i, -1);
296 lua_pop( L, 1);
297 if( is_batched)
298 {
299 // no need to pass linda.batched in the keeper state
300 ++ key_i;
301 // make sure the keys are of a valid type
302 check_key_types( L, key_i, key_i);
303 // receive multiple values from a single slot
304 keeper_receive = KEEPER_API( receive_batched);
305 // we expect a user-defined amount of return value
306 expected_pushed_min = (int)luaL_checkinteger( L, key_i + 1);
307 expected_pushed_max = (int)luaL_optinteger( L, key_i + 2, expected_pushed_min);
308 // don't forget to count the key in addition to the values
309 ++ expected_pushed_min;
310 ++ expected_pushed_max;
311 if( expected_pushed_min > expected_pushed_max)
312 {
313 return luaL_error( L, "batched min/max error");
314 }
315 }
316 else
317 {
318 // make sure the keys are of a valid type
319 check_key_types( L, key_i, lua_gettop( L));
320 // receive a single value, checking multiple slots
321 keeper_receive = KEEPER_API( receive);
322 // we expect a single (value, key) pair of returned values
323 expected_pushed_min = expected_pushed_max = 2;
324 }
325 }
326
327 {
328 bool_t try_again = TRUE;
329 Lane* const s = get_lane_from_registry( L);
330 Keeper* K = which_keeper( linda->U->keepers, LINDA_KEEPER_HASHSEED( linda));
331 if( K == NULL) return 0;
332 for( ;;)
333 {
334 if( s != NULL)
335 {
336 cancel = s->cancel_request;
337 }
338 cancel = (cancel != CANCEL_NONE) ? cancel : linda->simulate_cancel;
339 // if user wants to cancel, or looped because of a timeout, the call returns without sending anything
340 if( !try_again || cancel != CANCEL_NONE)
341 {
342 pushed = 0;
343 break;
344 }
345
346 // all arguments of receive() but the first are passed to the keeper's receive function
347 pushed = keeper_call( linda->U, K->L, keeper_receive, L, linda, key_i);
348 if( pushed < 0)
349 {
350 break;
351 }
352 if( pushed > 0)
353 {
354 ASSERT_L( pushed >= expected_pushed_min && pushed <= expected_pushed_max);
355 // replace sentinels with real nils
356 keeper_toggle_nil_sentinels( L, lua_gettop( L) - pushed, eLM_FromKeeper);
357 // To be done from within the 'K' locking area
358 //
359 SIGNAL_ALL( &linda->read_happened);
360 break;
361 }
362
363 if( timeout == 0.0)
364 {
365 break; /* instant timeout */
366 }
367
368 // nothing received, wait until timeout or signalled that we should try again
369 {
370 enum e_status prev_status = ERROR_ST; // prevent 'might be used uninitialized' warnings
371 if( s != NULL)
372 {
373 // change status of lane to "waiting"
374 prev_status = s->status; // RUNNING, most likely
375 ASSERT_L( prev_status == RUNNING); // but check, just in case
376 s->status = WAITING;
377 ASSERT_L( s->waiting_on == NULL);
378 s->waiting_on = &linda->write_happened;
379 }
380 // not enough data to read: wakeup when data was sent, or when timeout is reached
381 try_again = SIGNAL_WAIT( &linda->write_happened, &K->keeper_cs, timeout);
382 if( s != NULL)
383 {
384 s->waiting_on = NULL;
385 s->status = prev_status;
386 }
387 }
388 }
389 }
390
391 if( pushed < 0)
392 {
393 return luaL_error( L, "tried to copy unsupported types");
394 }
395
396 switch( cancel)
397 {
398 case CANCEL_SOFT:
399 // if user wants to soft-cancel, the call returns CANCEL_ERROR
400 push_unique_key( L, CANCEL_ERROR);
401 return 1;
402
403 case CANCEL_HARD:
404 // raise an error interrupting execution only in case of hard cancel
405 return cancel_error( L); // raises an error and doesn't return
406
407 default:
408 return pushed;
409 }
410}
411
412
413/*
414* [true|lanes.cancel_error] = linda_set( linda_ud, key_num|str|bool|lightuserdata [, value [, ...]])
415*
416* Set one or more value to Linda.
417* TODO: what do we do if we set to non-nil and limit is 0?
418*
419* Existing slot value is replaced, and possible queued entries removed.
420*/
421LUAG_FUNC( linda_set)
422{
423 struct s_Linda* const linda = lua_toLinda( L, 1);
424 int pushed;
425 bool_t has_value = lua_gettop( L) > 2;
426
427 // make sure the key is of a valid type (throws an error if not the case)
428 check_key_types( L, 2, 2);
429
430 {
431 Keeper* K = which_keeper( linda->U->keepers, LINDA_KEEPER_HASHSEED( linda));
432
433 if( linda->simulate_cancel == CANCEL_NONE)
434 {
435 if( has_value)
436 {
437 // convert nils to some special non-nil sentinel in sent values
438 keeper_toggle_nil_sentinels( L, 3, eLM_ToKeeper);
439 }
440 pushed = keeper_call( linda->U, K->L, KEEPER_API( set), L, linda, 2);
441 if( pushed >= 0) // no error?
442 {
443 ASSERT_L( pushed == 0 || pushed == 1);
444
445 if( has_value)
446 {
447 // we put some data in the slot, tell readers that they should wake
448 SIGNAL_ALL( &linda->write_happened); // To be done from within the 'K' locking area
449 }
450 if( pushed == 1)
451 {
452 // the key was full, but it is no longer the case, tell writers they should wake
453 ASSERT_L( lua_type( L, -1) == LUA_TBOOLEAN && lua_toboolean( L, -1) == 1);
454 SIGNAL_ALL( &linda->read_happened); // To be done from within the 'K' locking area
455 }
456 }
457 }
458 else // linda is cancelled
459 {
460 // do nothing and return lanes.cancel_error
461 push_unique_key( L, CANCEL_ERROR);
462 pushed = 1;
463 }
464 }
465
466 // must trigger any error after keeper state has been released
467 return (pushed < 0) ? luaL_error( L, "tried to copy unsupported types") : pushed;
468}
469
470
471/*
472 * [val] = linda_count( linda_ud, [key [, ...]])
473 *
474 * Get a count of the pending elements in the specified keys
475 */
476LUAG_FUNC( linda_count)
477{
478 struct s_Linda* linda = lua_toLinda( L, 1);
479 int pushed;
480
481 // make sure the keys are of a valid type
482 check_key_types( L, 2, lua_gettop( L));
483
484 {
485 Keeper* K = which_keeper( linda->U->keepers, LINDA_KEEPER_HASHSEED( linda));
486 pushed = keeper_call( linda->U, K->L, KEEPER_API( count), L, linda, 2);
487 if( pushed < 0)
488 {
489 return luaL_error( L, "tried to count an invalid key");
490 }
491 }
492 return pushed;
493}
494
495
496/*
497* [val [, ...]] = linda_get( linda_ud, key_num|str|bool|lightuserdata [, count = 1])
498*
499* Get one or more values from Linda.
500*/
501LUAG_FUNC( linda_get)
502{
503 struct s_Linda* const linda = lua_toLinda( L, 1);
504 int pushed;
505 lua_Integer count = luaL_optinteger( L, 3, 1);
506 luaL_argcheck( L, count >= 1, 3, "count should be >= 1");
507 luaL_argcheck( L, lua_gettop( L) <= 3, 4, "too many arguments");
508
509 // make sure the key is of a valid type (throws an error if not the case)
510 check_key_types( L, 2, 2);
511 {
512 Keeper* K = which_keeper( linda->U->keepers, LINDA_KEEPER_HASHSEED( linda));
513
514 if( linda->simulate_cancel == CANCEL_NONE)
515 {
516 pushed = keeper_call( linda->U, K->L, KEEPER_API( get), L, linda, 2);
517 if( pushed > 0)
518 {
519 keeper_toggle_nil_sentinels( L, lua_gettop( L) - pushed, eLM_FromKeeper);
520 }
521 }
522 else // linda is cancelled
523 {
524 // do nothing and return lanes.cancel_error
525 push_unique_key( L, CANCEL_ERROR);
526 pushed = 1;
527 }
528 // an error can be raised if we attempt to read an unregistered function
529 if( pushed < 0)
530 {
531 return luaL_error( L, "tried to copy unsupported types");
532 }
533 }
534
535 return pushed;
536}
537
538
539/*
540* [true] = linda_limit( linda_ud, key_num|str|bool|lightuserdata, int)
541*
542* Set limit to 1 Linda keys.
543* Optionally wake threads waiting to write on the linda, in case the limit enables them to do so
544*/
545LUAG_FUNC( linda_limit)
546{
547 struct s_Linda* linda = lua_toLinda( L, 1);
548 int pushed;
549
550 // make sure we got 3 arguments: the linda, a key and a limit
551 luaL_argcheck( L, lua_gettop( L) == 3, 2, "wrong number of arguments");
552 // make sure we got a numeric limit
553 luaL_checknumber( L, 3);
554 // make sure the key is of a valid type
555 check_key_types( L, 2, 2);
556
557 {
558 Keeper* K = which_keeper( linda->U->keepers, LINDA_KEEPER_HASHSEED( linda));
559
560 if( linda->simulate_cancel == CANCEL_NONE)
561 {
562 pushed = keeper_call( linda->U, K->L, KEEPER_API( limit), L, linda, 2);
563 ASSERT_L( pushed == 0 || pushed == 1); // no error, optional boolean value saying if we should wake blocked writer threads
564 if( pushed == 1)
565 {
566 ASSERT_L( lua_type( L, -1) == LUA_TBOOLEAN && lua_toboolean( L, -1) == 1);
567 SIGNAL_ALL( &linda->read_happened); // To be done from within the 'K' locking area
568 }
569 }
570 else // linda is cancelled
571 {
572 // do nothing and return lanes.cancel_error
573 push_unique_key( L, CANCEL_ERROR);
574 pushed = 1;
575 }
576 }
577 // propagate pushed boolean if any
578 return pushed;
579}
580
581
582/*
583* (void) = linda_cancel( linda_ud, "read"|"write"|"both"|"none")
584*
585* Signal linda so that waiting threads wake up as if their own lane was cancelled
586*/
587LUAG_FUNC( linda_cancel)
588{
589 struct s_Linda* linda = lua_toLinda( L, 1);
590 char const* who = luaL_optstring( L, 2, "both");
591
592 // make sure we got 3 arguments: the linda, a key and a limit
593 luaL_argcheck( L, lua_gettop( L) <= 2, 2, "wrong number of arguments");
594
595 linda->simulate_cancel = CANCEL_SOFT;
596 if( strcmp( who, "both") == 0) // tell everyone writers to wake up
597 {
598 SIGNAL_ALL( &linda->write_happened);
599 SIGNAL_ALL( &linda->read_happened);
600 }
601 else if( strcmp( who, "none") == 0) // reset flag
602 {
603 linda->simulate_cancel = CANCEL_NONE;
604 }
605 else if( strcmp( who, "read") == 0) // tell blocked readers to wake up
606 {
607 SIGNAL_ALL( &linda->write_happened);
608 }
609 else if( strcmp( who, "write") == 0) // tell blocked writers to wake up
610 {
611 SIGNAL_ALL( &linda->read_happened);
612 }
613 else
614 {
615 return luaL_error( L, "unknown wake hint '%s'", who);
616 }
617 return 0;
618}
619
620
621/*
622* lightuserdata= linda_deep( linda_ud )
623*
624* Return the 'deep' userdata pointer, identifying the Linda.
625*
626* This is needed for using Lindas as key indices (timer system needs it);
627* separately created proxies of the same underlying deep object will have
628* different userdata and won't be known to be essentially the same deep one
629* without this.
630*/
631LUAG_FUNC( linda_deep)
632{
633 struct s_Linda* linda= lua_toLinda( L, 1);
634 lua_pushlightuserdata( L, linda); // just the address
635 return 1;
636}
637
638
639/*
640* string = linda:__tostring( linda_ud)
641*
642* Return the stringification of a linda
643*
644* Useful for concatenation or debugging purposes
645*/
646
647static int linda_tostring( lua_State* L, int idx_, bool_t opt_)
648{
649 struct s_Linda* linda = (struct s_Linda*) luaG_todeep( L, linda_id, idx_);
650 if( !opt_)
651 {
652 luaL_argcheck( L, linda, idx_, "expecting a linda object");
653 }
654 if( linda != NULL)
655 {
656 char text[128];
657 int len;
658 if( linda->name[0])
659 len = sprintf( text, "Linda: %.*s", (int)sizeof(text) - 8, linda->name);
660 else
661 len = sprintf( text, "Linda: %p", linda);
662 lua_pushlstring( L, text, len);
663 return 1;
664 }
665 return 0;
666}
667
668LUAG_FUNC( linda_tostring)
669{
670 return linda_tostring( L, 1, FALSE);
671}
672
673
674/*
675* string = linda:__concat( a, b)
676*
677* Return the concatenation of a pair of items, one of them being a linda
678*
679* Useful for concatenation or debugging purposes
680*/
681LUAG_FUNC( linda_concat)
682{ // linda1? linda2?
683 bool_t atLeastOneLinda = FALSE;
684 // Lua semantics enforce that one of the 2 arguments is a Linda, but not necessarily both.
685 if( linda_tostring( L, 1, TRUE))
686 {
687 atLeastOneLinda = TRUE;
688 lua_replace( L, 1);
689 }
690 if( linda_tostring( L, 2, TRUE))
691 {
692 atLeastOneLinda = TRUE;
693 lua_replace( L, 2);
694 }
695 if( !atLeastOneLinda) // should not be possible
696 {
697 return luaL_error( L, "internal error: linda_concat called on non-Linda");
698 }
699 lua_concat( L, 2);
700 return 1;
701}
702
703/*
704 * table = linda:dump()
705 * return a table listing all pending data inside the linda
706 */
707LUAG_FUNC( linda_dump)
708{
709 struct s_Linda* linda = lua_toLinda( L, 1);
710 ASSERT_L( linda->U == universe_get( L));
711 return keeper_push_linda_storage( linda->U, L, linda, LINDA_KEEPER_HASHSEED( linda));
712}
713
714/*
715 * table = linda:dump()
716 * return a table listing all pending data inside the linda
717 */
718LUAG_FUNC( linda_towatch)
719{
720 struct s_Linda* linda = lua_toLinda( L, 1);
721 int pushed;
722 ASSERT_L( linda->U == universe_get( L));
723 pushed = keeper_push_linda_storage( linda->U, L, linda, LINDA_KEEPER_HASHSEED( linda));
724 if( pushed == 0)
725 {
726 // if the linda is empty, don't return nil
727 pushed = linda_tostring( L, 1, FALSE);
728 }
729 return pushed;
730}
731
732/*
733* Identity function of a shared userdata object.
734*
735* lightuserdata= linda_id( "new" [, ...] )
736* = linda_id( "delete", lightuserdata )
737*
738* Creation and cleanup of actual 'deep' objects. 'luaG_...' will wrap them into
739* regular userdata proxies, per each state using the deep data.
740*
741* tbl= linda_id( "metatable" )
742*
743* Returns a metatable for the proxy objects ('__gc' method not needed; will
744* be added by 'luaG_...')
745*
746* string= linda_id( "module")
747*
748* Returns the name of the module that a state should require
749* in order to keep a handle on the shared library that exported the idfunc
750*
751* = linda_id( str, ... )
752*
753* For any other strings, the ID function must not react at all. This allows
754* future extensions of the system.
755*/
756static void* linda_id( lua_State* L, DeepOp op_)
757{
758 switch( op_)
759 {
760 case eDO_new:
761 {
762 struct s_Linda* s;
763 size_t name_len = 0;
764 char const* linda_name = NULL;
765 unsigned long linda_group = 0;
766 // should have a string and/or a number of the stack as parameters (name and group)
767 switch( lua_gettop( L))
768 {
769 default: // 0
770 break;
771
772 case 1: // 1 parameter, either a name or a group
773 if( lua_type( L, -1) == LUA_TSTRING)
774 {
775 linda_name = lua_tolstring( L, -1, &name_len);
776 }
777 else
778 {
779 linda_group = (unsigned long) lua_tointeger( L, -1);
780 }
781 break;
782
783 case 2: // 2 parameters, a name and group, in that order
784 linda_name = lua_tolstring( L, -2, &name_len);
785 linda_group = (unsigned long) lua_tointeger( L, -1);
786 break;
787 }
788
789 /* The deep data is allocated separately of Lua stack; we might no
790 * longer be around when last reference to it is being released.
791 * One can use any memory allocation scheme.
792 * just don't use L's allocF because we don't know which state will get the honor of GCing the linda
793 */
794 s = (struct s_Linda*) malloc( sizeof(struct s_Linda) + name_len); // terminating 0 is already included
795 if( s)
796 {
797 SIGNAL_INIT( &s->read_happened);
798 SIGNAL_INIT( &s->write_happened);
799 s->U = universe_get( L);
800 s->simulate_cancel = CANCEL_NONE;
801 s->group = linda_group << KEEPER_MAGIC_SHIFT;
802 s->name[0] = 0;
803 memcpy( s->name, linda_name, name_len ? name_len + 1 : 0);
804 }
805 return s;
806 }
807
808 case eDO_delete:
809 {
810 Keeper* K;
811 struct s_Linda* linda = lua_touserdata( L, 1);
812 ASSERT_L( linda);
813
814 // Clean associated structures in the keeper state.
815 K = keeper_acquire( linda->U->keepers, LINDA_KEEPER_HASHSEED( linda));
816 if( K && K->L) // can be NULL if this happens during main state shutdown (lanes is GC'ed -> no keepers -> no need to cleanup)
817 {
818 // hopefully this won't ever raise an error as we would jump to the closest pcall site while forgetting to release the keeper mutex...
819 keeper_call( linda->U, K->L, KEEPER_API( clear), L, linda, 0);
820 }
821 keeper_release( K);
822
823 // There aren't any lanes waiting on these lindas, since all proxies have been gc'ed. Right?
824 SIGNAL_FREE( &linda->read_happened);
825 SIGNAL_FREE( &linda->write_happened);
826 free( linda);
827 return NULL;
828 }
829
830 case eDO_metatable:
831 {
832
833 STACK_CHECK( L);
834 lua_newtable( L);
835 // metatable is its own index
836 lua_pushvalue( L, -1);
837 lua_setfield( L, -2, "__index");
838
839 // protect metatable from external access
840 lua_pushliteral( L, "Linda");
841 lua_setfield( L, -2, "__metatable");
842
843 lua_pushcfunction( L, LG_linda_tostring);
844 lua_setfield( L, -2, "__tostring");
845
846 // Decoda __towatch support
847 lua_pushcfunction( L, LG_linda_towatch);
848 lua_setfield( L, -2, "__towatch");
849
850 lua_pushcfunction( L, LG_linda_concat);
851 lua_setfield( L, -2, "__concat");
852
853 // protected calls, to ensure associated keeper is always released even in case of error
854 // all function are the protected call wrapper, where the actual operation is provided as upvalue
855 // note that this kind of thing can break function lookup as we use the function pointer here and there
856
857 lua_pushcfunction( L, LG_linda_send);
858 lua_pushcclosure( L, LG_linda_protected_call, 1);
859 lua_setfield( L, -2, "send");
860
861 lua_pushcfunction( L, LG_linda_receive);
862 lua_pushcclosure( L, LG_linda_protected_call, 1);
863 lua_setfield( L, -2, "receive");
864
865 lua_pushcfunction( L, LG_linda_limit);
866 lua_pushcclosure( L, LG_linda_protected_call, 1);
867 lua_setfield( L, -2, "limit");
868
869 lua_pushcfunction( L, LG_linda_set);
870 lua_pushcclosure( L, LG_linda_protected_call, 1);
871 lua_setfield( L, -2, "set");
872
873 lua_pushcfunction( L, LG_linda_count);
874 lua_pushcclosure( L, LG_linda_protected_call, 1);
875 lua_setfield( L, -2, "count");
876
877 lua_pushcfunction( L, LG_linda_get);
878 lua_pushcclosure( L, LG_linda_protected_call, 1);
879 lua_setfield( L, -2, "get");
880
881 lua_pushcfunction( L, LG_linda_cancel);
882 lua_setfield( L, -2, "cancel");
883
884 lua_pushcfunction( L, LG_linda_deep);
885 lua_setfield( L, -2, "deep");
886
887 lua_pushcfunction( L, LG_linda_dump);
888 lua_pushcclosure( L, LG_linda_protected_call, 1);
889 lua_setfield( L, -2, "dump");
890
891 // some constants
892 lua_pushliteral( L, BATCH_SENTINEL);
893 lua_setfield(L, -2, "batched");
894
895 push_unique_key( L, NIL_SENTINEL);
896 lua_setfield(L, -2, "null");
897
898 luaG_pushdeepversion( L);
899 STACK_END( L, 2);
900 return NULL;
901 }
902
903 case eDO_module:
904 // linda is a special case because we know lanes must be loaded from the main lua state
905 // to be able to ever get here, so we know it will remain loaded as long a the main state is around
906 // in other words, forever.
907 default:
908 {
909 return NULL;
910 }
911 }
912}
913
914/*
915 * ud = lanes.linda( [name[,group]])
916 *
917 * returns a linda object, or raises an error if creation failed
918 */
919LUAG_FUNC( linda)
920{
921 int const top = lua_gettop( L);
922 luaL_argcheck( L, top <= 2, top, "too many arguments");
923 if( top == 1)
924 {
925 int const t = lua_type( L, 1);
926 luaL_argcheck( L, t == LUA_TSTRING || t == LUA_TNUMBER, 1, "wrong parameter (should be a string or a number)");
927 }
928 else if( top == 2)
929 {
930 luaL_checktype( L, 1, LUA_TSTRING);
931 luaL_checktype( L, 2, LUA_TNUMBER);
932 }
933 return luaG_newdeepuserdata( L, linda_id);
934}