Ruby
2.0.0p247(2013-06-27revision41674)
|
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