@@ -10513,8 +10513,8 @@ rb_gc_abort_threads()
10513
10513
} END_FOREACH_FROM (main_thread , th );
10514
10514
}
10515
10515
10516
- static void
10517
- thread_free (th )
10516
+ static inline void
10517
+ stack_free (th )
10518
10518
rb_thread_t th ;
10519
10519
{
10520
10520
if (th -> stk_ptr ) free (th -> stk_ptr );
@@ -10523,6 +10523,13 @@ thread_free(th)
10523
10523
if (th -> bstr_ptr ) free (th -> bstr_ptr );
10524
10524
th -> bstr_ptr = 0 ;
10525
10525
#endif
10526
+ }
10527
+
10528
+ static void
10529
+ thread_free (th )
10530
+ rb_thread_t th ;
10531
+ {
10532
+ stack_free (th );
10526
10533
if (th -> locals ) st_free_table (th -> locals );
10527
10534
if (th -> status != THREAD_KILLED ) {
10528
10535
if (th -> prev ) th -> prev -> next = th -> next ;
@@ -10815,8 +10822,7 @@ rb_thread_die(th)
10815
10822
{
10816
10823
th -> thgroup = 0 ;
10817
10824
th -> status = THREAD_KILLED ;
10818
- if (th -> stk_ptr ) free (th -> stk_ptr );
10819
- th -> stk_ptr = 0 ;
10825
+ stack_free (th );
10820
10826
}
10821
10827
10822
10828
static void
@@ -13006,6 +13012,38 @@ rb_thread_atfork()
13006
13012
}
13007
13013
13008
13014
13015
+ static void
13016
+ cc_purge (cc )
13017
+ rb_thread_t cc ;
13018
+ {
13019
+ /* free continuation's stack if it has just died */
13020
+ if (NIL_P (cc -> thread )) return ;
13021
+ if (rb_thread_check (cc -> thread )-> status == THREAD_KILLED ) {
13022
+ cc -> thread = Qnil ;
13023
+ rb_thread_die (cc ); /* can't possibly activate this stack */
13024
+ }
13025
+ }
13026
+
13027
+ static void
13028
+ cc_mark (cc )
13029
+ rb_thread_t cc ;
13030
+ {
13031
+ /* mark this continuation's stack only if its parent thread is still alive */
13032
+ cc_purge (cc );
13033
+ thread_mark (cc );
13034
+ }
13035
+
13036
+ static rb_thread_t
13037
+ rb_cont_check (data )
13038
+ VALUE data ;
13039
+ {
13040
+ if (TYPE (data ) != T_DATA || RDATA (data )-> dmark != (RUBY_DATA_FUNC )cc_mark ) {
13041
+ rb_raise (rb_eTypeError , "wrong argument type %s (expected Continuation)" ,
13042
+ rb_obj_classname (data ));
13043
+ }
13044
+ return (rb_thread_t )RDATA (data )-> data ;
13045
+ }
13046
+
13009
13047
/*
13010
13048
* Document-class: Continuation
13011
13049
*
@@ -13080,14 +13118,16 @@ rb_callcc(self)
13080
13118
struct RVarmap * vars ;
13081
13119
13082
13120
THREAD_ALLOC (th );
13083
- cont = Data_Wrap_Struct (rb_cCont , thread_mark , thread_free , th );
13121
+ /* must finish th initialization before any possible gc.
13122
+ * brent@mbari.org */
13123
+ th -> thread = curr_thread -> thread ;
13124
+ th -> thgroup = cont_protect ;
13125
+ cont = Data_Wrap_Struct (rb_cCont , cc_mark , thread_free , th );
13084
13126
13085
13127
scope_dup (ruby_scope );
13086
13128
for (tag = prot_tag ; tag ; tag = tag -> prev ) {
13087
13129
scope_dup (tag -> scope );
13088
13130
}
13089
- th -> thread = curr_thread -> thread ;
13090
- th -> thgroup = cont_protect ;
13091
13131
13092
13132
for (vars = ruby_dyna_vars ; vars ; vars = vars -> next ) {
13093
13133
if (FL_TEST (vars , DVAR_DONT_RECYCLE )) break ;
@@ -13124,7 +13164,7 @@ rb_cont_call(argc, argv, cont)
13124
13164
VALUE * argv ;
13125
13165
VALUE cont ;
13126
13166
{
13127
- rb_thread_t th = rb_thread_check (cont );
13167
+ rb_thread_t th = rb_cont_check (cont );
13128
13168
13129
13169
if (th -> thread != curr_thread -> thread ) {
13130
13170
rb_raise (rb_eRuntimeError , "continuation called across threads" );
@@ -13300,10 +13340,6 @@ thgroup_add(group, thread)
13300
13340
13301
13341
rb_secure (4 );
13302
13342
th = rb_thread_check (thread );
13303
- if (!th -> next || !th -> prev ) {
13304
- rb_raise (rb_eTypeError , "wrong argument type %s (expected Thread)" ,
13305
- rb_obj_classname (thread ));
13306
- }
13307
13343
13308
13344
if (OBJ_FROZEN (group )) {
13309
13345
rb_raise (rb_eThreadError , "can't move to the frozen thread group" );
0 commit comments