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