* throw.c (scm_ithrow): Abort when scm_i_critical_section_level is
[bpt/guile.git] / libguile / throw.c
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/async.h"
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"
30 #include "libguile/debug.h"
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"
36 #include "libguile/lang.h"
37 #include "libguile/validate.h"
38 #include "libguile/throw.h"
39 #include "libguile/init.h"
40
41 \f
42 /* the jump buffer data structure */
43 static scm_t_bits tc16_jmpbuffer;
44
45 #define SCM_JMPBUFP(OBJ) SCM_TYP16_PREDICATE (tc16_jmpbuffer, OBJ)
46
47 #define JBACTIVE(OBJ) (SCM_CELL_WORD_0 (OBJ) & (1L << 16L))
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))))
52
53 #define JBJMPBUF(OBJ) ((jmp_buf *) SCM_CELL_WORD_1 (OBJ))
54 #define SETJBJMPBUF(x, v) (SCM_SET_CELL_WORD_1 ((x), (scm_t_bits) (v)))
55 #define SCM_JBDFRAME(x) ((scm_t_debug_frame *) SCM_CELL_WORD_2 (x))
56 #define SCM_SETJBDFRAME(x, v) (SCM_SET_CELL_WORD_2 ((x), (scm_t_bits) (v)))
57
58 static int
59 jmpbuffer_print (SCM exp, SCM port, scm_print_state *pstate SCM_UNUSED)
60 {
61 scm_puts ("#<jmpbuffer ", port);
62 scm_puts (JBACTIVE(exp) ? "(active) " : "(inactive) ", port);
63 scm_uintprint((scm_t_bits) JBJMPBUF (exp), 16, port);
64 scm_putc ('>', port);
65 return 1 ;
66 }
67
68 static SCM
69 make_jmpbuf (void)
70 {
71 SCM answer;
72 SCM_CRITICAL_SECTION_START;
73 {
74 SCM_NEWSMOB2 (answer, tc16_jmpbuffer, 0, 0);
75 SETJBJMPBUF(answer, (jmp_buf *)0);
76 DEACTIVATEJB(answer);
77 }
78 SCM_CRITICAL_SECTION_END;
79 return answer;
80 }
81
82 \f
83 /* scm_internal_catch (the guts of catch) */
84
85 struct 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
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:
106 BODY (BODY_DATA)
107 where:
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.
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:
114 HANDLER (HANDLER_DATA, THROWN_TAG, THROW_ARGS)
115 where
116 HANDLER_DATA is the HANDLER_DATA argument we recevied; it's the
117 same idea as BODY_DATA above.
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.
121 THROW_ARGS is the list of arguments the user passed to the THROW
122 function, after the tag.
123
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. */
139
140 SCM
141 scm_internal_catch (SCM tag, scm_t_catch_body body, void *body_data, scm_t_catch_handler handler, void *handler_data)
142 {
143 struct jmp_buf_and_retval jbr;
144 SCM jmpbuf;
145 SCM answer;
146
147 jmpbuf = make_jmpbuf ();
148 answer = SCM_EOL;
149 scm_i_set_dynwinds (scm_acons (tag, jmpbuf, scm_i_dynwinds ()));
150 SETJBJMPBUF(jmpbuf, &jbr.buf);
151 SCM_SETJBDFRAME(jmpbuf, scm_i_last_debug_frame ());
152 if (setjmp (jbr.buf))
153 {
154 SCM throw_tag;
155 SCM throw_args;
156
157 #ifdef STACK_CHECKING
158 scm_stack_checking_enabled_p = SCM_STACK_CHECKING_P;
159 #endif
160 SCM_CRITICAL_SECTION_START;
161 DEACTIVATEJB (jmpbuf);
162 scm_i_set_dynwinds (SCM_CDR (scm_i_dynwinds ()));
163 SCM_CRITICAL_SECTION_END;
164 throw_args = jbr.retval;
165 throw_tag = jbr.throw_tag;
166 jbr.throw_tag = SCM_EOL;
167 jbr.retval = SCM_EOL;
168 answer = handler (handler_data, throw_tag, throw_args);
169 }
170 else
171 {
172 ACTIVATEJB (jmpbuf);
173 answer = body (body_data);
174 SCM_CRITICAL_SECTION_START;
175 DEACTIVATEJB (jmpbuf);
176 scm_i_set_dynwinds (SCM_CDR (scm_i_dynwinds ()));
177 SCM_CRITICAL_SECTION_END;
178 }
179 return answer;
180 }
181
182
183 \f
184 /* scm_internal_lazy_catch (the guts of lazy catching) */
185
186 /* The smob tag for lazy_catch smobs. */
187 static scm_t_bits tc16_lazy_catch;
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.) */
197 struct lazy_catch {
198 scm_t_catch_handler handler;
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... */
206 static int
207 lazy_catch_print (SCM closure, SCM port, scm_print_state *pstate SCM_UNUSED)
208 {
209 struct lazy_catch *c = (struct lazy_catch *) SCM_CELL_WORD_1 (closure);
210 char buf[200];
211
212 sprintf (buf, "#<lazy-catch 0x%lx 0x%lx>",
213 (long) c->handler, (long) c->handler_data);
214 scm_puts (buf, port);
215
216 return 1;
217 }
218
219
220 /* Given a pointer to a lazy catch structure, return a smob for it,
221 suitable for inclusion in the wind list. ("Ah yes, a Château
222 Gollombiere '72, non?"). */
223 static SCM
224 make_lazy_catch (struct lazy_catch *c)
225 {
226 SCM_RETURN_NEWSMOB (tc16_lazy_catch, c);
227 }
228
229 #define SCM_LAZY_CATCH_P(obj) (SCM_TYP16_PREDICATE (tc16_lazy_catch, obj))
230
231
232 /* Exactly like scm_internal_catch, except:
233 - It does not unwind the stack (this is the major difference).
234 - The handler is not allowed to return. */
235 SCM
236 scm_internal_lazy_catch (SCM tag, scm_t_catch_body body, void *body_data, scm_t_catch_handler handler, void *handler_data)
237 {
238 SCM lazy_catch, answer;
239 struct lazy_catch c;
240
241 c.handler = handler;
242 c.handler_data = handler_data;
243 lazy_catch = make_lazy_catch (&c);
244
245 SCM_CRITICAL_SECTION_START;
246 scm_i_set_dynwinds (scm_acons (tag, lazy_catch, scm_i_dynwinds ()));
247 SCM_CRITICAL_SECTION_END;
248
249 answer = (*body) (body_data);
250
251 SCM_CRITICAL_SECTION_START;
252 scm_i_set_dynwinds (SCM_CDR (scm_i_dynwinds ()));
253 SCM_CRITICAL_SECTION_END;
254
255 return answer;
256 }
257
258 \f
259 /* scm_internal_stack_catch
260 Use this one if you want debugging information to be stored in
261 scm_the_last_stack_fluid_var on error. */
262
263 static SCM
264 ss_handler (void *data SCM_UNUSED, SCM tag, SCM throw_args)
265 {
266 /* Save the stack */
267 scm_fluid_set_x (SCM_VARIABLE_REF (scm_the_last_stack_fluid_var),
268 scm_make_stack (SCM_BOOL_T, SCM_EOL));
269 /* Throw the error */
270 return scm_throw (tag, throw_args);
271 }
272
273 struct cwss_data
274 {
275 SCM tag;
276 scm_t_catch_body body;
277 void *data;
278 };
279
280 static SCM
281 cwss_body (void *data)
282 {
283 struct cwss_data *d = data;
284 return scm_internal_lazy_catch (d->tag, d->body, d->data, ss_handler, NULL);
285 }
286
287 SCM
288 scm_internal_stack_catch (SCM tag,
289 scm_t_catch_body body,
290 void *body_data,
291 scm_t_catch_handler handler,
292 void *handler_data)
293 {
294 struct cwss_data d;
295 d.tag = tag;
296 d.body = body;
297 d.data = body_data;
298 return scm_internal_catch (tag, cwss_body, &d, handler, handler_data);
299 }
300
301
302 \f
303 /* body and handler functions for use with any of the above catch variants */
304
305 /* This is a body function you can pass to scm_internal_catch if you
306 want the body to be like Scheme's `catch' --- a thunk.
307
308 BODY_DATA is a pointer to a scm_body_thunk_data structure, which
309 contains the Scheme procedure to invoke as the body, and the tag
310 we're catching. */
311
312 SCM
313 scm_body_thunk (void *body_data)
314 {
315 struct scm_body_thunk_data *c = (struct scm_body_thunk_data *) body_data;
316
317 return scm_call_0 (c->body_proc);
318 }
319
320
321 /* This is a handler function you can pass to scm_internal_catch if
322 you want the handler to act like Scheme's catch: (throw TAG ARGS ...)
323 applies a handler procedure to (TAG ARGS ...).
324
325 If the user does a throw to this catch, this function runs a
326 handler procedure written in Scheme. HANDLER_DATA is a pointer to
327 an SCM variable holding the Scheme procedure object to invoke. It
328 ought to be a pointer to an automatic variable (i.e., one living on
329 the stack), or the procedure object should be otherwise protected
330 from GC. */
331 SCM
332 scm_handle_by_proc (void *handler_data, SCM tag, SCM throw_args)
333 {
334 SCM *handler_proc_p = (SCM *) handler_data;
335
336 return scm_apply_1 (*handler_proc_p, tag, throw_args);
337 }
338
339 /* SCM_HANDLE_BY_PROC_CATCHING_ALL is like SCM_HANDLE_BY_PROC but
340 catches all throws that the handler might emit itself. The handler
341 used for these `secondary' throws is SCM_HANDLE_BY_MESSAGE_NO_EXIT. */
342
343 struct hbpca_data {
344 SCM proc;
345 SCM args;
346 };
347
348 static SCM
349 hbpca_body (void *body_data)
350 {
351 struct hbpca_data *data = (struct hbpca_data *)body_data;
352 return scm_apply_0 (data->proc, data->args);
353 }
354
355 SCM
356 scm_handle_by_proc_catching_all (void *handler_data, SCM tag, SCM throw_args)
357 {
358 SCM *handler_proc_p = (SCM *) handler_data;
359 struct hbpca_data data;
360 data.proc = *handler_proc_p;
361 data.args = scm_cons (tag, throw_args);
362
363 return scm_internal_catch (SCM_BOOL_T,
364 hbpca_body, &data,
365 scm_handle_by_message_noexit, NULL);
366 }
367
368 /* Derive the an exit status from the arguments to (quit ...). */
369 int
370 scm_exit_status (SCM args)
371 {
372 if (!SCM_NULL_OR_NIL_P (args))
373 {
374 SCM cqa = SCM_CAR (args);
375
376 if (scm_is_integer (cqa))
377 return (scm_to_int (cqa));
378 else if (scm_is_false (cqa))
379 return 1;
380 }
381 return 0;
382 }
383
384
385 static void
386 handler_message (void *handler_data, SCM tag, SCM args)
387 {
388 char *prog_name = (char *) handler_data;
389 SCM p = scm_current_error_port ();
390
391 if (scm_ilength (args) == 4)
392 {
393 SCM stack = scm_make_stack (SCM_BOOL_T, SCM_EOL);
394 SCM subr = SCM_CAR (args);
395 SCM message = SCM_CADR (args);
396 SCM parts = SCM_CADDR (args);
397 SCM rest = SCM_CADDDR (args);
398
399 if (SCM_BACKTRACE_P && scm_is_true (stack))
400 {
401 SCM highlights;
402
403 if (scm_is_eq (tag, scm_arg_type_key)
404 || scm_is_eq (tag, scm_out_of_range_key))
405 highlights = rest;
406 else
407 highlights = SCM_EOL;
408
409 scm_puts ("Backtrace:\n", p);
410 scm_display_backtrace_with_highlights (stack, p,
411 SCM_BOOL_F, SCM_BOOL_F,
412 highlights);
413 scm_newline (p);
414 }
415 scm_i_display_error (stack, p, subr, message, parts, rest);
416 }
417 else
418 {
419 if (! prog_name)
420 prog_name = "guile";
421
422 scm_puts (prog_name, p);
423 scm_puts (": ", p);
424
425 scm_puts ("uncaught throw to ", p);
426 scm_prin1 (tag, p, 0);
427 scm_puts (": ", p);
428 scm_prin1 (args, p, 1);
429 scm_putc ('\n', p);
430 }
431 }
432
433
434 /* This is a handler function to use if you want scheme to print a
435 message and die. Useful for dealing with throws to uncaught keys
436 at the top level.
437
438 At boot time, we establish a catch-all that uses this as its handler.
439 1) If the user wants something different, they can use (catch #t
440 ...) to do what they like.
441 2) Outside the context of a read-eval-print loop, there isn't
442 anything else good to do; libguile should not assume the existence
443 of a read-eval-print loop.
444 3) Given that we shouldn't do anything complex, it's much more
445 robust to do it in C code.
446
447 HANDLER_DATA, if non-zero, is assumed to be a char * pointing to a
448 message header to print; if zero, we use "guile" instead. That
449 text is followed by a colon, then the message described by ARGS. */
450
451 /* Dirk:FIXME:: The name of the function should make clear that the
452 * application gets terminated.
453 */
454
455 SCM
456 scm_handle_by_message (void *handler_data, SCM tag, SCM args)
457 {
458 if (scm_is_true (scm_eq_p (tag, scm_from_locale_symbol ("quit"))))
459 exit (scm_exit_status (args));
460
461 handler_message (handler_data, tag, args);
462 scm_i_pthread_exit (NULL);
463 }
464
465
466 /* This is just like scm_handle_by_message, but it doesn't exit; it
467 just returns #f. It's useful in cases where you don't really know
468 enough about the body to handle things in a better way, but don't
469 want to let throws fall off the bottom of the wind list. */
470 SCM
471 scm_handle_by_message_noexit (void *handler_data, SCM tag, SCM args)
472 {
473 if (scm_is_true (scm_eq_p (tag, scm_from_locale_symbol ("quit"))))
474 exit (scm_exit_status (args));
475
476 handler_message (handler_data, tag, args);
477
478 return SCM_BOOL_F;
479 }
480
481
482 SCM
483 scm_handle_by_throw (void *handler_data SCM_UNUSED, SCM tag, SCM args)
484 {
485 scm_ithrow (tag, args, 1);
486 return SCM_UNSPECIFIED; /* never returns */
487 }
488
489
490 \f
491 /* the Scheme-visible CATCH and LAZY-CATCH functions */
492
493 SCM_DEFINE (scm_catch, "catch", 3, 0, 0,
494 (SCM key, SCM thunk, SCM handler),
495 "Invoke @var{thunk} in the dynamic context of @var{handler} for\n"
496 "exceptions matching @var{key}. If thunk throws to the symbol\n"
497 "@var{key}, then @var{handler} is invoked this way:\n"
498 "@lisp\n"
499 "(handler key args ...)\n"
500 "@end lisp\n"
501 "\n"
502 "@var{key} is a symbol or @code{#t}.\n"
503 "\n"
504 "@var{thunk} takes no arguments. If @var{thunk} returns\n"
505 "normally, that is the return value of @code{catch}.\n"
506 "\n"
507 "Handler is invoked outside the scope of its own @code{catch}.\n"
508 "If @var{handler} again throws to the same key, a new handler\n"
509 "from further up the call chain is invoked.\n"
510 "\n"
511 "If the key is @code{#t}, then a throw to @emph{any} symbol will\n"
512 "match this call to @code{catch}.")
513 #define FUNC_NAME s_scm_catch
514 {
515 struct scm_body_thunk_data c;
516
517 SCM_ASSERT (scm_is_symbol (key) || scm_is_eq (key, SCM_BOOL_T),
518 key, SCM_ARG1, FUNC_NAME);
519
520 c.tag = key;
521 c.body_proc = thunk;
522
523 /* scm_internal_catch takes care of all the mechanics of setting up
524 a catch key; we tell it to call scm_body_thunk to run the body,
525 and scm_handle_by_proc to deal with any throws to this catch.
526 The former receives a pointer to c, telling it how to behave.
527 The latter receives a pointer to HANDLER, so it knows who to call. */
528 return scm_internal_catch (key,
529 scm_body_thunk, &c,
530 scm_handle_by_proc, &handler);
531 }
532 #undef FUNC_NAME
533
534
535 SCM_DEFINE (scm_lazy_catch, "lazy-catch", 3, 0, 0,
536 (SCM key, SCM thunk, SCM handler),
537 "This behaves exactly like @code{catch}, except that it does\n"
538 "not unwind the stack before invoking @var{handler}.\n"
539 "The @var{handler} procedure is not allowed to return:\n"
540 "it must throw to another catch, or otherwise exit non-locally.")
541 #define FUNC_NAME s_scm_lazy_catch
542 {
543 struct scm_body_thunk_data c;
544
545 SCM_ASSERT (scm_is_symbol (key) || scm_is_eq (key, SCM_BOOL_T),
546 key, SCM_ARG1, FUNC_NAME);
547
548 c.tag = key;
549 c.body_proc = thunk;
550
551 /* scm_internal_lazy_catch takes care of all the mechanics of
552 setting up a lazy catch key; we tell it to call scm_body_thunk to
553 run the body, and scm_handle_by_proc to deal with any throws to
554 this catch. The former receives a pointer to c, telling it how
555 to behave. The latter receives a pointer to HANDLER, so it knows
556 who to call. */
557 return scm_internal_lazy_catch (key,
558 scm_body_thunk, &c,
559 scm_handle_by_proc, &handler);
560 }
561 #undef FUNC_NAME
562
563
564 \f
565 /* throwing */
566
567 SCM_DEFINE (scm_throw, "throw", 1, 0, 1,
568 (SCM key, SCM args),
569 "Invoke the catch form matching @var{key}, passing @var{args} to the\n"
570 "@var{handler}. \n\n"
571 "@var{key} is a symbol. It will match catches of the same symbol or of\n"
572 "@code{#t}.\n\n"
573 "If there is no handler at all, Guile prints an error and then exits.")
574 #define FUNC_NAME s_scm_throw
575 {
576 SCM_VALIDATE_SYMBOL (1, key);
577 return scm_ithrow (key, args, 1);
578 }
579 #undef FUNC_NAME
580
581 SCM
582 scm_ithrow (SCM key, SCM args, int noreturn SCM_UNUSED)
583 {
584 SCM jmpbuf = SCM_UNDEFINED;
585 SCM wind_goal;
586
587 SCM dynpair = SCM_UNDEFINED;
588 SCM winds;
589
590 if (scm_i_critical_section_level)
591 {
592 fprintf (stderr, "throw from within critical section.\n");
593 abort ();
594 }
595
596 /* Search the wind list for an appropriate catch.
597 "Waiter, please bring us the wind list." */
598 for (winds = scm_i_dynwinds (); scm_is_pair (winds); winds = SCM_CDR (winds))
599 {
600 dynpair = SCM_CAR (winds);
601 if (scm_is_pair (dynpair))
602 {
603 SCM this_key = SCM_CAR (dynpair);
604
605 if (scm_is_eq (this_key, SCM_BOOL_T) || scm_is_eq (this_key, key))
606 break;
607 }
608 }
609
610 /* If we didn't find anything, print a message and abort the process
611 right here. If you don't want this, establish a catch-all around
612 any code that might throw up. */
613 if (scm_is_null (winds))
614 {
615 scm_handle_by_message (NULL, key, args);
616 abort ();
617 }
618
619 /* If the wind list is malformed, bail. */
620 if (!scm_is_pair (winds))
621 abort ();
622
623 jmpbuf = SCM_CDR (dynpair);
624
625 for (wind_goal = scm_i_dynwinds ();
626 !scm_is_eq (SCM_CDAR (wind_goal), jmpbuf);
627 wind_goal = SCM_CDR (wind_goal))
628 ;
629
630 /* Is a lazy catch? In wind list entries for lazy catches, the key
631 is bound to a lazy_catch smob, not a jmpbuf. */
632 if (SCM_LAZY_CATCH_P (jmpbuf))
633 {
634 struct lazy_catch *c = (struct lazy_catch *) SCM_CELL_WORD_1 (jmpbuf);
635 SCM handle, answer;
636 scm_dowinds (wind_goal, (scm_ilength (scm_i_dynwinds ())
637 - scm_ilength (wind_goal)));
638 SCM_CRITICAL_SECTION_START;
639 handle = scm_i_dynwinds ();
640 scm_i_set_dynwinds (SCM_CDR (handle));
641 SCM_CRITICAL_SECTION_END;
642 answer = (c->handler) (c->handler_data, key, args);
643 scm_misc_error ("throw", "lazy-catch handler did return.", SCM_EOL);
644 }
645
646 /* Otherwise, it's a normal catch. */
647 else if (SCM_JMPBUFP (jmpbuf))
648 {
649 struct jmp_buf_and_retval * jbr;
650 scm_dowinds (wind_goal, (scm_ilength (scm_i_dynwinds ())
651 - scm_ilength (wind_goal)));
652 jbr = (struct jmp_buf_and_retval *)JBJMPBUF (jmpbuf);
653 jbr->throw_tag = key;
654 jbr->retval = args;
655 scm_i_set_last_debug_frame (SCM_JBDFRAME (jmpbuf));
656 longjmp (*JBJMPBUF (jmpbuf), 1);
657 }
658
659 /* Otherwise, it's some random piece of junk. */
660 else
661 abort ();
662 }
663
664
665 void
666 scm_init_throw ()
667 {
668 tc16_jmpbuffer = scm_make_smob_type ("jmpbuffer", 0);
669 scm_set_smob_print (tc16_jmpbuffer, jmpbuffer_print);
670
671 tc16_lazy_catch = scm_make_smob_type ("lazy-catch", 0);
672 scm_set_smob_print (tc16_lazy_catch, lazy_catch_print);
673
674 #include "libguile/throw.x"
675 }
676
677 /*
678 Local Variables:
679 c-file-style: "gnu"
680 End:
681 */