diff options
-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 |