fix arbiter compilation with the generic codepath
[bpt/guile.git] / libguile / throw.c
CommitLineData
5c8cefe5 1/* Copyright (C) 1995,1996,1997,1998,2000,2001, 2003, 2004, 2006, 2008, 2009 Free Software Foundation, Inc.
0f2d19dd 2 *
73be1d9e 3 * This library is free software; you can redistribute it and/or
53befeb7
NJ
4 * modify it under the terms of the GNU Lesser General Public License
5 * as published by the Free Software Foundation; either version 3 of
6 * the License, or (at your option) any later version.
0f2d19dd 7 *
53befeb7
NJ
8 * This library is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of
73be1d9e
MV
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Lesser General Public License for more details.
0f2d19dd 12 *
73be1d9e
MV
13 * You should have received a copy of the GNU Lesser General Public
14 * License along with this library; if not, write to the Free Software
53befeb7
NJ
15 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
16 * 02110-1301 USA
73be1d9e 17 */
1bbd0b84 18
1bbd0b84 19
0f2d19dd 20\f
dbb605f5
LC
21#ifdef HAVE_CONFIG_H
22# include <config.h>
23#endif
0f2d19dd
JB
24
25#include <stdio.h>
27646f41 26#include <unistdio.h>
a0599745 27#include "libguile/_scm.h"
54f2445b 28#include "libguile/async.h"
a0599745
MD
29#include "libguile/smob.h"
30#include "libguile/alist.h"
31#include "libguile/eval.h"
32#include "libguile/eq.h"
33#include "libguile/dynwind.h"
34#include "libguile/backtrace.h"
a0599745 35#include "libguile/debug.h"
a0599745
MD
36#include "libguile/continuations.h"
37#include "libguile/stackchk.h"
38#include "libguile/stacks.h"
39#include "libguile/fluids.h"
40#include "libguile/ports.h"
c96d76b8 41#include "libguile/lang.h"
a0599745
MD
42#include "libguile/validate.h"
43#include "libguile/throw.h"
9de87eea 44#include "libguile/init.h"
a2c40dc7 45#include "libguile/strings.h"
747a1635 46#include "libguile/vm.h"
0f2d19dd 47
22fc179a
HWN
48#include "libguile/private-options.h"
49
50
32f7b3a1 51\f
74229f75 52/* the jump buffer data structure */
92c2555f 53static scm_t_bits tc16_jmpbuffer;
0f2d19dd 54
e841c3e0 55#define SCM_JMPBUFP(OBJ) SCM_TYP16_PREDICATE (tc16_jmpbuffer, OBJ)
c209c88e 56
0b1733c7
AW
57#define JBACTIVE(OBJ) (SCM_SMOB_FLAGS (OBJ) & 1L)
58#define ACTIVATEJB(x) (SCM_SET_SMOB_FLAGS ((x), 1L))
59#define DEACTIVATEJB(x) (SCM_SET_SMOB_FLAGS ((x), 0L))
0f2d19dd 60
0b1733c7
AW
61#define JBJMPBUF(OBJ) ((scm_i_jmp_buf *) SCM_SMOB_DATA_1 (OBJ))
62#define SETJBJMPBUF(x, v) (SCM_SET_SMOB_DATA_1 ((x), (scm_t_bits) (v)))
63#define SCM_JBPREUNWIND(x) ((struct pre_unwind_data *) SCM_SMOB_DATA_3 (x))
64#define SCM_SETJBPREUNWIND(x, v) (SCM_SET_SMOB_DATA_3 ((x), (scm_t_bits) (v)))
0f2d19dd 65
0f2d19dd 66static int
e81d98ec 67jmpbuffer_print (SCM exp, SCM port, scm_print_state *pstate SCM_UNUSED)
0f2d19dd 68{
b7f3516f
TT
69 scm_puts ("#<jmpbuffer ", port);
70 scm_puts (JBACTIVE(exp) ? "(active) " : "(inactive) ", port);
0345e278 71 scm_uintprint((scm_t_bits) JBJMPBUF (exp), 16, port);
b7f3516f 72 scm_putc ('>', port);
0f2d19dd
JB
73 return 1 ;
74}
75
0f2d19dd 76static SCM
1bbd0b84 77make_jmpbuf (void)
0f2d19dd
JB
78{
79 SCM answer;
86a597f8 80 SCM_NEWSMOB2 (answer, tc16_jmpbuffer, 0, 0);
a4dbe1ac 81 SETJBJMPBUF(answer, (scm_i_jmp_buf *)0);
86a597f8 82 DEACTIVATEJB(answer);
0f2d19dd
JB
83 return answer;
84}
85
74229f75 86\f
43e01b1e 87/* scm_c_catch (the guts of catch) */
74229f75 88
0f2d19dd
JB
89struct jmp_buf_and_retval /* use only on the stack, in scm_catch */
90{
a4dbe1ac 91 scm_i_jmp_buf buf; /* must be first */
0f2d19dd
JB
92 SCM throw_tag;
93 SCM retval;
94};
95
43e01b1e
NJ
96/* These are the structures we use to store pre-unwind handling (aka
97 "lazy") information for a regular catch, and put on the wind list
98 for a "lazy" catch. They store the pre-unwind handler function to
99 call, and the data pointer to pass through to it. It's not a
100 Scheme closure, but it is a function with data, so the term
101 "closure" is appropriate in its broader sense.
650fa1ab 102
43e01b1e
NJ
103 (We don't need anything like this to run the normal (post-unwind)
104 catch handler, because the same C frame runs both the body and the
105 handler.) */
106
107struct pre_unwind_data {
108 scm_t_catch_handler handler;
109 void *handler_data;
110 int running;
111 int lazy_catch_p;
112};
113
114
115/* scm_c_catch is the guts of catch. It handles all the mechanics of
116 setting up a catch target, invoking the catch body, and perhaps
117 invoking the handler if the body does a throw.
650fa1ab
JB
118
119 The function is designed to be usable from C code, but is general
120 enough to implement all the semantics Guile Scheme expects from
121 throw.
122
123 TAG is the catch tag. Typically, this is a symbol, but this
124 function doesn't actually care about that.
125
126 BODY is a pointer to a C function which runs the body of the catch;
127 this is the code you can throw from. We call it like this:
19b27fa2 128 BODY (BODY_DATA)
650fa1ab 129 where:
816a6f06
JB
130 BODY_DATA is just the BODY_DATA argument we received; we pass it
131 through to BODY as its first argument. The caller can make
132 BODY_DATA point to anything useful that BODY might need.
650fa1ab
JB
133
134 HANDLER is a pointer to a C function to deal with a throw to TAG,
135 should one occur. We call it like this:
86327304 136 HANDLER (HANDLER_DATA, THROWN_TAG, THROW_ARGS)
650fa1ab 137 where
816a6f06
JB
138 HANDLER_DATA is the HANDLER_DATA argument we recevied; it's the
139 same idea as BODY_DATA above.
86327304
JB
140 THROWN_TAG is the tag that the user threw to; usually this is
141 TAG, but it could be something else if TAG was #t (i.e., a
142 catch-all), or the user threw to a jmpbuf.
650fa1ab 143 THROW_ARGS is the list of arguments the user passed to the THROW
4dd8323f 144 function, after the tag.
650fa1ab 145
3eed3475
JB
146 BODY_DATA is just a pointer we pass through to BODY. HANDLER_DATA
147 is just a pointer we pass through to HANDLER. We don't actually
148 use either of those pointers otherwise ourselves. The idea is
149 that, if our caller wants to communicate something to BODY or
150 HANDLER, it can pass a pointer to it as MUMBLE_DATA, which BODY and
151 HANDLER can then use. Think of it as a way to make BODY and
152 HANDLER closures, not just functions; MUMBLE_DATA points to the
153 enclosed variables.
154
155 Of course, it's up to the caller to make sure that any data a
156 MUMBLE_DATA needs is protected from GC. A common way to do this is
157 to make MUMBLE_DATA a pointer to data stored in an automatic
158 structure variable; since the collector must scan the stack for
159 references anyway, this assures that any references in MUMBLE_DATA
160 will be found. */
650fa1ab 161
0f2d19dd 162SCM
43e01b1e
NJ
163scm_c_catch (SCM tag,
164 scm_t_catch_body body, void *body_data,
165 scm_t_catch_handler handler, void *handler_data,
166 scm_t_catch_handler pre_unwind_handler, void *pre_unwind_handler_data)
0f2d19dd
JB
167{
168 struct jmp_buf_and_retval jbr;
169 SCM jmpbuf;
170 SCM answer;
747a1635
AW
171 SCM vm;
172 SCM *sp = NULL, *fp = NULL; /* to reset the vm */
43e01b1e 173 struct pre_unwind_data pre_unwind;
0f2d19dd 174
747a1635 175 vm = scm_the_vm ();
5c8cefe5 176 if (scm_is_true (vm))
747a1635
AW
177 {
178 sp = SCM_VM_DATA (vm)->sp;
179 fp = SCM_VM_DATA (vm)->fp;
180 }
181
11702758 182 jmpbuf = make_jmpbuf ();
0f2d19dd 183 answer = SCM_EOL;
9de87eea 184 scm_i_set_dynwinds (scm_acons (tag, jmpbuf, scm_i_dynwinds ()));
0f2d19dd 185 SETJBJMPBUF(jmpbuf, &jbr.buf);
43e01b1e
NJ
186
187 pre_unwind.handler = pre_unwind_handler;
188 pre_unwind.handler_data = pre_unwind_handler_data;
189 pre_unwind.running = 0;
190 pre_unwind.lazy_catch_p = 0;
191 SCM_SETJBPREUNWIND(jmpbuf, &pre_unwind);
192
a4dbe1ac 193 if (SCM_I_SETJMP (jbr.buf))
0f2d19dd
JB
194 {
195 SCM throw_tag;
196 SCM throw_args;
197
7f759d79
MD
198#ifdef STACK_CHECKING
199 scm_stack_checking_enabled_p = SCM_STACK_CHECKING_P;
200#endif
9de87eea 201 SCM_CRITICAL_SECTION_START;
0f2d19dd 202 DEACTIVATEJB (jmpbuf);
9de87eea
MV
203 scm_i_set_dynwinds (SCM_CDR (scm_i_dynwinds ()));
204 SCM_CRITICAL_SECTION_END;
0f2d19dd
JB
205 throw_args = jbr.retval;
206 throw_tag = jbr.throw_tag;
207 jbr.throw_tag = SCM_EOL;
208 jbr.retval = SCM_EOL;
8b22ed7a 209 if (scm_is_true (vm))
747a1635
AW
210 {
211 SCM_VM_DATA (vm)->sp = sp;
212 SCM_VM_DATA (vm)->fp = fp;
213#ifdef VM_ENABLE_STACK_NULLING
214 /* see vm.c -- you'll have to enable this manually */
215 memset (sp + 1, 0,
216 (SCM_VM_DATA (vm)->stack_size
217 - (sp + 1 - SCM_VM_DATA (vm)->stack_base)) * sizeof(SCM));
218#endif
219 }
8b22ed7a 220 else if (scm_is_true ((vm = scm_the_vm ())))
747a1635
AW
221 {
222 /* oof, it's possible this catch was called before the vm was
223 booted... yick. anyway, try to reset the vm stack. */
224 SCM_VM_DATA (vm)->sp = SCM_VM_DATA (vm)->stack_base - 1;
225 SCM_VM_DATA (vm)->fp = NULL;
226#ifdef VM_ENABLE_STACK_NULLING
227 /* see vm.c -- you'll have to enable this manually */
228 memset (SCM_VM_DATA (vm)->stack_base, 0,
229 SCM_VM_DATA (vm)->stack_size * sizeof(SCM));
230#endif
231 }
232
816a6f06 233 answer = handler (handler_data, throw_tag, throw_args);
0f2d19dd
JB
234 }
235 else
236 {
237 ACTIVATEJB (jmpbuf);
492960a4 238 answer = body (body_data);
9de87eea 239 SCM_CRITICAL_SECTION_START;
0f2d19dd 240 DEACTIVATEJB (jmpbuf);
9de87eea
MV
241 scm_i_set_dynwinds (SCM_CDR (scm_i_dynwinds ()));
242 SCM_CRITICAL_SECTION_END;
0f2d19dd
JB
243 }
244 return answer;
245}
246
43e01b1e
NJ
247SCM
248scm_internal_catch (SCM tag,
249 scm_t_catch_body body, void *body_data,
250 scm_t_catch_handler handler, void *handler_data)
251{
252 return scm_c_catch(tag,
253 body, body_data,
254 handler, handler_data,
255 NULL, NULL);
256}
650fa1ab 257
18eadcbe 258
43e01b1e
NJ
259\f
260/* The smob tag for pre_unwind_data smobs. */
261static scm_t_bits tc16_pre_unwind_data;
18eadcbe
JB
262
263/* Strictly speaking, we could just pass a zero for our print
264 function, because we don't need to print them. They should never
265 appear in normal data structures, only in the wind list. However,
266 it might be nice for debugging someday... */
267static int
43e01b1e 268pre_unwind_data_print (SCM closure, SCM port, scm_print_state *pstate SCM_UNUSED)
18eadcbe 269{
0b1733c7 270 struct pre_unwind_data *c = (struct pre_unwind_data *) SCM_SMOB_DATA_1 (closure);
18eadcbe
JB
271 char buf[200];
272
43e01b1e 273 sprintf (buf, "#<pre-unwind-data 0x%lx 0x%lx>",
18eadcbe 274 (long) c->handler, (long) c->handler_data);
b7f3516f 275 scm_puts (buf, port);
18eadcbe
JB
276
277 return 1;
278}
279
18eadcbe 280
43e01b1e 281/* Given a pointer to a pre_unwind_data structure, return a smob for it,
18eadcbe
JB
282