*** empty log message ***
[bpt/guile.git] / libguile / root.c
CommitLineData
0f2d19dd
JB
1/* Copyright (C) 1995,1996 Free Software Foundation, Inc.
2 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation; either version 2, or (at your option)
6 * any later version.
7 *
8 * This program 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
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this software; see the file COPYING. If not, write to
82892bed
JB
15 * the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
16 * Boston, MA 02111-1307 USA
0f2d19dd
JB
17 *
18 * As a special exception, the Free Software Foundation gives permission
19 * for additional uses of the text contained in its release of GUILE.
20 *
21 * The exception is that, if you link the GUILE library with other files
22 * to produce an executable, this does not by itself cause the
23 * resulting executable to be covered by the GNU General Public License.
24 * Your use of that executable is in no way restricted on account of
25 * linking the GUILE library code into it.
26 *
27 * This exception does not however invalidate any other reasons why
28 * the executable file might be covered by the GNU General Public License.
29 *
30 * This exception applies only to the code released by the
31 * Free Software Foundation under the name GUILE. If you copy
32 * code from other Free Software Foundation releases into a copy of
33 * GUILE, as the General Public License permits, the exception does
34 * not apply to the code that you add in this way. To avoid misleading
35 * anyone as to the status of such modified files, you must delete
36 * this exception notice from them.
37 *
38 * If you write modifications of your own for GUILE, it is your choice
39 * whether to permit this exception to apply to your modifications.
82892bed 40 * If you do not wish that, delete this exception notice. */
0f2d19dd
JB
41\f
42
43#include <stdio.h>
44#include "_scm.h"
20e6290e 45#include "stackchk.h"
d564d753
MD
46#include "dynwind.h"
47#include "eval.h"
48#include "genio.h"
49#include "smob.h"
50#include "pairs.h"
51#include "throw.h"
0f2d19dd 52
20e6290e 53#include "root.h"
0f2d19dd
JB
54\f
55
56SCM scm_sys_protects[SCM_NUM_PROTECTS];
d564d753
MD
57
58long scm_tc16_root;
59
60#ifndef USE_THREADS
61struct scm_root_state *scm_root;
62#endif
0f2d19dd
JB
63
64\f
65
d564d753
MD
66static SCM mark_root SCM_P ((SCM));
67
68static SCM
69mark_root (root)
70 SCM root;
71{
72 scm_root_state *s = SCM_ROOT_STATE (root);
73 SCM_SETGC8MARK (root);
74 scm_gc_mark (s->rootcont);
75 scm_gc_mark (s->dynwinds);
76 scm_gc_mark (s->continuation_stack);
77 scm_gc_mark (s->continuation_stack_ptr);
78 scm_gc_mark (s->progargs);
79 scm_gc_mark (s->exitval);
80 scm_gc_mark (s->cur_inp);
81 scm_gc_mark (s->cur_outp);
82 scm_gc_mark (s->cur_errp);
83 scm_gc_mark (s->def_inp);
84 scm_gc_mark (s->def_outp);
85 scm_gc_mark (s->def_errp);
dc19d1d2 86 scm_gc_mark (s->top_level_lookup_closure_var);
d564d753 87 scm_gc_mark (s->system_transformer);
5aab5d96 88 scm_gc_mark (s->the_last_stack_var);
d564d753
MD
89 return SCM_ROOT_STATE (root) -> parent;
90}
0f2d19dd 91
d564d753
MD
92static scm_sizet free_root SCM_P ((SCM));
93
94static scm_sizet
95free_root (root)
96 SCM root;
97{
98 scm_must_free ((char *) SCM_ROOT_STATE (root));
99 return sizeof (scm_root_state);
100}
101
102static int print_root SCM_P ((SCM exp, SCM port, scm_print_state *pstate));
103
104static int
105print_root (exp, port, pstate)
106 SCM exp;
107 SCM port;
108 scm_print_state *pstate;
109{
110 scm_gen_puts (scm_regular_string, "#<root ", port);
111 scm_intprint(SCM_SEQ (SCM_ROOT_STATE (exp) -> rootcont), 16, port);
112 scm_gen_putc('>', port);
113 return 1;
114}
115
116static scm_smobfuns root_smob =
117{
118 mark_root,
119 free_root,
120 print_root,
121 0
122};
123
124\f
125
126SCM
127scm_make_root (parent)
128 SCM parent;
129{
130 SCM root;
131 scm_root_state *root_state;
132
133 root_state = (scm_root_state *) scm_must_malloc (sizeof (scm_root_state),
134 "scm_make_root");
135 if (SCM_NIMP (parent) && SCM_ROOTP (parent))
136 {
137 memcpy (root_state, SCM_ROOT_STATE (parent), sizeof (scm_root_state));
138 root_state->parent = parent;
139 }
140 else
141 {
142 root_state->parent = SCM_BOOL_F;
143 }
144 SCM_NEWCELL (root);
145 SCM_REDEFER_INTS;
146 SCM_SETCAR (root, scm_tc16_root);
147 SCM_SETCDR (root, root_state);
148 root_state->handle = root;
149 SCM_REALLOW_INTS;
150 return root;
151}
152
1cc91f1b 153/* {call-with-dynamic-root}
d564d753
MD
154 *
155 * Suspending the current thread to evaluate a thunk on the
156 * same C stack but under a new root.
157 *
1cc91f1b 158 * Calls to call-with-dynamic-root return exactly once (unless
d564d753
MD
159 * the process is somehow exitted).
160 */
161
650fa1ab
JB
162/* Some questions about cwdr:
163
164 Couldn't the body just be a closure? Do we really need to pass
165 args through to it?
166
167 The semantics are a lot like catch's; in fact, we call
168 scm_internal_catch to take care of that part of things. Wouldn't
169 it be cleaner to say that uncaught throws just disappear into the
170 ether (or print a message to stderr), and let the caller use catch
171 themselves if they want to?
172
173 -JimB */
174
d564d753
MD
175#if 0
176SCM scm_exitval; /* INUM with return value */
177#endif
178static int n_dynamic_roots = 0;
179
650fa1ab
JB
180
181/* cwdr fills out one of these structures, and then passes a pointer
816a6f06
JB
182 to it through scm_internal_catch to the cwdr_body function, to tell
183 it how to behave.
650fa1ab
JB
184
185 A cwdr is a lot like a catch, except there is no tag (all
186 exceptions are caught), and the body procedure takes the arguments
187 passed to cwdr as A1 and ARGS. */
188
189struct cwdr_body_data {
190
191 /* Arguments to pass to the cwdr body function. */
192 SCM a1, args;
193
194 /* Scheme procedure to use as body of cwdr. */
195 SCM body_proc;
650fa1ab
JB
196};
197
198
199/* Invoke the body of a cwdr, assuming that the throw handler has
200 already been set up. DATA points to a struct set up by cwdr that
816a6f06
JB
201 says what proc to call, and what args to apply it to.
202
203 With a little thought, we could replace this with scm_body_thunk,
204 but I don't want to mess with that at the moment. */
650fa1ab
JB
205static SCM cwdr_body SCM_P ((void *, SCM));
206
207static SCM
208cwdr_body (void *data, SCM jmpbuf)
209{
210 struct cwdr_body_data *c = (struct cwdr_body_data *) data;
211
212 return scm_apply (c->body_proc, c->a1, c->args);
213}
214
215
8938d022 216static SCM cwdr SCM_P ((SCM thunk, SCM a1, SCM args, SCM handler, SCM_STACKITEM *stack_start));
d564d753
MD
217
218/* This is the basic code for new root creation.
219 *
220 * WARNING! The order of actions in this routine is in many ways
221 * critical. E. g., it is essential that an error doesn't leave Guile
650fa1ab 222 * in a messed up state. */
d564d753
MD
223
224static SCM
8938d022
MD
225cwdr (proc, a1, args, handler, stack_start)
226 SCM proc;
d564d753
MD
227 SCM a1;
228 SCM args;
229 SCM handler;
230 SCM_STACKITEM *stack_start;
231{
232 int old_ints_disabled = scm_ints_disabled;
8938d022 233 SCM old_rootcont, old_winds;
d564d753
MD
234 SCM answer;
235
d564d753
MD
236 /* Create a fresh root continuation.
237 */
238 {
239 SCM new_rootcont;
240 SCM_NEWCELL (new_rootcont);
241 SCM_REDEFER_INTS;
242 SCM_SETJMPBUF (new_rootcont,
0db18cf4 243 scm_must_malloc ((long) sizeof (scm_contregs),
d564d753 244 "inferior root continuation"));
a6c64c3c 245 SCM_SETCAR (new_rootcont, scm_tc7_contin);
d564d753
MD
246 SCM_DYNENV (new_rootcont) = SCM_EOL;
247 SCM_BASE (new_rootcont) = stack_start;
8938d022 248 SCM_SEQ (new_rootcont) = ++n_dynamic_roots;
d564d753
MD
249#ifdef DEBUG_EXTENSIONS
250 SCM_DFRAME (new_rootcont) = 0;
251#endif
8938d022
MD
252 old_rootcont = scm_rootcont;
253 scm_rootcont = new_rootcont;
d564d753
MD
254 SCM_REALLOW_INTS;
255 }
256
8938d022
MD
257 /* Exit caller's dynamic state.
258 */
259 old_winds = scm_dynwinds;
260 scm_dowinds (SCM_EOL, scm_ilength (scm_dynwinds));
d564d753 261#ifdef DEBUG_EXTENSIONS
308277cb 262 SCM_DFRAME (old_rootcont) = scm_last_debug_frame;
8938d022 263 scm_last_debug_frame = 0;
d564d753 264#endif
d564d753 265
d564d753 266 /* Catch all errors. */
650fa1ab
JB
267 {
268 struct cwdr_body_data c;
269
270 c.a1 = a1;
271 c.args = args;
272 c.body_proc = proc;
650fa1ab 273
816a6f06
JB
274 answer = scm_internal_catch (SCM_BOOL_T,
275 cwdr_body, &c,
276 scm_handle_by_proc, &handler);
650fa1ab 277 }
d564d753
MD
278
279 scm_dowinds (old_winds, - scm_ilength (old_winds));
280 SCM_REDEFER_INTS;
d564d753 281#ifdef DEBUG_EXTENSIONS
308277cb 282 scm_last_debug_frame = SCM_DFRAME (old_rootcont);
d564d753 283#endif
308277cb 284 scm_rootcont = old_rootcont;
d564d753
MD
285 SCM_REALLOW_INTS;
286 scm_ints_disabled = old_ints_disabled;
287 return answer;
288}
289
290
8938d022 291SCM_PROC(s_call_with_dynamic_root, "call-with-dynamic-root", 2, 0, 0, scm_call_with_dynamic_root);
d564d753 292SCM
8938d022 293scm_call_with_dynamic_root (thunk, handler)
d564d753
MD
294 SCM thunk;
295 SCM handler;
d564d753
MD
296{
297 SCM_STACKITEM stack_place;
298
8938d022 299 return cwdr (thunk, SCM_EOL, SCM_EOL, handler, &stack_place);
d564d753
MD
300}
301
302SCM_PROC(s_dynamic_root, "dynamic-root", 0, 0, 0, scm_dynamic_root);
d564d753
MD
303SCM
304scm_dynamic_root ()
d564d753
MD
305{
306 return scm_ulong2num (SCM_SEQ (scm_root->rootcont));
307}
308
d564d753 309SCM
8938d022 310scm_apply_with_dynamic_root (proc, a1, args, handler)
d564d753
MD
311 SCM proc;
312 SCM a1;
313 SCM args;
1cc91f1b 314 SCM handler;
d564d753
MD
315{
316 SCM_STACKITEM stack_place;
8938d022 317 return cwdr (proc, a1, args, handler, &stack_place);
d564d753 318}
0f2d19dd
JB
319
320\f
321
322/* Call thunk(closure) underneath a top-level error handler.
323 * If an error occurs, pass the exitval through err_filter and return it.
324 * If no error occurs, return the value of thunk.
325 */
326
327
328#ifdef _UNICOS
329typedef int setjmp_type;
330#else
331typedef long setjmp_type;
332#endif
333
334
1cc91f1b 335
0f2d19dd
JB
336SCM
337scm_call_catching_errors (thunk, err_filter, closure)
338 SCM (*thunk)();
339 SCM (*err_filter)();
d564d753 340 void *closure;
0f2d19dd
JB
341{
342 SCM answer;
343 setjmp_type i;
faa6b3df 344#ifdef DEBUG_EXTENSIONS
8938d022 345 SCM_DFRAME (scm_rootcont) = scm_last_debug_frame;
faa6b3df 346#endif
0f2d19dd 347 i = setjmp (SCM_JMPBUF (scm_rootcont));
faa6b3df 348 scm_stack_checking_enabled_p = SCM_STACK_CHECKING_P;
0f2d19dd
JB
349 if (!i)
350 {
351 scm_gc_heap_lock = 0;
352 answer = thunk (closure);
353 }
354 else
355 {
356 scm_gc_heap_lock = 1;
357 answer = err_filter (scm_exitval, closure);
358 }
359 return answer;
360}
361
d564d753
MD
362void
363scm_init_root ()
364{
365 scm_tc16_root = scm_newsmob (&root_smob);
366#include "root.x"
367}