Ruby 1.9.2p136(2010-12-25revision30365)

- 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