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