diff options
-rw-r--r-- | CHANGES | 7 | ||||
-rw-r--r-- | docs/index.html | 30 | ||||
-rw-r--r-- | src/keeper.c | 96 | ||||
-rw-r--r-- | src/lanes.c | 55 |
4 files changed, 123 insertions, 65 deletions
@@ -1,5 +1,12 @@ | |||
1 | CHANGES: | 1 | CHANGES: |
2 | 2 | ||
3 | CHANGE 89: BGe 09-Jan-14 | ||
4 | * version 3.7.7 | ||
5 | * fix crash when calling linda:count() on unknown keys | ||
6 | * purge key storage with linda:set( key, nil) on an unlimited key to reduce memory usage with lots of keys | ||
7 | * linda:limit() wakes write-blocked threads if necessary when the new limit enables writes to occur again | ||
8 | * linda:set() wakes write-blocked threads if necessary if the operation created some room to write into | ||
9 | |||
3 | CHANGE 88: BGe 06-Jan-14 | 10 | CHANGE 88: BGe 06-Jan-14 |
4 | * version 3.7.6 | 11 | * version 3.7.6 |
5 | * if config.on_state_create() is a C function, call it by direct C closure reconstruction in newly created states | 12 | * if config.on_state_create() is a C function, call it by direct C closure reconstruction in newly created states |
diff --git a/docs/index.html b/docs/index.html index 931a961..c62f64f 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 06-Jan-14, and applies to version <tt>3.7.6</tt>. | 73 | This document was revised on 09-Jan-14, and applies to version <tt>3.7.7</tt>. |
74 | </p> | 74 | </p> |
75 | </font> | 75 | </font> |
76 | </center> | 76 | </center> |
@@ -1010,13 +1010,13 @@ | |||
1010 | <table border="1" bgcolor="#E0E0FF" cellpadding="10" style="width:50%"><tr><td><pre> | 1010 | <table border="1" bgcolor="#E0E0FF" cellpadding="10" style="width:50%"><tr><td><pre> |
1011 | h = lanes.linda( [opt_name]) | 1011 | h = lanes.linda( [opt_name]) |
1012 | 1012 | ||
1013 | bool = h:send( [timeout_secs,] key, ... ) | 1013 | bool = h:send( [timeout_secs,] key, ...) |
1014 | 1014 | ||
1015 | [key, val] = h:receive( [timeout_secs,] key [, ...]) | 1015 | [key, val] = h:receive( [timeout_secs,] key [, ...]) |
1016 | 1016 | ||
1017 | [key, val [, ...]] = h:receive( timeout, h.batched, key, n_uint_min[, n_uint_max]) | 1017 | [key, val [, ...]] = h:receive( timeout, h.batched, key, n_uint_min[, n_uint_max]) |
1018 | 1018 | ||
1019 | void = h:limit( key, n_uint) | 1019 | [true] = h:limit( key, n_uint) |
1020 | </pre></td></tr></table> | 1020 | </pre></td></tr></table> |
1021 | 1021 | ||
1022 | <p> | 1022 | <p> |
@@ -1024,7 +1024,11 @@ | |||
1024 | </p> | 1024 | </p> |
1025 | 1025 | ||
1026 | <p> | 1026 | <p> |
1027 | By default, stack sizes are unlimited but limits can be enforced using the <tt>limit</tt> method. This can be useful to balance execution speeds in a producer/consumer scenario. | 1027 | By default, stack sizes are unlimited but limits can be enforced using the <tt>limit</tt> method. This can be useful to balance execution speeds in a producer/consumer scenario. Any negative value removes the limit. |
1028 | <br/> | ||
1029 | A limit of 0 is allowed to block everything. | ||
1030 | <br/> | ||
1031 | (Since version 3.7.7) if the key was full but the limit change added some room, <tt>limit()</tt> returns <tt>true</tt> and the linda is signalled so that <tt>send()</tt>-blocked threads are awakened. | ||
1028 | </p> | 1032 | </p> |
1029 | 1033 | ||
1030 | <p> | 1034 | <p> |
@@ -1036,13 +1040,13 @@ | |||
1036 | </p> | 1040 | </p> |
1037 | 1041 | ||
1038 | <p> | 1042 | <p> |
1039 | <tt>send</tt> returns <tt>true</tt> if the sending succeeded, and <tt>false</tt> if the queue limit was met, and the queue did not empty enough during the given timeout. | 1043 | <tt>send()</tt> returns <tt>true</tt> if the sending succeeded, and <tt>false</tt> if the queue limit was met, and the queue did not empty enough during the given timeout. |
1040 | </p> | 1044 | </p> |
1041 | 1045 | ||
1042 | <p> | 1046 | <p> |
1043 | Equally, <tt>receive</tt> returns a key and the value extracted from it, or nothing for timeout. Note that <tt>nil</tt>s can be sent and received; the <tt>key</tt> value will tell it apart from a timeout. | 1047 | Equally, <tt>receive()</tt> returns a key and the value extracted from it, or nothing for timeout. Note that <tt>nil</tt>s can be sent and received; the <tt>key</tt> value will tell it apart from a timeout. |
1044 | <br> | 1048 | <br> |
1045 | Version 3.4.0 introduces an API change in the returned values: <tt>receive</tt> returns the key followed by the value(s), in that order, and not the other way around. | 1049 | Version 3.4.0 introduces an API change in the returned values: <tt>receive()</tt> returns the key followed by the value(s), in that order, and not the other way around. |
1046 | </p> | 1050 | </p> |
1047 | 1051 | ||
1048 | <p> | 1052 | <p> |
@@ -1055,9 +1059,9 @@ | |||
1055 | </p> | 1059 | </p> |
1056 | 1060 | ||
1057 | <table border="1" bgcolor="#E0E0FF" cellpadding="10" style="width:50%"><tr><td><pre> | 1061 | <table border="1" bgcolor="#E0E0FF" cellpadding="10" style="width:50%"><tr><td><pre> |
1058 | linda_h:set( key, [val]) | 1062 | [true] = linda_h:set( key, [val]) |
1059 | 1063 | ||
1060 | [val] = linda_h:get( key ) | 1064 | [val] = linda_h:get( key) |
1061 | </pre></td></tr></table> | 1065 | </pre></td></tr></table> |
1062 | 1066 | ||
1063 | <p> | 1067 | <p> |
@@ -1065,7 +1069,13 @@ | |||
1065 | </p> | 1069 | </p> |
1066 | 1070 | ||
1067 | <p> | 1071 | <p> |
1068 | Writing to a slot overwrites existing value, and clears any possible queued entries. 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. | 1072 | Writing to a slot never blocks because it ignores the limit. It overwrites existing value and clears any possible queued entries. |
1073 | <br/> | ||
1074 | <tt>set()</tt> signals the linda from write if a value is stored. | ||
1075 | <br/> | ||
1076 | (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. | ||
1077 | <br/> | ||
1078 | 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. | ||
1069 | </p> | 1079 | </p> |
1070 | 1080 | ||
1071 | <table border="1" bgcolor="#E0E0FF" cellpadding="10" style="width:50%"><tr><td><pre> | 1081 | <table border="1" bgcolor="#E0E0FF" cellpadding="10" style="width:50%"><tr><td><pre> |
diff --git a/src/keeper.c b/src/keeper.c index 4c90069..6d5ecbf 100644 --- a/src/keeper.c +++ b/src/keeper.c | |||
@@ -95,7 +95,7 @@ static void fifo_new( lua_State* L) | |||
95 | } | 95 | } |
96 | 96 | ||
97 | // in: expect fifo ... on top of the stack | 97 | // in: expect fifo ... on top of the stack |
98 | // out: nothing, removes all pushed values on the stack | 98 | // out: nothing, removes all pushed values from the stack |
99 | static void fifo_push( lua_State* L, keeper_fifo* fifo, int _count) | 99 | static void fifo_push( lua_State* L, keeper_fifo* fifo, int _count) |
100 | { | 100 | { |
101 | int idx = lua_gettop( L) - _count; | 101 | int idx = lua_gettop( L) - _count; |
@@ -349,7 +349,7 @@ int keepercall_receive_batched( lua_State* L) | |||
349 | } | 349 | } |
350 | 350 | ||
351 | // in: linda_ud key n | 351 | // in: linda_ud key n |
352 | // out: nothing | 352 | // out: true or nil |
353 | int keepercall_limit( lua_State* L) | 353 | int keepercall_limit( lua_State* L) |
354 | { | 354 | { |
355 | keeper_fifo* fifo; | 355 | keeper_fifo* fifo; |
@@ -358,22 +358,37 @@ int keepercall_limit( lua_State* L) | |||
358 | lua_replace( L, 1); // fifos key n | 358 | lua_replace( L, 1); // fifos key n |
359 | lua_pop( L, 1); // fifos key | 359 | lua_pop( L, 1); // fifos key |
360 | lua_pushvalue( L, -1); // fifos key key | 360 | lua_pushvalue( L, -1); // fifos key key |
361 | lua_rawget( L, -3); // fifos key fifo | 361 | lua_rawget( L, -3); // fifos key fifo|nil |
362 | fifo = (keeper_fifo*) lua_touserdata( L, -1); | 362 | fifo = (keeper_fifo*) lua_touserdata( L, -1); |
363 | if( fifo == NULL) | 363 | if( fifo == NULL) |
364 | { | 364 | { // fifos key nil |
365 | lua_pop( L, 1); // fifos key | 365 | lua_pop( L, 1); // fifos key |
366 | fifo_new( L); // fifos key fifo | 366 | fifo_new( L); // fifos key fifo |
367 | fifo = (keeper_fifo*) lua_touserdata( L, -1); | 367 | fifo = (keeper_fifo*) lua_touserdata( L, -1); |
368 | lua_rawset( L, -3); // fifos | 368 | lua_rawset( L, -3); // fifos |
369 | } | 369 | } |
370 | // remove any clutter on the stack | ||
371 | lua_settop( L, 0); | ||
372 | // return true if we decide that blocked threads waiting to write on that key should be awakened | ||
373 | // this is the case if we detect the key was full but it is no longer the case | ||
374 | if( | ||
375 | ((fifo->limit >= 0) && (fifo->count >= fifo->limit)) // the key was full if limited and count exceeded the previous limit | ||
376 | && ((limit < 0) || (fifo->count < limit)) // the key is not full if unlimited or count is lower than the new limit | ||
377 | ) | ||
378 | { | ||
379 | lua_pushboolean( L, 1); | ||
380 | } | ||
381 | // set the new limit | ||
370 | fifo->limit = limit; | 382 | fifo->limit = limit; |
371 | return 0; | 383 | // return 0 or 1 value |
384 | return lua_gettop( L); | ||
372 | } | 385 | } |
373 | 386 | ||
374 | //in: linda_ud key [val] | 387 | //in: linda_ud key [val] |
388 | //out: true or nil | ||
375 | int keepercall_set( lua_State* L) | 389 | int keepercall_set( lua_State* L) |
376 | { | 390 | { |
391 | bool_t should_wake_writers = FALSE; | ||
377 | STACK_GROW( L, 6); | 392 | STACK_GROW( L, 6); |
378 | // make sure we have a value on the stack | 393 | // make sure we have a value on the stack |
379 | if( lua_gettop( L) == 2) // ud key val? | 394 | if( lua_gettop( L) == 2) // ud key val? |
@@ -391,16 +406,18 @@ int keepercall_set( lua_State* L) | |||
391 | lua_pushvalue( L, -2); // fifos key val key | 406 | lua_pushvalue( L, -2); // fifos key val key |
392 | lua_rawget( L, 1); // fifos key val fifo|nil | 407 | lua_rawget( L, 1); // fifos key val fifo|nil |
393 | fifo = (keeper_fifo*) lua_touserdata( L, -1); | 408 | fifo = (keeper_fifo*) lua_touserdata( L, -1); |
394 | if( fifo == NULL) // might be NULL if we set a nonexistent key to nil | 409 | if( fifo == NULL) // can be NULL if we store a value at a new key |
395 | { | 410 | { // fifos key val nil |
396 | lua_pop( L, 1); // fifos key val | 411 | lua_pop( L, 1); // fifos key val |
397 | fifo_new( L); // fifos key val fifo | 412 | fifo_new( L); // fifos key val fifo |
398 | lua_pushvalue( L, 2); // fifos key val fifo key | 413 | lua_pushvalue( L, 2); // fifos key val fifo key |
399 | lua_pushvalue( L, -2); // fifos key val fifo key fifo | 414 | lua_pushvalue( L, -2); // fifos key val fifo key fifo |
400 | lua_rawset( L, 1); // fifos key val fifo | 415 | lua_rawset( L, 1); // fifos key val fifo |
401 | } | 416 | } |
402 | else // the fifo exists, we just want to clear its contents | 417 | else // the fifo exists, we just want to update its contents |
403 | { | 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); | ||
404 | // empty the fifo for the specified key: replace uservalue with a virgin table, reset counters, but leave limit unchanged! | 421 | // empty the fifo for the specified key: replace uservalue with a virgin table, reset counters, but leave limit unchanged! |
405 | lua_newtable( L); // fifos key val fifo {} | 422 | lua_newtable( L); // fifos key val fifo {} |
406 | lua_setuservalue( L, -2); // fifos key val fifo | 423 | lua_setuservalue( L, -2); // fifos key val fifo |
@@ -411,22 +428,35 @@ int keepercall_set( lua_State* L) | |||
411 | lua_insert( L, -2); // fifos key fifo val | 428 | lua_insert( L, -2); // fifos key fifo val |
412 | fifo_push( L, fifo, 1); // fifos key fifo | 429 | fifo_push( L, fifo, 1); // fifos key fifo |
413 | } | 430 | } |
414 | else // val == nil // fifos key nil | 431 | else // val == nil: we clear the key contents |
415 | { | 432 | { // fifos key nil |
416 | keeper_fifo* fifo; | 433 | keeper_fifo* fifo; |
417 | lua_pop( L, 1); // fifos key | 434 | lua_pop( L, 1); // fifos key |
418 | lua_rawget( L, 1); // fifos fifo|nil | 435 | lua_pushvalue( L, -1); // fifos key key |
436 | lua_rawget( L, 1); // fifos key fifo|nil | ||
419 | // empty the fifo for the specified key: replace uservalue with a virgin table, reset counters, but leave limit unchanged! | 437 | // empty the fifo for the specified key: replace uservalue with a virgin table, reset counters, but leave limit unchanged! |
420 | fifo = (keeper_fifo*) lua_touserdata( L, -1); | 438 | fifo = (keeper_fifo*) lua_touserdata( L, -1); |
421 | if( fifo != NULL) // might be NULL if we set a nonexistent key to nil | 439 | if( fifo != NULL) // might be NULL if we set a nonexistent key to nil |
422 | { | 440 | { // fifos key fifo |
423 | lua_newtable( L); // fifos fifo {} | 441 | if( fifo->limit < 0) // fifo limit value is the default (unlimited): we can totally remove it |
424 | lua_setuservalue( L, -2); // fifos fifo | 442 | { |
425 | fifo->first = 1; | 443 | lua_pop( L, 1); // fifos key |
426 | fifo->count = 0; | 444 | lua_pushnil( L); // fifos key nil |
445 | lua_rawset( L, -3); // fifos | ||
446 | } | ||
447 | else | ||
448 | { | ||
449 | // we create room if the fifo was full but it is no longer the case | ||
450 | should_wake_writers = (fifo->limit > 0) && (fifo->count >= fifo->limit); | ||
451 | lua_remove( L, -2); // fifos fifo | ||
452 | lua_newtable( L); // fifos fifo {} | ||
453 | lua_setuservalue( L, -2); // fifos fifo | ||
454 | fifo->first = 1; | ||
455 | fifo->count = 0; | ||
456 | } | ||
427 | } | 457 | } |
428 | } | 458 | } |
429 | return 0; | 459 | return should_wake_writers ? (lua_pushboolean( L, 1), 1) : 0; |
430 | } | 460 | } |
431 | 461 | ||
432 | // in: linda_ud key | 462 | // in: linda_ud key |
@@ -476,11 +506,18 @@ int keepercall_count( lua_State* L) | |||
476 | { | 506 | { |
477 | keeper_fifo* fifo; | 507 | keeper_fifo* fifo; |
478 | lua_replace( L, 1); // fifos key | 508 | lua_replace( L, 1); // fifos key |
479 | lua_rawget( L, -2); // fifos fifo | 509 | lua_rawget( L, -2); // fifos fifo|nil |
480 | fifo = prepare_fifo_access( L, -1); // fifos fifo | 510 | if( lua_isnil( L, -1)) // the key is unknown |
481 | lua_pushinteger( L, fifo->count); // fifos fifo count | 511 | { // fifos nil |
482 | lua_replace( L, -3); // count fifo | 512 | lua_remove( L, -2); // nil |
483 | lua_pop( L, 1); // count | 513 | } |
514 | else // the key is known | ||
515 | { // fifos fifo | ||
516 | fifo = prepare_fifo_access( L, -1); // fifos fifo | ||
517 | lua_pushinteger( L, fifo->count); // fifos fifo count | ||
518 | lua_replace( L, -3); // count fifo | ||
519 | lua_pop( L, 1); // count | ||
520 | } | ||
484 | } | 521 | } |
485 | break; | 522 | break; |
486 | 523 | ||
@@ -494,21 +531,22 @@ int keepercall_count( lua_State* L) | |||
494 | { | 531 | { |
495 | keeper_fifo* fifo; | 532 | keeper_fifo* fifo; |
496 | lua_pushvalue( L, -1); // out fifos keys key | 533 | lua_pushvalue( L, -1); // out fifos keys key |
497 | lua_rawget( L, 2); // out fifos keys fifo | 534 | lua_rawget( L, 2); // out fifos keys fifo|nil |
498 | fifo = prepare_fifo_access( L, -1); // out fifos keys fifo | 535 | fifo = prepare_fifo_access( L, -1); // out fifos keys fifo|nil |
499 | lua_pop( L, 1); // out fifos keys | 536 | lua_pop( L, 1); // out fifos keys |
500 | if( fifo != NULL) | 537 | if( fifo != NULL) // the key is known |
501 | { | 538 | { |
502 | lua_pushinteger( L, fifo->count); // out fifos keys count | 539 | lua_pushinteger( L, fifo->count); // out fifos keys count |
503 | lua_rawset( L, 1); // out fifos keys | 540 | lua_rawset( L, 1); // out fifos keys |
504 | } | 541 | } |
505 | else | 542 | else // the key is unknown |
506 | { | 543 | { |
507 | lua_pop( L, 1); // out fifos keys | 544 | lua_pop( L, 1); // out fifos keys |
508 | } | 545 | } |
509 | } | 546 | } |
510 | lua_pop( L, 1); // out | 547 | lua_pop( L, 1); // out |
511 | } | 548 | } |
549 | ASSERT_L( lua_gettop( L) == 1); | ||
512 | return 1; | 550 | return 1; |
513 | } | 551 | } |
514 | 552 | ||
@@ -681,7 +719,7 @@ void keeper_toggle_nil_sentinels( lua_State* L, int _val_i, int _nil_to_sentinel | |||
681 | * | 719 | * |
682 | * Returns: number of return values (pushed to 'L') or -1 in case of error | 720 | * Returns: number of return values (pushed to 'L') or -1 in case of error |
683 | */ | 721 | */ |
684 | int keeper_call( lua_State *K, keeper_api_t _func, lua_State *L, void *linda, uint_t starting_index) | 722 | int keeper_call( lua_State* K, keeper_api_t func_, lua_State* L, void* linda, uint_t starting_index) |
685 | { | 723 | { |
686 | int const args = starting_index ? (lua_gettop( L) - starting_index + 1) : 0; | 724 | int const args = starting_index ? (lua_gettop( L) - starting_index + 1) : 0; |
687 | int const Ktos = lua_gettop( K); | 725 | int const Ktos = lua_gettop( K); |
@@ -689,7 +727,7 @@ int keeper_call( lua_State *K, keeper_api_t _func, lua_State *L, void *linda, ui | |||
689 | 727 | ||
690 | STACK_GROW( K, 2); | 728 | STACK_GROW( K, 2); |
691 | 729 | ||
692 | PUSH_KEEPER_FUNC( K, _func); | 730 | PUSH_KEEPER_FUNC( K, func_); |
693 | 731 | ||
694 | lua_pushlightuserdata( K, linda); | 732 | lua_pushlightuserdata( K, linda); |
695 | 733 | ||
diff --git a/src/lanes.c b/src/lanes.c index 3ccf915..d852a20 100644 --- a/src/lanes.c +++ b/src/lanes.c | |||
@@ -52,7 +52,7 @@ | |||
52 | * ... | 52 | * ... |
53 | */ | 53 | */ |
54 | 54 | ||
55 | char const* VERSION = "3.7.6"; | 55 | char const* VERSION = "3.7.7"; |
56 | 56 | ||
57 | /* | 57 | /* |
58 | =============================================================================== | 58 | =============================================================================== |
@@ -672,7 +672,7 @@ LUAG_FUNC( linda_receive) | |||
672 | 672 | ||
673 | 673 | ||
674 | /* | 674 | /* |
675 | * = linda_set( linda_ud, key_num|str|bool|lightuserdata [,value] ) | 675 | * [true] = linda_set( linda_ud, key_num|str|bool|lightuserdata [,value] ) |
676 | * | 676 | * |
677 | * Set a value to Linda. | 677 | * Set a value to Linda. |
678 | * TODO: what do we do if we set to non-nil and limit is 0? | 678 | * TODO: what do we do if we set to non-nil and limit is 0? |
@@ -682,6 +682,7 @@ LUAG_FUNC( linda_receive) | |||
682 | LUAG_FUNC( linda_set) | 682 | LUAG_FUNC( linda_set) |
683 | { | 683 | { |
684 | struct s_Linda *linda = lua_toLinda( L, 1); | 684 | struct s_Linda *linda = lua_toLinda( L, 1); |
685 | int pushed; | ||
685 | bool_t has_value = !lua_isnil( L, 3); | 686 | bool_t has_value = !lua_isnil( L, 3); |
686 | luaL_argcheck( L, linda, 1, "expected a linda object!"); | 687 | luaL_argcheck( L, linda, 1, "expected a linda object!"); |
687 | luaL_argcheck( L, lua_gettop( L) <= 3, 4, "too many arguments"); | 688 | luaL_argcheck( L, lua_gettop( L) <= 3, 4, "too many arguments"); |
@@ -690,31 +691,31 @@ LUAG_FUNC( linda_set) | |||
690 | check_key_types( L, 2, 2); | 691 | check_key_types( L, 2, 2); |
691 | 692 | ||
692 | { | 693 | { |
693 | int pushed; | 694 | struct s_Keeper* K = keeper_acquire( linda); |
694 | struct s_Keeper *K = keeper_acquire( linda); | ||
695 | if( K == NULL) return 0; | 695 | if( K == NULL) return 0; |
696 | // no nil->sentinel toggling, we really clear the linda contents for the given key with a set() | 696 | // no nil->sentinel toggling, we really clear the linda contents for the given key with a set() |
697 | pushed = keeper_call( K->L, KEEPER_API( set), L, linda, 2); | 697 | pushed = keeper_call( K->L, KEEPER_API( set), L, linda, 2); |
698 | if( pushed >= 0) // no error? | 698 | if( pushed >= 0) // no error? |
699 | { | 699 | { |
700 | ASSERT_L( pushed == 0); | 700 | ASSERT_L( pushed == 0 || pushed == 1); |
701 | 701 | ||
702 | /* Set the signal from within 'K' locking. | ||
703 | */ | ||
704 | if( has_value) | 702 | if( has_value) |
705 | { | 703 | { |
706 | SIGNAL_ALL( &linda->write_happened); | 704 | // we put some data in the slot, tell readers that they should wake |
705 | SIGNAL_ALL( &linda->write_happened); // To be done from within the 'K' locking area | ||
706 | } | ||
707 | if( pushed == 1) | ||
708 | { | ||
709 | // the key was full, but it is no longer the case, tell writers they should wake | ||
710 | ASSERT_L( lua_type( L, -1) == LUA_TBOOLEAN && lua_toboolean( L, -1) == 1); | ||
711 | SIGNAL_ALL( &linda->read_happened); // To be done from within the 'K' locking area | ||
707 | } | 712 | } |
708 | } | 713 | } |
709 | keeper_release( K); | 714 | keeper_release( K); |
710 | // must trigger error after keeper state has been released | ||
711 | if( pushed < 0) | ||
712 | { | ||
713 | return luaL_error( L, "tried to copy unsupported types"); | ||
714 | } | ||
715 | } | 715 | } |
716 | 716 | ||
717 | return 0; | 717 | // must trigger any error after keeper state has been released |
718 | return (pushed < 0) ? luaL_error( L, "tried to copy unsupported types") : pushed; | ||
718 | } | 719 | } |
719 | 720 | ||
720 | 721 | ||
@@ -783,18 +784,20 @@ LUAG_FUNC( linda_get) | |||
783 | 784 | ||
784 | 785 | ||
785 | /* | 786 | /* |
786 | * = linda_limit( linda_ud, key_num|str|bool|lightuserdata, uint [, ...] ) | 787 | * [true] = linda_limit( linda_ud, key_num|str|bool|lightuserdata, int [, bool] ) |
787 | * | 788 | * |
788 | * Set limits to 1 or more Linda keys. | 789 | * Set limit to 1 Linda keys. |
790 | * Optionally wake threads waiting to write on the linda, in case the limit enables them to do so | ||
789 | */ | 791 | */ |
790 | LUAG_FUNC( linda_limit) | 792 | LUAG_FUNC( linda_limit) |
791 | { | 793 | { |
792 | struct s_Linda* linda= lua_toLinda( L, 1); | 794 | struct s_Linda* linda = lua_toLinda( L, 1); |
793 | int pushed; | 795 | int pushed; |
796 | bool_t wake_writers = FALSE; | ||
794 | 797 | ||
798 | // make sure we got at most 4 arguments: the linda, a key, a limit, and an optional wake-up flag. | ||
795 | luaL_argcheck( L, linda, 1, "expected a linda object!"); | 799 | luaL_argcheck( L, linda, 1, "expected a linda object!"); |
796 | // make sure we got a key and a limit | 800 | luaL_argcheck( L, lua_gettop( L) <= 4, 2, "wrong number of arguments"); |
797 | luaL_argcheck( L, lua_gettop( L) == 3, 2, "wrong number of arguments"); | ||
798 | // make sure we got a numeric limit | 801 | // make sure we got a numeric limit |
799 | luaL_checknumber( L, 3); | 802 | luaL_checknumber( L, 3); |
800 | // make sure the key is of a valid type | 803 | // make sure the key is of a valid type |
@@ -804,16 +807,16 @@ LUAG_FUNC( linda_limit) | |||
804 | struct s_Keeper* K = keeper_acquire( linda); | 807 | struct s_Keeper* K = keeper_acquire( linda); |
805 | if( K == NULL) return 0; | 808 | if( K == NULL) return 0; |
806 | pushed = keeper_call( K->L, KEEPER_API( limit), L, linda, 2); | 809 | pushed = keeper_call( K->L, KEEPER_API( limit), L, linda, 2); |
807 | ASSERT_L( pushed <= 0); // either error or no return values | 810 | ASSERT_L( pushed == 0 || pushed == 1); // no error, optional boolean value saying if we should wake blocked writer threads |
808 | keeper_release( K); | 811 | if( pushed == 1) |
809 | // must trigger error after keeper state has been released | ||
810 | if( pushed < 0) | ||
811 | { | 812 | { |
812 | return luaL_error( L, "tried to copy unsupported types"); | 813 | ASSERT_L( lua_type( L, -1) == LUA_TBOOLEAN && lua_toboolean( L, -1) == 1); |
814 | SIGNAL_ALL( &linda->read_happened); // To be done from within the 'K' locking area | ||
813 | } | 815 | } |
816 | keeper_release( K); | ||
814 | } | 817 | } |
815 | 818 | // propagate pushed boolean if any | |
816 | return 0; | 819 | return pushed; |
817 | } | 820 | } |
818 | 821 | ||
819 | 822 | ||