Ruby 1.9.3p327(2012-11-10revision37606)
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 
00103     while (ephemeral_end_procs) {
00104         link = ephemeral_end_procs;
00105         ephemeral_end_procs = link->next;
00106 
00107         PUSH_TAG();
00108         if ((status = EXEC_TAG()) == 0) {
00109             rb_set_safe_level_force(link->safe);
00110             (*link->func) (link->data);
00111         }
00112         POP_TAG();
00113         if (status) {
00114             error_handle(status);
00115         }
00116         xfree(link);
00117     }
00118 
00119     while (end_procs) {
00120         link = end_procs;
00121         end_procs = link->next;
00122 
00123         PUSH_TAG();
00124         if ((status = EXEC_TAG()) == 0) {
00125             rb_set_safe_level_force(link->safe);
00126             (*link->func) (link->data);
00127         }
00128         POP_TAG();
00129         if (status) {
00130             error_handle(status);
00131         }
00132         xfree(link);
00133     }
00134     rb_set_safe_level_force(safe);
00135 }
00136 
00137 void
00138 Init_jump(void)
00139 {
00140     rb_define_global_function("at_exit", rb_f_at_exit, 0);
00141 }
00142