diff options
-rw-r--r-- | CHANGES | 3 | ||||
-rw-r--r-- | docs/index.html | 7 | ||||
-rw-r--r-- | src/keeper.c | 8 | ||||
-rw-r--r-- | src/keeper.h | 7 | ||||
-rw-r--r-- | src/lanes.c | 70 | ||||
-rw-r--r-- | src/lanes.lua | 11 | ||||
-rw-r--r-- | tests/keeper.lua | 4 |
7 files changed, 66 insertions, 44 deletions
@@ -1,5 +1,8 @@ | |||
1 | CHANGES: | 1 | CHANGES: |
2 | 2 | ||
3 | CHANGE 100: BGe 17-Feb-14 | ||
4 | * lanes.linda() accepts an optional integer group to give control on keeper state repartition | ||
5 | |||
3 | CHANGE 99: BGe 17-Feb-14 | 6 | CHANGE 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: <opt_name>"</tt></li> | 1031 | <li><tt>tostring( linda)</tt> returns a string of the form <tt>"Linda: <opt_name>"</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 | ||
189 | int keeper_push_linda_storage( lua_State* L, void* ptr) | 189 | int 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 | ||
688 | struct s_Keeper* keeper_acquire( void const* ptr) | 688 | struct 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); | |||
18 | void close_keepers( void); | 18 | void close_keepers( void); |
19 | #endif // HAVE_KEEPER_ATEXIT_DESINIT | 19 | #endif // HAVE_KEEPER_ATEXIT_DESINIT |
20 | 20 | ||
21 | struct s_Keeper *keeper_acquire( const void *ptr); | 21 | struct s_Keeper *keeper_acquire( unsigned long magic_); |
22 | void keeper_release( struct s_Keeper *K); | 22 | #define KEEPER_MAGIC_SHIFT 3 |
23 | void keeper_release( struct s_Keeper* K); | ||
23 | void keeper_toggle_nil_sentinels( lua_State *L, int _val_i, enum eLookupMode const mode_); | 24 | void keeper_toggle_nil_sentinels( lua_State *L, int _val_i, enum eLookupMode const mode_); |
24 | int keeper_push_linda_storage( lua_State* L, void* ptr); | 25 | int keeper_push_linda_storage( lua_State* L, void* ptr, unsigned long magic_); |
25 | 26 | ||
26 | typedef lua_CFunction keeper_api_t; | 27 | typedef 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 | ||
425 | static void* linda_id( lua_State*, enum eDeepOp); | 427 | static 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) | |||
1057 | LUAG_FUNC( linda_dump) | 1059 | LUAG_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 | */ |
1216 | LUAG_FUNC( linda) | 1236 | LUAG_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 |
307 | end | 307 | end |
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 | ||
317 | local 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) | |||
19 | end | 19 | end |
20 | 20 | ||
21 | -- | 21 | -- |
22 | local lindaA= lanes.linda() | 22 | local lindaA= lanes.linda( "A", 1) |
23 | local A= keeper( lindaA ) | 23 | local A= keeper( lindaA ) |
24 | 24 | ||
25 | local lindaB= lanes.linda() | 25 | local lindaB= lanes.linda( "B", 2) |
26 | local B= keeper( lindaB ) | 26 | local B= keeper( lindaB ) |
27 | 27 | ||
28 | A.some= 1 | 28 | A.some= 1 |