@@ -10230,8 +10230,8 @@ rb_gc_abort_threads()
10230
10230
} END_FOREACH_FROM (main_thread , th );
10231
10231
}
10232
10232
10233
- static void
10234
- thread_free (th )
10233
+ static inline void
10234
+ stack_free (th )
10235
10235
rb_thread_t th ;
10236
10236
{
10237
10237
if (th -> stk_ptr ) free (th -> stk_ptr );
@@ -10240,6 +10240,13 @@ thread_free(th)
10240
10240
if (th -> bstr_ptr ) free (th -> bstr_ptr );
10241
10241
th -> bstr_ptr = 0 ;
10242
10242
#endif
10243
+ }
10244
+
10245
+ static void
10246
+ thread_free (th )
10247
+ rb_thread_t th ;
10248
+ {
10249
+ stack_free (th );
10243
10250
if (th -> locals ) st_free_table (th -> locals );
10244
10251
if (th -> status != THREAD_KILLED ) {
10245
10252
if (th -> prev ) th -> prev -> next = th -> next ;
@@ -10532,8 +10539,7 @@ rb_thread_die(th)
10532
10539
{
10533
10540
th -> thgroup = 0 ;
10534
10541
th -> status = THREAD_KILLED ;
10535
- if (th -> stk_ptr ) free (th -> stk_ptr );
10536
- th -> stk_ptr = 0 ;
10542
+ stack_free (th );
10537
10543
}
10538
10544
10539
10545
static void
@@ -12776,6 +12782,38 @@ rb_thread_atfork()
12776
12782
}
12777
12783
12778
12784
12785
+ static void
12786
+ cc_purge (cc )
12787
+ rb_thread_t cc ;
12788
+ {
12789
+ /* free continuation's stack if it has just died */
12790
+ if (NIL_P (cc -> thread )) return ;
12791
+ if (rb_thread_check (cc -> thread )-> status == THREAD_KILLED ) {
12792
+ cc -> thread = Qnil ;
12793
+ rb_thread_die (cc ); /* can't possibly activate this stack */
12794
+ }
12795
+ }
12796
+
12797
+ static void
12798
+ cc_mark (cc )
12799
+ rb_thread_t cc ;
12800
+ {
12801
+ /* mark this continuation's stack only if its parent thread is still alive */
12802
+ cc_purge (cc );
12803
+ thread_mark (cc );
12804
+ }
12805
+
12806
+ static rb_thread_t
12807
+ rb_cont_check (data )
12808
+ VALUE data ;
12809
+ {
12810
+ if (TYPE (data ) != T_DATA || RDATA (data )-> dmark != (RUBY_DATA_FUNC )cc_mark ) {
12811
+ rb_raise (rb_eTypeError , "wrong argument type %s (expected Continuation)" ,
12812
+ rb_obj_classname (data ));
12813
+ }
12814
+ return (rb_thread_t )RDATA (data )-> data ;
12815
+ }
12816
+
12779
12817
/*
12780
12818
* Document-class: Continuation
12781
12819
*
@@ -12850,14 +12888,16 @@ rb_callcc(self)
12850
12888
struct RVarmap * vars ;
12851
12889
12852
12890
THREAD_ALLOC (th );
12853
- cont = Data_Wrap_Struct (rb_cCont , thread_mark , thread_free , th );
12891
+ /* must finish th initialization before any possible gc.
12892
+ * brent@mbari.org */
12893
+ th -> thread = curr_thread -> thread ;
12894
+ th -> thgroup = cont_protect ;
12895
+ cont = Data_Wrap_Struct (rb_cCont , cc_mark , thread_free , th );
12854
12896
12855
12897
scope_dup (ruby_scope );
12856
12898
for (tag = prot_tag ; tag ; tag = tag -> prev ) {
12857
12899
scope_dup (tag -> scope );
12858
12900
}
12859
- th -> thread = curr_thread -> thread ;
12860
- th -> thgroup = cont_protect ;
12861
12901
12862
12902
for (vars = ruby_dyna_vars ; vars ; vars = vars -> next ) {
12863
12903
if (FL_TEST (vars , DVAR_DONT_RECYCLE )) break ;
@@ -12894,7 +12934,7 @@ rb_cont_call(argc, argv, cont)
12894
12934
VALUE * argv ;
12895
12935
VALUE cont ;
12896
12936
{
12897
- rb_thread_t th = rb_thread_check (cont );
12937
+ rb_thread_t th = rb_cont_check (cont );
12898
12938
12899
12939
if (th -> thread != curr_thread -> thread ) {
12900
12940
rb_raise (rb_eRuntimeError , "continuation called across threads" );
@@ -13070,10 +13110,6 @@ thgroup_add(group, thread)
13070
13110
13071
13111
rb_secure (4 );
13072
13112
th = rb_thread_check (thread );
13073
- if (!th -> next || !th -> prev ) {
13074
- rb_raise (rb_eTypeError , "wrong argument type %s (expected Thread)" ,
13075
- rb_obj_classname (thread ));
13076
- }
13077
13113
13078
13114
if (OBJ_FROZEN (group )) {
13079
13115
rb_raise (rb_eThreadError , "can't move to the frozen thread group" );
0 commit comments