@@ -541,6 +541,7 @@ thread_cleanup_func(void *th_ptr, int atfork)
541
541
}
542
542
543
543
static VALUE rb_threadptr_raise (rb_thread_t * , int , VALUE * );
544
+ static VALUE rb_thread_inspect (VALUE thread );
544
545
545
546
void
546
547
ruby_thread_init_stack (rb_thread_t * th )
@@ -609,6 +610,13 @@ thread_start_func_2(rb_thread_t *th, VALUE *stack_start, VALUE *register_stack_s
609
610
th -> abort_on_exception || RTEST (ruby_debug )) {
610
611
/* exit on main_thread */
611
612
}
613
+ else if (th -> report_on_exception ) {
614
+ VALUE mesg = rb_thread_inspect (th -> self );
615
+ rb_str_cat_cstr (mesg , " terminated with exception:\n" );
616
+ rb_write_error_str (mesg );
617
+ rb_threadptr_error_print (th , errinfo );
618
+ errinfo = Qnil ;
619
+ }
612
620
else {
613
621
errinfo = Qnil ;
614
622
}
@@ -700,6 +708,7 @@ thread_create_core(VALUE thval, VALUE args, VALUE (*fn)(ANYARGS))
700
708
701
709
native_mutex_initialize (& th -> interrupt_lock );
702
710
native_cond_initialize (& th -> interrupt_cond , RB_CONDATTR_CLOCK_MONOTONIC );
711
+ th -> report_on_exception = th -> vm -> thread_report_on_exception ;
703
712
704
713
/* kick thread */
705
714
err = native_thread_create (th );
@@ -2593,6 +2602,116 @@ rb_thread_abort_exc_set(VALUE thread, VALUE val)
2593
2602
}
2594
2603
2595
2604
2605
+ /*
2606
+ * call-seq:
2607
+ * Thread.report_on_exception -> true or false
2608
+ *
2609
+ * Returns the status of the global ``report on exception'' condition.
2610
+ *
2611
+ * The default is +false+.
2612
+ *
2613
+ * When set to +true+, all threads will report the exception if an
2614
+ * exception is raised in any thread.
2615
+ *
2616
+ * See also ::report_on_exception=.
2617
+ *
2618
+ * There is also an instance level method to set this for a specific thread,
2619
+ * see #report_on_exception.
2620
+ */
2621
+
2622
+ static VALUE
2623
+ rb_thread_s_report_exc (void )
2624
+ {
2625
+ return GET_THREAD ()-> vm -> thread_report_on_exception ? Qtrue : Qfalse ;
2626
+ }
2627
+
2628
+
2629
+ /*
2630
+ * call-seq:
2631
+ * Thread.report_on_exception= boolean -> true or false
2632
+ *
2633
+ * When set to +true+, all threads will report the exception if an
2634
+ * exception is raised. Returns the new state.
2635
+ *
2636
+ * Thread.report_on_exception = true
2637
+ * t1 = Thread.new do
2638
+ * puts "In new thread"
2639
+ * raise "Exception from thread"
2640
+ * end
2641
+ * sleep(1)
2642
+ * puts "In the main thread"
2643
+ *
2644
+ * This will produce:
2645
+ *
2646
+ * In new thread
2647
+ * prog.rb:4: Exception from thread (RuntimeError)
2648
+ * from prog.rb:2:in `initialize'
2649
+ * from prog.rb:2:in `new'
2650
+ * from prog.rb:2
2651
+ * In the main thread
2652
+ *
2653
+ * See also ::report_on_exception.
2654
+ *
2655
+ * There is also an instance level method to set this for a specific thread,
2656
+ * see #report_on_exception=.
2657
+ */
2658
+
2659
+ static VALUE
2660
+ rb_thread_s_report_exc_set (VALUE self , VALUE val )
2661
+ {
2662
+ GET_THREAD ()-> vm -> thread_report_on_exception = RTEST (val );
2663
+ return val ;
2664
+ }
2665
+
2666
+
2667
+ /*
2668
+ * call-seq:
2669
+ * thr.report_on_exception -> true or false
2670
+ *
2671
+ * Returns the status of the thread-local ``report on exception'' condition for
2672
+ * this +thr+.
2673
+ *
2674
+ * The default is +false+.
2675
+ *
2676
+ * See also #report_on_exception=.
2677
+ *
2678
+ * There is also a class level method to set this for all threads, see
2679
+ * ::report_on_exception.
2680
+ */
2681
+
2682
+ static VALUE
2683
+ rb_thread_report_exc (VALUE thread )
2684
+ {
2685
+ rb_thread_t * th ;
2686
+ GetThreadPtr (thread , th );
2687
+ return th -> report_on_exception ? Qtrue : Qfalse ;
2688
+ }
2689
+
2690
+
2691
+ /*
2692
+ * call-seq:
2693
+ * thr.report_on_exception= boolean -> true or false
2694
+ *
2695
+ * When set to +true+, all threads (including the main program) will
2696
+ * report the exception if an exception is raised in this +thr+.
2697
+ *
2698
+ * See also #report_on_exception.
2699
+ *
2700
+ * There is also a class level method to set this for all threads, see
2701
+ * ::report_on_exception=.
2702
+ */
2703
+
2704
+ static VALUE
2705
+ rb_thread_report_exc_set (VALUE thread , VALUE val )
2706
+ {
2707
+ rb_thread_t * th ;
2708
+
2709
+ GetThreadPtr (thread , th );
2710
+ th -> report_on_exception = RTEST (val );
2711
+ return val ;
2712
+ }
2713
+
2714
+
2596
2715
/*
2597
2716
* call-seq:
2598
2717
* thr.group -> thgrp or nil
@@ -4633,6 +4752,8 @@ Init_Thread(void)
4633
4752
rb_define_singleton_method (rb_cThread , "list" , rb_thread_list , 0 );
4634
4753
rb_define_singleton_method (rb_cThread , "abort_on_exception" , rb_thread_s_abort_exc , 0 );
4635
4754
rb_define_singleton_method (rb_cThread , "abort_on_exception=" , rb_thread_s_abort_exc_set , 1 );
4755
+ rb_define_singleton_method (rb_cThread , "report_on_exception" , rb_thread_s_report_exc , 0 );
4756
+ rb_define_singleton_method (rb_cThread , "report_on_exception=" , rb_thread_s_report_exc_set , 1 );
4636
4757
#if THREAD_DEBUG < 0
4637
4758
rb_define_singleton_method (rb_cThread , "DEBUG" , rb_thread_s_debug , 0 );
4638
4759
rb_define_singleton_method (rb_cThread , "DEBUG=" , rb_thread_s_debug_set , 1 );
@@ -4665,6 +4786,8 @@ Init_Thread(void)
4665
4786
rb_define_method (rb_cThread , "stop?" , rb_thread_stop_p , 0 );
4666
4787
rb_define_method (rb_cThread , "abort_on_exception" , rb_thread_abort_exc , 0 );
4667
4788
rb_define_method (rb_cThread , "abort_on_exception=" , rb_thread_abort_exc_set , 1 );
4789
+ rb_define_method (rb_cThread , "report_on_exception" , rb_thread_report_exc , 0 );
4790
+ rb_define_method (rb_cThread , "report_on_exception=" , rb_thread_report_exc_set , 1 );
4668
4791
rb_define_method (rb_cThread , "safe_level" , rb_thread_safe_level , 0 );
4669
4792
rb_define_method (rb_cThread , "group" , rb_thread_group , 0 );
4670
4793
rb_define_method (rb_cThread , "backtrace" , rb_thread_backtrace_m , -1 );
0 commit comments