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