aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGES5
-rw-r--r--docs/index.html24
-rw-r--r--src/keeper.c102
-rw-r--r--src/keeper.h2
-rw-r--r--src/lanes.c44
-rw-r--r--src/lanes.lua2
6 files changed, 101 insertions, 78 deletions
diff --git a/CHANGES b/CHANGES
index f450700..3639295 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,5 +1,10 @@
1CHANGES: 1CHANGES:
2 2
3CHANGE 91: BGe 20-Jan-14
4 * version 3.8.0
5 * linda:set() accepts multiple values to set in the specified slot
6 * linda:get() accepts an optional count to peek several values at once
7
3CHANGE 90: BGe 16-Jan-14 8CHANGE 90: BGe 16-Jan-14
4 * version 3.7.8 9 * version 3.7.8
5 * lane:cancel() now accepts a boolean second argument when soft cancelling (negative timeout) to wake the thread if necessary 10 * lane:cancel() now accepts a boolean second argument when soft cancelling (negative timeout) to wake the thread if necessary
diff --git a/docs/index.html b/docs/index.html
index 3b64cb4..da37cef 100644
--- a/docs/index.html
+++ b/docs/index.html
@@ -70,7 +70,7 @@
70 </p> 70 </p>
71 71
72 <p> 72 <p>
73 This document was revised on 16-Jan-14, and applies to version <tt>3.7.8</tt>. 73 This document was revised on 20-Jan-14, and applies to version <tt>3.8.0</tt>.
74 </p> 74 </p>
75 </font> 75 </font>
76 </center> 76 </center>
@@ -1068,23 +1068,31 @@
1068</p> 1068</p>
1069 1069
1070<table border="1" bgcolor="#E0E0FF" cellpadding="10" style="width:50%"><tr><td><pre> 1070<table border="1" bgcolor="#E0E0FF" cellpadding="10" style="width:50%"><tr><td><pre>
1071 [true] = linda_h:set( key, [val]) 1071 [bool] = linda_h:set( key [, val [, ...]])
1072 1072
1073 [val] = linda_h:get( key) 1073 [val [, ...]] = linda_h:get( key [, count = 1])
1074</pre></td></tr></table> 1074</pre></td></tr></table>
1075 1075
1076<p> 1076<p>
1077 The table access methods are for accessing a slot without queuing or consuming. They can be used for making shared tables of storage among the lanes. 1077 The table access methods are for accessing a slot without queuing or consuming. They can be used for making shared tables of storage among the lanes.
1078 <br/>
1079 Writing to a slot never blocks because it ignores the limit. It overwrites existing value and clears any possible queued entries.
1080 <br/>
1081 Reading doesn't block either because <tt>get()</tt> returns whatever is available (which can be nothing), up to the specified count.
1082 <br/>
1083 Table access and <tt>send()</tt>/<tt>receive()</tt> can be used together; reading a slot essentially peeks the next outcoming value of a queue.
1078</p> 1084</p>
1079 1085
1080<p> 1086<p>
1081 Writing to a slot never blocks because it ignores the limit. It overwrites existing value and clears any possible queued entries. 1087 <tt>set()</tt> signals the linda for write if a value is stored.
1082 <br/> 1088 <br/>
1083 <tt>set()</tt> signals the linda from write if a value is stored. 1089 (Since version 3.7.7) if the key was full but the new data count of the key after <tt>set()</tt> is below its limit, <tt>set()</tt> returns <tt>true</tt> and the linda is also signaled for read so that send()-blocked threads are awakened.
1084 <br/> 1090</p>
1085 (Since version 3.7.7) if the key was full but the new data count of the key after <tt>set()</tt> is below its limit, <tt>set()</tt> returns <tt>true</tt> and the linda is also signaled for read so that send()-blocked threads are awakened. 1091
1092<p>
1093 Since version 3.8.0, <tt>set()</tt> can write several values at the specified key, writing <tt>nil</tt> values is now possible, and clearing the contents at the specified key is done by not providing any value.
1086 <br/> 1094 <br/>
1087 Table access and <tt>send()</tt>/<tt>receive()</tt> can be used together; reading a slot essentially peeks the next outcoming value of a queue. 1095 Also, <tt>get()</tt> can read several values at once. If the key contains no data, <tt>get()</tt> returns no value. This can be used to separate the case when reading stored <tt>nil</tt> values.
1088</p> 1096</p>
1089 1097
1090<table border="1" bgcolor="#E0E0FF" cellpadding="10" style="width:50%"><tr><td><pre> 1098<table border="1" bgcolor="#E0E0FF" cellpadding="10" style="width:50%"><tr><td><pre>
diff --git a/src/keeper.c b/src/keeper.c
index 6d5ecbf..b0db8b4 100644
--- a/src/keeper.c
+++ b/src/keeper.c
@@ -115,11 +115,11 @@ static void fifo_push( lua_State* L, keeper_fifo* fifo, int _count)
115// expects exactly 1 value on the stack! 115// expects exactly 1 value on the stack!
116// currently only called with a count of 1, but this may change in the future 116// currently only called with a count of 1, but this may change in the future
117// function assumes that there is enough data in the fifo to satisfy the request 117// function assumes that there is enough data in the fifo to satisfy the request
118static void fifo_peek( lua_State* L, keeper_fifo* fifo, int _count) 118static void fifo_peek( lua_State* L, keeper_fifo* fifo, int count_)
119{ 119{
120 int i; 120 int i;
121 STACK_GROW( L, _count); 121 STACK_GROW( L, count_);
122 for( i = 0; i < _count; ++ i) 122 for( i = 0; i < count_; ++ i)
123 { 123 {
124 lua_rawgeti( L, 1, fifo->first + i); 124 lua_rawgeti( L, 1, fifo->first + i);
125 } 125 }
@@ -384,54 +384,21 @@ int keepercall_limit( lua_State* L)
384 return lua_gettop( L); 384 return lua_gettop( L);
385} 385}
386 386
387//in: linda_ud key [val] 387//in: linda_ud key [[val] ...]
388//out: true or nil 388//out: true or nil
389int keepercall_set( lua_State* L) 389int keepercall_set( lua_State* L)
390{ 390{
391 bool_t should_wake_writers = FALSE; 391 bool_t should_wake_writers = FALSE;
392 STACK_GROW( L, 6); 392 STACK_GROW( L, 6);
393 // make sure we have a value on the stack
394 if( lua_gettop( L) == 2) // ud key val?
395 {
396 lua_pushnil( L); // ud key nil
397 }
398 393
399 // retrieve fifos associated with the linda 394 // retrieve fifos associated with the linda
400 push_table( L, 1); // ud key val fifos 395 push_table( L, 1); // ud key [val [, ...]] fifos
401 lua_replace( L, 1); // fifos key val 396 lua_replace( L, 1); // fifos key [val [, ...]]
402 397
403 if( !lua_isnil( L, 3)) // set/replace contents stored at the specified key? 398 // make sure we have a value on the stack
399 if( lua_gettop( L) == 2) // fifos key
404 { 400 {
405 keeper_fifo* fifo; 401 keeper_fifo* fifo;
406 lua_pushvalue( L, -2); // fifos key val key
407 lua_rawget( L, 1); // fifos key val fifo|nil
408 fifo = (keeper_fifo*) lua_touserdata( L, -1);
409 if( fifo == NULL) // can be NULL if we store a value at a new key
410 { // fifos key val nil
411 lua_pop( L, 1); // fifos key val
412 fifo_new( L); // fifos key val fifo
413 lua_pushvalue( L, 2); // fifos key val fifo key
414 lua_pushvalue( L, -2); // fifos key val fifo key fifo
415 lua_rawset( L, 1); // fifos key val fifo
416 }
417 else // the fifo exists, we just want to update its contents
418 { // fifos key val fifo
419 // we create room if the fifo was full but it is no longer the case
420 should_wake_writers = (fifo->limit > 0) && (fifo->count >= fifo->limit);
421 // empty the fifo for the specified key: replace uservalue with a virgin table, reset counters, but leave limit unchanged!
422 lua_newtable( L); // fifos key val fifo {}
423 lua_setuservalue( L, -2); // fifos key val fifo
424 fifo->first = 1;
425 fifo->count = 0;
426 }
427 fifo = prepare_fifo_access( L, -1);
428 lua_insert( L, -2); // fifos key fifo val
429 fifo_push( L, fifo, 1); // fifos key fifo
430 }
431 else // val == nil: we clear the key contents
432 { // fifos key nil
433 keeper_fifo* fifo;
434 lua_pop( L, 1); // fifos key
435 lua_pushvalue( L, -1); // fifos key key 402 lua_pushvalue( L, -1); // fifos key key
436 lua_rawget( L, 1); // fifos key fifo|nil 403 lua_rawget( L, 1); // fifos key fifo|nil
437 // empty the fifo for the specified key: replace uservalue with a virgin table, reset counters, but leave limit unchanged! 404 // empty the fifo for the specified key: replace uservalue with a virgin table, reset counters, but leave limit unchanged!
@@ -456,13 +423,51 @@ int keepercall_set( lua_State* L)
456 } 423 }
457 } 424 }
458 } 425 }
426 else // set/replace contents stored at the specified key?
427 {
428 int count = lua_gettop( L) - 2; // number of items we want to store
429 keeper_fifo* fifo; // fifos key [val [, ...]]
430 lua_pushvalue( L, 2); // fifos key [val [, ...]] key
431 lua_rawget( L, 1); // fifos key [val [, ...]] fifo|nil
432 fifo = (keeper_fifo*) lua_touserdata( L, -1);
433 if( fifo == NULL) // can be NULL if we store a value at a new key
434 { // fifos key [val [, ...]] nil
435 // no need to wake writers in that case, because a writer can't wait on an inexistent key
436 lua_pop( L, 1); // fifos key [val [, ...]]
437 fifo_new( L); // fifos key [val [, ...]] fifo
438 lua_pushvalue( L, 2); // fifos key [val [, ...]] fifo key
439 lua_pushvalue( L, -2); // fifos key [val [, ...]] fifo key fifo
440 lua_rawset( L, 1); // fifos key [val [, ...]] fifo
441 }
442 else // the fifo exists, we just want to update its contents
443 { // fifos key [val [, ...]] fifo
444 // we create room if the fifo was full but it is no longer the case
445 should_wake_writers = (fifo->limit > 0) && (fifo->count >= fifo->limit) && (count < fifo->limit);
446 // empty the fifo for the specified key: replace uservalue with a virgin table, reset counters, but leave limit unchanged!
447 lua_newtable( L); // fifos key [val [, ...]] fifo {}
448 lua_setuservalue( L, -2); // fifos key [val [, ...]] fifo
449 fifo->first = 1;
450 fifo->count = 0;
451 }
452 fifo = prepare_fifo_access( L, -1);
453 // move the fifo below the values we want to store
454 lua_insert( L, 3); // fifos key fifo [val [, ...]]
455 fifo_push( L, fifo, count); // fifos key fifo
456 }
459 return should_wake_writers ? (lua_pushboolean( L, 1), 1) : 0; 457 return should_wake_writers ? (lua_pushboolean( L, 1), 1) : 0;
460} 458}
461 459
462// in: linda_ud key 460// in: linda_ud key [count]
461// out: at most <count> values
463int keepercall_get( lua_State* L) 462int keepercall_get( lua_State* L)
464{ 463{
465 keeper_fifo* fifo; 464 keeper_fifo* fifo;
465 int count = 1;
466 if( lua_gettop( L) == 3) // ud key count
467 {
468 count = lua_tointeger( L, 3);
469 lua_pop( L, 1); // ud key
470 }
466 push_table( L, 1); // ud key fifos 471 push_table( L, 1); // ud key fifos
467 lua_replace( L, 1); // fifos key 472 lua_replace( L, 1); // fifos key
468 lua_rawget( L, 1); // fifos fifo 473 lua_rawget( L, 1); // fifos fifo
@@ -470,9 +475,10 @@ int keepercall_get( lua_State* L)
470 if( fifo != NULL && fifo->count > 0) 475 if( fifo != NULL && fifo->count > 0)
471 { 476 {
472 lua_remove( L, 1); // fifo 477 lua_remove( L, 1); // fifo
473 // read one value off the fifo 478 count = __min( count, fifo->count);
474 fifo_peek( L, fifo, 1); // fifo ... 479 // read <count> value off the fifo
475 return 1; 480 fifo_peek( L, fifo, count); // fifo ...
481 return count;
476 } 482 }
477 // no fifo was ever registered for this key, or it is empty 483 // no fifo was ever registered for this key, or it is empty
478 return 0; 484 return 0;
@@ -682,16 +688,16 @@ void keeper_release( struct s_Keeper* K)
682 if( K) MUTEX_UNLOCK( &K->lock_); 688 if( K) MUTEX_UNLOCK( &K->lock_);
683} 689}
684 690
685void keeper_toggle_nil_sentinels( lua_State* L, int _val_i, int _nil_to_sentinel) 691void keeper_toggle_nil_sentinels( lua_State* L, int val_i_, enum eLookupMode mode_)
686{ 692{
687 int i, n = lua_gettop( L); 693 int i, n = lua_gettop( L);
688 /* We could use an empty table in 'keeper.lua' as the sentinel, but maybe 694 /* We could use an empty table in 'keeper.lua' as the sentinel, but maybe
689 * checking for a lightuserdata is faster. (any unique value will do -> take the address of some global of ours) 695 * checking for a lightuserdata is faster. (any unique value will do -> take the address of some global of ours)
690 */ 696 */
691 void* nil_sentinel = &GNbKeepers; 697 void* nil_sentinel = &GNbKeepers;
692 for( i = _val_i; i <= n; ++ i) 698 for( i = val_i_; i <= n; ++ i)
693 { 699 {
694 if( _nil_to_sentinel) 700 if( mode_ == eLM_ToKeeper)
695 { 701 {
696 if( lua_isnil( L, i)) 702 if( lua_isnil( L, i))
697 { 703 {
diff --git a/src/keeper.h b/src/keeper.h
index 2ef443d..c0fd5d0 100644
--- a/src/keeper.h
+++ b/src/keeper.h
@@ -20,7 +20,7 @@ void close_keepers( void);
20 20
21struct s_Keeper *keeper_acquire( const void *ptr); 21struct s_Keeper *keeper_acquire( const void *ptr);
22void keeper_release( struct s_Keeper *K); 22void keeper_release( struct s_Keeper *K);
23void keeper_toggle_nil_sentinels( lua_State *L, int _val_i, int _nil_to_sentinel); 23void keeper_toggle_nil_sentinels( lua_State *L, int _val_i, enum eLookupMode const mode_);
24int keeper_push_linda_storage( lua_State* L, void* ptr); 24int keeper_push_linda_storage( lua_State* L, void* ptr);
25 25
26typedef lua_CFunction keeper_api_t; 26typedef lua_CFunction keeper_api_t;
diff --git a/src/lanes.c b/src/lanes.c
index cad8fb1..f62c39f 100644
--- a/src/lanes.c
+++ b/src/lanes.c
@@ -52,7 +52,7 @@
52 * ... 52 * ...
53 */ 53 */
54 54
55char const* VERSION = "3.7.8"; 55char const* VERSION = "3.8.0";
56 56
57/* 57/*
58=============================================================================== 58===============================================================================
@@ -464,7 +464,7 @@ LUAG_FUNC( linda_send)
464 } 464 }
465 465
466 // convert nils to some special non-nil sentinel in sent values 466 // convert nils to some special non-nil sentinel in sent values
467 keeper_toggle_nil_sentinels( L, key_i + 1, 1); 467 keeper_toggle_nil_sentinels( L, key_i + 1, eLM_ToKeeper);
468 468
469 STACK_GROW( L, 1); 469 STACK_GROW( L, 1);
470 { 470 {
@@ -649,7 +649,7 @@ LUAG_FUNC( linda_receive)
649 { 649 {
650 ASSERT_L( pushed >= expected_pushed_min && pushed <= expected_pushed_max); 650 ASSERT_L( pushed >= expected_pushed_min && pushed <= expected_pushed_max);
651 // replace sentinels with real nils 651 // replace sentinels with real nils
652 keeper_toggle_nil_sentinels( L, lua_gettop( L) - pushed, 0); 652 keeper_toggle_nil_sentinels( L, lua_gettop( L) - pushed, eLM_FromKeeper);
653 // To be done from within the 'K' locking area 653 // To be done from within the 'K' locking area
654 // 654 //
655 SIGNAL_ALL( &linda->read_happened); 655 SIGNAL_ALL( &linda->read_happened);
@@ -725,28 +725,31 @@ LUAG_FUNC( linda_receive)
725 725
726 726
727/* 727/*
728* [true] = linda_set( linda_ud, key_num|str|bool|lightuserdata [,value] ) 728* [true] = linda_set( linda_ud, key_num|str|bool|lightuserdata [, value [, ...]])
729* 729*
730* Set a value to Linda. 730* Set one or more value to Linda.
731* TODO: what do we do if we set to non-nil and limit is 0? 731* TODO: what do we do if we set to non-nil and limit is 0?
732* 732*
733* Existing slot value is replaced, and possible queue entries removed. 733* Existing slot value is replaced, and possible queued entries removed.
734*/ 734*/
735LUAG_FUNC( linda_set) 735LUAG_FUNC( linda_set)
736{ 736{
737 struct s_Linda *linda = lua_toLinda( L, 1); 737 struct s_Linda* const linda = lua_toLinda( L, 1);
738 int pushed; 738 int pushed;
739 bool_t has_value = !lua_isnil( L, 3); 739 bool_t has_value = lua_gettop( L) > 2;
740 luaL_argcheck( L, linda, 1, "expected a linda object!"); 740 luaL_argcheck( L, linda, 1, "expected a linda object!");
741 luaL_argcheck( L, lua_gettop( L) <= 3, 4, "too many arguments");
742 741
743 // make sure the key is of a valid type 742 // make sure the key is of a valid type (throws an error if not the case)
744 check_key_types( L, 2, 2); 743 check_key_types( L, 2, 2);
745 744
746 { 745 {
747 struct s_Keeper* K = keeper_acquire( linda); 746 struct s_Keeper* K = keeper_acquire( linda);
748 if( K == NULL) return 0; 747 if( K == NULL) return 0;
749 // no nil->sentinel toggling, we really clear the linda contents for the given key with a set() 748 if( has_value)
749 {
750 // convert nils to some special non-nil sentinel in sent values
751 keeper_toggle_nil_sentinels( L, 3, eLM_ToKeeper);
752 }
750 pushed = keeper_call( K->L, KEEPER_API( set), L, linda, 2); 753 pushed = keeper_call( K->L, KEEPER_API( set), L, linda, 2);
751 if( pushed >= 0) // no error? 754 if( pushed >= 0) // no error?
752 { 755 {
@@ -801,31 +804,32 @@ LUAG_FUNC( linda_count)
801 804
802 805
803/* 806/*
804* [val]= linda_get( linda_ud, key_num|str|bool|lightuserdata ) 807* [val [, ...]] = linda_get( linda_ud, key_num|str|bool|lightuserdata [, count = 1])
805* 808*
806* Get a value from Linda. 809* Get one or more values from Linda.
807* TODO: add support to get multiple values?
808*/ 810*/
809LUAG_FUNC( linda_get) 811LUAG_FUNC( linda_get)
810{ 812{
811 struct s_Linda *linda= lua_toLinda( L, 1); 813 struct s_Linda* const linda = lua_toLinda( L, 1);
812 int pushed; 814 int pushed;
815 int count = luaL_optint( L, 3, 1);
816 luaL_argcheck( L, count >= 1, 3, "count should be >= 1");
817 luaL_argcheck( L, linda, 1, "expected a linda object");
818 luaL_argcheck( L, lua_gettop( L) <= 3, 4, "too many arguments");
813 819
814 luaL_argcheck( L, linda, 1, "expected a linda object!"); 820 // make sure the key is of a valid type (throws an error if not the case)
815 // make sure the key is of a valid type
816 check_key_types( L, 2, 2); 821 check_key_types( L, 2, 2);
817
818 { 822 {
819 struct s_Keeper* K = keeper_acquire( linda); 823 struct s_Keeper* K = keeper_acquire( linda);
820 if( K == NULL) return 0; 824 if( K == NULL) return 0;
821 pushed = keeper_call( K->L, KEEPER_API( get), L, linda, 2); 825 pushed = keeper_call( K->L, KEEPER_API( get), L, linda, 2);
822 ASSERT_L( pushed == 0 || pushed == 1);
823 if( pushed > 0) 826 if( pushed > 0)
824 { 827 {
825 keeper_toggle_nil_sentinels( L, lua_gettop( L) - pushed, 0); 828 keeper_toggle_nil_sentinels( L, lua_gettop( L) - pushed, eLM_FromKeeper);
826 } 829 }
827 keeper_release( K); 830 keeper_release( K);
828 // must trigger error after keeper state has been released 831 // must trigger error after keeper state has been released
832 // (an error can be raised if we attempt to read an unregistered function)
829 if( pushed < 0) 833 if( pushed < 0)
830 { 834 {
831 return luaL_error( L, "tried to copy unsupported types"); 835 return luaL_error( L, "tried to copy unsupported types");
diff --git a/src/lanes.lua b/src/lanes.lua
index e7b9715..9a0287d 100644
--- a/src/lanes.lua
+++ b/src/lanes.lua
@@ -596,8 +596,8 @@ end -- settings.with_timers
596-- 596--
597-- PUBLIC LANES API 597-- PUBLIC LANES API
598local genlock = function( linda, key, N) 598local genlock = function( linda, key, N)
599 linda:set( key) -- clears existing data
599 linda:limit( key, N) 600 linda:limit( key, N)
600 linda:set( key, nil) -- clears existing data
601 601
602 -- 602 --
603 -- [true [, ...]= trues(uint) 603 -- [true [, ...]= trues(uint)