Merge remote-tracking branch 'origin/stable-2.0'
[bpt/guile.git] / libguile / continuations.c
CommitLineData
f9654187 1/* Copyright (C) 1995,1996,1998,2000,2001,2004, 2006, 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
0f2d19dd 2 *
73be1d9e 3 * This library is free software; you can redistribute it and/or
53befeb7
NJ
4 * modify it under the terms of the GNU Lesser General Public License
5 * as published by the Free Software Foundation; either version 3 of
6 * the License, or (at your option) any later version.
0f2d19dd 7 *
53befeb7
NJ
8 * This library is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of
73be1d9e
MV
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
53befeb7
NJ
15 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
16 * 02110-1301 USA
73be1d9e 17 */
1bbd0b84 18
1bbd0b84 19
0f2d19dd 20\f
dbb605f5
LC
21#ifdef HAVE_CONFIG_H
22# include <config.h>
23#endif
0f2d19dd 24
bbd43f03
RB
25#include "libguile/_scm.h"
26
13070bd3 27#include <string.h>
8b7f0bb3 28#include <stdio.h>
13070bd3 29
8b7f0bb3 30#include "libguile/async.h"
d0f6ceb8 31#include "libguile/debug.h"
a0599745
MD
32#include "libguile/root.h"
33#include "libguile/stackchk.h"
5f144b10
GH
34#include "libguile/smob.h"
35#include "libguile/ports.h"
36#include "libguile/dynwind.h"
9de87eea 37#include "libguile/eval.h"
bfffd258 38#include "libguile/vm.h"
1d1cae0e 39#include "libguile/instructions.h"
5f144b10 40
db4b4ca6 41#include "libguile/validate.h"
a0599745 42#include "libguile/continuations.h"
01c8a3dd 43
0f2d19dd
JB
44\f
45
1d1cae0e
AW
46static scm_t_bits tc16_continuation;
47#define SCM_CONTREGSP(x) SCM_TYP16_PREDICATE (tc16_continuation, x)
48
49#define SCM_CONTREGS(x) ((scm_t_contregs *) SCM_SMOB_DATA_1 (x))
50
51#define SCM_CONTINUATION_LENGTH(x) (SCM_CONTREGS (x)->num_stack_items)
52#define SCM_SET_CONTINUATION_LENGTH(x, n)\
53 (SCM_CONTREGS (x)->num_stack_items = (n))
54#define SCM_JMPBUF(x) ((SCM_CONTREGS (x))->jmpbuf)
55#define SCM_DYNENV(x) ((SCM_CONTREGS (x))->dynenv)
1d1cae0e
AW
56#define SCM_CONTINUATION_ROOT(x) ((SCM_CONTREGS (x))->root)
57#define SCM_DFRAME(x) ((SCM_CONTREGS (x))->dframe)
58
59\f
60
997659f8 61/* scm_i_make_continuation will return a procedure whose objcode contains an
1d1cae0e
AW
62 instruction to reinstate the continuation. Here, as in gsubr.c and smob.c, we
63 define the form of that trampoline function.
0f2d19dd
JB
64 */
65
1d1cae0e 66#ifdef WORDS_BIGENDIAN
babfc7b2
AW
67#define OBJCODE_HEADER(main,meta) 0, 0, 0, main, 0, 0, 0, meta+8
68#define META_HEADER(meta) 0, 0, 0, meta, 0, 0, 0, 0
1d1cae0e 69#else
babfc7b2
AW
70#define OBJCODE_HEADER(main,meta) main, 0, 0, 0, meta+8, 0, 0, 0
71#define META_HEADER(meta) meta, 0, 0, 0, 0, 0, 0, 0
1d1cae0e
AW
72#endif
73
1d1cae0e
AW
74#define ALIGN_PTR(type,p,align) (type*)(ROUND_UP (((scm_t_bits)p), align))
75
76#ifdef SCM_ALIGNED
1c05a2a1 77#define SCM_DECLARE_STATIC_ALIGNED_ARRAY(type, sym) \
1d1cae0e 78static const type sym[]
1c05a2a1 79#define SCM_STATIC_ALIGNED_ARRAY(alignment, type, sym) \
1d1cae0e
AW
80static SCM_ALIGNED (alignment) const type sym[]
81#else
1c05a2a1 82#define SCM_DECLARE_STATIC_ALIGNED_ARRAY(type, sym) \
1d1cae0e
AW
83static type *sym
84#define SCM_STATIC_ALIGNED_ARRAY(alignment, type, sym) \
1c05a2a1 85SCM_SNARF_INIT(sym = scm_malloc_pointerless (sizeof(sym##__unaligned)); \
1d1cae0e
AW
86 memcpy (sym, sym##__unaligned, sizeof(sym##__unaligned));) \
87static type *sym = NULL; \
88static const type sym##__unaligned[]
89#endif
90
91#define STATIC_OBJCODE_TAG \
f9654187 92 SCM_PACK (SCM_MAKE_OBJCODE_TAG (SCM_OBJCODE_TYPE_STATIC, 0))
1d1cae0e
AW
93
94#define SCM_STATIC_OBJCODE(sym) \
95 SCM_DECLARE_STATIC_ALIGNED_ARRAY (scm_t_uint8, sym##__bytecode); \
96 SCM_STATIC_ALIGNED_ARRAY (8, scm_t_cell, sym##__cells) = { \
97 { STATIC_OBJCODE_TAG, SCM_PACK (sym##__bytecode) }, \
98 { SCM_BOOL_F, SCM_PACK (0) } \
99 }; \
100 static const SCM sym = SCM_PACK (sym##__cells); \
101 SCM_STATIC_ALIGNED_ARRAY (8, scm_t_uint8, sym##__bytecode)
102
103
104SCM_STATIC_OBJCODE (cont_objcode) = {
2ac16429
AW
105 /* This code is the same as in gsubr.c, except we use continuation_call
106 instead of subr_call. */
babfc7b2 107 OBJCODE_HEADER (8, 19),
1d1cae0e
AW
108 /* leave args on the stack */
109 /* 0 */ scm_op_object_ref, 0, /* push scm_t_contregs smob */
110 /* 2 */ scm_op_continuation_call, /* and longjmp (whee) */
111 /* 3 */ scm_op_nop, /* pad to 8 bytes */
112 /* 4 */ scm_op_nop, scm_op_nop, scm_op_nop, scm_op_nop,
113 /* 8 */
114
115 /* We could put some meta-info to say that this proc is a continuation. Not sure
116 how to do that, though. */
babfc7b2 117 META_HEADER (19),
1d1cae0e
AW
118 /* 0 */ scm_op_make_eol, /* bindings */
119 /* 1 */ scm_op_make_eol, /* sources */
120 /* 2 */ scm_op_make_int8, 0, scm_op_make_int8, 3, /* arity: from ip 0 to ip 3 */
121 /* 6 */ scm_op_make_int8_0, /* the arity is 0 required args */
122 /* 7 */ scm_op_make_int8_0, /* 0 optionals */
123 /* 8 */ scm_op_make_true, /* and a rest arg */
124 /* 9 */ scm_op_list, 0, 5, /* make a list of those 5 vals */
125 /* 12 */ scm_op_list, 0, 1, /* and the arities will be a list of that one list */
126 /* 15 */ scm_op_list, 0, 3, /* pack bindings, sources, and arities into list */
127 /* 18 */ scm_op_return /* and return */
128 /* 19 */
129};
130
131
babfc7b2
AW
132SCM_STATIC_OBJCODE (call_cc_objcode) = {
133 /* Before Scheme's call/cc is compiled, eval.c will use this hand-coded
134 call/cc. */
135 OBJCODE_HEADER (8, 17),
136 /* 0 */ scm_op_assert_nargs_ee, 0, 1, /* assert that nargs==1 */
137 /* 3 */ scm_op_local_ref, 0, /* push the proc */
138 /* 5 */ scm_op_tail_call_cc, /* and call/cc */
139 /* 6 */ scm_op_nop, scm_op_nop, /* pad to 8 bytes */
140 /* 8 */
141
142 META_HEADER (17),
143 /* 0 */ scm_op_make_eol, /* bindings */
144 /* 1 */ scm_op_make_eol, /* sources */
145 /* 2 */ scm_op_make_int8, 3, scm_op_make_int8, 6, /* arity: from ip 0 to ip 6 */
146 /* 6 */ scm_op_make_int8_1, /* the arity is 0 required args */
147 /* 7 */ scm_op_list, 0, 3, /* make a list of those 5 vals */
148 /* 10 */ scm_op_list, 0, 1, /* and the arities will be a list of that one list */
149 /* 13 */ scm_op_list, 0, 3, /* pack bindings, sources, and arities into list */
150 /* 16 */ scm_op_return /* and return */
151 /* 17 */
152};
153
154
1d1cae0e
AW
155static SCM
156make_continuation_trampoline (SCM contregs)
157{
158 SCM ret = scm_make_program (cont_objcode,
159 scm_c_make_vector (1, contregs),
160 SCM_BOOL_F);
161 SCM_SET_CELL_WORD_0 (ret,
162 SCM_CELL_WORD_0 (ret) | SCM_F_PROGRAM_IS_CONTINUATION);
163
164 return ret;
165}
166
167
168/* {Continuations}
169 */
0f2d19dd 170
01c8a3dd 171
e841c3e0 172static int
e81d98ec 173continuation_print (SCM obj, SCM port, scm_print_state *state SCM_UNUSED)
5f144b10 174{
92c2555f 175 scm_t_contregs *continuation = SCM_CONTREGS (obj);
5f144b10 176
0607ebbf 177 scm_puts_unlocked ("#<continuation ", port);
5f144b10 178 scm_intprint (continuation->num_stack_items, 10, port);
0607ebbf 179 scm_puts_unlocked (" @ ", port);
0236bc68 180 scm_uintprint (SCM_SMOB_DATA_1 (obj), 16, port);
0607ebbf 181 scm_putc_unlocked ('>', port);
5f144b10
GH
182 return 1;
183}
1cc91f1b 184
2acdd822
AW
185/* James Clark came up with this neat one instruction fix for
186 * continuations on the SPARC. It flushes the register windows so
187 * that all the state of the process is contained in the stack.
188 */
189
190#if defined (sparc) || defined (__sparc__) || defined (__sparc)
191# define SCM_FLUSH_REGISTER_WINDOWS asm("ta 3")
192#else
193# define SCM_FLUSH_REGISTER_WINDOWS /* empty */
194#endif
195
5f144b10 196/* this may return more than once: the first time with the escape
d8873dfe
AW
197 procedure, then subsequently with SCM_UNDEFINED (the vals already having been
198 placed on the VM stack). */
997659f8 199#define FUNC_NAME "scm_i_make_continuation"
0f2d19dd 200SCM
269479e3 201scm_i_make_continuation (int *first, SCM vm, SCM vm_cont)
0f2d19dd 202{
9de87eea
MV
203 scm_i_thread *thread = SCM_I_CURRENT_THREAD;
204 SCM cont;
92c2555f 205 scm_t_contregs *continuation;
c014a02e 206 long stack_size;
01c8a3dd 207 SCM_STACKITEM * src;
0f2d19dd 208
0f2d19dd 209 SCM_FLUSH_REGISTER_WINDOWS;
9de87eea 210 stack_size = scm_stack_size (thread->continuation_base);
4c9419ac
MV
211 continuation = scm_gc_malloc (sizeof (scm_t_contregs)
212 + (stack_size - 1) * sizeof (SCM_STACKITEM),
213 "continuation");
5f144b10 214 continuation->num_stack_items = stack_size;
9de87eea 215 continuation->dynenv = scm_i_dynwinds ();
9de87eea 216 continuation->root = thread->continuation_root;
9de87eea 217 src = thread->continuation_base;
4ccb2cd2 218#if ! SCM_STACK_GROWS_UP
5f144b10
GH
219 src -= stack_size;
220#endif
5c5c27dc 221 continuation->offset = continuation->stack - src;
5f144b10 222 memcpy (continuation->stack, src, sizeof (SCM_STACKITEM) * stack_size);
269479e3
AW
223 continuation->vm = vm;
224 continuation->vm_cont = vm_cont;
5f144b10 225
1d1cae0e 226 SCM_NEWSMOB (cont, tc16_continuation, continuation);
79824460 227
a4dbe1ac 228 *first = !SCM_I_SETJMP (continuation->jmpbuf);
346e4402 229 if (*first)
193297d8 230 {
346e4402 231#ifdef __ia64__
9a5fa6e9 232 continuation->backing_store_size =
346e4402 233 (char *) scm_ia64_ar_bsp(&continuation->jmpbuf.ctx)
9a5fa6e9 234 -
346e4402 235 (char *) thread->register_backing_store_base;
193297d8
RB
236 continuation->backing_store = NULL;
237 continuation->backing_store =
4c9419ac
MV
238 scm_gc_malloc (continuation->backing_store_size,
239 "continuation backing store");
193297d8 240 memcpy (continuation->backing_store,
346e4402 241 (void *) thread->register_backing_store_base,
193297d8 242 continuation->backing_store_size);
346e4402 243#endif /* __ia64__ */
1d1cae0e 244 return make_continuation_trampoline (cont);
193297d8
RB
245 }
246 else
d8873dfe 247 return SCM_UNDEFINED;
0f2d19dd 248}
5f144b10 249#undef FUNC_NAME
0f2d19dd 250
babfc7b2
AW
251SCM
252scm_i_call_with_current_continuation (SCM proc)
253{
254 static SCM call_cc = SCM_BOOL_F;
255
256 if (scm_is_false (call_cc))
257 call_cc = scm_make_program (call_cc_objcode, SCM_BOOL_F, SCM_BOOL_F);
258
259 return scm_call_1 (call_cc, proc);
260}
261
1d1cae0e
AW
262SCM
263scm_i_continuation_to_frame (SCM continuation)
264{
265 SCM contregs;
266 scm_t_contregs *cont;
267
268 contregs = scm_c_vector_ref (scm_program_objects (continuation), 0);
269 cont = SCM_CONTREGS (contregs);
270
269479e3 271 if (scm_is_true (cont->vm_cont))
1d1cae0e 272 {
269479e3
AW
273 struct scm_vm_cont *data = SCM_VM_CONT_DATA (cont->vm_cont);
274 return scm_c_make_frame (cont->vm_cont,
1d1cae0e
AW
275 data->fp + data->reloc,
276 data->sp + data->reloc,
d8873dfe 277 data->ra,
1d1cae0e
AW
278 data->reloc);
279 }
280 else
281 return SCM_BOOL_F;
282}
283
d8873dfe
AW
284SCM
285scm_i_contregs_vm (SCM contregs)
286{
287 return SCM_CONTREGS (contregs)->vm;
288}
289
290SCM
291scm_i_contregs_vm_cont (SCM contregs)
292{
293 return SCM_CONTREGS (contregs)->vm_cont;
294}
295
1d1cae0e
AW
296
297/* {Apply}
298 */
d3c6aef9
MV
299
300/* Invoking a continuation proceeds as follows:
301 *
302 * - the stack is made large enough for the called continuation
303 * - the old windchain is unwound down to the branching point
304 * - the continuation stack is copied into place
305 * - the windchain is rewound up to the continuation's context
306 * - the continuation is invoked via longjmp (or setcontext)
307 *
308 * This order is important so that unwind and rewind handlers are run
309 * with their correct stack.
310 */
311
d8873dfe 312static void scm_dynthrow (SCM);
01c8a3dd
DH
313
314/* Grow the stack by a fixed amount to provide space to copy in the
315 * continuation. Possibly this function has to be called several times
316 * recursively before enough space is available. Make sure the compiler does
317 * not optimize the growth array away by storing it's address into a global
318 * variable.
319 */
320
8c93b597 321static scm_t_bits scm_i_dummy;
1cc91f1b 322
0f2d19dd 323static void
d8873dfe 324grow_stack (SCM cont)
01c8a3dd 325{
92c2555f 326 scm_t_bits growth[100];
01c8a3dd 327
92c2555f 328 scm_i_dummy = (scm_t_bits) growth;
d8873dfe 329 scm_dynthrow (cont);
0f2d19dd 330}
0f2d19dd 331
1cc91f1b 332
01c8a3dd
DH
333/* Copy the continuation stack into the current stack. Calling functions from
334 * within this function is safe, since only stack frames below this function's
335 * own frame are overwritten. Thus, memcpy can be used for best performance.
336 */
d3c6aef9
MV
337
338typedef struct {
339 scm_t_contregs *continuation;
340 SCM_STACKITEM *dst;
341} copy_stack_data;
342
01c8a3dd 343static void
d3c6aef9
MV
344copy_stack (void *data)
345{
346 copy_stack_data *d = (copy_stack_data *)data;
347 memcpy (d->dst, d->continuation->stack,
348 sizeof (SCM_STACKITEM) * d->continuation->num_stack_items);
346e4402
NJ
349#ifdef __ia64__
350 SCM_I_CURRENT_THREAD->pending_rbs_continuation = d->continuation;
351#endif
d3c6aef9
MV
352}
353
354static void
d8873dfe 355copy_stack_and_call (scm_t_contregs *continuation,
5f144b10 356 SCM_STACKITEM * dst)
0f2d19dd 357{
d3c6aef9
MV
358 long delta;
359 copy_stack_data data;
360
9de87eea 361 delta = scm_ilength (scm_i_dynwinds ()) - scm_ilength (continuation->dynenv);
d3c6aef9
MV
362 data.continuation = continuation;
363 data.dst = dst;
14578fa4 364 scm_i_dowinds (continuation->dynenv, delta, copy_stack, &data);
01c8a3dd 365
a4dbe1ac 366 SCM_I_LONGJMP (continuation->jmpbuf, 1);
01c8a3dd
DH
367}
368
346e4402
NJ
369#ifdef __ia64__
370void
a4dbe1ac 371scm_ia64_longjmp (scm_i_jmp_buf *JB, int VAL)
346e4402
NJ
372{
373 scm_i_thread *t = SCM_I_CURRENT_THREAD;
374
375 if (t->pending_rbs_continuation)
376 {
377 memcpy (t->register_backing_store_base,
378 t->pending_rbs_continuation->backing_store,
379 t->pending_rbs_continuation->backing_store_size);
380 t->pending_rbs_continuation = NULL;
381 }
382 setcontext (&JB->ctx);
383}
384#endif
385
01c8a3dd
DH
386/* Call grow_stack until the stack space is large enough, then, as the current
387 * stack frame might get overwritten, let copy_stack_and_call perform the
388 * actual copying and continuation calling.
389 */
390static void
d8873dfe 391scm_dynthrow (SCM cont)
01c8a3dd 392{
9de87eea 393 scm_i_thread *thread = SCM_I_CURRENT_THREAD;
92c2555f 394 scm_t_contregs *continuation = SCM_CONTREGS (cont);
9de87eea 395 SCM_STACKITEM *dst = thread->continuation_base;
01c8a3dd
DH
396 SCM_STACKITEM stack_top_element;
397
87f30eda 398 if (thread->critical_section_level)
8b7f0bb3
MV
399 {
400 fprintf (stderr, "continuation invoked from within critical section.\n");
401 abort ();
402 }
403
4ccb2cd2 404#if SCM_STACK_GROWS_UP
5afcf08b 405 if (dst + continuation->num_stack_items >= &stack_top_element)
d8873dfe 406 grow_stack (cont);
0f2d19dd 407#else
5f144b10 408 dst -= continuation->num_stack_items;
c8a1bdc4 409 if (dst <= &stack_top_element)
d8873dfe 410 grow_stack (cont);
0f2d19dd 411#endif /* def SCM_STACK_GROWS_UP */
01c8a3dd 412
5f144b10 413 SCM_FLUSH_REGISTER_WINDOWS;
d8873dfe 414 copy_stack_and_call (continuation, dst);
0f2d19dd
JB
415}
416
db4b4ca6 417
1d1cae0e 418void
d8873dfe 419scm_i_check_continuation (SCM cont)
0f2d19dd 420{
9de87eea 421 scm_i_thread *thread = SCM_I_CURRENT_THREAD;
92c2555f 422 scm_t_contregs *continuation = SCM_CONTREGS (cont);
5f144b10 423
d223c3fc 424 if (!scm_is_eq (continuation->root, thread->continuation_root))
1d1cae0e
AW
425 scm_misc_error
426 ("%continuation-call",
427 "invoking continuation would cross continuation barrier: ~A",
428 scm_list_1 (cont));
d8873dfe
AW
429}
430
431void
432scm_i_reinstate_continuation (SCM cont)
433{
434 scm_dynthrow (cont);
0f2d19dd 435}
0f2d19dd 436
9de87eea
MV
437SCM
438scm_i_with_continuation_barrier (scm_t_catch_body body,
439 void *body_data,
440 scm_t_catch_handler handler,
43e01b1e
NJ
441 void *handler_data,
442 scm_t_catch_handler pre_unwind_handler,
443 void *pre_unwind_handler_data)
9de87eea
MV
444{
445 SCM_STACKITEM stack_item;
446 scm_i_thread *thread = SCM_I_CURRENT_THREAD;
447 SCM old_controot;
448 SCM_STACKITEM *old_contbase;
9de87eea
MV
449 SCM result;
450
451 /* Establish a fresh continuation root.
452 */
453 old_controot = thread->continuation_root;
454 old_contbase = thread->continuation_base;
9de87eea
MV
455 thread->continuation_root = scm_cons (thread->handle, old_controot);
456 thread->continuation_base = &stack_item;
9de87eea
MV
457
458 /* Call FUNC inside a catch all. This is now guaranteed to return
459 directly and exactly once.
460 */
43e01b1e
NJ
461 result = scm_c_catch (SCM_BOOL_T,
462 body, body_data,
463 handler, handler_data,
464 pre_unwind_handler, pre_unwind_handler_data);
9de87eea
MV
465
466 /* Return to old continuation root.
467 */
9de87eea
MV
468 thread->continuation_base = old_contbase;
469 thread->continuation_root = old_controot;
470
471 return result;
472}
473
e309f3bf
AW
474\f
475
476static int
477should_print_backtrace (SCM tag, SCM stack)
478{
479 return SCM_BACKTRACE_P
480 && scm_is_true (stack)
481 && scm_initialized_p
482 /* It's generally not useful to print backtraces for errors reading
483 or expanding code in these fallback catch statements. */
484 && !scm_is_eq (tag, scm_from_latin1_symbol ("read-error"))
485 && !scm_is_eq (tag, scm_from_latin1_symbol ("syntax-error"));
486}
487
488static void
489print_exception_and_backtrace (SCM port, SCM tag, SCM args)
490{
491 SCM stack, frame;
492
493 /* We get here via a throw to a catch-all. In that case there is the
494 throw frame active, and this catch closure, so narrow by two
495 frames. */
496 stack = scm_make_stack (SCM_BOOL_T, scm_list_1 (scm_from_int (2)));
497 frame = scm_is_true (stack) ? scm_stack_ref (stack, SCM_INUM0) : SCM_BOOL_F;
498
499 if (should_print_backtrace (tag, stack))
500 {
0607ebbf 501 scm_puts_unlocked ("Backtrace:\n", port);
e309f3bf
AW
502 scm_display_backtrace_with_highlights (stack, port,
503 SCM_BOOL_F, SCM_BOOL_F,
504 SCM_EOL);
505 scm_newline (port);
506 }
507
508 scm_print_exception (port, frame, tag, args);
509}
510
511\f
512
9de87eea
MV
513struct c_data {
514 void *(*func) (void *);
515 void *data;
516 void *result;
517};
518
519static SCM
520c_body (void *d)
521{
522 struct c_data *data = (struct c_data *)d;
523 data->result = data->func (data->data);
524 return SCM_UNSPECIFIED;
525}
526
527static SCM
528c_handler (void *d, SCM tag, SCM args)
529{
e309f3bf
AW
530 struct c_data *data;
531
532 /* If TAG is `quit', exit() the process. */
533 if (scm_is_eq (tag, scm_from_latin1_symbol ("quit")))
534 exit (scm_exit_status (args));
535
536 data = (struct c_data *)d;
9de87eea
MV
537 data->result = NULL;
538 return SCM_UNSPECIFIED;
539}
540
e309f3bf
AW
541static SCM
542pre_unwind_handler (void *error_port, SCM tag, SCM args)
543{
544 /* Print the exception unless TAG is `quit'. */
545 if (!scm_is_eq (tag, scm_from_latin1_symbol ("quit")))
21041372 546 print_exception_and_backtrace (SCM_PACK_POINTER (error_port), tag, args);
e309f3bf
AW
547
548 return SCM_UNSPECIFIED;
549}
550
9de87eea
MV
551void *
552scm_c_with_continuation_barrier (void *(*func) (void *), void *data)
553{
554 struct c_data c_data;
555 c_data.func = func;
556 c_data.data = data;
557 scm_i_with_continuation_barrier (c_body, &c_data,
43e01b1e 558 c_handler, &c_data,
e309f3bf 559 pre_unwind_handler,
21041372 560 SCM_UNPACK_POINTER (scm_current_error_port ()));
9de87eea
MV
561 return c_data.result;
562}
563
564struct scm_data {
565 SCM proc;
566};
567
568static SCM
569scm_body (void *d)
570{
571 struct scm_data *data = (struct scm_data *)d;
572 return scm_call_0 (data->proc);
573}
574
575static SCM
576scm_handler (void *d, SCM tag, SCM args)
577{
e309f3bf
AW
578 /* Print a message. Note that if TAG is `quit', this will exit() the
579 process. */
580 scm_handle_by_message_noexit (NULL, tag, args);
581
9de87eea
MV
582 return SCM_BOOL_F;
583}
584
585SCM_DEFINE (scm_with_continuation_barrier, "with-continuation-barrier", 1,0,0,
586 (SCM proc),
69d2000d
MV
587"Call @var{proc} and return its result. Do not allow the invocation of\n"
588"continuations that would leave or enter the dynamic extent of the call\n"
589"to @code{with-continuation-barrier}. Such an attempt causes an error\n"
590"to be signaled.\n"
591"\n"
592"Throws (such as errors) that are not caught from within @var{proc} are\n"
593"caught by @code{with-continuation-barrier}. In that case, a short\n"
594"message is printed to the current error port and @code{#f} is returned.\n"
595"\n"
596"Thus, @code{with-continuation-barrier} returns exactly once.\n")
9de87eea
MV
597#define FUNC_NAME s_scm_with_continuation_barrier
598{
599 struct scm_data scm_data;
600 scm_data.proc = proc;
601 return scm_i_with_continuation_barrier (scm_body, &scm_data,
43e01b1e 602 scm_handler, &scm_data,
e309f3bf 603 pre_unwind_handler,
21041372 604 SCM_UNPACK_POINTER (scm_current_error_port ()));
9de87eea
MV
605}
606#undef FUNC_NAME
db4b4ca6 607
0f2d19dd
JB
608void
609scm_init_continuations ()
0f2d19dd 610{
1d1cae0e
AW
611 tc16_continuation = scm_make_smob_type ("continuation", 0);
612 scm_set_smob_print (tc16_continuation, continuation_print);
a0599745 613#include "libguile/continuations.x"
0f2d19dd
JB
614}
615
89e00824
ML
616/*
617 Local Variables:
618 c-file-style: "gnu"
619 End:
620*/