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