Ruby  2.0.0p481(2014-05-08revision45883)
eval_jump.c
Go to the documentation of this file.
00001 /* -*-c-*- */
00002 /*
00003  * from eval.c
00004  */
00005 
00006 #include "eval_intern.h"
00007 
00008 /* exit */
00009 
00010 void
00011 rb_call_end_proc(VALUE data)
00012 {
00013     rb_proc_call(data, rb_ary_new());
00014 }
00015 
00016 /*
00017  *  call-seq:
00018  *     at_exit { block } -> proc
00019  *
00020  *  Converts _block_ to a +Proc+ object (and therefore
00021  *  binds it at the point of call) and registers it for execution when
00022  *  the program exits. If multiple handlers are registered, they are
00023  *  executed in reverse order of registration.
00024  *
00025  *     def do_at_exit(str1)
00026  *       at_exit { print str1 }
00027  *     end
00028  *     at_exit { puts "cruel world" }
00029  *     do_at_exit("goodbye ")
00030  *     exit
00031  *
00032  *  <em>produces:</em>
00033  *
00034  *     goodbye cruel world
00035  */
00036 
00037 static VALUE
00038 rb_f_at_exit(void)
00039 {
00040     VALUE proc;
00041 
00042     if (!rb_block_given_p()) {
00043         rb_raise(rb_eArgError, "called without a block");
00044     }
00045     proc = rb_block_proc();
00046     rb_set_end_proc(rb_call_end_proc, proc);
00047     return proc;
00048 }
00049 
00050 struct end_proc_data {
00051     void (*func) ();
00052     VALUE data;
00053     int safe;
00054     struct end_proc_data *next;
00055 };
00056 
00057 static struct end_proc_data *end_procs, *ephemeral_end_procs;
00058 
00059 void
00060 rb_set_end_proc(void (*func)(VALUE), VALUE data)
00061 {
00062     struct end_proc_data *link = ALLOC(struct end_proc_data);
00063     struct end_proc_data **list;
00064     rb_thread_t *th = GET_THREAD();
00065 
00066     if (th->top_wrapper) {
00067         list = &ephemeral_end_procs;
00068     }
00069     else {
00070         list = &end_procs;
00071     }
00072     link->next = *list;
00073     link->func = func;
00074     link->data = data;
00075     link->safe = rb_safe_level();
00076     *list = link;
00077 }
00078 
00079 void
00080 rb_mark_end_proc(void)
00081 {
00082     struct end_proc_data *link;
00083 
00084     link = end_procs;
00085     while (link) {
00086         rb_gc_mark(link->data);
00087         link = link->next;
00088     }
00089     link = ephemeral_end_procs;
00090     while (link) {
00091         rb_gc_mark(link->data);
00092         link = link->next;
00093     }
00094 }
00095 
00096 void
00097 rb_exec_end_proc(void)
00098 {
00099     struct end_proc_data volatile endproc;
00100     struct end_proc_data volatile *link;
00101     int status;
00102     volatile int safe = rb_safe_level();
00103     rb_thread_t *th = GET_THREAD();
00104     volatile VALUE errinfo = th->errinfo;
00105 
00106     while (ephemeral_end_procs) {
00107         link = ephemeral_end_procs;
00108         ephemeral_end_procs = link->next;
00109         endproc = *link;
00110         xfree((void *)link);
00111         link = &endproc;
00112 
00113         PUSH_TAG();
00114         if ((status = EXEC_TAG()) == 0) {
00115             rb_set_safe_level_force(link->safe);
00116             (*link->func) (link->data);
00117         }
00118         POP_TAG();
00119         if (status) {
00120             error_handle(status);
00121             if (!NIL_P(th->errinfo)) errinfo = th->errinfo;
00122         }
00123     }
00124 
00125     while (end_procs) {
00126         link = end_procs;
00127         end_procs = link->next;
00128         endproc = *link;
00129         xfree((void *)link);
00130         link = &endproc;
00131 
00132         PUSH_TAG();
00133         if ((status = EXEC_TAG()) == 0) {
00134             rb_set_safe_level_force(link->safe);
00135             (*link->func) (link->data);
00136         }
00137         POP_TAG();
00138         if (status) {
00139             error_handle(status);
00140             if (!NIL_P(th->errinfo)) errinfo = th->errinfo;
00141         }
00142     }
00143 
00144     rb_set_safe_level_force(safe);
00145     th->errinfo = errinfo;
00146 }
00147 
00148 void
00149 Init_jump(void)
00150 {
00151     rb_define_global_function("at_exit", rb_f_at_exit, 0);
00152 }
00153