aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/lanes.c1014
-rw-r--r--src/lanes_private.h117
-rw-r--r--src/linda.c934
-rw-r--r--src/tools.h2
4 files changed, 1055 insertions, 1012 deletions
diff --git a/src/lanes.c b/src/lanes.c
index f0a5697..f2e3065 100644
--- a/src/lanes.c
+++ b/src/lanes.c
@@ -52,7 +52,7 @@
52 * ... 52 * ...
53 */ 53 */
54 54
55char const* VERSION = "3.13"; 55char const* VERSION = "3.13.0";
56 56
57/* 57/*
58=============================================================================== 58===============================================================================
@@ -93,7 +93,7 @@ THE SOFTWARE.
93#include "tools.h" 93#include "tools.h"
94#include "universe.h" 94#include "universe.h"
95#include "keeper.h" 95#include "keeper.h"
96#include "uniquekey.h" 96#include "lanes_private.h"
97 97
98#if !(defined( PLATFORM_XBOX) || defined( PLATFORM_WIN32) || defined( PLATFORM_POCKETPC)) 98#if !(defined( PLATFORM_XBOX) || defined( PLATFORM_WIN32) || defined( PLATFORM_POCKETPC))
99# include <sys/time.h> 99# include <sys/time.h>
@@ -111,105 +111,6 @@ THE SOFTWARE.
111*/ 111*/
112#define ERROR_FULL_STACK 1 // must be either 0 or 1 as we do some index arithmetics with it! 112#define ERROR_FULL_STACK 1 // must be either 0 or 1 as we do some index arithmetics with it!
113 113
114/*
115 * Lane cancellation request modes
116 */
117enum e_cancel_request
118{
119 CANCEL_NONE, // no pending cancel request
120 CANCEL_SOFT, // user wants the lane to cancel itself manually on cancel_test()
121 CANCEL_HARD // user wants the lane to be interrupted (meaning code won't return from those functions) from inside linda:send/receive calls
122};
123
124// NOTE: values to be changed by either thread, during execution, without
125// locking, are marked "volatile"
126//
127struct s_Lane
128{
129 THREAD_T thread;
130 //
131 // M: sub-thread OS thread
132 // S: not used
133
134 char const* debug_name;
135
136 lua_State* L;
137 Universe* U;
138 //
139 // M: prepares the state, and reads results
140 // S: while S is running, M must keep out of modifying the state
141
142 volatile enum e_status status;
143 //
144 // M: sets to PENDING (before launching)
145 // S: updates -> RUNNING/WAITING -> DONE/ERROR_ST/CANCELLED
146
147 SIGNAL_T* volatile waiting_on;
148 //
149 // When status is WAITING, points on the linda's signal the thread waits on, else NULL
150
151 volatile enum e_cancel_request cancel_request;
152 //
153 // M: sets to FALSE, flags TRUE for cancel request
154 // S: reads to see if cancel is requested
155
156#if THREADWAIT_METHOD == THREADWAIT_CONDVAR
157 SIGNAL_T done_signal;
158 //
159 // M: Waited upon at lane ending (if Posix with no PTHREAD_TIMEDJOIN)
160 // S: sets the signal once cancellation is noticed (avoids a kill)
161
162 MUTEX_T done_lock;
163 //
164 // Lock required by 'done_signal' condition variable, protecting
165 // lane status changes to DONE/ERROR_ST/CANCELLED.
166#endif // THREADWAIT_METHOD == THREADWAIT_CONDVAR
167
168 volatile enum
169 {
170 NORMAL, // normal master side state
171 KILLED // issued an OS kill
172 } mstatus;
173 //
174 // M: sets to NORMAL, if issued a kill changes to KILLED
175 // S: not used
176
177 struct s_Lane* volatile selfdestruct_next;
178 //
179 // M: sets to non-NULL if facing lane handle '__gc' cycle but the lane
180 // is still running
181 // S: cleans up after itself if non-NULL at lane exit
182
183#if HAVE_LANE_TRACKING
184 struct s_Lane* volatile tracking_next;
185#endif // HAVE_LANE_TRACKING
186 //
187 // For tracking only
188};
189typedef struct s_Lane Lane;
190
191// To allow free-running threads (longer lifespan than the handle's)
192// 'Lane' are malloc/free'd and the handle only carries a pointer.
193// This is not deep userdata since the handle's not portable among lanes.
194//
195#define lua_toLane( L, i) (*((Lane**) luaL_checkudata( L, i, "Lane")))
196
197// crc64/we of string "CANCEL_TEST_KEY" generated at http://www.nitrxgen.net/hashgen/
198static DECLARE_CONST_UNIQUE_KEY( CANCEL_TEST_KEY, 0xe66f5960c57d133a); // used as registry key
199
200static inline Lane* get_lane_from_registry( lua_State* L)
201{
202 Lane* s;
203 STACK_GROW( L, 1);
204 STACK_CHECK( L);
205 push_unique_key( L, CANCEL_TEST_KEY);
206 lua_rawget( L, LUA_REGISTRYINDEX);
207 s = lua_touserdata( L, -1); // lightuserdata (true 's_lane' pointer) / nil
208 lua_pop( L, 1);
209 STACK_END( L, 0);
210 return s;
211}
212
213// intern the debug name in the specified lua state so that the pointer remains valid when the lane's state is closed 114// intern the debug name in the specified lua state so that the pointer remains valid when the lane's state is closed
214static void securize_debug_threadname( lua_State* L, Lane* s) 115static void securize_debug_threadname( lua_State* L, Lane* s)
215{ 116{
@@ -241,16 +142,6 @@ static inline enum e_cancel_request cancel_test( lua_State* L)
241 return s ? s->cancel_request : CANCEL_NONE; 142 return s ? s->cancel_request : CANCEL_NONE;
242} 143}
243 144
244// crc64/we of string "CANCEL_ERROR" generated at http://www.nitrxgen.net/hashgen/
245static DECLARE_CONST_UNIQUE_KEY( CANCEL_ERROR, 0xe97d41626cc97577); // 'cancel_error' sentinel
246
247static int cancel_error( lua_State* L)
248{
249 STACK_GROW( L, 1);
250 push_unique_key( L, CANCEL_ERROR); // special error value
251 return lua_error( L); // doesn't return
252}
253
254static void cancel_hook( lua_State* L, lua_Debug* ar) 145static void cancel_hook( lua_State* L, lua_Debug* ar)
255{ 146{
256 (void)ar; 147 (void)ar;
@@ -411,905 +302,6 @@ static void lane_cleanup( Lane* s)
411 302
412/* 303/*
413 * ############################################################################################### 304 * ###############################################################################################
414 * ############################################ Linda ############################################
415 * ###############################################################################################
416 */
417
418/*
419* Actual data is kept within a keeper state, which is hashed by the 's_Linda'
420* pointer (which is same to all userdatas pointing to it).
421*/
422struct s_Linda
423{
424 SIGNAL_T read_happened;
425 SIGNAL_T write_happened;
426 Universe* U; // the universe this linda belongs to
427 ptrdiff_t group; // a group to control keeper allocation between lindas
428 enum e_cancel_request simulate_cancel;
429 char name[1];
430};
431#define LINDA_KEEPER_HASHSEED( linda) (linda->group ? linda->group : (ptrdiff_t)linda)
432
433static void* linda_id( lua_State*, DeepOp);
434
435static inline struct s_Linda* lua_toLinda( lua_State* L, int idx_)
436{
437 struct s_Linda* linda = (struct s_Linda*) luaG_todeep( L, linda_id, idx_);
438 luaL_argcheck( L, linda != NULL, idx_, "expecting a linda object");
439 return linda;
440}
441
442static void check_key_types( lua_State* L, int start_, int end_)
443{
444 int i;
445 for( i = start_; i <= end_; ++ i)
446 {
447 int t = lua_type( L, i);
448 if( t == LUA_TBOOLEAN || t == LUA_TNUMBER || t == LUA_TSTRING || t == LUA_TLIGHTUSERDATA)
449 {
450 continue;
451 }
452 (void) luaL_error( L, "argument #%d: invalid key type (not a boolean, string, number or light userdata)", i);
453 }
454}
455
456LUAG_FUNC( linda_protected_call)
457{
458 int rc = LUA_OK;
459 struct s_Linda* linda = lua_toLinda( L, 1);
460
461 // acquire the keeper
462 Keeper* K = keeper_acquire( linda->U->keepers, LINDA_KEEPER_HASHSEED(linda));
463 lua_State* KL = K ? K->L : NULL; // need to do this for 'STACK_CHECK'
464 if( KL == NULL) return 0;
465
466 // retrieve the actual function to be called and move it before the arguments
467 lua_pushvalue( L, lua_upvalueindex( 1));
468 lua_insert( L, 1);
469 // do a protected call
470 rc = lua_pcall( L, lua_gettop( L) - 1, LUA_MULTRET, 0);
471
472 // release the keeper
473 keeper_release( K);
474
475 // if there was an error, forward it
476 if( rc != LUA_OK)
477 {
478 return lua_error( L);
479 }
480 // return whatever the actual operation provided
481 return lua_gettop( L);
482}
483
484/*
485* bool= linda_send( linda_ud, [timeout_secs=-1,] [linda.null,] key_num|str|bool|lightuserdata, ... )
486*
487* Send one or more values to a Linda. If there is a limit, all values must fit.
488*
489* Returns: 'true' if the value was queued
490* 'false' for timeout (only happens when the queue size is limited)
491* nil, CANCEL_ERROR if cancelled
492*/
493LUAG_FUNC( linda_send)
494{
495 struct s_Linda* linda = lua_toLinda( L, 1);
496 bool_t ret = FALSE;
497 enum e_cancel_request cancel = CANCEL_NONE;
498 int pushed;
499 time_d timeout = -1.0;
500 uint_t key_i = 2; // index of first key, if timeout not there
501 bool_t as_nil_sentinel; // if not NULL, send() will silently send a single nil if nothing is provided
502
503 if( lua_type( L, 2) == LUA_TNUMBER) // we don't want to use lua_isnumber() because of autocoercion
504 {
505 timeout = SIGNAL_TIMEOUT_PREPARE( lua_tonumber( L, 2));
506 ++ key_i;
507 }
508 else if( lua_isnil( L, 2)) // alternate explicit "no timeout" by passing nil before the key
509 {
510 ++ key_i;
511 }
512
513 as_nil_sentinel = equal_unique_key( L, key_i, NIL_SENTINEL);
514 if( as_nil_sentinel)
515 {
516 // the real key to send data to is after the NIL_SENTINEL marker
517 ++ key_i;
518 }
519
520 // make sure the key is of a valid type
521 check_key_types( L, key_i, key_i);
522
523 STACK_GROW( L, 1);
524
525 // make sure there is something to send
526 if( (uint_t)lua_gettop( L) == key_i)
527 {
528 if( as_nil_sentinel)
529 {
530 // send a single nil if nothing is provided
531 push_unique_key( L, NIL_SENTINEL);
532 }
533 else
534 {
535 return luaL_error( L, "no data to send");
536 }
537 }
538
539 // convert nils to some special non-nil sentinel in sent values
540 keeper_toggle_nil_sentinels( L, key_i + 1, eLM_ToKeeper);
541
542 {
543 bool_t try_again = TRUE;
544 Lane* const s = get_lane_from_registry( L);
545 Keeper* K = which_keeper( linda->U->keepers, LINDA_KEEPER_HASHSEED( linda));
546 lua_State* KL = K ? K->L : NULL; // need to do this for 'STACK_CHECK'
547 if( KL == NULL) return 0;
548 STACK_CHECK( KL);
549 for( ;;)
550 {
551 if( s != NULL)
552 {
553 cancel = s->cancel_request;
554 }
555 cancel = (cancel != CANCEL_NONE) ? cancel : linda->simulate_cancel;
556 // if user wants to cancel, or looped because of a timeout, the call returns without sending anything
557 if( !try_again || cancel != CANCEL_NONE)
558 {
559 pushed = 0;
560 break;
561 }
562
563 STACK_MID( KL, 0);
564 pushed = keeper_call( linda->U, KL, KEEPER_API( send), L, linda, key_i);
565 if( pushed < 0)
566 {
567 break;
568 }
569 ASSERT_L( pushed == 1);
570
571 ret = lua_toboolean( L, -1);
572 lua_pop( L, 1);
573
574 if( ret)
575 {
576 // Wake up ALL waiting threads
577 SIGNAL_ALL( &linda->write_happened);
578 break;
579 }
580
581 // instant timout to bypass the wait syscall
582 if( timeout == 0.0)
583 {
584 break; /* no wait; instant timeout */
585 }
586
587 // storage limit hit, wait until timeout or signalled that we should try again
588 {
589 enum e_status prev_status = ERROR_ST; // prevent 'might be used uninitialized' warnings
590 if( s != NULL)
591 {
592 // change status of lane to "waiting"
593 prev_status = s->status; // RUNNING, most likely
594 ASSERT_L( prev_status == RUNNING); // but check, just in case
595 s->status = WAITING;
596 ASSERT_L( s->waiting_on == NULL);
597 s->waiting_on = &linda->read_happened;
598 }
599 // could not send because no room: wait until some data was read before trying again, or until timeout is reached
600 try_again = SIGNAL_WAIT( &linda->read_happened, &K->keeper_cs, timeout);
601 if( s != NULL)
602 {
603 s->waiting_on = NULL;
604 s->status = prev_status;
605 }
606 }
607 }
608 STACK_END( KL, 0);
609 }
610
611 if( pushed < 0)
612 {
613 return luaL_error( L, "tried to copy unsupported types");
614 }
615
616 switch( cancel)
617 {
618 case CANCEL_SOFT:
619 // if user wants to soft-cancel, the call returns lanes.cancel_error
620 push_unique_key( L, CANCEL_ERROR);
621 return 1;
622
623 case CANCEL_HARD:
624 // raise an error interrupting execution only in case of hard cancel
625 return cancel_error( L); // raises an error and doesn't return
626
627 default:
628 lua_pushboolean( L, ret); // true (success) or false (timeout)
629 return 1;
630 }
631}
632
633
634/*
635 * 2 modes of operation
636 * [val, key]= linda_receive( linda_ud, [timeout_secs_num=-1], key_num|str|bool|lightuserdata [, ...] )
637 * Consumes a single value from the Linda, in any key.
638 * Returns: received value (which is consumed from the slot), and the key which had it
639
640 * [val1, ... valCOUNT]= linda_receive( linda_ud, [timeout_secs_num=-1], linda.batched, key_num|str|bool|lightuserdata, min_COUNT[, max_COUNT])
641 * Consumes between min_COUNT and max_COUNT values from the linda, from a single key.
642 * returns the actual consumed values, or nil if there weren't enough values to consume
643 *
644 */
645#define BATCH_SENTINEL "270e6c9d-280f-4983-8fee-a7ecdda01475"
646LUAG_FUNC( linda_receive)
647{
648 struct s_Linda* linda = lua_toLinda( L, 1);
649 int pushed, expected_pushed_min, expected_pushed_max;
650 enum e_cancel_request cancel = CANCEL_NONE;
651 keeper_api_t keeper_receive;
652
653 time_d timeout = -1.0;
654 uint_t key_i = 2;
655
656 if( lua_type( L, 2) == LUA_TNUMBER) // we don't want to use lua_isnumber() because of autocoercion
657 {
658 timeout = SIGNAL_TIMEOUT_PREPARE( lua_tonumber( L, 2));
659 ++ key_i;
660 }
661 else if( lua_isnil( L, 2)) // alternate explicit "no timeout" by passing nil before the key
662 {
663 ++ key_i;
664 }
665
666 // are we in batched mode?
667 {
668 int is_batched;
669 lua_pushliteral( L, BATCH_SENTINEL);
670 is_batched = lua501_equal( L, key_i, -1);
671 lua_pop( L, 1);
672 if( is_batched)
673 {
674 // no need to pass linda.batched in the keeper state
675 ++ key_i;
676 // make sure the keys are of a valid type
677 check_key_types( L, key_i, key_i);
678 // receive multiple values from a single slot
679 keeper_receive = KEEPER_API( receive_batched);
680 // we expect a user-defined amount of return value
681 expected_pushed_min = (int)luaL_checkinteger( L, key_i + 1);
682 expected_pushed_max = (int)luaL_optinteger( L, key_i + 2, expected_pushed_min);
683 // don't forget to count the key in addition to the values
684 ++ expected_pushed_min;
685 ++ expected_pushed_max;
686 if( expected_pushed_min > expected_pushed_max)
687 {
688 return luaL_error( L, "batched min/max error");
689 }
690 }
691 else
692 {
693 // make sure the keys are of a valid type
694 check_key_types( L, key_i, lua_gettop( L));
695 // receive a single value, checking multiple slots
696 keeper_receive = KEEPER_API( receive);
697 // we expect a single (value, key) pair of returned values
698 expected_pushed_min = expected_pushed_max = 2;
699 }
700 }
701
702 {
703 bool_t try_again = TRUE;
704 Lane* const s = get_lane_from_registry( L);
705 Keeper* K = which_keeper( linda->U->keepers, LINDA_KEEPER_HASHSEED( linda));
706 if( K == NULL) return 0;
707 for( ;;)
708 {
709 if( s != NULL)
710 {
711 cancel = s->cancel_request;
712 }
713 cancel = (cancel != CANCEL_NONE) ? cancel : linda->simulate_cancel;
714 // if user wants to cancel, or looped because of a timeout, the call returns without sending anything
715 if( !try_again || cancel != CANCEL_NONE)
716 {
717 pushed = 0;
718 break;
719 }
720
721 // all arguments of receive() but the first are passed to the keeper's receive function
722 pushed = keeper_call( linda->U, K->L, keeper_receive, L, linda, key_i);
723 if( pushed < 0)
724 {
725 break;
726 }
727 if( pushed > 0)
728 {
729 ASSERT_L( pushed >= expected_pushed_min && pushed <= expected_pushed_max);
730 // replace sentinels with real nils
731 keeper_toggle_nil_sentinels( L, lua_gettop( L) - pushed, eLM_FromKeeper);
732 // To be done from within the 'K' locking area
733 //
734 SIGNAL_ALL( &linda->read_happened);
735 break;
736 }
737
738 if( timeout == 0.0)
739 {
740 break; /* instant timeout */
741 }
742
743 // nothing received, wait until timeout or signalled that we should try again
744 {
745 enum e_status prev_status = ERROR_ST; // prevent 'might be used uninitialized' warnings
746 if( s != NULL)
747 {
748 // change status of lane to "waiting"
749 prev_status = s->status; // RUNNING, most likely
750 ASSERT_L( prev_status == RUNNING); // but check, just in case
751 s->status = WAITING;
752 ASSERT_L( s->waiting_on == NULL);
753 s->waiting_on = &linda->write_happened;
754 }
755 // not enough data to read: wakeup when data was sent, or when timeout is reached
756 try_again = SIGNAL_WAIT( &linda->write_happened, &K->keeper_cs, timeout);
757 if( s != NULL)
758 {
759 s->waiting_on = NULL;
760 s->status = prev_status;
761 }
762 }
763 }
764 }
765
766 if( pushed < 0)
767 {
768 return luaL_error( L, "tried to copy unsupported types");
769 }
770
771 switch( cancel)
772 {
773 case CANCEL_SOFT:
774 // if user wants to soft-cancel, the call returns CANCEL_ERROR
775 push_unique_key( L, CANCEL_ERROR);
776 return 1;
777
778 case CANCEL_HARD:
779 // raise an error interrupting execution only in case of hard cancel
780 return cancel_error( L); // raises an error and doesn't return
781
782 default:
783 return pushed;
784 }
785}
786
787
788/*
789* [true|lanes.cancel_error] = linda_set( linda_ud, key_num|str|bool|lightuserdata [, value [, ...]])
790*
791* Set one or more value to Linda.
792* TODO: what do we do if we set to non-nil and limit is 0?
793*
794* Existing slot value is replaced, and possible queued entries removed.
795*/
796LUAG_FUNC( linda_set)
797{
798 struct s_Linda* const linda = lua_toLinda( L, 1);
799 int pushed;
800 bool_t has_value = lua_gettop( L) > 2;
801
802 // make sure the key is of a valid type (throws an error if not the case)
803 check_key_types( L, 2, 2);
804
805 {
806 Keeper* K = which_keeper( linda->U->keepers, LINDA_KEEPER_HASHSEED( linda));
807
808 if( linda->simulate_cancel == CANCEL_NONE)
809 {
810 if( has_value)
811 {
812 // convert nils to some special non-nil sentinel in sent values
813 keeper_toggle_nil_sentinels( L, 3, eLM_ToKeeper);
814 }
815 pushed = keeper_call( linda->U, K->L, KEEPER_API( set), L, linda, 2);
816 if( pushed >= 0) // no error?
817 {
818 ASSERT_L( pushed == 0 || pushed == 1);
819
820 if( has_value)
821 {
822 // we put some data in the slot, tell readers that they should wake
823 SIGNAL_ALL( &linda->write_happened); // To be done from within the 'K' locking area
824 }
825 if( pushed == 1)
826 {
827 // the key was full, but it is no longer the case, tell writers they should wake
828 ASSERT_L( lua_type( L, -1) == LUA_TBOOLEAN && lua_toboolean( L, -1) == 1);
829 SIGNAL_ALL( &linda->read_happened); // To be done from within the 'K' locking area
830 }
831 }
832 }
833 else // linda is cancelled
834 {
835 // do nothing and return lanes.cancel_error
836 push_unique_key( L, CANCEL_ERROR);
837 pushed = 1;
838 }
839 }
840
841 // must trigger any error after keeper state has been released
842 return (pushed < 0) ? luaL_error( L, "tried to copy unsupported types") : pushed;
843}
844
845
846/*
847 * [val] = linda_count( linda_ud, [key [, ...]])
848 *
849 * Get a count of the pending elements in the specified keys
850 */
851LUAG_FUNC( linda_count)
852{
853 struct s_Linda* linda = lua_toLinda( L, 1);
854 int pushed;
855
856 // make sure the keys are of a valid type
857 check_key_types( L, 2, lua_gettop( L));
858
859 {
860 Keeper* K = which_keeper( linda->U->keepers, LINDA_KEEPER_HASHSEED( linda));
861 pushed = keeper_call( linda->U, K->L, KEEPER_API( count), L, linda, 2);
862 if( pushed < 0)
863 {
864 return luaL_error( L, "tried to count an invalid key");
865 }
866 }
867 return pushed;
868}
869
870
871/*
872* [val [, ...]] = linda_get( linda_ud, key_num|str|bool|lightuserdata [, count = 1])
873*
874* Get one or more values from Linda.
875*/
876LUAG_FUNC( linda_get)
877{
878 struct s_Linda* const linda = lua_toLinda( L, 1);
879 int pushed;
880 lua_Integer count = luaL_optinteger( L, 3, 1);
881 luaL_argcheck( L, count >= 1, 3, "count should be >= 1");
882 luaL_argcheck( L, lua_gettop( L) <= 3, 4, "too many arguments");
883
884 // make sure the key is of a valid type (throws an error if not the case)
885 check_key_types( L, 2, 2);
886 {
887 Keeper* K = which_keeper( linda->U->keepers, LINDA_KEEPER_HASHSEED( linda));
888
889 if( linda->simulate_cancel == CANCEL_NONE)
890 {
891 pushed = keeper_call( linda->U, K->L, KEEPER_API( get), L, linda, 2);
892 if( pushed > 0)
893 {
894 keeper_toggle_nil_sentinels( L, lua_gettop( L) - pushed, eLM_FromKeeper);
895 }
896 }
897 else // linda is cancelled
898 {
899 // do nothing and return lanes.cancel_error
900 push_unique_key( L, CANCEL_ERROR);
901 pushed = 1;
902 }
903 // an error can be raised if we attempt to read an unregistered function
904 if( pushed < 0)
905 {
906 return luaL_error( L, "tried to copy unsupported types");
907 }
908 }
909
910 return pushed;
911}
912
913
914/*
915* [true] = linda_limit( linda_ud, key_num|str|bool|lightuserdata, int)
916*
917* Set limit to 1 Linda keys.
918* Optionally wake threads waiting to write on the linda, in case the limit enables them to do so
919*/
920LUAG_FUNC( linda_limit)
921{
922 struct s_Linda* linda = lua_toLinda( L, 1);
923 int pushed;
924
925 // make sure we got 3 arguments: the linda, a key and a limit
926 luaL_argcheck( L, lua_gettop( L) == 3, 2, "wrong number of arguments");
927 // make sure we got a numeric limit
928 luaL_checknumber( L, 3);
929 // make sure the key is of a valid type
930 check_key_types( L, 2, 2);
931
932 {
933 Keeper* K = which_keeper( linda->U->keepers, LINDA_KEEPER_HASHSEED( linda));
934
935 if( linda->simulate_cancel == CANCEL_NONE)
936 {
937 pushed = keeper_call( linda->U, K->L, KEEPER_API( limit), L, linda, 2);
938 ASSERT_L( pushed == 0 || pushed == 1); // no error, optional boolean value saying if we should wake blocked writer threads
939 if( pushed == 1)
940 {
941 ASSERT_L( lua_type( L, -1) == LUA_TBOOLEAN && lua_toboolean( L, -1) == 1);
942 SIGNAL_ALL( &linda->read_happened); // To be done from within the 'K' locking area
943 }
944 }
945 else // linda is cancelled
946 {
947 // do nothing and return lanes.cancel_error
948 push_unique_key( L, CANCEL_ERROR);
949 pushed = 1;
950 }
951 }
952 // propagate pushed boolean if any
953 return pushed;
954}
955
956
957/*
958* (void) = linda_cancel( linda_ud, "read"|"write"|"both"|"none")
959*
960* Signal linda so that waiting threads wake up as if their own lane was cancelled
961*/
962LUAG_FUNC( linda_cancel)
963{
964 struct s_Linda* linda = lua_toLinda( L, 1);
965 char const* who = luaL_optstring( L, 2, "both");
966
967 // make sure we got 3 arguments: the linda, a key and a limit
968 luaL_argcheck( L, lua_gettop( L) <= 2, 2, "wrong number of arguments");
969
970 linda->simulate_cancel = CANCEL_SOFT;
971 if( strcmp( who, "both") == 0) // tell everyone writers to wake up
972 {
973 SIGNAL_ALL( &linda->write_happened);
974 SIGNAL_ALL( &linda->read_happened);
975 }
976 else if( strcmp( who, "none") == 0) // reset flag
977 {
978 linda->simulate_cancel = CANCEL_NONE;
979 }
980 else if( strcmp( who, "read") == 0) // tell blocked readers to wake up
981 {
982 SIGNAL_ALL( &linda->write_happened);
983 }
984 else if( strcmp( who, "write") == 0) // tell blocked writers to wake up
985 {
986 SIGNAL_ALL( &linda->read_happened);
987 }
988 else
989 {
990 return luaL_error( L, "unknown wake hint '%s'", who);
991 }
992 return 0;
993}
994
995
996/*
997* lightuserdata= linda_deep( linda_ud )
998*
999* Return the 'deep' userdata pointer, identifying the Linda.
1000*
1001* This is needed for using Lindas as key indices (timer system needs it);
1002* separately created proxies of the same underlying deep object will have
1003* different userdata and won't be known to be essentially the same deep one
1004* without this.
1005*/
1006LUAG_FUNC( linda_deep)
1007{
1008 struct s_Linda* linda= lua_toLinda( L, 1);
1009 lua_pushlightuserdata( L, linda); // just the address
1010 return 1;
1011}
1012
1013
1014/*
1015* string = linda:__tostring( linda_ud)
1016*
1017* Return the stringification of a linda
1018*
1019* Useful for concatenation or debugging purposes
1020*/
1021
1022static int linda_tostring( lua_State* L, int idx_, bool_t opt_)
1023{
1024 struct s_Linda* linda = (struct s_Linda*) luaG_todeep( L, linda_id, idx_);
1025 if( !opt_)
1026 {
1027 luaL_argcheck( L, linda, idx_, "expecting a linda object");
1028 }
1029 if( linda != NULL)
1030 {
1031 char text[128];
1032 int len;
1033 if( linda->name[0])
1034 len = sprintf( text, "Linda: %.*s", (int)sizeof(text) - 8, linda->name);
1035 else
1036 len = sprintf( text, "Linda: %p", linda);
1037 lua_pushlstring( L, text, len);
1038 return 1;
1039 }
1040 return 0;
1041}
1042
1043LUAG_FUNC( linda_tostring)
1044{
1045 return linda_tostring( L, 1, FALSE);
1046}
1047
1048
1049/*
1050* string = linda:__concat( a, b)
1051*
1052* Return the concatenation of a pair of items, one of them being a linda
1053*
1054* Useful for concatenation or debugging purposes
1055*/
1056LUAG_FUNC( linda_concat)
1057{ // linda1? linda2?
1058 bool_t atLeastOneLinda = FALSE;
1059 // Lua semantics enforce that one of the 2 arguments is a Linda, but not necessarily both.
1060 if( linda_tostring( L, 1, TRUE))
1061 {
1062 atLeastOneLinda = TRUE;
1063 lua_replace( L, 1);
1064 }
1065 if( linda_tostring( L, 2, TRUE))
1066 {
1067 atLeastOneLinda = TRUE;
1068 lua_replace( L, 2);
1069 }
1070 if( !atLeastOneLinda) // should not be possible
1071 {
1072 return luaL_error( L, "internal error: linda_concat called on non-Linda");
1073 }
1074 lua_concat( L, 2);
1075 return 1;
1076}
1077
1078/*
1079 * table = linda:dump()
1080 * return a table listing all pending data inside the linda
1081 */
1082LUAG_FUNC( linda_dump)
1083{
1084 struct s_Linda* linda = lua_toLinda( L, 1);
1085 ASSERT_L( linda->U == universe_get( L));
1086 return keeper_push_linda_storage( linda->U, L, linda, LINDA_KEEPER_HASHSEED( linda));
1087}
1088
1089/*
1090 * table = linda:dump()
1091 * return a table listing all pending data inside the linda
1092 */
1093LUAG_FUNC( linda_towatch)
1094{
1095 struct s_Linda* linda = lua_toLinda( L, 1);
1096 int pushed;
1097 ASSERT_L( linda->U == universe_get( L));
1098 pushed = keeper_push_linda_storage( linda->U, L, linda, LINDA_KEEPER_HASHSEED( linda));
1099 if( pushed == 0)
1100 {
1101 // if the linda is empty, don't return nil
1102 pushed = linda_tostring( L, 1, FALSE);
1103 }
1104 return pushed;
1105}
1106
1107/*
1108* Identity function of a shared userdata object.
1109*
1110* lightuserdata= linda_id( "new" [, ...] )
1111* = linda_id( "delete", lightuserdata )
1112*
1113* Creation and cleanup of actual 'deep' objects. 'luaG_...' will wrap them into
1114* regular userdata proxies, per each state using the deep data.
1115*
1116* tbl= linda_id( "metatable" )
1117*
1118* Returns a metatable for the proxy objects ('__gc' method not needed; will
1119* be added by 'luaG_...')
1120*
1121* string= linda_id( "module")
1122*
1123* Returns the name of the module that a state should require
1124* in order to keep a handle on the shared library that exported the idfunc
1125*
1126* = linda_id( str, ... )
1127*
1128* For any other strings, the ID function must not react at all. This allows
1129* future extensions of the system.
1130*/
1131static void* linda_id( lua_State* L, DeepOp op_)
1132{
1133 switch( op_)
1134 {
1135 case eDO_new:
1136 {
1137 struct s_Linda* s;
1138 size_t name_len = 0;
1139 char const* linda_name = NULL;
1140 unsigned long linda_group = 0;
1141 // should have a string and/or a number of the stack as parameters (name and group)
1142 switch( lua_gettop( L))
1143 {
1144 default: // 0
1145 break;
1146
1147 case 1: // 1 parameter, either a name or a group
1148 if( lua_type( L, -1) == LUA_TSTRING)
1149 {
1150 linda_name = lua_tolstring( L, -1, &name_len);
1151 }
1152 else
1153 {
1154 linda_group = (unsigned long) lua_tointeger( L, -1);
1155 }
1156 break;
1157
1158 case 2: // 2 parameters, a name and group, in that order
1159 linda_name = lua_tolstring( L, -2, &name_len);
1160 linda_group = (unsigned long) lua_tointeger( L, -1);
1161 break;
1162 }
1163
1164 /* The deep data is allocated separately of Lua stack; we might no
1165 * longer be around when last reference to it is being released.
1166 * One can use any memory allocation scheme.
1167 * just don't use L's allocF because we don't know which state will get the honor of GCing the linda
1168 */
1169 s = (struct s_Linda*) malloc( sizeof(struct s_Linda) + name_len); // terminating 0 is already included
1170 if( s)
1171 {
1172 SIGNAL_INIT( &s->read_happened);
1173 SIGNAL_INIT( &s->write_happened);
1174 s->U = universe_get( L);
1175 s->simulate_cancel = CANCEL_NONE;
1176 s->group = linda_group << KEEPER_MAGIC_SHIFT;
1177 s->name[0] = 0;
1178 memcpy( s->name, linda_name, name_len ? name_len + 1 : 0);
1179 }
1180 return s;
1181 }
1182
1183 case eDO_delete:
1184 {
1185 Keeper* K;
1186 struct s_Linda* linda = lua_touserdata( L, 1);
1187 ASSERT_L( linda);
1188
1189 // Clean associated structures in the keeper state.
1190 K = keeper_acquire( linda->U->keepers, LINDA_KEEPER_HASHSEED( linda));
1191 if( K && K->L) // can be NULL if this happens during main state shutdown (lanes is GC'ed -> no keepers -> no need to cleanup)
1192 {
1193 // hopefully this won't ever raise an error as we would jump to the closest pcall site while forgetting to release the keeper mutex...
1194 keeper_call( linda->U, K->L, KEEPER_API( clear), L, linda, 0);
1195 }
1196 keeper_release( K);
1197
1198 // There aren't any lanes waiting on these lindas, since all proxies have been gc'ed. Right?
1199 SIGNAL_FREE( &linda->read_happened);
1200 SIGNAL_FREE( &linda->write_happened);
1201 free( linda);
1202 return NULL;
1203 }
1204
1205 case eDO_metatable:
1206 {
1207
1208 STACK_CHECK( L);
1209 lua_newtable( L);
1210 // metatable is its own index
1211 lua_pushvalue( L, -1);
1212 lua_setfield( L, -2, "__index");
1213
1214 // protect metatable from external access
1215 lua_pushliteral( L, "Linda");
1216 lua_setfield( L, -2, "__metatable");
1217
1218 lua_pushcfunction( L, LG_linda_tostring);
1219 lua_setfield( L, -2, "__tostring");
1220
1221 // Decoda __towatch support
1222 lua_pushcfunction( L, LG_linda_towatch);
1223 lua_setfield( L, -2, "__towatch");
1224
1225 lua_pushcfunction( L, LG_linda_concat);
1226 lua_setfield( L, -2, "__concat");
1227
1228 // protected calls, to ensure associated keeper is always released even in case of error
1229 // all function are the protected call wrapper, where the actual operation is provided as upvalue
1230 // note that this kind of thing can break function lookup as we use the function pointer here and there
1231
1232 lua_pushcfunction( L, LG_linda_send);
1233 lua_pushcclosure( L, LG_linda_protected_call, 1);
1234 lua_setfield( L, -2, "send");
1235
1236 lua_pushcfunction( L, LG_linda_receive);
1237 lua_pushcclosure( L, LG_linda_protected_call, 1);
1238 lua_setfield( L, -2, "receive");
1239
1240 lua_pushcfunction( L, LG_linda_limit);
1241 lua_pushcclosure( L, LG_linda_protected_call, 1);
1242 lua_setfield( L, -2, "limit");
1243
1244 lua_pushcfunction( L, LG_linda_set);
1245 lua_pushcclosure( L, LG_linda_protected_call, 1);
1246 lua_setfield( L, -2, "set");
1247
1248 lua_pushcfunction( L, LG_linda_count);
1249 lua_pushcclosure( L, LG_linda_protected_call, 1);
1250 lua_setfield( L, -2, "count");
1251
1252 lua_pushcfunction( L, LG_linda_get);
1253 lua_pushcclosure( L, LG_linda_protected_call, 1);
1254 lua_setfield( L, -2, "get");
1255
1256 lua_pushcfunction( L, LG_linda_cancel);
1257 lua_setfield( L, -2, "cancel");
1258
1259 lua_pushcfunction( L, LG_linda_deep);
1260 lua_setfield( L, -2, "deep");
1261
1262 lua_pushcfunction( L, LG_linda_dump);
1263 lua_pushcclosure( L, LG_linda_protected_call, 1);
1264 lua_setfield( L, -2, "dump");
1265
1266 // some constants
1267 lua_pushliteral( L, BATCH_SENTINEL);
1268 lua_setfield(L, -2, "batched");
1269
1270 push_unique_key( L, NIL_SENTINEL);
1271 lua_setfield(L, -2, "null");
1272
1273 luaG_pushdeepversion( L);
1274 STACK_END( L, 2);
1275 return NULL;
1276 }
1277
1278 case eDO_module:
1279 // linda is a special case because we know lanes must be loaded from the main lua state
1280 // to be able to ever get here, so we know it will remain loaded as long a the main state is around
1281 // in other words, forever.
1282 default:
1283 {
1284 return NULL;
1285 }
1286 }
1287}
1288
1289/*
1290 * ud = lanes.linda( [name[,group]])
1291 *
1292 * returns a linda object, or raises an error if creation failed
1293 */
1294LUAG_FUNC( linda)
1295{
1296 int const top = lua_gettop( L);
1297 luaL_argcheck( L, top <= 2, top, "too many arguments");
1298 if( top == 1)
1299 {
1300 int const t = lua_type( L, 1);
1301 luaL_argcheck( L, t == LUA_TSTRING || t == LUA_TNUMBER, 1, "wrong parameter (should be a string or a number)");
1302 }
1303 else if( top == 2)
1304 {
1305 luaL_checktype( L, 1, LUA_TSTRING);
1306 luaL_checktype( L, 2, LUA_TNUMBER);
1307 }
1308 return luaG_newdeepuserdata( L, linda_id);
1309}
1310
1311/*
1312 * ###############################################################################################
1313 * ########################################## Finalizer ########################################## 305 * ########################################## Finalizer ##########################################
1314 * ############################################################################################### 306 * ###############################################################################################
1315 */ 307 */
@@ -3000,6 +1992,7 @@ LUAG_FUNC( wakeup_conv )
3000 * ############################################################################################### 1992 * ###############################################################################################
3001 */ 1993 */
3002 1994
1995extern int LG_linda( lua_State* L);
3003static const struct luaL_Reg lanes_functions [] = { 1996static const struct luaL_Reg lanes_functions [] = {
3004 {"linda", LG_linda}, 1997 {"linda", LG_linda},
3005 {"now_secs", LG_now_secs}, 1998 {"now_secs", LG_now_secs},
@@ -3012,7 +2005,6 @@ static const struct luaL_Reg lanes_functions [] = {
3012 {NULL, NULL} 2005 {NULL, NULL}
3013}; 2006};
3014 2007
3015
3016/* 2008/*
3017 * One-time initializations 2009 * One-time initializations
3018 * settings table it at position 1 on the stack 2010 * settings table it at position 1 on the stack
diff --git a/src/lanes_private.h b/src/lanes_private.h
new file mode 100644
index 0000000..a7e21d7
--- /dev/null
+++ b/src/lanes_private.h
@@ -0,0 +1,117 @@
1#if !defined __lanes_private_h__
2#define __lanes_private_h__ 1
3
4#include "uniquekey.h"
5
6/*
7 * Lane cancellation request modes
8 */
9enum e_cancel_request
10{
11 CANCEL_NONE, // no pending cancel request
12 CANCEL_SOFT, // user wants the lane to cancel itself manually on cancel_test()
13 CANCEL_HARD // user wants the lane to be interrupted (meaning code won't return from those functions) from inside linda:send/receive calls
14};
15
16// NOTE: values to be changed by either thread, during execution, without
17// locking, are marked "volatile"
18//
19struct s_Lane
20{
21 THREAD_T thread;
22 //
23 // M: sub-thread OS thread
24 // S: not used
25
26 char const* debug_name;
27
28 lua_State* L;
29 Universe* U;
30 //
31 // M: prepares the state, and reads results
32 // S: while S is running, M must keep out of modifying the state
33
34 volatile enum e_status status;
35 //
36 // M: sets to PENDING (before launching)
37 // S: updates -> RUNNING/WAITING -> DONE/ERROR_ST/CANCELLED
38
39 SIGNAL_T* volatile waiting_on;
40 //
41 // When status is WAITING, points on the linda's signal the thread waits on, else NULL
42
43 volatile enum e_cancel_request cancel_request;
44 //
45 // M: sets to FALSE, flags TRUE for cancel request
46 // S: reads to see if cancel is requested
47
48#if THREADWAIT_METHOD == THREADWAIT_CONDVAR
49 SIGNAL_T done_signal;
50 //
51 // M: Waited upon at lane ending (if Posix with no PTHREAD_TIMEDJOIN)
52 // S: sets the signal once cancellation is noticed (avoids a kill)
53
54 MUTEX_T done_lock;
55 //
56 // Lock required by 'done_signal' condition variable, protecting
57 // lane status changes to DONE/ERROR_ST/CANCELLED.
58#endif // THREADWAIT_METHOD == THREADWAIT_CONDVAR
59
60 volatile enum
61 {
62 NORMAL, // normal master side state
63 KILLED // issued an OS kill
64 } mstatus;
65 //
66 // M: sets to NORMAL, if issued a kill changes to KILLED
67 // S: not used
68
69 struct s_Lane* volatile selfdestruct_next;
70 //
71 // M: sets to non-NULL if facing lane handle '__gc' cycle but the lane
72 // is still running
73 // S: cleans up after itself if non-NULL at lane exit
74
75#if HAVE_LANE_TRACKING
76 struct s_Lane* volatile tracking_next;
77#endif // HAVE_LANE_TRACKING
78 //
79 // For tracking only
80};
81typedef struct s_Lane Lane;
82
83// To allow free-running threads (longer lifespan than the handle's)
84// 'Lane' are malloc/free'd and the handle only carries a pointer.
85// This is not deep userdata since the handle's not portable among lanes.
86//
87#define lua_toLane( L, i) (*((Lane**) luaL_checkudata( L, i, "Lane")))
88
89// crc64/we of string "CANCEL_ERROR" generated at http://www.nitrxgen.net/hashgen/
90static DECLARE_CONST_UNIQUE_KEY(CANCEL_ERROR, 0xe97d41626cc97577); // 'cancel_error' sentinel
91
92// crc64/we of string "CANCEL_TEST_KEY" generated at http://www.nitrxgen.net/hashgen/
93static DECLARE_CONST_UNIQUE_KEY(CANCEL_TEST_KEY, 0xe66f5960c57d133a); // used as registry key
94
95static inline Lane* get_lane_from_registry( lua_State* L)
96{
97 Lane* s;
98 STACK_GROW( L, 1);
99 STACK_CHECK( L);
100 push_unique_key( L, CANCEL_TEST_KEY);
101 lua_rawget( L, LUA_REGISTRYINDEX);
102 s = lua_touserdata( L, -1); // lightuserdata (true 's_lane' pointer) / nil
103 lua_pop( L, 1);
104 STACK_END( L, 0);
105 return s;
106}
107
108static inline int cancel_error( lua_State* L)
109{
110 STACK_GROW( L, 1);
111 push_unique_key( L, CANCEL_ERROR); // special error value
112 return lua_error( L); // doesn't return
113}
114
115
116
117#endif // __lanes_private_h__ \ No newline at end of file
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}
diff --git a/src/tools.h b/src/tools.h
index 2f78b73..84e323c 100644
--- a/src/tools.h
+++ b/src/tools.h
@@ -13,7 +13,7 @@ typedef struct s_Universe Universe;
13 13
14// ################################################################################################ 14// ################################################################################################
15 15
16#define LUAG_FUNC( func_name ) static int LG_##func_name( lua_State* L) 16#define LUAG_FUNC( func_name) int LG_##func_name( lua_State* L)
17 17
18#define luaG_optunsigned(L,i,d) ((uint_t) luaL_optinteger(L,i,d)) 18#define luaG_optunsigned(L,i,d) ((uint_t) luaL_optinteger(L,i,d))
19#define luaG_tounsigned(L,i) ((uint_t) lua_tointeger(L,i)) 19#define luaG_tounsigned(L,i) ((uint_t) lua_tointeger(L,i))