deprecate scm_internal_dynamic_wind
[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
GH
176
177 scm_puts ("#<continuation ", port);
178 scm_intprint (continuation->num_stack_items, 10, port);
179 scm_puts (" @ ", port);
0236bc68 180 scm_uintprint (SCM_SMOB_DATA_1 (obj), 16, port);
5f144b10
GH
181 scm_putc ('>', port);
182 return 1;
183}
1cc91f1b 184
5f144b10 185/* this may return more than once: the first time with the escape
d8873dfe
AW
186 procedure, then subsequently with SCM_UNDEFINED (the vals already having been
187 placed on the VM stack). */
997659f8 188#define FUNC_NAME "scm_i_make_continuation"
0f2d19dd 189SCM
269479e3 190scm_i_make_continuation (int *first, SCM vm, SCM vm_cont)
0f2d19dd 191{
9de87eea
MV
192 scm_i_thread *thread = SCM_I_CURRENT_THREAD;
193 SCM cont;
92c2555f 194 scm_t_contregs *continuation;
c014a02e 195 long stack_size;
01c8a3dd 196 SCM_STACKITEM * src;
0f2d19dd 197
0f2d19dd 198 SCM_FLUSH_REGISTER_WINDOWS;
9de87eea 199 stack_size = scm_stack_size (thread->continuation_base);
4c9419ac
MV
200 continuation = scm_gc_malloc (sizeof (scm_t_contregs)
201 + (stack_size - 1) * sizeof (SCM_STACKITEM),
202 "continuation");
5f144b10 203 continuation->num_stack_items = stack_size;
9de87eea 204 continuation->dynenv = scm_i_dynwinds ();
9de87eea 205 continuation->root = thread->continuation_root;
9de87eea 206 src = thread->continuation_base;
4ccb2cd2 207#if ! SCM_STACK_GROWS_UP
5f144b10
GH
208 src -= stack_size;
209#endif
5c5c27dc 210 continuation->offset = continuation->stack - src;
5f144b10 211 memcpy (continuation->stack, src, sizeof (SCM_STACKITEM) * stack_size);
269479e3
AW
212 continuation->vm = vm;
213 continuation->vm_cont = vm_cont;
5f144b10 214
1d1cae0e 215 SCM_NEWSMOB (cont, tc16_continuation, continuation);
79824460 216
a4dbe1ac 217 *first = !SCM_I_SETJMP (continuation->jmpbuf);
346e4402 218 if (*first)
193297d8 219 {
346e4402 220#ifdef __ia64__
9a5fa6e9 221 continuation->backing_store_size =
346e4402 222 (char *) scm_ia64_ar_bsp(&continuation->jmpbuf.ctx)
9a5fa6e9 223 -
346e4402 224 (char *) thread->register_backing_store_base;
193297d8
RB
225 continuation->backing_store = NULL;
226 continuation->backing_store =
4c9419ac
MV
227 scm_gc_malloc (continuation->backing_store_size,
228 "continuation backing store");
193297d8 229 memcpy (continuation->backing_store,
346e4402 230 (void *) thread->register_backing_store_base,
193297d8 231 continuation->backing_store_size);
346e4402 232#endif /* __ia64__ */
1d1cae0e 233 return make_continuation_trampoline (cont);
193297d8
RB
234 }
235 else
d8873dfe 236 return SCM_UNDEFINED;
0f2d19dd 237}
5f144b10 238#undef FUNC_NAME
0f2d19dd 239
babfc7b2
AW
240SCM
241scm_i_call_with_current_continuation (SCM proc)
242{
243 static SCM call_cc = SCM_BOOL_F;
244
245 if (scm_is_false (call_cc))
246 call_cc = scm_make_program (call_cc_objcode, SCM_BOOL_F, SCM_BOOL_F);
247
248 return scm_call_1 (call_cc, proc);
249}
250
1d1cae0e
AW
251SCM
252scm_i_continuation_to_frame (SCM continuation)
253{
254 SCM contregs;
255 scm_t_contregs *cont;
256
257 contregs = scm_c_vector_ref (scm_program_objects (continuation), 0);
258 cont = SCM_CONTREGS (contregs);
259
269479e3 260 if (scm_is_true (cont->vm_cont))
1d1cae0e 261 {
269479e3
AW
262 struct scm_vm_cont *data = SCM_VM_CONT_DATA (cont->vm_cont);
263 return scm_c_make_frame (cont->vm_cont,
1d1cae0e
AW
264 data->fp + data->reloc,
265 data->sp + data->reloc,
d8873dfe 266 data->ra,
1d1cae0e
AW
267 data->reloc);
268 }
269 else
270 return SCM_BOOL_F;
271}
272
d8873dfe
AW
273SCM
274scm_i_contregs_vm (SCM contregs)
275{
276 return SCM_CONTREGS (contregs)->vm;
277}
278
279SCM
280scm_i_contregs_vm_cont (SCM contregs)
281{
282 return SCM_CONTREGS (contregs)->vm_cont;
283}
284
1d1cae0e
AW
285
286/* {Apply}
287 */
d3c6aef9
MV
288
289/* Invoking a continuation proceeds as follows:
290 *
291 * - the stack is made large enough for the called continuation
292 * - the old windchain is unwound down to the branching point
293 * - the continuation stack is copied into place
294 * - the windchain is rewound up to the continuation's context
295 * - the continuation is invoked via longjmp (or setcontext)
296 *
297 * This order is important so that unwind and rewind handlers are run
298 * with their correct stack.
299 */
300
d8873dfe 301static void scm_dynthrow (SCM);
01c8a3dd
DH
302
303/* Grow the stack by a fixed amount to provide space to copy in the
304 * continuation. Possibly this function has to be called several times
305 * recursively before enough space is available. Make sure the compiler does
306 * not optimize the growth array away by storing it's address into a global
307 * variable.
308 */
309
8c93b597 310static scm_t_bits scm_i_dummy;
1cc91f1b 311
0f2d19dd 312static void
d8873dfe 313grow_stack (SCM cont)
01c8a3dd 314{
92c2555f 315 scm_t_bits growth[100];
01c8a3dd 316
92c2555f 317 scm_i_dummy = (scm_t_bits) growth;
d8873dfe 318 scm_dynthrow (cont);
0f2d19dd 319}
0f2d19dd 320
1cc91f1b 321
01c8a3dd
DH
322/* Copy the continuation stack into the current stack. Calling functions from
323 * within this function is safe, since only stack frames below this function's
324 * own frame are overwritten. Thus, memcpy can be used for best performance.
325 */
d3c6aef9
MV
326
327typedef struct {
328 scm_t_contregs *continuation;
329 SCM_STACKITEM *dst;
330} copy_stack_data;
331
01c8a3dd 332static void
d3c6aef9
MV
333copy_stack (void *data)
334{
335 copy_stack_data *d = (copy_stack_data *)data;
336 memcpy (d->dst, d->continuation->stack,
337 sizeof (SCM_STACKITEM) * d->continuation->num_stack_items);
346e4402
NJ
338#ifdef __ia64__
339 SCM_I_CURRENT_THREAD->pending_rbs_continuation = d->continuation;
340#endif
d3c6aef9
MV
341}
342
343static void
d8873dfe 344copy_stack_and_call (scm_t_contregs *continuation,
5f144b10 345 SCM_STACKITEM * dst)
0f2d19dd 346{
d3c6aef9
MV
347 long delta;
348 copy_stack_data data;
349
9de87eea 350 delta = scm_ilength (scm_i_dynwinds ()) - scm_ilength (continuation->dynenv);
d3c6aef9
MV
351 data.continuation = continuation;
352 data.dst = dst;
14578fa4 353 scm_i_dowinds (continuation->dynenv, delta, copy_stack, &data);
01c8a3dd 354
a4dbe1ac 355 SCM_I_LONGJMP (continuation->jmpbuf, 1);
01c8a3dd
DH
356}
357
346e4402
NJ
358#ifdef __ia64__
359void
a4dbe1ac 360scm_ia64_longjmp (scm_i_jmp_buf *JB, int VAL)
346e4402
NJ
361{
362 scm_i_thread *t = SCM_I_CURRENT_THREAD;
363
364 if (t->pending_rbs_continuation)
365 {
366 memcpy (t->register_backing_store_base,
367 t->pending_rbs_continuation->backing_store,
368 t->pending_rbs_continuation->backing_store_size);
369 t->pending_rbs_continuation = NULL;
370 }
371 setcontext (&JB->ctx);
372}
373#endif
374
01c8a3dd
DH
375/* Call grow_stack until the stack space is large enough, then, as the current
376 * stack frame might get overwritten, let copy_stack_and_call perform the
377 * actual copying and continuation calling.
378 */
379static void
d8873dfe 380scm_dynthrow (SCM cont)
01c8a3dd 381{
9de87eea 382 scm_i_thread *thread = SCM_I_CURRENT_THREAD;
92c2555f 383 scm_t_contregs *continuation = SCM_CONTREGS (cont);
9de87eea 384 SCM_STACKITEM *dst = thread->continuation_base;
01c8a3dd
DH
385 SCM_STACKITEM stack_top_element;
386
87f30eda 387 if (thread->critical_section_level)
8b7f0bb3
MV
388 {
389 fprintf (stderr, "continuation invoked from within critical section.\n");
390 abort ();
391 }
392
4ccb2cd2 393#if SCM_STACK_GROWS_UP
5afcf08b 394 if (dst + continuation->num_stack_items >= &stack_top_element)
d8873dfe 395 grow_stack (cont);
0f2d19dd 396#else
5f144b10 397 dst -= continuation->num_stack_items;
c8a1bdc4 398 if (dst <= &stack_top_element)
d8873dfe 399 grow_stack (cont);
0f2d19dd 400#endif /* def SCM_STACK_GROWS_UP */
01c8a3dd 401
5f144b10 402 SCM_FLUSH_REGISTER_WINDOWS;
d8873dfe 403 copy_stack_and_call (continuation, dst);
0f2d19dd
JB
404}
405
db4b4ca6 406
1d1cae0e 407void
d8873dfe 408scm_i_check_continuation (SCM cont)
0f2d19dd 409{
9de87eea 410 scm_i_thread *thread = SCM_I_CURRENT_THREAD;
92c2555f 411 scm_t_contregs *continuation = SCM_CONTREGS (cont);
5f144b10 412
9de87eea 413 if (continuation->root != thread->continuation_root)
1d1cae0e
AW
414 scm_misc_error
415 ("%continuation-call",
416 "invoking continuation would cross continuation barrier: ~A",
417 scm_list_1 (cont));
d8873dfe
AW
418}
419
420void
421scm_i_reinstate_continuation (SCM cont)
422{
423 scm_dynthrow (cont);
0f2d19dd 424}
0f2d19dd 425
9de87eea
MV
426SCM
427scm_i_with_continuation_barrier (scm_t_catch_body body,
428 void *body_data,
429 scm_t_catch_handler handler,
43e01b1e
NJ
430 void *handler_data,
431 scm_t_catch_handler pre_unwind_handler,
432 void *pre_unwind_handler_data)
9de87eea
MV
433{
434 SCM_STACKITEM stack_item;
435 scm_i_thread *thread = SCM_I_CURRENT_THREAD;
436 SCM old_controot;
437 SCM_STACKITEM *old_contbase;
9de87eea
MV
438 SCM result;
439
440 /* Establish a fresh continuation root.
441 */
442 old_controot = thread->continuation_root;
443 old_contbase = thread->continuation_base;
9de87eea
MV
444 thread->continuation_root = scm_cons (thread->handle, old_controot);
445 thread->continuation_base = &stack_item;
9de87eea
MV
446
447 /* Call FUNC inside a catch all. This is now guaranteed to return
448 directly and exactly once.
449 */
43e01b1e
NJ
450 result = scm_c_catch (SCM_BOOL_T,
451 body, body_data,
452 handler, handler_data,
453 pre_unwind_handler, pre_unwind_handler_data);
9de87eea
MV
454
455 /* Return to old continuation root.
456 */
9de87eea
MV
457 thread->continuation_base = old_contbase;
458 thread->continuation_root = old_controot;
459
460 return result;
461}
462
e309f3bf
AW
463\f
464
465static int
466should_print_backtrace (SCM tag, SCM stack)
467{
468 return SCM_BACKTRACE_P
469 && scm_is_true (stack)
470 && scm_initialized_p
471 /* It's generally not useful to print backtraces for errors reading
472 or expanding code in these fallback catch statements. */
473 && !scm_is_eq (tag, scm_from_latin1_symbol ("read-error"))
474 && !scm_is_eq (tag, scm_from_latin1_symbol ("syntax-error"));
475}
476
477static void
478print_exception_and_backtrace (SCM port, SCM tag, SCM args)
479{
480 SCM stack, frame;
481
482 /* We get here via a throw to a catch-all. In that case there is the
483 throw frame active, and this catch closure, so narrow by two
484 frames. */
485 stack = scm_make_stack (SCM_BOOL_T, scm_list_1 (scm_from_int (2)));
486 frame = scm_is_true (stack) ? scm_stack_ref (stack, SCM_INUM0) : SCM_BOOL_F;
487
488 if (should_print_backtrace (tag, stack))
489 {
490 scm_puts ("Backtrace:\n", port);
491 scm_display_backtrace_with_highlights (stack, port,
492 SCM_BOOL_F, SCM_BOOL_F,
493 SCM_EOL);
494 scm_newline (port);
495 }
496
497 scm_print_exception (port, frame, tag, args);
498}
499
500\f
501
9de87eea
MV
502struct c_data {
503 void *(*func) (void *);
504 void *data;
505 void *result;
506};
507
508static SCM
509c_body (void *d)
510{
511 struct c_data *data = (struct c_data *)d;
512 data->result = data->func (data->data);
513 return SCM_UNSPECIFIED;
514}
515
516static SCM
517c_handler (void *d, SCM tag, SCM args)
518{
e309f3bf
AW
519 struct c_data *data;
520
521 /* If TAG is `quit', exit() the process. */
522 if (scm_is_eq (tag, scm_from_latin1_symbol ("quit")))
523 exit (scm_exit_status (args));
524
525 data = (struct c_data *)d;
9de87eea
MV
526 data->result = NULL;
527 return SCM_UNSPECIFIED;
528}
529
e309f3bf
AW
530static SCM
531pre_unwind_handler (void *error_port, SCM tag, SCM args)
532{
533 /* Print the exception unless TAG is `quit'. */
534 if (!scm_is_eq (tag, scm_from_latin1_symbol ("quit")))
535 print_exception_and_backtrace (PTR2SCM (error_port), tag, args);
536
537 return SCM_UNSPECIFIED;
538}
539
9de87eea
MV
540void *
541scm_c_with_continuation_barrier (void *(*func) (void *), void *data)
542{
543 struct c_data c_data;
544 c_data.func = func;
545 c_data.data = data;
546 scm_i_with_continuation_barrier (c_body, &c_data,
43e01b1e 547 c_handler, &c_data,
e309f3bf
AW
548 pre_unwind_handler,
549 SCM2PTR (scm_current_error_port ()));
9de87eea
MV
550 return c_data.result;
551}
552
553struct scm_data {
554 SCM proc;
555};
556
557static SCM
558scm_body (void *d)
559{
560 struct scm_data *data = (struct scm_data *)d;
561 return scm_call_0 (data->proc);
562}
563
564static SCM
565scm_handler (void *d, SCM tag, SCM args)
566{
e309f3bf
AW
567 /* Print a message. Note that if TAG is `quit', this will exit() the
568 process. */
569 scm_handle_by_message_noexit (NULL, tag, args);
570
9de87eea
MV
571 return SCM_BOOL_F;
572}
573
574SCM_DEFINE (scm_with_continuation_barrier, "with-continuation-barrier", 1,0,0,
575 (SCM proc),
69d2000d
MV
576"Call @var{proc} and return its result. Do not allow the invocation of\n"
577"continuations that would leave or enter the dynamic extent of the call\n"
578"to @code{with-continuation-barrier}. Such an attempt causes an error\n"
579"to be signaled.\n"
580"\n"
581"Throws (such as errors) that are not caught from within @var{proc} are\n"
582"caught by @code{with-continuation-barrier}. In that case, a short\n"
583"message is printed to the current error port and @code{#f} is returned.\n"
584"\n"
585"Thus, @code{with-continuation-barrier} returns exactly once.\n")
9de87eea
MV
586#define FUNC_NAME s_scm_with_continuation_barrier
587{
588 struct scm_data scm_data;
589 scm_data.proc = proc;
590 return scm_i_with_continuation_barrier (scm_body, &scm_data,
43e01b1e 591 scm_handler, &scm_data,
e309f3bf
AW
592 pre_unwind_handler,
593 SCM2PTR (scm_current_error_port ()));
9de87eea
MV
594}
595#undef FUNC_NAME
db4b4ca6 596
0f2d19dd
JB
597void
598scm_init_continuations ()
0f2d19dd 599{
1d1cae0e
AW
600 tc16_continuation = scm_make_smob_type ("continuation", 0);
601 scm_set_smob_print (tc16_continuation, continuation_print);
a0599745 602#include "libguile/continuations.x"
0f2d19dd
JB
603}
604
89e00824
ML
605/*
606 Local Variables:
607 c-file-style: "gnu"
608 End:
609*/