1/* -*-c-*- */ 2/* 3 * from eval.c 4 */ 5 6#include "eval_intern.h" 7 8/* exit */ 9 10void 11rb_call_end_proc(VALUE data) 12{ 13 rb_proc_call(data, rb_ary_new()); 14} 15 16/* 17 * call-seq: 18 * at_exit { block } -> proc 19 * 20 * Converts _block_ to a +Proc+ object (and therefore 21 * binds it at the point of call) and registers it for execution when 22 * the program exits. If multiple handlers are registered, they are 23 * executed in reverse order of registration. 24 * 25 * def do_at_exit(str1) 26 * at_exit { print str1 } 27 * end 28 * at_exit { puts "cruel world" } 29 * do_at_exit("goodbye ") 30 * exit 31 * 32 * <em>produces:</em> 33 * 34 * goodbye cruel world 35 */ 36 37static VALUE 38rb_f_at_exit(void) 39{ 40 VALUE proc; 41 42 if (!rb_block_given_p()) { 43 rb_raise(rb_eArgError, "called without a block"); 44 } 45 proc = rb_block_proc(); 46 rb_set_end_proc(rb_call_end_proc, proc); 47 return proc; 48} 49 50struct end_proc_data { 51 void (*func) (); 52 VALUE data; 53 int safe; 54 struct end_proc_data *next; 55}; 56 57static struct end_proc_data *end_procs, *ephemeral_end_procs; 58 59void 60rb_set_end_proc(void (*func)(VALUE), VALUE data) 61{ 62 struct end_proc_data *link = ALLOC(struct end_proc_data); 63 struct end_proc_data **list; 64 rb_thread_t *th = GET_THREAD(); 65 66 if (th->top_wrapper) { 67 list = &ephemeral_end_procs; 68 } 69 else { 70 list = &end_procs; 71 } 72 link->next = *list; 73 link->func = func; 74 link->data = data; 75 link->safe = rb_safe_level(); 76 *list = link; 77} 78 79void 80rb_mark_end_proc(void) 81{ 82 struct end_proc_data *link; 83 84 link = end_procs; 85 while (link) { 86 rb_gc_mark(link->data); 87 link = link->next; 88 } 89 link = ephemeral_end_procs; 90 while (link) { 91 rb_gc_mark(link->data); 92 link = link->next; 93 } 94} 95 96void 97rb_exec_end_proc(void) 98{ 99 struct end_proc_data volatile endproc; 100 struct end_proc_data volatile *link; 101 int status; 102 volatile int safe = rb_safe_level(); 103 rb_thread_t *th = GET_THREAD(); 104 volatile VALUE errinfo = th->errinfo; 105 106 while (ephemeral_end_procs) { 107 link = ephemeral_end_procs; 108 ephemeral_end_procs = link->next; 109 endproc = *link; 110 xfree((void *)link); 111 link = &endproc; 112 113 PUSH_TAG(); 114 if ((status = EXEC_TAG()) == 0) { 115 rb_set_safe_level_force(link->safe); 116 (*link->func) (link->data); 117 } 118 POP_TAG(); 119 if (status) { 120 error_handle(status); 121 if (!NIL_P(th->errinfo)) errinfo = th->errinfo; 122 } 123 } 124 125 while (end_procs) { 126 link = end_procs; 127 end_procs = link->next; 128 endproc = *link; 129 xfree((void *)link); 130 link = &endproc; 131 132 PUSH_TAG(); 133 if ((status = EXEC_TAG()) == 0) { 134 rb_set_safe_level_force(link->safe); 135 (*link->func) (link->data); 136 } 137 POP_TAG(); 138 if (status) { 139 error_handle(status); 140 if (!NIL_P(th->errinfo)) errinfo = th->errinfo; 141 } 142 } 143 144 rb_set_safe_level_force(safe); 145 th->errinfo = errinfo; 146} 147 148void 149Init_jump(void) 150{ 151 rb_define_global_function("at_exit", rb_f_at_exit, 0); 152} 153