diff options
| author | Benoit Germain <bnt period germain arrobase gmail period com> | 2013-12-20 11:47:38 +0100 |
|---|---|---|
| committer | Benoit Germain <bnt period germain arrobase gmail period com> | 2013-12-20 11:47:38 +0100 |
| commit | 95c696cffe7bf16e27d6d766750c96a38dd23b32 (patch) | |
| tree | c12099fbff87a330bc0998ec6961c97e03c1c8f2 | |
| parent | 4ece73b1e0d8f75fa63a5b39a91731147870bd0a (diff) | |
| download | lanes-95c696cffe7bf16e27d6d766750c96a38dd23b32.tar.gz lanes-95c696cffe7bf16e27d6d766750c96a38dd23b32.tar.bz2 lanes-95c696cffe7bf16e27d6d766750c96a38dd23b32.zip | |
fixed a shutdown crash
* fixed a crash that can occur at shutdown when an object stored inside
a keeper state performs a linda operation on a linda making use of
another keeper
* bumped version to 3.7.5
| -rw-r--r-- | CHANGES | 5 | ||||
| -rw-r--r-- | docs/index.html | 32 | ||||
| -rw-r--r-- | src/keeper.c | 16 | ||||
| -rw-r--r-- | src/lanes.c | 25 |
4 files changed, 54 insertions, 24 deletions
| @@ -1,5 +1,10 @@ | |||
| 1 | CHANGES: | 1 | CHANGES: |
| 2 | 2 | ||
| 3 | CHANGE 87: BGe 20-Dec-13 | ||
| 4 | * version 3.7.5 | ||
| 5 | * fixed a crash that can occur at shutdown when an object stored inside a keeper state performs a linda operation on a linda making use of another keeper | ||
| 6 | * new setting demote_full_userdata to select between light userdata demotion or raising an error when attempting to transfer a non-deep full userdata | ||
| 7 | |||
| 3 | CHANGE 86: BGe 3-Dec-13 | 8 | CHANGE 86: BGe 3-Dec-13 |
| 4 | * version 3.7.4 | 9 | * version 3.7.4 |
| 5 | * internal refactoring of pthread priority management code | 10 | * internal refactoring of pthread priority management code |
diff --git a/docs/index.html b/docs/index.html index af08397..f25463d 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 3-Dec-13, and applies to version <tt>3.7.4</tt>. | 73 | This document was revised on 20-Dec-13, and applies to version <tt>3.7.5</tt>. |
| 74 | </p> | 74 | </p> |
| 75 | </font> | 75 | </font> |
| 76 | </center> | 76 | </center> |
| @@ -273,7 +273,7 @@ | |||
| 273 | <th style="width:70%">definition</th> | 273 | <th style="width:70%">definition</th> |
| 274 | </tr> | 274 | </tr> |
| 275 | <tr valign=top> | 275 | <tr valign=top> |
| 276 | <td> | 276 | <td id="nb_keepers"> |
| 277 | <code>.nb_keepers</code> | 277 | <code>.nb_keepers</code> |
| 278 | </td> | 278 | </td> |
| 279 | <td>integer >= 1</td> | 279 | <td>integer >= 1</td> |
| @@ -283,7 +283,7 @@ | |||
| 283 | </tr> | 283 | </tr> |
| 284 | 284 | ||
| 285 | <tr valign=top> | 285 | <tr valign=top> |
| 286 | <td> | 286 | <td id="with_timers"> |
| 287 | <code>.with_timers</code> | 287 | <code>.with_timers</code> |
| 288 | </td> | 288 | </td> |
| 289 | <td> | 289 | <td> |
| @@ -296,7 +296,7 @@ | |||
| 296 | </tr> | 296 | </tr> |
| 297 | 297 | ||
| 298 | <tr valign=top> | 298 | <tr valign=top> |
| 299 | <td> | 299 | <td id="verbose_errors"> |
| 300 | <code>.verbose_errors</code> | 300 | <code>.verbose_errors</code> |
| 301 | </td> | 301 | </td> |
| 302 | <td> | 302 | <td> |
| @@ -309,7 +309,7 @@ | |||
| 309 | </tr> | 309 | </tr> |
| 310 | 310 | ||
| 311 | <tr valign=top> | 311 | <tr valign=top> |
| 312 | <td> | 312 | <td id="protect_allocator"> |
| 313 | <code>.protect_allocator</code> | 313 | <code>.protect_allocator</code> |
| 314 | </td> | 314 | </td> |
| 315 | <td> | 315 | <td> |
| @@ -322,6 +322,19 @@ | |||
| 322 | </tr> | 322 | </tr> |
| 323 | 323 | ||
| 324 | <tr valign=top> | 324 | <tr valign=top> |
| 325 | <td id="demote_full_userdata"> | ||
| 326 | <code>.demote_full_userdata</code> | ||
| 327 | </td> | ||
| 328 | <td> | ||
| 329 | <tt>nil</tt>/<tt>false</tt>/<tt>true</tt> | ||
| 330 | </td> | ||
| 331 | <td> | ||
| 332 | (Since v3.7.5) If equal to <tt>false</tt> or <tt>nil</tt>, Lanes raises an error when attempting to transfer a non-deep full userdata, else it will be demoted to a light userdata in the destination. | ||
| 333 | Default is <tt>false</tt> (set to <tt>true</tt> to get the legacy behaviour). | ||
| 334 | </td> | ||
| 335 | </tr> | ||
| 336 | |||
| 337 | <tr valign=top> | ||
| 325 | <td id="track_lanes"> | 338 | <td id="track_lanes"> |
| 326 | <code>.track_lanes</code> | 339 | <code>.track_lanes</code> |
| 327 | </td> | 340 | </td> |
| @@ -335,7 +348,7 @@ | |||
| 335 | </tr> | 348 | </tr> |
| 336 | 349 | ||
| 337 | <tr valign=top> | 350 | <tr valign=top> |
| 338 | <td> | 351 | <td id="on_state_create"> |
| 339 | <code>.on_state_create</code> | 352 | <code>.on_state_create</code> |
| 340 | </td> | 353 | </td> |
| 341 | <td> | 354 | <td> |
| @@ -354,8 +367,8 @@ | |||
| 354 | </tr> | 367 | </tr> |
| 355 | 368 | ||
| 356 | <tr valign=top> | 369 | <tr valign=top> |
| 357 | <td> | 370 | <td id="shutdown_timeout"> |
| 358 | <code>.shutdown_timeout</code> <br/> | 371 | <code>.shutdown_timeout</code> |
| 359 | </td> | 372 | </td> |
| 360 | <td> | 373 | <td> |
| 361 | number >= 0 | 374 | number >= 0 |
| @@ -1133,7 +1146,7 @@ events to a common Linda, but... :).</font> | |||
| 1133 | </pre></td></tr></table> | 1146 | </pre></td></tr></table> |
| 1134 | 1147 | ||
| 1135 | <p> | 1148 | <p> |
| 1136 | Timers are implemented as a lane. They can be disabled by setting <tt>"with_timers"</tt> to <tt>nil</tt> or <tt>false</tt> to <tt>lanes.configure()</tt>. | 1149 | Timers are implemented as a lane. They can be disabled by setting "<tt><a href="#with_timers">with_timers</a></tt>" to <tt>nil</tt> or <tt>false</tt> to <tt>lanes.configure()</tt>. |
| 1137 | </p> | 1150 | </p> |
| 1138 | 1151 | ||
| 1139 | <p> | 1152 | <p> |
| @@ -1289,6 +1302,7 @@ events to a common Linda, but... :).</font> | |||
| 1289 | Full userdata can be passed only if it's prepared using the <a href="#deep_userdata">deep userdata</a> system, which handles its lifespan management | 1302 | Full userdata can be passed only if it's prepared using the <a href="#deep_userdata">deep userdata</a> system, which handles its lifespan management |
| 1290 | <ul> | 1303 | <ul> |
| 1291 | <li>In particular, lane handles cannot be passed between lanes.</li> | 1304 | <li>In particular, lane handles cannot be passed between lanes.</li> |
| 1305 | <li>Lanes can either throw an error or attempt a <a href="#demote_full_userdata">light userdata demotion</a>.</li> | ||
| 1292 | </ul> | 1306 | </ul> |
| 1293 | </li> | 1307 | </li> |
| 1294 | <li>Coroutines cannot be passed. A coroutine's Lua state is tied to the Lua state that created it, and there is no way the mixed C/Lua stack of a coroutine can be transfered from one Lua state to another.</li> | 1308 | <li>Coroutines cannot be passed. A coroutine's Lua state is tied to the Lua state that created it, and there is no way the mixed C/Lua stack of a coroutine can be transfered from one Lua state to another.</li> |
diff --git a/src/keeper.c b/src/keeper.c index 99f510b..4c90069 100644 --- a/src/keeper.c +++ b/src/keeper.c | |||
| @@ -184,7 +184,8 @@ static void push_table( lua_State* L, int idx) | |||
| 184 | int keeper_push_linda_storage( lua_State* L, void* ptr) | 184 | int keeper_push_linda_storage( lua_State* L, void* ptr) |
| 185 | { | 185 | { |
| 186 | struct s_Keeper* K = keeper_acquire( ptr); | 186 | struct s_Keeper* K = keeper_acquire( ptr); |
| 187 | lua_State* KL = K->L; | 187 | lua_State* KL = K ? K->L : NULL; |
| 188 | if( KL == NULL) return 0; | ||
| 188 | STACK_CHECK( KL); | 189 | STACK_CHECK( KL); |
| 189 | lua_pushlightuserdata( KL, fifos_key); // fifos_key | 190 | lua_pushlightuserdata( KL, fifos_key); // fifos_key |
| 190 | lua_rawget( KL, LUA_REGISTRYINDEX); // fifos | 191 | lua_rawget( KL, LUA_REGISTRYINDEX); // fifos |
| @@ -535,14 +536,18 @@ void close_keepers( void) | |||
| 535 | #endif // HAVE_KEEPER_ATEXIT_DESINIT | 536 | #endif // HAVE_KEEPER_ATEXIT_DESINIT |
| 536 | { | 537 | { |
| 537 | int i; | 538 | int i; |
| 538 | // 2-pass close, in case a keeper holds a reference to a linda bound to another keeoer | 539 | int const nbKeepers = GNbKeepers; |
| 539 | for( i = 0; i < GNbKeepers; ++ i) | 540 | // NOTE: imagine some keeper state N+1 currently holds a linda that uses another keeper N, and a _gc that will make use of it |
| 541 | // when keeper N+1 is closed, object is GCed, linda operation is called, which attempts to acquire keeper N, whose Lua state no longer exists | ||
| 542 | // in that case, the linda operation should do nothing. which means that these operations must check for keeper acquisition success | ||
| 543 | GNbKeepers = 0; | ||
| 544 | for( i = 0; i < nbKeepers; ++ i) | ||
| 540 | { | 545 | { |
| 541 | lua_State* L = GKeepers[i].L; | 546 | lua_State* L = GKeepers[i].L; |
| 542 | GKeepers[i].L = NULL; | 547 | GKeepers[i].L = NULL; |
| 543 | lua_close( L); | 548 | lua_close( L); |
| 544 | } | 549 | } |
| 545 | for( i = 0; i < GNbKeepers; ++ i) | 550 | for( i = 0; i < nbKeepers; ++ i) |
| 546 | { | 551 | { |
| 547 | MUTEX_FREE( &GKeepers[i].lock_); | 552 | MUTEX_FREE( &GKeepers[i].lock_); |
| 548 | } | 553 | } |
| @@ -551,7 +556,6 @@ void close_keepers( void) | |||
| 551 | free( GKeepers); | 556 | free( GKeepers); |
| 552 | } | 557 | } |
| 553 | GKeepers = NULL; | 558 | GKeepers = NULL; |
| 554 | GNbKeepers = 0; | ||
| 555 | } | 559 | } |
| 556 | 560 | ||
| 557 | /* | 561 | /* |
| @@ -626,7 +630,7 @@ struct s_Keeper* keeper_acquire( void const* ptr) | |||
| 626 | * have to cast to unsigned long to avoid compilation warnings about loss of data when converting pointer-to-integer | 630 | * have to cast to unsigned long to avoid compilation warnings about loss of data when converting pointer-to-integer |
| 627 | */ | 631 | */ |
| 628 | unsigned int i = (unsigned int)(((unsigned long)(ptr) >> 3) % GNbKeepers); | 632 | unsigned int i = (unsigned int)(((unsigned long)(ptr) >> 3) % GNbKeepers); |
| 629 | struct s_Keeper *K= &GKeepers[i]; | 633 | struct s_Keeper* K= &GKeepers[i]; |
| 630 | 634 | ||
| 631 | MUTEX_LOCK( &K->lock_); | 635 | MUTEX_LOCK( &K->lock_); |
| 632 | //++ K->count; | 636 | //++ K->count; |
diff --git a/src/lanes.c b/src/lanes.c index 6621735..e66342d 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.4"; | 55 | char const* VERSION = "3.7.5"; |
| 56 | 56 | ||
| 57 | /* | 57 | /* |
| 58 | =============================================================================== | 58 | =============================================================================== |
| @@ -420,7 +420,8 @@ LUAG_FUNC( linda_send) | |||
| 420 | STACK_GROW(L, 1); | 420 | STACK_GROW(L, 1); |
| 421 | { | 421 | { |
| 422 | struct s_Keeper* K = keeper_acquire( linda); | 422 | struct s_Keeper* K = keeper_acquire( linda); |
| 423 | lua_State* KL = K->L; // need to do this for 'STACK_CHECK' | 423 | lua_State* KL = K ? K->L : NULL; // need to do this for 'STACK_CHECK' |
| 424 | if( KL == NULL) return 0; | ||
| 424 | STACK_CHECK( KL); | 425 | STACK_CHECK( KL); |
| 425 | for( ;;) | 426 | for( ;;) |
| 426 | { | 427 | { |
| @@ -584,6 +585,7 @@ LUAG_FUNC( linda_receive) | |||
| 584 | 585 | ||
| 585 | { | 586 | { |
| 586 | struct s_Keeper *K = keeper_acquire( linda); | 587 | struct s_Keeper *K = keeper_acquire( linda); |
| 588 | if( K == NULL) return 0; | ||
| 587 | for( ;;) | 589 | for( ;;) |
| 588 | { | 590 | { |
| 589 | // all arguments of receive() but the first are passed to the keeper's receive function | 591 | // all arguments of receive() but the first are passed to the keeper's receive function |
| @@ -690,6 +692,7 @@ LUAG_FUNC( linda_set) | |||
| 690 | { | 692 | { |
| 691 | int pushed; | 693 | int pushed; |
| 692 | struct s_Keeper *K = keeper_acquire( linda); | 694 | struct s_Keeper *K = keeper_acquire( linda); |
| 695 | if( K == NULL) return 0; | ||
| 693 | // 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() |
| 694 | pushed = keeper_call( K->L, KEEPER_API( set), L, linda, 2); | 697 | pushed = keeper_call( K->L, KEEPER_API( set), L, linda, 2); |
| 695 | if( pushed >= 0) // no error? | 698 | if( pushed >= 0) // no error? |
| @@ -722,7 +725,7 @@ LUAG_FUNC( linda_set) | |||
| 722 | */ | 725 | */ |
| 723 | LUAG_FUNC( linda_count) | 726 | LUAG_FUNC( linda_count) |
| 724 | { | 727 | { |
| 725 | struct s_Linda *linda= lua_toLinda( L, 1); | 728 | struct s_Linda* linda = lua_toLinda( L, 1); |
| 726 | int pushed; | 729 | int pushed; |
| 727 | 730 | ||
| 728 | luaL_argcheck( L, linda, 1, "expected a linda object!"); | 731 | luaL_argcheck( L, linda, 1, "expected a linda object!"); |
| @@ -730,7 +733,8 @@ LUAG_FUNC( linda_count) | |||
| 730 | check_key_types( L, 2, lua_gettop( L)); | 733 | check_key_types( L, 2, lua_gettop( L)); |
| 731 | 734 | ||
| 732 | { | 735 | { |
| 733 | struct s_Keeper *K = keeper_acquire( linda); | 736 | struct s_Keeper* K = keeper_acquire( linda); |
| 737 | if( K == NULL) return 0; | ||
| 734 | pushed = keeper_call( K->L, KEEPER_API( count), L, linda, 2); | 738 | pushed = keeper_call( K->L, KEEPER_API( count), L, linda, 2); |
| 735 | keeper_release( K); | 739 | keeper_release( K); |
| 736 | if( pushed < 0) | 740 | if( pushed < 0) |
| @@ -758,14 +762,15 @@ LUAG_FUNC( linda_get) | |||
| 758 | check_key_types( L, 2, 2); | 762 | check_key_types( L, 2, 2); |
| 759 | 763 | ||
| 760 | { | 764 | { |
| 761 | struct s_Keeper *K = keeper_acquire( linda); | 765 | struct s_Keeper* K = keeper_acquire( linda); |
| 766 | if( K == NULL) return 0; | ||
| 762 | pushed = keeper_call( K->L, KEEPER_API( get), L, linda, 2); | 767 | pushed = keeper_call( K->L, KEEPER_API( get), L, linda, 2); |
| 763 | ASSERT_L( pushed==0 || pushed==1 ); | 768 | ASSERT_L( pushed == 0 || pushed == 1); |
| 764 | if( pushed > 0) | 769 | if( pushed > 0) |
| 765 | { | 770 | { |
| 766 | keeper_toggle_nil_sentinels( L, lua_gettop( L) - pushed, 0); | 771 | keeper_toggle_nil_sentinels( L, lua_gettop( L) - pushed, 0); |
| 767 | } | 772 | } |
| 768 | keeper_release(K); | 773 | keeper_release( K); |
| 769 | // must trigger error after keeper state has been released | 774 | // must trigger error after keeper state has been released |
| 770 | if( pushed < 0) | 775 | if( pushed < 0) |
| 771 | { | 776 | { |
| @@ -784,7 +789,8 @@ LUAG_FUNC( linda_get) | |||
| 784 | */ | 789 | */ |
| 785 | LUAG_FUNC( linda_limit) | 790 | LUAG_FUNC( linda_limit) |
| 786 | { | 791 | { |
| 787 | struct s_Linda* linda= lua_toLinda( L, 1 ); | 792 | struct s_Linda* linda= lua_toLinda( L, 1); |
| 793 | int pushed; | ||
| 788 | 794 | ||
| 789 | luaL_argcheck( L, linda, 1, "expected a linda object!"); | 795 | luaL_argcheck( L, linda, 1, "expected a linda object!"); |
| 790 | // make sure we got a key and a limit | 796 | // make sure we got a key and a limit |
| @@ -796,7 +802,8 @@ LUAG_FUNC( linda_limit) | |||
| 796 | 802 | ||
| 797 | { | 803 | { |
| 798 | struct s_Keeper* K = keeper_acquire( linda); | 804 | struct s_Keeper* K = keeper_acquire( linda); |
| 799 | int pushed = keeper_call( K->L, KEEPER_API( limit), L, linda, 2); | 805 | if( K == NULL) return 0; |
| 806 | pushed = keeper_call( K->L, KEEPER_API( limit), L, linda, 2); | ||
| 800 | ASSERT_L( pushed <= 0); // either error or no return values | 807 | ASSERT_L( pushed <= 0); // either error or no return values |
| 801 | keeper_release( K); | 808 | keeper_release( K); |
| 802 | // must trigger error after keeper state has been released | 809 | // must trigger error after keeper state has been released |
