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