aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGES3
-rw-r--r--docs/index.html7
-rw-r--r--src/keeper.c8
-rw-r--r--src/keeper.h7
-rw-r--r--src/lanes.c70
-rw-r--r--src/lanes.lua11
-rw-r--r--tests/keeper.lua4
7 files changed, 66 insertions, 44 deletions
diff --git a/CHANGES b/CHANGES
index dd0917f..e7a08f7 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,5 +1,8 @@
1CHANGES: 1CHANGES:
2 2
3CHANGE 100: BGe 17-Feb-14
4 * lanes.linda() accepts an optional integer group to give control on keeper state repartition
5
3CHANGE 99: BGe 17-Feb-14 6CHANGE 99: BGe 17-Feb-14
4 * version 3.9.0 7 * version 3.9.0
5 * keepers now require "package", receive package.path & package.cpath, and call on_state_create() if it is a C function 8 * keepers now require "package", receive package.path & package.cpath, and call on_state_create() if it is a C function
diff --git a/docs/index.html b/docs/index.html
index 051f9d0..c6d612f 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 17-Feb-14, and applies to version <tt>3.9.0</tt>. 73 This document was revised on 17-Feb-14, and applies to version <tt>3.9.1</tt>.
74 </p> 74 </p>
75 </font> 75 </font>
76 </center> 76 </center>
@@ -1029,11 +1029,12 @@
1029 <li><tt>receive</tt> has a batched mode to consume more than one value from a single key, as in <tt>linda:receive( 1.0, linda.batched, "key", 3, 6).</tt></li> 1029 <li><tt>receive</tt> has a batched mode to consume more than one value from a single key, as in <tt>linda:receive( 1.0, linda.batched, "key", 3, 6).</tt></li>
1030 <li>individual keys' queue length can be limited, balancing speed differences in a producer/consumer scenario (making <tt>:send</tt> wait).</li> 1030 <li>individual keys' queue length can be limited, balancing speed differences in a producer/consumer scenario (making <tt>:send</tt> wait).</li>
1031 <li><tt>tostring( linda)</tt> returns a string of the form <tt>"Linda: &lt;opt_name&gt;"</tt></li> 1031 <li><tt>tostring( linda)</tt> returns a string of the form <tt>"Linda: &lt;opt_name&gt;"</tt></li>
1032 <li>several lindas may share the same keeper state. Since version 3.9.1, state assignation can be controlled with the linda's group (an integer). All lindas belonging to the same group will share the same keeper state. One keeper state may be shared by several groups.</li>
1032 </ul> 1033 </ul>
1033</p> 1034</p>
1034 1035
1035<table border="1" bgcolor="#E0E0FF" cellpadding="10" style="width:50%"><tr><td><pre> 1036<table border="1" bgcolor="#E0E0FF" cellpadding="10" style="width:50%"><tr><td><pre>
1036 h = lanes.linda( [opt_name]) 1037 h = lanes.linda( [opt_name, [opt_group]])
1037 1038
1038 [true|lanes.cancel_error] = h:send( [timeout_secs,] key, ...) 1039 [true|lanes.cancel_error] = h:send( [timeout_secs,] key, ...)
1039 1040
@@ -1171,7 +1172,7 @@
1171 <br/> 1172 <br/>
1172 If the thread is woken but the condition is not yet fulfilled, it goes back to sleep, until the timeout expires. 1173 If the thread is woken but the condition is not yet fulfilled, it goes back to sleep, until the timeout expires.
1173 <br/> 1174 <br/>
1174 When a lane is cancelled, the signal it is waiting on (if any) is signalled. In that case, the linda operation will return no data. 1175 When a lane is cancelled, the signal it is waiting on (if any) is signalled. In that case, the linda operation will return <tt>lanes.cancel_error</tt>.
1175</p> 1176</p>
1176 1177
1177<p> 1178<p>
diff --git a/src/keeper.c b/src/keeper.c
index 4eb8bb3..9b77c75 100644
--- a/src/keeper.c
+++ b/src/keeper.c
@@ -186,9 +186,9 @@ static void push_table( lua_State* L, int idx)
186 STACK_END( L, 1); 186 STACK_END( L, 1);
187} 187}
188 188
189int keeper_push_linda_storage( lua_State* L, void* ptr) 189int keeper_push_linda_storage( lua_State* L, void* ptr, unsigned long magic_)
190{ 190{
191 struct s_Keeper* K = keeper_acquire( ptr); 191 struct s_Keeper* K = keeper_acquire( magic_);
192 lua_State* KL = K ? K->L : NULL; 192 lua_State* KL = K ? K->L : NULL;
193 if( KL == NULL) return 0; 193 if( KL == NULL) return 0;
194 STACK_GROW( KL, 4); 194 STACK_GROW( KL, 4);
@@ -685,7 +685,7 @@ char const* init_keepers( lua_State* L)
685 return NULL; // ok 685 return NULL; // ok
686} 686}
687 687
688struct s_Keeper* keeper_acquire( void const* ptr) 688struct s_Keeper* keeper_acquire( unsigned long magic_)
689{ 689{
690 // can be 0 if this happens during main state shutdown (lanes is being GC'ed -> no keepers) 690 // can be 0 if this happens during main state shutdown (lanes is being GC'ed -> no keepers)
691 if( GNbKeepers == 0) 691 if( GNbKeepers == 0)
@@ -701,7 +701,7 @@ struct s_Keeper* keeper_acquire( void const* ptr)
701 * Pointers are often aligned by 8 or so - ignore the low order bits 701 * Pointers are often aligned by 8 or so - ignore the low order bits
702 * have to cast to unsigned long to avoid compilation warnings about loss of data when converting pointer-to-integer 702 * have to cast to unsigned long to avoid compilation warnings about loss of data when converting pointer-to-integer
703 */ 703 */
704 unsigned int i = (unsigned int)(((unsigned long)(ptr) >> 3) % GNbKeepers); 704 unsigned int i = (unsigned int)((magic_ >> KEEPER_MAGIC_SHIFT) % GNbKeepers);
705 struct s_Keeper* K= &GKeepers[i]; 705 struct s_Keeper* K= &GKeepers[i];
706 706
707 MUTEX_LOCK( &K->lock_); 707 MUTEX_LOCK( &K->lock_);
diff --git a/src/keeper.h b/src/keeper.h
index c0fd5d0..ed11ec4 100644
--- a/src/keeper.h
+++ b/src/keeper.h
@@ -18,10 +18,11 @@ char const* init_keepers( lua_State* L);
18void close_keepers( void); 18void close_keepers( void);
19#endif // HAVE_KEEPER_ATEXIT_DESINIT 19#endif // HAVE_KEEPER_ATEXIT_DESINIT
20 20
21struct s_Keeper *keeper_acquire( const void *ptr); 21struct s_Keeper *keeper_acquire( unsigned long magic_);
22void keeper_release( struct s_Keeper *K); 22#define KEEPER_MAGIC_SHIFT 3
23void keeper_release( struct s_Keeper* K);
23void keeper_toggle_nil_sentinels( lua_State *L, int _val_i, enum eLookupMode const mode_); 24void keeper_toggle_nil_sentinels( lua_State *L, int _val_i, enum eLookupMode const mode_);
24int keeper_push_linda_storage( lua_State* L, void* ptr); 25int keeper_push_linda_storage( lua_State* L, void* ptr, unsigned long magic_);
25 26
26typedef lua_CFunction keeper_api_t; 27typedef lua_CFunction keeper_api_t;
27#define KEEPER_API( _op) keepercall_ ## _op 28#define KEEPER_API( _op) keepercall_ ## _op
diff --git a/src/lanes.c b/src/lanes.c
index 597ac4b..71a9000 100644
--- a/src/lanes.c
+++ b/src/lanes.c
@@ -419,8 +419,10 @@ struct s_Linda
419 SIGNAL_T read_happened; 419 SIGNAL_T read_happened;
420 SIGNAL_T write_happened; 420 SIGNAL_T write_happened;
421 enum e_cancel_request simulate_cancel; 421 enum e_cancel_request simulate_cancel;
422 unsigned long group;
422 char name[1]; 423 char name[1];
423}; 424};
425#define LINDA_KEEPER_HASHSEED( linda) (linda->group ? linda->group : (unsigned long)linda)
424 426
425static void* linda_id( lua_State*, enum eDeepOp); 427static void* linda_id( lua_State*, enum eDeepOp);
426 428
@@ -489,7 +491,7 @@ LUAG_FUNC( linda_send)
489 { 491 {
490 bool_t try_again = TRUE; 492 bool_t try_again = TRUE;
491 struct s_lane* const s = get_lane_from_registry( L); 493 struct s_lane* const s = get_lane_from_registry( L);
492 struct s_Keeper* K = keeper_acquire( linda); 494 struct s_Keeper* K = keeper_acquire( LINDA_KEEPER_HASHSEED( linda));
493 lua_State* KL = K ? K->L : NULL; // need to do this for 'STACK_CHECK' 495 lua_State* KL = K ? K->L : NULL; // need to do this for 'STACK_CHECK'
494 if( KL == NULL) return 0; 496 if( KL == NULL) return 0;
495 STACK_CHECK( KL); 497 STACK_CHECK( KL);
@@ -652,7 +654,7 @@ LUAG_FUNC( linda_receive)
652 { 654 {
653 bool_t try_again = TRUE; 655 bool_t try_again = TRUE;
654 struct s_lane* const s = get_lane_from_registry( L); 656 struct s_lane* const s = get_lane_from_registry( L);
655 struct s_Keeper* K = keeper_acquire( linda); 657 struct s_Keeper* K = keeper_acquire( LINDA_KEEPER_HASHSEED( linda));
656 if( K == NULL) return 0; 658 if( K == NULL) return 0;
657 for( ;;) 659 for( ;;)
658 { 660 {
@@ -755,7 +757,7 @@ LUAG_FUNC( linda_set)
755 check_key_types( L, 2, 2); 757 check_key_types( L, 2, 2);
756 758
757 { 759 {
758 struct s_Keeper* K = keeper_acquire( linda); 760 struct s_Keeper* K = keeper_acquire( LINDA_KEEPER_HASHSEED( linda));
759 if( K == NULL) return 0; 761 if( K == NULL) return 0;
760 762
761 if( linda->simulate_cancel == CANCEL_NONE) 763 if( linda->simulate_cancel == CANCEL_NONE)
@@ -811,7 +813,7 @@ LUAG_FUNC( linda_count)
811 check_key_types( L, 2, lua_gettop( L)); 813 check_key_types( L, 2, lua_gettop( L));
812 814
813 { 815 {
814 struct s_Keeper* K = keeper_acquire( linda); 816 struct s_Keeper* K = keeper_acquire( LINDA_KEEPER_HASHSEED( linda));
815 if( K == NULL) return 0; 817 if( K == NULL) return 0;
816 pushed = keeper_call( K->L, KEEPER_API( count), L, linda, 2); 818 pushed = keeper_call( K->L, KEEPER_API( count), L, linda, 2);
817 keeper_release( K); 819 keeper_release( K);
@@ -840,7 +842,7 @@ LUAG_FUNC( linda_get)
840 // make sure the key is of a valid type (throws an error if not the case) 842 // make sure the key is of a valid type (throws an error if not the case)
841 check_key_types( L, 2, 2); 843 check_key_types( L, 2, 2);
842 { 844 {
843 struct s_Keeper* K = keeper_acquire( linda); 845 struct s_Keeper* K = keeper_acquire( LINDA_KEEPER_HASHSEED( linda));
844 if( K == NULL) return 0; 846 if( K == NULL) return 0;
845 847
846 if( linda->simulate_cancel == CANCEL_NONE) 848 if( linda->simulate_cancel == CANCEL_NONE)
@@ -890,7 +892,7 @@ LUAG_FUNC( linda_limit)
890 check_key_types( L, 2, 2); 892 check_key_types( L, 2, 2);
891 893
892 { 894 {
893 struct s_Keeper* K = keeper_acquire( linda); 895 struct s_Keeper* K = keeper_acquire( LINDA_KEEPER_HASHSEED( linda));
894 if( K == NULL) return 0; 896 if( K == NULL) return 0;
895 897
896 if( linda->simulate_cancel == CANCEL_NONE) 898 if( linda->simulate_cancel == CANCEL_NONE)
@@ -931,7 +933,7 @@ LUAG_FUNC( linda_cancel)
931 luaL_argcheck( L, lua_gettop( L) <= 2, 2, "wrong number of arguments"); 933 luaL_argcheck( L, lua_gettop( L) <= 2, 2, "wrong number of arguments");
932 934
933 // signalling must be done from inside the K locking area 935 // signalling must be done from inside the K locking area
934 K = keeper_acquire( linda); 936 K = keeper_acquire( LINDA_KEEPER_HASHSEED( linda));
935 if( K == NULL) return 0; 937 if( K == NULL) return 0;
936 938
937 linda->simulate_cancel = CANCEL_SOFT; 939 linda->simulate_cancel = CANCEL_SOFT;
@@ -1057,7 +1059,7 @@ LUAG_FUNC( linda_concat)
1057LUAG_FUNC( linda_dump) 1059LUAG_FUNC( linda_dump)
1058{ 1060{
1059 struct s_Linda* linda = lua_toLinda( L, 1); 1061 struct s_Linda* linda = lua_toLinda( L, 1);
1060 return keeper_push_linda_storage( L, linda); 1062 return keeper_push_linda_storage( L, linda, LINDA_KEEPER_HASHSEED( linda));
1061} 1063}
1062 1064
1063/* 1065/*
@@ -1093,11 +1095,28 @@ static void* linda_id( lua_State* L, enum eDeepOp op_)
1093 struct s_Linda* s; 1095 struct s_Linda* s;
1094 size_t name_len = 0; 1096 size_t name_len = 0;
1095 char const* linda_name = NULL; 1097 char const* linda_name = NULL;
1096 int const top = lua_gettop( L); 1098 unsigned long linda_group = 0;
1097 1099 // should have a string and/or a number of the stack as parameters (name and group)
1098 if( top > 0 && lua_type( L, top) == LUA_TSTRING) 1100 switch( lua_gettop( L))
1099 { 1101 {
1100 linda_name = lua_tolstring( L, top, &name_len); 1102 default: // 0
1103 break;
1104
1105 case 1: // 1 parameter, either a name or a group
1106 if( lua_type( L, -1) == LUA_TSTRING)
1107 {
1108 linda_name = lua_tolstring( L, -1, &name_len);
1109 }
1110 else
1111 {
1112 linda_group = (unsigned long) lua_tointeger( L, -1);
1113 }
1114 break;
1115
1116 case 2: // 2 parameters, a name and group, in that order
1117 linda_name = lua_tolstring( L, -2, &name_len);
1118 linda_group = lua_tointeger( L, -1);
1119 break;
1101 } 1120 }
1102 1121
1103 /* The deep data is allocated separately of Lua stack; we might no 1122 /* The deep data is allocated separately of Lua stack; we might no
@@ -1110,6 +1129,7 @@ static void* linda_id( lua_State* L, enum eDeepOp op_)
1110 SIGNAL_INIT( &s->read_happened); 1129 SIGNAL_INIT( &s->read_happened);
1111 SIGNAL_INIT( &s->write_happened); 1130 SIGNAL_INIT( &s->write_happened);
1112 s->simulate_cancel = CANCEL_NONE; 1131 s->simulate_cancel = CANCEL_NONE;
1132 s->group = linda_group << KEEPER_MAGIC_SHIFT;
1113 s->name[0] = 0; 1133 s->name[0] = 0;
1114 memcpy( s->name, linda_name, name_len ? name_len + 1 : 0); 1134 memcpy( s->name, linda_name, name_len ? name_len + 1 : 0);
1115 return s; 1135 return s;
@@ -1118,24 +1138,24 @@ static void* linda_id( lua_State* L, enum eDeepOp op_)
1118 case eDO_delete: 1138 case eDO_delete:
1119 { 1139 {
1120 struct s_Keeper* K; 1140 struct s_Keeper* K;
1121 struct s_Linda* l = lua_touserdata( L, 1); 1141 struct s_Linda* linda = lua_touserdata( L, 1);
1122 ASSERT_L( l); 1142 ASSERT_L( linda);
1123 1143
1124 /* Clean associated structures in the keeper state. 1144 /* Clean associated structures in the keeper state.
1125 */ 1145 */
1126 K = keeper_acquire( l); 1146 K = keeper_acquire( LINDA_KEEPER_HASHSEED( linda));
1127 if( K && K->L) // can be NULL if this happens during main state shutdown (lanes is GC'ed -> no keepers -> no need to cleanup) 1147 if( K && K->L) // can be NULL if this happens during main state shutdown (lanes is GC'ed -> no keepers -> no need to cleanup)
1128 { 1148 {
1129 keeper_call( K->L, KEEPER_API( clear), L, l, 0); 1149 keeper_call( K->L, KEEPER_API( clear), L, linda, 0);
1130 } 1150 }
1131 keeper_release( K); 1151 keeper_release( K);
1132 1152
1133 /* There aren't any lanes waiting on these lindas, since all proxies 1153 /* There aren't any lanes waiting on these lindas, since all proxies
1134 * have been gc'ed. Right? 1154 * have been gc'ed. Right?
1135 */ 1155 */
1136 SIGNAL_FREE( &l->read_happened); 1156 SIGNAL_FREE( &linda->read_happened);
1137 SIGNAL_FREE( &l->write_happened); 1157 SIGNAL_FREE( &linda->write_happened);
1138 free( l); 1158 free( linda);
1139 return NULL; 1159 return NULL;
1140 } 1160 }
1141 1161
@@ -1209,16 +1229,24 @@ static void* linda_id( lua_State* L, enum eDeepOp op_)
1209} 1229}
1210 1230
1211/* 1231/*
1212 * ud = lanes.linda() 1232 * ud = lanes.linda( [name[,group]])
1213 * 1233 *
1214 * returns a linda object 1234 * returns a linda object
1215 */ 1235 */
1216LUAG_FUNC( linda) 1236LUAG_FUNC( linda)
1217{ 1237{
1218 int const top = lua_gettop( L); 1238 int const top = lua_gettop( L);
1219 luaL_argcheck( L, top <= 1, top, "too many arguments"); 1239 luaL_argcheck( L, top <= 2, top, "too many arguments");
1220 if( top == 1) 1240 if( top == 1)
1241 {
1242 int const t = lua_type( L, 1);
1243 luaL_argcheck( L, t == LUA_TSTRING || t == LUA_TNUMBER, 1, "wrong parameter (should be a string or a number)");
1244 }
1245 else if( top == 2)
1246 {
1221 luaL_checktype( L, 1, LUA_TSTRING); 1247 luaL_checktype( L, 1, LUA_TSTRING);
1248 luaL_checktype( L, 2, LUA_TNUMBER);
1249 }
1222 return luaG_newdeepuserdata( L, linda_id); 1250 return luaG_newdeepuserdata( L, linda_id);
1223} 1251}
1224 1252
diff --git a/src/lanes.lua b/src/lanes.lua
index 86dbe47..5dfe41d 100644
--- a/src/lanes.lua
+++ b/src/lanes.lua
@@ -306,17 +306,6 @@ local function gen( ... )
306 end 306 end
307end 307end
308 308
309---=== Lindas ===---
310
311-- We let the C code attach methods to userdata directly
312
313-----
314-- lanes.linda(["name"]) -> linda_ud
315--
316-- PUBLIC LANES API
317local linda = core.linda
318
319
320---=== Timers ===--- 309---=== Timers ===---
321 310
322-- PUBLIC LANES API 311-- PUBLIC LANES API
diff --git a/tests/keeper.lua b/tests/keeper.lua
index 73ed3cf..4aff51c 100644
--- a/tests/keeper.lua
+++ b/tests/keeper.lua
@@ -19,10 +19,10 @@ local function keeper(linda)
19end 19end
20 20
21-- 21--
22local lindaA= lanes.linda() 22local lindaA= lanes.linda( "A", 1)
23local A= keeper( lindaA ) 23local A= keeper( lindaA )
24 24
25local lindaB= lanes.linda() 25local lindaB= lanes.linda( "B", 2)
26local B= keeper( lindaB ) 26local B= keeper( lindaB )
27 27
28A.some= 1 28A.some= 1