2006-02-01 Ludovic Courtès <ludovic.courtes@laas.fr>
[bpt/guile.git] / libguile / throw.c
CommitLineData
aa79839a 1/* Copyright (C) 1995,1996,1997,1998,2000,2001, 2003, 2004 Free Software Foundation, Inc.
0f2d19dd 2 *
73be1d9e
MV
3 * This library is free software; you can redistribute it and/or
4 * modify it under the terms of the GNU Lesser General Public
5 * License as published by the Free Software Foundation; either
6 * version 2.1 of the License, or (at your option) any later version.
0f2d19dd 7 *
73be1d9e
MV
8 * This library is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
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
92205699 15 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
73be1d9e 16 */
1bbd0b84 17
1bbd0b84 18
0f2d19dd
JB
19\f
20
21#include <stdio.h>
a0599745 22#include "libguile/_scm.h"
54f2445b 23#include "libguile/async.h"
a0599745
MD
24#include "libguile/smob.h"
25#include "libguile/alist.h"
26#include "libguile/eval.h"
27#include "libguile/eq.h"
28#include "libguile/dynwind.h"
29#include "libguile/backtrace.h"
a0599745 30#include "libguile/debug.h"
a0599745
MD
31#include "libguile/continuations.h"
32#include "libguile/stackchk.h"
33#include "libguile/stacks.h"
34#include "libguile/fluids.h"
35#include "libguile/ports.h"
c96d76b8 36#include "libguile/lang.h"
a0599745
MD
37#include "libguile/validate.h"
38#include "libguile/throw.h"
9de87eea 39#include "libguile/init.h"
0f2d19dd 40
32f7b3a1 41\f
74229f75 42/* the jump buffer data structure */
92c2555f 43static scm_t_bits tc16_jmpbuffer;
0f2d19dd 44
e841c3e0 45#define SCM_JMPBUFP(OBJ) SCM_TYP16_PREDICATE (tc16_jmpbuffer, OBJ)
c209c88e 46
e841c3e0 47#define JBACTIVE(OBJ) (SCM_CELL_WORD_0 (OBJ) & (1L << 16L))
22a52da1
DH
48#define ACTIVATEJB(x) \
49 (SCM_SET_CELL_WORD_0 ((x), (SCM_CELL_WORD_0 (x) | (1L << 16L))))
50#define DEACTIVATEJB(x) \
51 (SCM_SET_CELL_WORD_0 ((x), (SCM_CELL_WORD_0 (x) & ~(1L << 16L))))
0f2d19dd 52
4260a7fc 53#define JBJMPBUF(OBJ) ((jmp_buf *) SCM_CELL_WORD_1 (OBJ))
770e048f 54#define SETJBJMPBUF(x, v) (SCM_SET_CELL_WORD_1 ((x), (scm_t_bits) (v)))
92c2555f 55#define SCM_JBDFRAME(x) ((scm_t_debug_frame *) SCM_CELL_WORD_2 (x))
770e048f 56#define SCM_SETJBDFRAME(x, v) (SCM_SET_CELL_WORD_2 ((x), (scm_t_bits) (v)))
0f2d19dd 57
0f2d19dd 58static int
e81d98ec 59jmpbuffer_print (SCM exp, SCM port, scm_print_state *pstate SCM_UNUSED)
0f2d19dd 60{
b7f3516f
TT
61 scm_puts ("#<jmpbuffer ", port);
62 scm_puts (JBACTIVE(exp) ? "(active) " : "(inactive) ", port);
0345e278 63 scm_uintprint((scm_t_bits) JBJMPBUF (exp), 16, port);
b7f3516f 64 scm_putc ('>', port);
0f2d19dd
JB
65 return 1 ;
66}
67
0f2d19dd 68static SCM
1bbd0b84 69make_jmpbuf (void)
0f2d19dd
JB
70{
71 SCM answer;
9de87eea 72 SCM_CRITICAL_SECTION_START;
0f2d19dd 73 {
e841c3e0 74 SCM_NEWSMOB2 (answer, tc16_jmpbuffer, 0, 0);
11702758
MD
75 SETJBJMPBUF(answer, (jmp_buf *)0);
76 DEACTIVATEJB(answer);
0f2d19dd 77 }
9de87eea 78 SCM_CRITICAL_SECTION_END;
0f2d19dd
JB
79 return answer;
80}
81
74229f75 82\f
18eadcbe 83/* scm_internal_catch (the guts of catch) */
74229f75 84
0f2d19dd
JB
85struct jmp_buf_and_retval /* use only on the stack, in scm_catch */
86{
87 jmp_buf buf; /* must be first */
88 SCM throw_tag;
89 SCM retval;
90};
91
650fa1ab
JB
92
93/* scm_internal_catch is the guts of catch. It handles all the
94 mechanics of setting up a catch target, invoking the catch body,
95 and perhaps invoking the handler if the body does a throw.
96
97 The function is designed to be usable from C code, but is general
98 enough to implement all the semantics Guile Scheme expects from
99 throw.
100
101 TAG is the catch tag. Typically, this is a symbol, but this
102 function doesn't actually care about that.
103
104 BODY is a pointer to a C function which runs the body of the catch;
105 this is the code you can throw from. We call it like this:
19b27fa2 106 BODY (BODY_DATA)
650fa1ab 107 where:
816a6f06
JB
108 BODY_DATA is just the BODY_DATA argument we received; we pass it
109 through to BODY as its first argument. The caller can make
110 BODY_DATA point to anything useful that BODY might need.
650fa1ab
JB
111
112 HANDLER is a pointer to a C function to deal with a throw to TAG,
113 should one occur. We call it like this:
86327304 114 HANDLER (HANDLER_DATA, THROWN_TAG, THROW_ARGS)
650fa1ab 115 where
816a6f06
JB
116 HANDLER_DATA is the HANDLER_DATA argument we recevied; it's the
117 same idea as BODY_DATA above.
86327304
JB
118 THROWN_TAG is the tag that the user threw to; usually this is
119 TAG, but it could be something else if TAG was #t (i.e., a
120 catch-all), or the user threw to a jmpbuf.
650fa1ab 121 THROW_ARGS is the list of arguments the user passed to the THROW
4dd8323f 122 function, after the tag.
650fa1ab 123
3eed3475
JB
124 BODY_DATA is just a pointer we pass through to BODY. HANDLER_DATA
125 is just a pointer we pass through to HANDLER. We don't actually
126 use either of those pointers otherwise ourselves. The idea is
127 that, if our caller wants to communicate something to BODY or
128 HANDLER, it can pass a pointer to it as MUMBLE_DATA, which BODY and
129 HANDLER can then use. Think of it as a way to make BODY and
130 HANDLER closures, not just functions; MUMBLE_DATA points to the
131 enclosed variables.
132
133 Of course, it's up to the caller to make sure that any data a
134 MUMBLE_DATA needs is protected from GC. A common way to do this is
135 to make MUMBLE_DATA a pointer to data stored in an automatic
136 structure variable; since the collector must scan the stack for
137 references anyway, this assures that any references in MUMBLE_DATA
138 will be found. */
650fa1ab 139
0f2d19dd 140SCM
92c2555f 141scm_internal_catch (SCM tag, scm_t_catch_body body, void *body_data, scm_t_catch_handler handler, void *handler_data)
0f2d19dd
JB
142{
143 struct jmp_buf_and_retval jbr;
144 SCM jmpbuf;
145 SCM answer;
146
11702758 147 jmpbuf = make_jmpbuf ();
0f2d19dd 148 answer = SCM_EOL;
9de87eea 149 scm_i_set_dynwinds (scm_acons (tag, jmpbuf, scm_i_dynwinds ()));
0f2d19dd 150 SETJBJMPBUF(jmpbuf, &jbr.buf);
9de87eea 151 SCM_SETJBDFRAME(jmpbuf, scm_i_last_debug_frame ());
0f2d19dd
JB
152 if (setjmp (jbr.buf))
153 {
154 SCM throw_tag;
155 SCM throw_args;
156
7f759d79
MD
157#ifdef STACK_CHECKING
158 scm_stack_checking_enabled_p = SCM_STACK_CHECKING_P;
159#endif
9de87eea 160 SCM_CRITICAL_SECTION_START;
0f2d19dd 161 DEACTIVATEJB (jmpbuf);
9de87eea
MV
162 scm_i_set_dynwinds (SCM_CDR (scm_i_dynwinds ()));
163 SCM_CRITICAL_SECTION_END;
0f2d19dd
JB
164 throw_args = jbr.retval;
165 throw_tag = jbr.throw_tag;
166 jbr.throw_tag = SCM_EOL;
167 jbr.retval = SCM_EOL;
816a6f06 168 answer = handler (handler_data, throw_tag, throw_args);
0f2d19dd
JB
169 }
170 else
171 {
172 ACTIVATEJB (jmpbuf);
492960a4 173 answer = body (body_data);
9de87eea 174 SCM_CRITICAL_SECTION_START;
0f2d19dd 175 DEACTIVATEJB (jmpbuf);
9de87eea
MV
176 scm_i_set_dynwinds (SCM_CDR (scm_i_dynwinds ()));
177 SCM_CRITICAL_SECTION_END;
0f2d19dd
JB
178 }
179 return answer;
180}
181
650fa1ab 182
18eadcbe
JB
183\f
184/* scm_internal_lazy_catch (the guts of lazy catching) */
185
186/* The smob tag for lazy_catch smobs. */
92c2555f 187static scm_t_bits tc16_lazy_catch;
18eadcbe
JB
188
189/* This is the structure we put on the wind list for a lazy catch. It
190 stores the handler function to call, and the data pointer to pass
191 through to it. It's not a Scheme closure, but it is a function
192 with data, so the term "closure" is appropriate in its broader
193 sense.
194
195 (We don't need anything like this in the "eager" catch code,
196 because the same C frame runs both the body and the handler.) */
197struct lazy_catch {
92c2555f 198 scm_t_catch_handler handler;
18eadcbe
JB
199 void *handler_data;
200};
201
202/* Strictly speaking, we could just pass a zero for our print
203 function, because we don't need to print them. They should never
204 appear in normal data structures, only in the wind list. However,
205 it might be nice for debugging someday... */
206static int
e81d98ec 207lazy_catch_print (SCM closure, SCM port, scm_print_state *pstate SCM_UNUSED)
18eadcbe 208{
4260a7fc 209 struct lazy_catch *c = (struct lazy_catch *) SCM_CELL_WORD_1 (closure);
18eadcbe
JB
210 char buf[200];
211
212 sprintf (buf, "#<lazy-catch 0x%lx 0x%lx>",
213 (long) c->handler, (long) c->handler_data);
b7f3516f 214 scm_puts (buf, port);
18eadcbe
JB
215
216 return 1;
217}
218
18eadcbe
JB
219
220/* Given a pointer to a lazy catch structure, return a smob for it,
221