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