1:
2:
3:
4:
5:
6: #include "eval_intern.h"
7:
8: NORETURN(static VALUE rb_f_throw _((int, VALUE *)));
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22: static VALUE
23: rb_f_throw(int argc, VALUE *argv)
24: {
25: VALUE tag, value;
26: rb_thread_t *th = GET_THREAD();
27: struct rb_vm_tag *tt = th->tag;
28:
29: rb_scan_args(argc, argv, "11", &tag, &value);
30: while (tt) {
31: if (tt->tag == tag) {
32: tt->retval = value;
33: break;
34: }
35: tt = tt->prev;
36: }
37: if (!tt) {
38: VALUE desc = rb_inspect(tag);
39: rb_raise(rb_eArgError, "uncaught throw %s", RSTRING_PTR(desc));
40: }
41: rb_trap_restore_mask();
42: th->errinfo = NEW_THROW_OBJECT(tag, 0, TAG_THROW);
43:
44: JUMP_TAG(TAG_THROW);
45: #ifndef __GNUC__
46: return Qnil;
47: #endif
48: }
49:
50: void
51: rb_throw(const char *tag, VALUE val)
52: {
53: VALUE argv[2];
54:
55: argv[0] = ID2SYM(rb_intern(tag));
56: argv[1] = val;
57: rb_f_throw(2, argv);
58: }
59:
60: void
61: rb_throw_obj(VALUE tag, VALUE val)
62: {
63: VALUE argv[2];
64:
65: argv[0] = tag;
66: argv[1] = val;
67: rb_f_throw(2, argv);
68: }
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:
91:
92:
93:
94:
95:
96:
97:
98:
99:
100:
101: static VALUE
102: rb_f_catch(int argc, VALUE *argv)
103: {
104: VALUE tag;
105: int state;
106: VALUE val = Qnil;
107: rb_thread_t *th = GET_THREAD();
108:
109: rb_scan_args(argc, argv, "01", &tag);
110: if (argc == 0) {
111: tag = rb_obj_alloc(rb_cObject);
112: }
113: PUSH_TAG();
114:
115: th->tag->tag = tag;
116:
117: if ((state = EXEC_TAG()) == 0) {
118: val = rb_yield_0(1, &tag);
119: }
120: else if (state == TAG_THROW && RNODE(th->errinfo)->u1.value == tag) {
121: val = th->tag->retval;
122: th->errinfo = Qnil;
123: state = 0;
124: }
125: POP_TAG();
126: if (state)
127: JUMP_TAG(state);
128:
129: return val;
130: }
131:
132: static VALUE
133: catch_null_i(VALUE dmy)
134: {
135: return rb_funcall(Qnil, rb_intern("catch"), 0, 0);
136: }
137:
138: static VALUE
139: catch_i(VALUE tag)
140: {
141: return rb_funcall(Qnil, rb_intern("catch"), 1, tag);
142: }
143:
144: VALUE
145: rb_catch(const char *tag, VALUE (*func)(), VALUE data)
146: {
147: if (!tag) {
148: return rb_iterate(catch_null_i, 0, func, data);
149: }
150: return rb_iterate(catch_i, ID2SYM(rb_intern(tag)), func, data);
151: }
152:
153: VALUE
154: rb_catch_obj(VALUE tag, VALUE (*func)(), VALUE data)
155: {
156: return rb_iterate((VALUE (*)_((VALUE)))catch_i, tag, func, data);
157: }
158:
159:
160:
161:
162: void
163: rb_call_end_proc(VALUE data)
164: {
165: rb_proc_call(data, rb_ary_new());
166: }
167:
168:
169:
170:
171:
172:
173:
174:
175:
176:
177:
178:
179:
180:
181:
182:
183:
184:
185:
186:
187:
188:
189: static VALUE
190: rb_f_at_exit(void)
191: {
192: VALUE proc;
193:
194: if (!rb_block_given_p()) {
195: rb_raise(rb_eArgError, "called without a block");
196: }
197: proc = rb_block_proc();
198: rb_set_end_proc(rb_call_end_proc, proc);
199: return proc;
200: }
201:
202: struct end_proc_data {
203: void (*func) ();
204: VALUE data;
205: int safe;
206: struct end_proc_data *next;
207: };
208:
209: static struct end_proc_data *end_procs, *ephemeral_end_procs, *tmp_end_procs;
210:
211: void
212: rb_set_end_proc(void (*func)(VALUE), VALUE data)
213: {
214: struct end_proc_data *link = ALLOC(struct end_proc_data);
215: struct end_proc_data **list;
216: rb_thread_t *th = GET_THREAD();
217:
218: if (th->top_wrapper) {
219: list = &ephemeral_end_procs;
220: }
221: else {
222: list = &end_procs;
223: }
224: link->next = *list;
225: link->func = func;
226: link->data = data;
227: link->safe = rb_safe_level();
228: *list = link;
229: }
230:
231: void
232: rb_mark_end_proc(void)
233: {
234: struct end_proc_data *link;
235:
236: link = end_procs;
237: while (link) {
238: rb_gc_mark(link->data);
239: link = link->next;
240: }
241: link = ephemeral_end_procs;
242: while (link) {
243: rb_gc_mark(link->data);
244: link = link->next;
245: }
246: link = tmp_end_procs;
247: while (link) {
248: rb_gc_mark(link->data);
249: link = link->next;
250: }
251: }
252:
253: void
254: rb_exec_end_proc(void)
255: {
256: struct end_proc_data *link, *tmp;
257: int status;
258: volatile int safe = rb_safe_level();
259:
260: while (ephemeral_end_procs) {
261: tmp_end_procs = link = ephemeral_end_procs;
262: ephemeral_end_procs = 0;
263: while (link) {
264: PUSH_TAG();
265: if ((status = EXEC_TAG()) == 0) {
266: rb_set_safe_level_force(link->safe);
267: (*link->func) (link->data);
268: }
269: POP_TAG();
270: if (status) {
271: error_handle(status);
272: }
273: tmp = link;
274: tmp_end_procs = link = link->next;
275: free(tmp);
276: }
277: }
278: while (end_procs) {
279: tmp_end_procs = link = end_procs;
280: end_procs = 0;
281: while (link) {
282: PUSH_TAG();
283: if ((status = EXEC_TAG()) == 0) {
284: rb_set_safe_level_force(link->safe);
285: (*link->func) (link->data);
286: }
287: POP_TAG();
288: if (status) {
289: error_handle(status);
290: }
291: tmp = link;
292: tmp_end_procs = link = link->next;
293: free(tmp);
294: }
295: }
296: rb_set_safe_level_force(safe);
297: }
298:
299: void
300: Init_jump(void)
301: {
302: rb_define_global_function("catch", rb_f_catch, -1);
303: rb_define_global_function("throw", rb_f_throw, -1);
304: rb_define_global_function("at_exit", rb_f_at_exit, 0);
305: }