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