* goops/dispatch.scm (cache-hashval): Corrected termination
[bpt/guile.git] / libguile / continuations.c
CommitLineData
e81d98ec 1/* Copyright (C) 1995,1996,1998,2000,2001 Free Software Foundation, Inc.
0f2d19dd 2 *
73be1d9e
MV
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.
0f2d19dd 7 *
73be1d9e
MV
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.
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
15 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16 */
1bbd0b84 17
1bbd0b84 18
0f2d19dd
JB
19\f
20
bbd43f03
RB
21#include "libguile/_scm.h"
22
13070bd3
DH
23#include <string.h>
24
a0599745
MD
25#include "libguile/root.h"
26#include "libguile/stackchk.h"
5f144b10
GH
27#include "libguile/smob.h"
28#include "libguile/ports.h"
29#include "libguile/dynwind.h"
ce212434 30#include "libguile/values.h"
5f144b10 31
311df4f0 32#ifdef DEBUG_EXTENSIONS
a0599745 33#include "libguile/debug.h"
311df4f0 34#endif
0f2d19dd 35
db4b4ca6 36#include "libguile/validate.h"
a0599745 37#include "libguile/continuations.h"
01c8a3dd 38
0f2d19dd
JB
39\f
40
41/* {Continuations}
42 */
43
92c2555f 44scm_t_bits scm_tc16_continuation;
0f2d19dd 45
e841c3e0
KN
46static SCM
47continuation_mark (SCM obj)
5f144b10 48{
92c2555f 49 scm_t_contregs *continuation = SCM_CONTREGS (obj);
01c8a3dd 50
5f144b10
GH
51 scm_gc_mark (continuation->throw_value);
52 scm_mark_locations (continuation->stack, continuation->num_stack_items);
193297d8
RB
53#ifdef __ia64__
54 if (continuation->backing_store)
55 scm_mark_locations (continuation->backing_store,
56 continuation->backing_store_size /
57 sizeof (SCM_STACKITEM));
58#endif /* __ia64__ */
5f144b10
GH
59 return continuation->dynenv;
60}
01c8a3dd 61
1be6b49c 62static size_t
e841c3e0 63continuation_free (SCM obj)
5f144b10 64{
92c2555f 65 scm_t_contregs *continuation = SCM_CONTREGS (obj);
5f144b10 66 /* stack array size is 1 if num_stack_items is 0 (rootcont). */
1be6b49c 67 size_t extra_items = (continuation->num_stack_items > 0)
5f144b10
GH
68 ? (continuation->num_stack_items - 1)
69 : 0;
92c2555f 70 size_t bytes_free = sizeof (scm_t_contregs)
5f144b10 71 + extra_items * sizeof (SCM_STACKITEM);
193297d8
RB
72
73#ifdef __ia64__
4c9419ac
MV
74 scm_gc_free (continuation->backing_store, continuation->backing_store_size,
75 "continuation backing store");
193297d8 76#endif /* __ia64__ */
4c9419ac
MV
77 scm_gc_free (continuation, bytes_free, "continuation");
78 return 0;
5f144b10 79}
01c8a3dd 80
e841c3e0 81static int
e81d98ec 82continuation_print (SCM obj, SCM port, scm_print_state *state SCM_UNUSED)
5f144b10 83{
92c2555f 84 scm_t_contregs *continuation = SCM_CONTREGS (obj);
5f144b10
GH
85
86 scm_puts ("#<continuation ", port);
87 scm_intprint (continuation->num_stack_items, 10, port);
88 scm_puts (" @ ", port);
89 scm_intprint (SCM_CELL_WORD_1 (obj), 16, port);
90 scm_putc ('>', port);
91 return 1;
92}
1cc91f1b 93
193297d8 94#ifdef __ia64__
87855fa2
MV
95/* Extern declaration of getcontext()/setcontext() in order to redefine
96 getcontext() since on ia64-linux the second return value indicates whether
97 it returned from getcontext() itself or by running setcontext(). */
193297d8
RB
98struct rv
99{
100 long retval;
101 long first_return;
102};
103extern struct rv getcontext (ucontext_t *);
104extern int setcontext (ucontext_t *);
105#endif /* __ia64__ */
106
5f144b10
GH
107/* this may return more than once: the first time with the escape
108 procedure, then subsequently with the value to be passed to the
109 continuation. */
110#define FUNC_NAME "scm_make_continuation"
0f2d19dd 111SCM
5f144b10 112scm_make_continuation (int *first)
0f2d19dd 113{
fcba9b58 114 volatile SCM cont;
92c2555f
MV
115 scm_t_contregs *continuation;
116 scm_t_contregs *rootcont = SCM_CONTREGS (scm_rootcont);
c014a02e 117 long stack_size;
01c8a3dd 118 SCM_STACKITEM * src;
193297d8
RB
119#ifdef __ia64__
120 struct rv rv;
87855fa2 121#endif /* __ia64__ */
0f2d19dd 122
f83e2737 123 SCM_ENTER_A_SECTION;
0f2d19dd 124 SCM_FLUSH_REGISTER_WINDOWS;
5f144b10 125 stack_size = scm_stack_size (rootcont->base);
4c9419ac
MV
126 continuation = scm_gc_malloc (sizeof (scm_t_contregs)
127 + (stack_size - 1) * sizeof (SCM_STACKITEM),
128 "continuation");
5f144b10
GH
129 continuation->num_stack_items = stack_size;
130 continuation->dynenv = scm_dynwinds;
131 continuation->throw_value = SCM_EOL;
132 continuation->base = src = rootcont->base;
133 continuation->seq = rootcont->seq;
0f2d19dd 134#ifdef DEBUG_EXTENSIONS
5f144b10 135 continuation->dframe = scm_last_debug_frame;
0f2d19dd 136#endif
5f144b10
GH
137 SCM_NEWSMOB (cont, scm_tc16_continuation, continuation);
138 SCM_EXIT_A_SECTION;
01c8a3dd 139
4ccb2cd2 140#if ! SCM_STACK_GROWS_UP
5f144b10
GH
141 src -= stack_size;
142#endif
143 memcpy (continuation->stack, src, sizeof (SCM_STACKITEM) * stack_size);
144
193297d8
RB
145#ifdef __ia64__
146 rv = getcontext (&continuation->ctx);
147 if (rv.first_return)
148 {
149 continuation->backing_store_size =
150 continuation->ctx.uc_mcontext.sc_ar_bsp -
87855fa2 151 (unsigned long) __libc_ia64_register_backing_store_base;
193297d8
RB
152 continuation->backing_store = NULL;
153 continuation->backing_store =
4c9419ac
MV
154 scm_gc_malloc (continuation->backing_store_size,
155 "continuation backing store");
193297d8
RB
156 memcpy (continuation->backing_store,
157 (void *) __libc_ia64_register_backing_store_base,
158 continuation->backing_store_size);
159 *first = 1;
160 return cont;
161 }
162 else
163 {
3c468478 164 SCM ret = continuation->throw_value;
193297d8 165 *first = 0;
3c468478
MV
166 continuation->throw_value = SCM_BOOL_F;
167 return ret;
193297d8
RB
168 }
169#else /* !__ia64__ */
5f144b10
GH
170 if (setjmp (continuation->jmpbuf))
171 {
3c468478 172 SCM ret = continuation->throw_value;
5f144b10 173 *first = 0;
3c468478
MV
174 continuation->throw_value = SCM_BOOL_F;
175 return ret;
5f144b10
GH
176 }
177 else
178 {
179 *first = 1;
180 return cont;
181 }
193297d8 182#endif /* !__ia64__ */
0f2d19dd 183}
5f144b10 184#undef FUNC_NAME
0f2d19dd 185
5f144b10 186static void scm_dynthrow (SCM, SCM);
01c8a3dd
DH
187
188/* Grow the stack by a fixed amount to provide space to copy in the
189 * continuation. Possibly this function has to be called several times
190 * recursively before enough space is available. Make sure the compiler does
191 * not optimize the growth array away by storing it's address into a global
192 * variable.
193 */
194
92c2555f 195scm_t_bits scm_i_dummy;
1cc91f1b 196
0f2d19dd 197static void
01c8a3dd
DH
198grow_stack (SCM cont, SCM val)
199{
92c2555f 200 scm_t_bits growth[100];
01c8a3dd 201
92c2555f 202 scm_i_dummy = (scm_t_bits) growth;
01c8a3dd 203 scm_dynthrow (cont, val);
0f2d19dd 204}
0f2d19dd 205
1cc91f1b 206
01c8a3dd
DH
207/* Copy the continuation stack into the current stack. Calling functions from
208 * within this function is safe, since only stack frames below this function's
209 * own frame are overwritten. Thus, memcpy can be used for best performance.
210 */
211static void
92c2555f 212copy_stack_and_call (scm_t_contregs *continuation, SCM val,
5f144b10 213 SCM_STACKITEM * dst)
0f2d19dd 214{
5f144b10
GH
215 memcpy (dst, continuation->stack,
216 sizeof (SCM_STACKITEM) * continuation->num_stack_items);
01c8a3dd
DH
217
218#ifdef DEBUG_EXTENSIONS
5f144b10 219 scm_last_debug_frame = continuation->dframe;
0f2d19dd 220#endif
01c8a3dd 221
5f144b10 222 continuation->throw_value = val;
193297d8
RB
223#ifdef __ia64__
224 memcpy ((void *) __libc_ia64_register_backing_store_base,
225 continuation->backing_store,
226 continuation->backing_store_size);
227 setcontext (&continuation->ctx);
228#else
5f144b10 229 longjmp (continuation->jmpbuf, 1);
193297d8 230#endif
01c8a3dd
DH
231}
232
233
234/* Call grow_stack until the stack space is large enough, then, as the current
235 * stack frame might get overwritten, let copy_stack_and_call perform the
236 * actual copying and continuation calling.
237 */
238static void
239scm_dynthrow (SCM cont, SCM val)
240{
92c2555f 241 scm_t_contregs *continuation = SCM_CONTREGS (cont);
01c8a3dd
DH
242 SCM_STACKITEM * dst = SCM_BASE (scm_rootcont);
243 SCM_STACKITEM stack_top_element;
244
4ccb2cd2 245#if SCM_STACK_GROWS_UP
5f144b10 246 if (SCM_PTR_GE (dst + continuation->num_stack_items, &stack_top_element))
01c8a3dd 247 grow_stack (cont, val);
0f2d19dd 248#else
5f144b10 249 dst -= continuation->num_stack_items;
c8a1bdc4 250 if (dst <= &stack_top_element)
01c8a3dd 251 grow_stack (cont, val);
0f2d19dd 252#endif /* def SCM_STACK_GROWS_UP */
01c8a3dd 253
5f144b10
GH
254 SCM_FLUSH_REGISTER_WINDOWS;
255 copy_stack_and_call (continuation, val, dst);
0f2d19dd
JB
256}
257
db4b4ca6
DH
258
259static SCM
260continuation_apply (SCM cont, SCM args)
5f144b10 261#define FUNC_NAME "continuation_apply"
0f2d19dd 262{
92c2555f
MV
263 scm_t_contregs *continuation = SCM_CONTREGS (cont);
264 scm_t_contregs *rootcont = SCM_CONTREGS (scm_rootcont);
5f144b10 265
5f144b10
GH
266 if (continuation->seq != rootcont->seq
267 /* this base comparison isn't needed */
268 || continuation->base != rootcont->base)
269 {
db4b4ca6 270 SCM_MISC_ERROR ("continuation from wrong top level: ~S",
1afff620 271 scm_list_1 (cont));
5f144b10 272 }
0f2d19dd 273
5f144b10 274 scm_dowinds (continuation->dynenv,
5bd44fc9
GH
275 scm_ilength (scm_dynwinds)
276 - scm_ilength (continuation->dynenv));
0f2d19dd 277
ce212434 278 scm_dynthrow (cont, scm_values (args));
0f2d19dd
JB
279 return SCM_UNSPECIFIED; /* not reached */
280}
5f144b10 281#undef FUNC_NAME
0f2d19dd 282
db4b4ca6 283
0f2d19dd
JB
284void
285scm_init_continuations ()
0f2d19dd 286{
5f144b10
GH
287 scm_tc16_continuation = scm_make_smob_type ("continuation", 0);
288 scm_set_smob_mark (scm_tc16_continuation, continuation_mark);
289 scm_set_smob_free (scm_tc16_continuation, continuation_free);
290 scm_set_smob_print (scm_tc16_continuation, continuation_print);
291 scm_set_smob_apply (scm_tc16_continuation, continuation_apply, 0, 0, 1);
a0599745 292#include "libguile/continuations.x"
0f2d19dd
JB
293}
294
89e00824
ML
295/*
296 Local Variables:
297 c-file-style: "gnu"
298 End:
299*/