Ruby  2.5.0dev(2017-10-22revision60238)
eval_jump.c
Go to the documentation of this file.
1 /* -*-c-*- */
2 /*
3  * from eval.c
4  */
5 
6 #include "eval_intern.h"
7 
8 /* exit */
9 
10 void
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 
37 static VALUE
38 rb_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();
47  return proc;
48 }
49 
50 struct end_proc_data {
51  void (*func) ();
53  int safe;
55 };
56 
57 static struct end_proc_data *end_procs, *ephemeral_end_procs;
58 
59 void
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 
79 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 
96 static void
97 exec_end_procs_chain(struct end_proc_data *volatile *procs, VALUE *errp)
98 {
99  struct end_proc_data volatile endproc;
100  struct end_proc_data *link;
101  VALUE errinfo = *errp;
102 
103  while ((link = *procs) != 0) {
104  *procs = link->next;
105  endproc = *link;
106  xfree(link);
107  rb_set_safe_level_force(endproc.safe);
108  (*endproc.func) (endproc.data);
109  *errp = errinfo;
110  }
111 }
112 
113 void
115 {
116  enum ruby_tag_type state;
117  volatile int safe = rb_safe_level();
118  rb_thread_t *th = GET_THREAD();
119  volatile VALUE errinfo = th->ec.errinfo;
120 
121  TH_PUSH_TAG(th);
122  if ((state = EXEC_TAG()) == TAG_NONE) {
123  again:
124  exec_end_procs_chain(&ephemeral_end_procs, &th->ec.errinfo);
125  exec_end_procs_chain(&end_procs, &th->ec.errinfo);
126  }
127  else {
128  VAR_INITIALIZED(th);
129  TH_TMPPOP_TAG();
130  error_handle(state);
131  if (!NIL_P(th->ec.errinfo)) errinfo = th->ec.errinfo;
132  TH_REPUSH_TAG();
133  goto again;
134  }
135  TH_POP_TAG();
136 
138  th->ec.errinfo = errinfo;
139 }
140 
141 void
143 {
144  rb_define_global_function("at_exit", rb_f_at_exit, 0);
145 }
ruby_tag_type
Definition: vm_core.h:151
#define TAG_NONE
Definition: vm_core.h:164
int rb_block_given_p(void)
Determines if the current method is given a block.
Definition: eval.c:835
void rb_raise(VALUE exc, const char *fmt,...)
Definition: error.c:2284
void rb_exec_end_proc(void)
Definition: eval_jump.c:114
void Init_jump(void)
Definition: eval_jump.c:142
void rb_gc_mark(VALUE ptr)
Definition: gc.c:4464
void rb_define_global_function(const char *name, VALUE(*func)(ANYARGS), int argc)
Defines a global function.
Definition: class.c:1745
#define GET_THREAD()
Definition: vm_core.h:1583
VALUE rb_eArgError
Definition: error.c:802
#define TH_POP_TAG()
Definition: eval_intern.h:138
void rb_mark_end_proc(void)
Definition: eval_jump.c:80
#define EXEC_TAG()
Definition: eval_intern.h:201
VALUE rb_ary_new(void)
Definition: array.c:499
#define NIL_P(v)
Definition: ruby.h:451
int link(const char *, const char *)
Definition: win32.c:4925
#define ALLOC(type)
Definition: ruby.h:1588
void rb_call_end_proc(VALUE data)
Definition: eval_jump.c:11
void(* func)()
Definition: eval_jump.c:51
VALUE data
Definition: eval_jump.c:52
unsigned long VALUE
Definition: ruby.h:85
#define TH_PUSH_TAG(th)
Definition: eval_intern.h:131
VALUE rb_proc_call(VALUE, VALUE)
Definition: proc.c:872
#define TH_TMPPOP_TAG()
Definition: eval_intern.h:142
void rb_set_end_proc(void(*func)(VALUE), VALUE data)
Definition: eval_jump.c:60
void rb_set_safe_level_force(int)
Definition: safe.c:41
VALUE top_wrapper
Definition: vm_core.h:805
int rb_safe_level(void)
Definition: safe.c:35
VALUE rb_block_proc(void)
Definition: proc.c:780
#define VAR_INITIALIZED(var)
Definition: eval_intern.h:156
struct rb_encoding_entry * list
Definition: encoding.c:55
rb_execution_context_t ec
Definition: vm_core.h:790
void void xfree(void *)
struct end_proc_data * next
Definition: eval_jump.c:54
#define TH_REPUSH_TAG()
Definition: eval_intern.h:145