Ruby 1.9.3p327(2012-11-10revision37606)
|
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