• Main Page
  • Modules
  • Data Structures
  • Files
  • File List
  • Globals

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, *tmp_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     link = tmp_end_procs;
00095     while (link) {
00096         rb_gc_mark(link->data);
00097         link = link->next;
00098     }
00099 }
00100 
00101 void
00102 rb_exec_end_proc(void)
00103 {
00104     struct end_proc_data *volatile link;
00105     struct end_proc_data *tmp;
00106     int status;
00107     volatile int safe = rb_safe_level();
00108 
00109     while (ephemeral_end_procs) {
00110         tmp_end_procs = link = ephemeral_end_procs;
00111         ephemeral_end_procs = 0;
00112         while (link) {
00113             PUSH_TAG();
00114             if ((status = EXEC_TAG()) == 0) {
00115                 rb_set_safe_level_force(link->safe);
00116                 (*link->func) (link->data);
00117             }
00118             POP_TAG();
00119             if (status) {
00120                 error_handle(status);
00121             }
00122             tmp = link;
00123             tmp_end_procs = link = link->next;
00124             xfree(tmp);
00125         }
00126     }
00127     while (end_procs) {
00128         tmp_end_procs = link = end_procs;
00129         end_procs = 0;
00130         while (link) {
00131             PUSH_TAG();
00132             if ((status = EXEC_TAG()) == 0) {
00133                 rb_set_safe_level_force(link->safe);
00134                 (*link->func) (link->data);
00135             }
00136             POP_TAG();
00137             if (status) {
00138                 error_handle(status);
00139             }
00140             tmp = link;
00141             tmp_end_procs = link = link->next;
00142             xfree(tmp);
00143         }
00144     }
00145     rb_set_safe_level_force(safe);
00146 }
00147 
00148 void
00149 Init_jump(void)
00150 {
00151     rb_define_global_function("at_exit", rb_f_at_exit, 0);
00152 }
00153 

Generated on Sat Jul 7 2012 15:29:02 for Ruby by  doxygen 1.7.1