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 static void 00097 exec_end_procs_chain(struct end_proc_data *volatile *procs) 00098 { 00099 struct end_proc_data volatile endproc; 00100 struct end_proc_data *link; 00101 00102 while ((link = *procs) != 0) { 00103 *procs = link->next; 00104 endproc = *link; 00105 xfree(link); 00106 rb_set_safe_level_force(endproc.safe); 00107 (*endproc.func) (endproc.data); 00108 } 00109 } 00110 00111 void 00112 rb_exec_end_proc(void) 00113 { 00114 int status; 00115 volatile int safe = rb_safe_level(); 00116 rb_thread_t *th = GET_THREAD(); 00117 volatile VALUE errinfo = th->errinfo; 00118 00119 PUSH_TAG(); 00120 if ((status = EXEC_TAG()) == 0) { 00121 again: 00122 exec_end_procs_chain(&ephemeral_end_procs); 00123 exec_end_procs_chain(&end_procs); 00124 } 00125 else { 00126 TH_TMPPOP_TAG(); 00127 error_handle(status); 00128 if (!NIL_P(th->errinfo)) errinfo = th->errinfo; 00129 TH_REPUSH_TAG(); 00130 goto again; 00131 } 00132 POP_TAG(); 00133 00134 rb_set_safe_level_force(safe); 00135 th->errinfo = errinfo; 00136 } 00137 00138 void 00139 Init_jump(void) 00140 { 00141 rb_define_global_function("at_exit", rb_f_at_exit, 0); 00142 } 00143
1.6.1