* stime.c (scm_init_stime): don't define ticks/sec.
[bpt/guile.git] / libguile / throw.c
CommitLineData
0f2d19dd
JB
1/* Copyright (C) 1995,1996 Free Software Foundation, Inc.
2 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation; either version 2, or (at your option)
6 * any later version.
7 *
8 * This program 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
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this software; see the file COPYING. If not, write to
15 * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
16 *
17 * As a special exception, the Free Software Foundation gives permission
18 * for additional uses of the text contained in its release of GUILE.
19 *
20 * The exception is that, if you link the GUILE library with other files
21 * to produce an executable, this does not by itself cause the
22 * resulting executable to be covered by the GNU General Public License.
23 * Your use of that executable is in no way restricted on account of
24 * linking the GUILE library code into it.
25 *
26 * This exception does not however invalidate any other reasons why
27 * the executable file might be covered by the GNU General Public License.
28 *
29 * This exception applies only to the code released by the
30 * Free Software Foundation under the name GUILE. If you copy
31 * code from other Free Software Foundation releases into a copy of
32 * GUILE, as the General Public License permits, the exception does
33 * not apply to the code that you add in this way. To avoid misleading
34 * anyone as to the status of such modified files, you must delete
35 * this exception notice from them.
36 *
37 * If you write modifications of your own for GUILE, it is your choice
38 * whether to permit this exception to apply to your modifications.
39 * If you do not wish that, delete this exception notice.
40 */
41\f
42
43#include <stdio.h>
44#include "_scm.h"
20e6290e
JB
45#include "genio.h"
46#include "smob.h"
47#include "alist.h"
48#include "eval.h"
1a36eef2 49#include "eq.h"
20e6290e 50#include "dynwind.h"
e82afdb8 51#include "backtrace.h"
20e6290e
JB
52#ifdef DEBUG_EXTENSIONS
53#include "debug.h"
54#endif
55#include "continuations.h"
7f759d79 56#include "stackchk.h"
0f2d19dd 57
20e6290e 58#include "throw.h"
0f2d19dd 59
32f7b3a1 60\f
0f2d19dd
JB
61/* {Catch and Throw}
62 */
63static int scm_tc16_jmpbuffer;
64
0f2d19dd
JB
65#define SCM_JMPBUFP(O) (SCM_TYP16(O) == scm_tc16_jmpbuffer)
66#define JBACTIVE(O) (SCM_CAR (O) & (1L << 16L))
898a256f
MD
67#define ACTIVATEJB(O) (SCM_SETOR_CAR (O, (1L << 16L)))
68#define DEACTIVATEJB(O) (SCM_SETAND_CAR (O, ~(1L << 16L)))
0f2d19dd 69
e137c6b3
MD
70#ifndef DEBUG_EXTENSIONS
71#define JBJMPBUF(O) ((jmp_buf*)SCM_CDR (O) )
72#define SETJBJMPBUF SCM_SETCDR
73#else
08b5b88c 74#define SCM_JBDFRAME(O) ((scm_debug_frame*)SCM_CAR (SCM_CDR (O)) )
0f2d19dd 75#define JBJMPBUF(O) ((jmp_buf*)SCM_CDR (SCM_CDR (O)) )
898a256f 76#define SCM_SETJBDFRAME(O,X) SCM_SETCAR (SCM_CDR (O), (SCM)(X))
0f2d19dd 77#define SETJBJMPBUF(O,X) SCM_SETCDR(SCM_CDR (O), X)
e137c6b3 78
32f7b3a1
JB
79static scm_sizet freejb SCM_P ((SCM jbsmob));
80
faa6b3df 81static scm_sizet
e137c6b3
MD
82freejb (jbsmob)
83 SCM jbsmob;
e137c6b3
MD
84{
85 scm_must_free ((char *) SCM_CDR (jbsmob));
86 return sizeof (scm_cell);
87}
0f2d19dd
JB
88#endif
89
32f7b3a1 90static int printjb SCM_P ((SCM exp, SCM port, scm_print_state *pstate));
0f2d19dd 91static int
9882ea19 92printjb (exp, port, pstate)
0f2d19dd
JB
93 SCM exp;
94 SCM port;
9882ea19 95 scm_print_state *pstate;
0f2d19dd
JB
96{
97 scm_gen_puts (scm_regular_string, "#<jmpbuffer ", port);
11702758 98 scm_gen_puts (scm_regular_string, JBACTIVE(exp) ? "(active) " : "(inactive) ", port);
0f2d19dd
JB
99 scm_intprint((SCM) JBJMPBUF(exp), 16, port);
100 scm_gen_putc ('>', port);
101 return 1 ;
102}
103
e137c6b3
MD
104static scm_smobfuns jbsmob = {
105 scm_mark0,
106#ifdef DEBUG_EXTENSIONS
107 freejb,
108#else
109 scm_free0,
110#endif
111 printjb,
112 0
113};
0f2d19dd 114
11702758 115static SCM make_jmpbuf SCM_P ((void));
0f2d19dd 116static SCM
11702758 117make_jmpbuf ()
0f2d19dd
JB
118{
119 SCM answer;
120 SCM_NEWCELL (answer);
7f759d79 121 SCM_REDEFER_INTS;
0f2d19dd 122 {
e137c6b3
MD
123#ifdef DEBUG_EXTENSIONS
124 char *mem = scm_must_malloc (sizeof (scm_cell), "jb");
125 SCM_SETCDR (answer, (SCM) mem);
126#endif
898a256f 127 SCM_SETCAR (answer, scm_tc16_jmpbuffer);
11702758
MD
128 SETJBJMPBUF(answer, (jmp_buf *)0);
129 DEACTIVATEJB(answer);
0f2d19dd 130 }
7f759d79 131 SCM_REALLOW_INTS;
0f2d19dd
JB
132 return answer;
133}
134
0f2d19dd
JB
135struct jmp_buf_and_retval /* use only on the stack, in scm_catch */
136{
137 jmp_buf buf; /* must be first */
138 SCM throw_tag;
139 SCM retval;
140};
141
650fa1ab
JB
142
143/* scm_internal_catch is the guts of catch. It handles all the
144 mechanics of setting up a catch target, invoking the catch body,
145 and perhaps invoking the handler if the body does a throw.
146
147 The function is designed to be usable from C code, but is general
148 enough to implement all the semantics Guile Scheme expects from
149 throw.
150
151 TAG is the catch tag. Typically, this is a symbol, but this
152 function doesn't actually care about that.
153
154 BODY is a pointer to a C function which runs the body of the catch;
155 this is the code you can throw from. We call it like this:
816a6f06 156 BODY (BODY_DATA, JMPBUF)
650fa1ab 157 where:
816a6f06
JB
158 BODY_DATA is just the BODY_DATA argument we received; we pass it
159 through to BODY as its first argument. The caller can make
160 BODY_DATA point to anything useful that BODY might need.
650fa1ab
JB
161 JMPBUF is the Scheme jmpbuf object corresponding to this catch,
162 which we have just created and initialized.
163
164 HANDLER is a pointer to a C function to deal with a throw to TAG,
165 should one occur. We call it like this:
816a6f06 166 HANDLER (HANDLER_DATA, TAG, THROW_ARGS)
650fa1ab 167 where
816a6f06
JB
168 HANDLER_DATA is the HANDLER_DATA argument we recevied; it's the
169 same idea as BODY_DATA above.
650fa1ab
JB
170 TAG is the tag that the user threw to; usually this is TAG, but
171 it could be something else if TAG was #t (i.e., a catch-all),
172 or the user threw to a jmpbuf.
173 THROW_ARGS is the list of arguments the user passed to the THROW
174 function.
175
3eed3475
JB
176 BODY_DATA is just a pointer we pass through to BODY. HANDLER_DATA
177 is just a pointer we pass through to HANDLER. We don't actually
178 use either of those pointers otherwise ourselves. The idea is
179 that, if our caller wants to communicate something to BODY or
180 HANDLER, it can pass a pointer to it as MUMBLE_DATA, which BODY and
181 HANDLER can then use. Think of it as a way to make BODY and
182 HANDLER closures, not just functions; MUMBLE_DATA points to the
183 enclosed variables.
184
185 Of course, it's up to the caller to make sure that any data a
186 MUMBLE_DATA needs is protected from GC. A common way to do this is
187 to make MUMBLE_DATA a pointer to data stored in an automatic
188 structure variable; since the collector must scan the stack for
189 references anyway, this assures that any references in MUMBLE_DATA
190 will be found. */
650fa1ab 191
0f2d19dd 192SCM
816a6f06 193scm_internal_catch (tag, body, body_data, handler, handler_data)
0f2d19dd 194 SCM tag;
650fa1ab 195 scm_catch_body_t body;
816a6f06 196 void *body_data;
650fa1ab 197 scm_catch_handler_t handler;
816a6f06 198 void *handler_data;
0f2d19dd
JB
199{
200 struct jmp_buf_and_retval jbr;
201 SCM jmpbuf;
202 SCM answer;
203
11702758 204 jmpbuf = make_jmpbuf ();
0f2d19dd
JB
205 answer = SCM_EOL;
206 scm_dynwinds = scm_acons (tag, jmpbuf, scm_dynwinds);
207 SETJBJMPBUF(jmpbuf, &jbr.buf);
208#ifdef DEBUG_EXTENSIONS
e68b42c1 209 SCM_SETJBDFRAME(jmpbuf, scm_last_debug_frame);
0f2d19dd
JB
210#endif
211 if (setjmp (jbr.buf))
212 {
213 SCM throw_tag;
214 SCM throw_args;
215
7f759d79
MD
216#ifdef STACK_CHECKING
217 scm_stack_checking_enabled_p = SCM_STACK_CHECKING_P;
218#endif
219 SCM_REDEFER_INTS;
0f2d19dd
JB
220 DEACTIVATEJB (jmpbuf);
221 scm_dynwinds = SCM_CDR (scm_dynwinds);
7f759d79 222 SCM_REALLOW_INTS;
0f2d19dd
JB
223 throw_args = jbr.retval;
224 throw_tag = jbr.throw_tag;
225 jbr.throw_tag = SCM_EOL;
226 jbr.retval = SCM_EOL;
816a6f06 227 answer = handler (handler_data, throw_tag, throw_args);
0f2d19dd
JB
228 }
229 else
230 {
231 ACTIVATEJB (jmpbuf);
816a6f06 232 answer = body (body_data, jmpbuf);
7f759d79 233 SCM_REDEFER_INTS;
0f2d19dd
JB
234 DEACTIVATEJB (jmpbuf);
235 scm_dynwinds = SCM_CDR (scm_dynwinds);
7f759d79 236 SCM_REALLOW_INTS;
0f2d19dd
JB
237 }
238 return answer;
239}
240
650fa1ab 241
816a6f06
JB
242/* This is a body function you can pass to scm_internal_catch if you
243 want the body to be like Scheme's `catch' --- a thunk, or a
244 function of one argument if the tag is #f.
650fa1ab 245
816a6f06
JB
246 DATA contains the Scheme procedure to invoke. If the tag being
247 caught is #f, then we pass JMPBUF to the body procedure; otherwise,
248 it gets no arguments. */
650fa1ab 249
816a6f06
JB
250SCM
251scm_body_thunk (body_data, jmpbuf)
252 void *body_data;
650fa1ab
JB
253 SCM jmpbuf;
254{
816a6f06 255 struct scm_body_thunk_data *c = (struct scm_body_thunk_data *) body_data;
650fa1ab
JB
256
257 if (c->tag == SCM_BOOL_F)
258 return scm_apply (c->body_proc, scm_cons (jmpbuf, SCM_EOL), SCM_EOL);
259 else
260 return scm_apply (c->body_proc, SCM_EOL, SCM_EOL);
261}
262
263
816a6f06
JB
264/* If the user does a throw to this catch, this function runs a
265 handler procedure written in Scheme. HANDLER_DATA is a pointer to
266 an SCM variable holding the Scheme procedure object to invoke. It
267 ought to be a pointer to an automatic, or the procedure object
268 should be otherwise protected from GC. */
269SCM
270scm_handle_by_proc (handler_data, tag, throw_args)
271 void *handler_data;
650fa1ab
JB
272 SCM tag;
273 SCM throw_args;
274{
816a6f06 275 SCM *handler_proc_p = (SCM *) handler_data;
650fa1ab 276
816a6f06 277 return scm_apply (*handler_proc_p, scm_cons (tag, throw_args), SCM_EOL);
650fa1ab
JB
278}
279
280
e68b42c1
MD
281SCM_PROC(s_catch, "catch", 3, 0, 0, scm_catch);
282SCM
283scm_catch (tag, thunk, handler)
284 SCM tag;
285 SCM thunk;
286 SCM handler;
287{
816a6f06 288 struct scm_body_thunk_data c;
650fa1ab 289
e68b42c1
MD
290 SCM_ASSERT ((tag == SCM_BOOL_F)
291 || (SCM_NIMP(tag) && SCM_SYMBOLP(tag))
292 || (tag == SCM_BOOL_T),
293 tag, SCM_ARG1, s_catch);
650fa1ab
JB
294
295 c.tag = tag;
296 c.body_proc = thunk;
650fa1ab
JB
297
298 /* scm_internal_catch takes care of all the mechanics of setting up
816a6f06
JB
299 a catch tag; we tell it to call scm_body_thunk to run the body,
300 and scm_handle_by_proc to deal with any throws to this catch.
301 The former receives a pointer to c, telling it how to behave.
302 The latter receives a pointer to HANDLER, so it knows who to call. */
303 return scm_internal_catch (tag,
304 scm_body_thunk, &c,
305 scm_handle_by_proc, &handler);
e68b42c1
MD
306}
307
3eed3475
JB
308
309/* The smob tag for lazy_catch smobs. */
310static long tc16_lazy_catch;
311
312/* This is the structure we put on the wind list for a lazy catch. It
313 stores the handler function to call, and the data pointer to pass
314 through to it. It's not a Scheme closure, but it is a function
315 with data, so the term "closure" is appropriate in its broader
316 sense.
317
318 (We don't need anything like this in the "eager" catch code,
319 because the same C frame runs both the body and the handler.) */
320struct lazy_catch {
321 scm_catch_handler_t handler;
322 void *handler_data;
323};
324
3eed3475
JB
325/* Strictly speaking, we could just pass a zero for our print
326 function, because we don't need to print them. They should never
327 appear in normal data structures, only in the wind list. However,
328 it might be nice for debugging someday... */
329static int
330print_lazy_catch (SCM closure, SCM port, scm_print_state *pstate)
331{
332 struct lazy_catch *c = (struct lazy_catch *) SCM_CDR (closure);
333 char buf[200];
334
335 sprintf (buf, "#<lazy-catch 0x%lx 0x%lx>",
336 (long) c->handler, (long) c->handler_data);
337 scm_gen_puts (scm_regular_string, buf, port);
338
339 return 1;
340}
341
342static scm_smobfuns lazy_catch_funs = {
3197e30d 343 scm_mark0, scm_free0, print_lazy_catch, 0
3eed3475
JB
344};
345
346
347/* Given a pointer to a lazy catch structure, return a smob for it,
348