Ruby  2.0.0p247(2013-06-27revision41674)
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 link;
00100     int status;
00101     volatile int safe = rb_safe_level();
00102     rb_thread_t *th = GET_THREAD();
00103     volatile VALUE errinfo = th->errinfo;
00104 
00105     while (ephemeral_end_procs) {
00106         link = ephemeral_end_procs;
00107         ephemeral_end_procs = link->next;
00108 
00109         PUSH_TAG();
00110         if ((status = EXEC_TAG()) == 0) {
00111             rb_set_safe_level_force(link->safe);
00112             (*link->func) (link->data);
00113         }
00114         POP_TAG();
00115         if (status) {
00116             error_handle(status);
00117             if (!NIL_P(th->errinfo)) errinfo = th->errinfo;
00118         }
00119         xfree(link);
00120     }
00121 
00122     while (end_procs) {
00123         link = end_procs;
00124         end_procs = link->next;
00125 
00126         PUSH_TAG();
00127         if ((status = EXEC_TAG()) == 0) {
00128             rb_set_safe_level_force(link->safe);
00129             (*link->func) (link->data);
00130         }
00131         POP_TAG();
00132         if (status) {
00133             error_handle(status);
00134             if (!NIL_P(th->errinfo)) errinfo = th->errinfo;
00135         }
00136         xfree(link);
00137     }
00138     rb_set_safe_level_force(safe);
00139     th->errinfo = errinfo;
00140 }
00141 
00142 void
00143 Init_jump(void)
00144 {
00145     rb_define_global_function("at_exit", rb_f_at_exit, 0);
00146 }
00147