* continuations.c (scm_make_continuation): No longer a critical
[bpt/guile.git] / libguile / throw.c
... / ...
CommitLineData
1/* Copyright (C) 1995,1996,1997,1998,2000,2001, 2003, 2004 Free Software Foundation, Inc.
2 *
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.
7 *
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.
12 *
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 */
17
18
19\f
20
21#include <stdio.h>
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"
29#include "libguile/debug.h"
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"
35#include "libguile/lang.h"
36#include "libguile/validate.h"
37#include "libguile/throw.h"
38#include "libguile/init.h"
39
40\f
41/* the jump buffer data structure */
42static scm_t_bits tc16_jmpbuffer;
43
44#define SCM_JMPBUFP(OBJ) SCM_TYP16_PREDICATE (tc16_jmpbuffer, OBJ)
45
46#define JBACTIVE(OBJ) (SCM_CELL_WORD_0 (OBJ) & (1L << 16L))
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))))
51
52#define JBJMPBUF(OBJ) ((jmp_buf *) SCM_CELL_WORD_1 (OBJ))
53#define SETJBJMPBUF(x, v) (SCM_SET_CELL_WORD_1 ((x), (scm_t_bits) (v)))
54#define SCM_JBDFRAME(x) ((scm_t_debug_frame *) SCM_CELL_WORD_2 (x))
55#define SCM_SETJBDFRAME(x, v) (SCM_SET_CELL_WORD_2 ((x), (scm_t_bits) (v)))
56
57static int
58jmpbuffer_print (SCM exp, SCM port, scm_print_state *pstate SCM_UNUSED)
59{
60 scm_puts ("#<jmpbuffer ", port);
61 scm_puts (JBACTIVE(exp) ? "(active) " : "(inactive) ", port);
62 scm_uintprint((scm_t_bits) JBJMPBUF (exp), 16, port);
63 scm_putc ('>', port);
64 return 1 ;
65}
66
67static SCM
68make_jmpbuf (void)
69{
70 SCM answer;
71 SCM_CRITICAL_SECTION_START;
72 {
73 SCM_NEWSMOB2 (answer, tc16_jmpbuffer, 0, 0);
74 SETJBJMPBUF(answer, (jmp_buf *)0);
75 DEACTIVATEJB(answer);
76 }
77 SCM_CRITICAL_SECTION_END;
78 return answer;
79}
80
81\f
82/* scm_internal_catch (the guts of catch) */
83
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
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:
105 BODY (BODY_DATA)
106 where:
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.
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:
113 HANDLER (HANDLER_DATA, THROWN_TAG, THROW_ARGS)
114 where
115 HANDLER_DATA is the HANDLER_DATA argument we recevied; it's the
116 same idea as BODY_DATA above.
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.
120 THROW_ARGS is the list of arguments the user passed to the THROW
121 function, after the tag.
122
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. */
138
139SCM
140scm_internal_catch (SCM tag, scm_t_catch_body body, void *body_data, scm_t_catch_handler handler, void *handler_data)
141{
142 struct jmp_buf_and_retval jbr;
143 SCM jmpbuf;
144 SCM answer;
145
146 jmpbuf = make_jmpbuf ();
147 answer = SCM_EOL;
148 scm_i_set_dynwinds (scm_acons (tag, jmpbuf, scm_i_dynwinds ()));
149 SETJBJMPBUF(jmpbuf, &jbr.buf);
150 SCM_SETJBDFRAME(jmpbuf, scm_i_last_debug_frame ());
151 if (setjmp (jbr.buf))
152 {
153 SCM throw_tag;
154 SCM throw_args;
155
156#ifdef STACK_CHECKING
157 scm_stack_checking_enabled_p = SCM_STACK_CHECKING_P;
158#endif
159 SCM_CRITICAL_SECTION_START;
160 DEACTIVATEJB (jmpbuf);
161 scm_i_set_dynwinds (SCM_CDR (scm_i_dynwinds ()));
162 SCM_CRITICAL_SECTION_END;
163 throw_args = jbr.retval;
164 throw_tag = jbr.throw_tag;
165 jbr.throw_tag = SCM_EOL;
166 jbr.retval = SCM_EOL;
167 answer = handler (handler_data, throw_tag, throw_args);
168 }
169 else
170 {
171 ACTIVATEJB (jmpbuf);
172 answer = body (body_data);
173 SCM_CRITICAL_SECTION_START;
174 DEACTIVATEJB (jmpbuf);
175 scm_i_set_dynwinds (SCM_CDR (scm_i_dynwinds ()));
176 SCM_CRITICAL_SECTION_END;
177 }
178 return answer;
179}
180
181
182\f
183/* scm_internal_lazy_catch (the guts of lazy catching) */
184
185/* The smob tag for lazy_catch smobs. */
186static scm_t_bits tc16_lazy_catch;
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 {
197 scm_t_catch_handler handler;
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
206lazy_catch_print (SCM closure, SCM port, scm_print_state *pstate SCM_UNUSED)
207{
208 struct lazy_catch *c = (struct lazy_catch *) SCM_CELL_WORD_1 (closure);
209 char buf[200];
210
211 sprintf (buf, "#<lazy-catch 0x%lx 0x%lx>",
212 (long) c->handler, (long) c->handler_data);
213 scm_puts (buf, port);
214
215 return 1;
216}
217
218
219/* Given a pointer to a lazy catch structure, return a smob for it,
220