little stuff
[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
161#if 0
162SCM scm_exitval; /* INUM with return value */
163#endif
164static int n_dynamic_roots = 0;
165
8938d022 166static SCM cwdr SCM_P ((SCM thunk, SCM a1, SCM args, SCM handler, SCM_STACKITEM *stack_start));
d564d753
MD
167
168/* This is the basic code for new root creation.
169 *
170 * WARNING! The order of actions in this routine is in many ways
171 * critical. E. g., it is essential that an error doesn't leave Guile
172 * in a messed up state.
173 */
174
175static SCM
8938d022
MD
176cwdr (proc, a1, args, handler, stack_start)
177 SCM proc;
d564d753
MD
178 SCM a1;
179 SCM args;
180 SCM handler;
181 SCM_STACKITEM *stack_start;
182{
183 int old_ints_disabled = scm_ints_disabled;
8938d022 184 SCM old_rootcont, old_winds;
d564d753
MD
185 SCM answer;
186
d564d753
MD
187 /* Create a fresh root continuation.
188 */
189 {
190 SCM new_rootcont;
191 SCM_NEWCELL (new_rootcont);
192 SCM_REDEFER_INTS;
193 SCM_SETJMPBUF (new_rootcont,
0db18cf4 194 scm_must_malloc ((long) sizeof (scm_contregs),
d564d753 195 "inferior root continuation"));
a6c64c3c 196 SCM_SETCAR (new_rootcont, scm_tc7_contin);
d564d753
MD
197 SCM_DYNENV (new_rootcont) = SCM_EOL;
198 SCM_BASE (new_rootcont) = stack_start;
8938d022 199 SCM_SEQ (new_rootcont) = ++n_dynamic_roots;
d564d753
MD
200#ifdef DEBUG_EXTENSIONS
201 SCM_DFRAME (new_rootcont) = 0;
202#endif
8938d022
MD
203 old_rootcont = scm_rootcont;
204 scm_rootcont = new_rootcont;
d564d753
MD
205 SCM_REALLOW_INTS;
206 }
207
8938d022
MD
208 /* Exit caller's dynamic state.
209 */
210 old_winds = scm_dynwinds;
211 scm_dowinds (SCM_EOL, scm_ilength (scm_dynwinds));
d564d753 212#ifdef DEBUG_EXTENSIONS
308277cb 213 SCM_DFRAME (old_rootcont) = scm_last_debug_frame;
8938d022 214 scm_last_debug_frame = 0;
d564d753 215#endif
d564d753 216
d564d753 217 /* Catch all errors. */
e93ffe59 218 answer = scm_catch_apply (SCM_BOOL_T, proc, a1, args, handler);
d564d753
MD
219
220 scm_dowinds (old_winds, - scm_ilength (old_winds));
221 SCM_REDEFER_INTS;
d564d753 222#ifdef DEBUG_EXTENSIONS
308277cb 223 scm_last_debug_frame = SCM_DFRAME (old_rootcont);
d564d753 224#endif
308277cb 225 scm_rootcont = old_rootcont;
d564d753
MD
226 SCM_REALLOW_INTS;
227 scm_ints_disabled = old_ints_disabled;
228 return answer;
229}
230
231
8938d022 232SCM_PROC(s_call_with_dynamic_root, "call-with-dynamic-root", 2, 0, 0, scm_call_with_dynamic_root);
d564d753 233SCM
8938d022 234scm_call_with_dynamic_root (thunk, handler)
d564d753
MD
235 SCM thunk;
236 SCM handler;
d564d753
MD
237{
238 SCM_STACKITEM stack_place;
239
8938d022 240 return cwdr (thunk, SCM_EOL, SCM_EOL, handler, &stack_place);
d564d753
MD
241}
242
243SCM_PROC(s_dynamic_root, "dynamic-root", 0, 0, 0, scm_dynamic_root);
d564d753
MD
244SCM
245scm_dynamic_root ()
d564d753
MD
246{
247 return scm_ulong2num (SCM_SEQ (scm_root->rootcont));
248}
249
d564d753 250SCM
8938d022 251scm_apply_with_dynamic_root (proc, a1, args, handler)
d564d753
MD
252 SCM proc;
253 SCM a1;
254 SCM args;
1cc91f1b 255 SCM handler;
d564d753
MD
256{
257 SCM_STACKITEM stack_place;
8938d022 258 return cwdr (proc, a1, args, handler, &stack_place);
d564d753 259}
0f2d19dd
JB
260
261\f
262
263/* Call thunk(closure) underneath a top-level error handler.
264 * If an error occurs, pass the exitval through err_filter and return it.
265 * If no error occurs, return the value of thunk.
266 */
267
268
269#ifdef _UNICOS
270typedef int setjmp_type;
271#else
272typedef long setjmp_type;
273#endif
274
275
1cc91f1b 276
0f2d19dd
JB
277SCM
278scm_call_catching_errors (thunk, err_filter, closure)
279 SCM (*thunk)();
280 SCM (*err_filter)();
d564d753 281 void *closure;
0f2d19dd
JB
282{
283 SCM answer;
284 setjmp_type i;
faa6b3df 285#ifdef DEBUG_EXTENSIONS
8938d022 286 SCM_DFRAME (scm_rootcont) = scm_last_debug_frame;
faa6b3df 287#endif
0f2d19dd 288 i = setjmp (SCM_JMPBUF (scm_rootcont));
faa6b3df 289 scm_stack_checking_enabled_p = SCM_STACK_CHECKING_P;
0f2d19dd
JB
290 if (!i)
291 {
292 scm_gc_heap_lock = 0;
293 answer = thunk (closure);
294 }
295 else
296 {
297 scm_gc_heap_lock = 1;
298 answer = err_filter (scm_exitval, closure);
299 }
300 return answer;
301}
302
d564d753
MD
303void
304scm_init_root ()
305{
306 scm_tc16_root = scm_newsmob (&root_smob);
307#include "root.x"
308}