* __scm.h (SCM_ASYNC_CLICK): Check pending_asyncs instead of
[bpt/guile.git] / libguile / root.c
CommitLineData
d4719ab8 1/* Copyright (C) 1995,1996,1997,1998,1999,2000, 2001, 2002 Free Software Foundation, Inc.
0f2d19dd
JB
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. */
1bbd0b84 41
1bbd0b84 42
0f2d19dd
JB
43\f
44
783e7774 45#include <string.h>
a0599745
MD
46#include "libguile/_scm.h"
47#include "libguile/stackchk.h"
48#include "libguile/dynwind.h"
49#include "libguile/eval.h"
50#include "libguile/smob.h"
51#include "libguile/pairs.h"
52#include "libguile/throw.h"
53#include "libguile/fluids.h"
54#include "libguile/ports.h"
55
56#include "libguile/root.h"
0f2d19dd
JB
57\f
58
59SCM scm_sys_protects[SCM_NUM_PROTECTS];
d564d753 60
92c2555f 61scm_t_bits scm_tc16_root;
d564d753
MD
62
63#ifndef USE_THREADS
64struct scm_root_state *scm_root;
65#endif
0f2d19dd
JB
66
67\f
68
d564d753 69static SCM
e841c3e0 70root_mark (SCM root)
d564d753
MD
71{
72 scm_root_state *s = SCM_ROOT_STATE (root);
dc53f026 73
d564d753
MD
74 scm_gc_mark (s->rootcont);
75 scm_gc_mark (s->dynwinds);
d564d753
MD
76 scm_gc_mark (s->progargs);
77 scm_gc_mark (s->exitval);
78 scm_gc_mark (s->cur_inp);
79 scm_gc_mark (s->cur_outp);
80 scm_gc_mark (s->cur_errp);
903073d5 81 /* No need to gc mark def_loadp */
d9dfcf80 82 scm_gc_mark (s->fluids);
a7d3641d 83 scm_gc_mark (s->active_asyncs);
1ceead47 84 scm_gc_mark (s->signal_asyncs);
d564d753
MD
85 return SCM_ROOT_STATE (root) -> parent;
86}
0f2d19dd 87
d564d753 88
d564d753 89static int
e81d98ec 90root_print (SCM exp, SCM port, scm_print_state *pstate SCM_UNUSED)
d564d753 91{
b7f3516f 92 scm_puts ("#<root ", port);
d564d753 93 scm_intprint(SCM_SEQ (SCM_ROOT_STATE (exp) -> rootcont), 16, port);
b7f3516f 94 scm_putc('>', port);
d564d753
MD
95 return 1;
96}
97
d564d753
MD
98
99\f
100
101SCM
1bbd0b84 102scm_make_root (SCM parent)
d564d753
MD
103{
104 SCM root;
105 scm_root_state *root_state;
106
4c9419ac
MV
107 root_state = (scm_root_state *) scm_gc_malloc (sizeof (scm_root_state),
108 "root state");
0c95b57d 109 if (SCM_ROOTP (parent))
d564d753
MD
110 {
111 memcpy (root_state, SCM_ROOT_STATE (parent), sizeof (scm_root_state));
d9dfcf80 112 scm_copy_fluids (root_state);
d564d753
MD
113 root_state->parent = parent;
114 }
115 else
116 {
117 root_state->parent = SCM_BOOL_F;
4ea1f83d
JB
118
119 /* Initialize everything right now, in case a GC happens early. */
120 root_state->rootcont
121 = root_state->dynwinds
4ea1f83d
JB
122 = root_state->progargs
123 = root_state->exitval
124 = root_state->cur_inp
125 = root_state->cur_outp
126 = root_state->cur_errp
4ea1f83d
JB
127 = root_state->cur_loadp
128 = root_state->fluids
4ea1f83d
JB
129 = root_state->handle
130 = root_state->parent
131 = SCM_BOOL_F;
d564d753 132 }
d4719ab8
MV
133
134 root_state->active_asyncs = SCM_EOL;
1ceead47 135 root_state->signal_asyncs = SCM_EOL;
8ee25fb9 136 root_state->block_asyncs = 0;
1ceead47 137 root_state->pending_asyncs = 1;
d4719ab8 138
d564d753 139 SCM_REDEFER_INTS;
23a62151 140 SCM_NEWSMOB (root, scm_tc16_root, root_state);
d564d753
MD
141 root_state->handle = root;
142 SCM_REALLOW_INTS;
143 return root;
144}
145
1cc91f1b 146/* {call-with-dynamic-root}
d564d753
MD
147 *
148 * Suspending the current thread to evaluate a thunk on the
149 * same C stack but under a new root.
150 *
1cc91f1b 151 * Calls to call-with-dynamic-root return exactly once (unless
e71575d9 152 * the process is somehow exitted). */
d564d753 153
650fa1ab
JB
154/* Some questions about cwdr:
155
156 Couldn't the body just be a closure? Do we really need to pass
157 args through to it?
158
159 The semantics are a lot like catch's; in fact, we call
160 scm_internal_catch to take care of that part of things. Wouldn't
161 it be cleaner to say that uncaught throws just disappear into the
162 ether (or print a message to stderr), and let the caller use catch
163 themselves if they want to?
164
165 -JimB */
166
d564d753
MD
167#if 0
168SCM scm_exitval; /* INUM with return value */
169#endif
c014a02e 170static long n_dynamic_roots = 0;
d564d753 171
650fa1ab 172
e71575d9
MV
173/* cwdr fills out both of these structures, and then passes a pointer
174 to them through scm_internal_catch to the cwdr_body and
175 cwdr_handler functions, to tell them how to behave and to get
176 information back from them.
650fa1ab
JB
177
178 A cwdr is a lot like a catch, except there is no tag (all
179 exceptions are caught), and the body procedure takes the arguments
e71575d9
MV
180 passed to cwdr as A1 and ARGS. The handler is also special since
181 it is not directly run from scm_internal_catch. It is executed
182 outside the new dynamic root. */
650fa1ab
JB
183
184struct cwdr_body_data {
650fa1ab
JB
185 /* Arguments to pass to the cwdr body function. */
186 SCM a1, args;
187
188 /* Scheme procedure to use as body of cwdr. */
189 SCM body_proc;
e71575d9
MV
190};
191
192struct cwdr_handler_data {
193 /* Do we need to run the handler? */
194 int run_handler;
f032b8a8 195
e71575d9
MV
196 /* The tag and args to pass it. */
197 SCM tag, args;
650fa1ab
JB
198};
199
200
201/* Invoke the body of a cwdr, assuming that the throw handler has
202 already been set up. DATA points to a struct set up by cwdr that
816a6f06
JB
203 says what proc to call, and what args to apply it to.
204
205 With a little thought, we could replace this with scm_body_thunk,
206 but I don't want to mess with that at the moment. */
650fa1ab 207static SCM
39752bec 208cwdr_body (void *data)
650fa1ab
JB
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
e71575d9
MV
215/* Record the fact that the body of the cwdr has thrown. Record
216 enough information to invoke the handler later when the dynamic
217 root has been deestablished. */
650fa1ab 218
f032b8a8 219static SCM
e71575d9 220cwdr_handler (void *data, SCM tag, SCM args)
f032b8a8 221{
e71575d9 222 struct cwdr_handler_data *c = (struct cwdr_handler_data *) data;
f032b8a8 223
e71575d9
MV
224 c->run_handler = 1;
225 c->tag = tag;
226 c->args = args;
227 return SCM_UNSPECIFIED;
f032b8a8 228}
d564d753
MD
229
230/* This is the basic code for new root creation.
231 *
232 * WARNING! The order of actions in this routine is in many ways
233 * critical. E. g., it is essential that an error doesn't leave Guile
650fa1ab 234 * in a messed up state. */
d564d753 235
e71575d9 236SCM
92c2555f
MV
237scm_internal_cwdr (scm_t_catch_body body, void *body_data,
238 scm_t_catch_handler handler, void *handler_data,
e71575d9 239 SCM_STACKITEM *stack_start)
d564d753
MD
240{
241 int old_ints_disabled = scm_ints_disabled;
8938d022 242 SCM old_rootcont, old_winds;
e71575d9 243 struct cwdr_handler_data my_handler_data;
d564d753
MD
244 SCM answer;
245
e71575d9 246 /* Create a fresh root continuation. */
d564d753
MD
247 {
248 SCM new_rootcont;
5f144b10 249
d564d753 250 SCM_REDEFER_INTS;
5f144b10 251 {
4c9419ac
MV
252 scm_t_contregs *contregs = scm_gc_malloc (sizeof (scm_t_contregs),
253 "continuation");
5f144b10
GH
254
255 contregs->num_stack_items = 0;
256 contregs->dynenv = SCM_EOL;
257 contregs->base = stack_start;
258 contregs->seq = ++n_dynamic_roots;
259 contregs->throw_value = SCM_BOOL_F;
d564d753 260#ifdef DEBUG_EXTENSIONS
5f144b10 261 contregs->dframe = 0;
d564d753 262#endif
5f144b10
GH
263 SCM_NEWSMOB (new_rootcont, scm_tc16_continuation, contregs);
264 }
8938d022
MD
265 old_rootcont = scm_rootcont;
266 scm_rootcont = new_rootcont;
d564d753
MD
267 SCM_REALLOW_INTS;
268 }
269
8938d022
MD
270 /* Exit caller's dynamic state.
271 */
272 old_winds = scm_dynwinds;
273 scm_dowinds (SCM_EOL, scm_ilength (scm_dynwinds));
d564d753 274#ifdef DEBUG_EXTENSIONS
308277cb 275 SCM_DFRAME (old_rootcont) = scm_last_debug_frame;
8938d022 276 scm_last_debug_frame = 0;
d564d753 277#endif
650fa1ab 278
e71575d9
MV
279 {
280 my_handler_data.run_handler = 0;
816a6f06 281 answer = scm_internal_catch (SCM_BOOL_T,
e71575d9
MV
282 body, body_data,
283 cwdr_handler, &my_handler_data);
650fa1ab 284 }
e71575d9 285
d564d753
MD
286 scm_dowinds (old_winds, - scm_ilength (old_winds));
287 SCM_REDEFER_INTS;
d564d753 288#ifdef DEBUG_EXTENSIONS
308277cb 289 scm_last_debug_frame = SCM_DFRAME (old_rootcont);
d564d753 290#endif
308277cb 291 scm_rootcont = old_rootcont;
d564d753
MD
292 SCM_REALLOW_INTS;
293 scm_ints_disabled = old_ints_disabled;
e71575d9
MV
294
295 /* Now run the real handler iff the body did a throw. */
296 if (my_handler_data.run_handler)
297 return handler (handler_data, my_handler_data.tag, my_handler_data.args);
298 else
299 return answer;
d564d753
MD
300}
301
e71575d9
MV
302/* The original CWDR for invoking Scheme code with a Scheme handler. */
303
304static SCM
305cwdr (SCM proc, SCM a1, SCM args, SCM handler, SCM_STACKITEM *stack_start)
306{
307 struct cwdr_body_data c;
308
309 c.a1 = a1;
310 c.args = args;
311 c.body_proc = proc;
312
313 return scm_internal_cwdr (cwdr_body, &c,
314 scm_handle_by_proc, &handler,
315 stack_start);
316}
d564d753 317
3b3b36dd 318SCM_DEFINE (scm_call_with_dynamic_root, "call-with-dynamic-root", 2, 0, 0,
1bbd0b84 319 (SCM thunk, SCM handler),
1bee0e70 320 "Evaluate @code{(thunk)} in a new dynamic context, returning its value.\n\n"
b380b885
MD
321 "If an error occurs during evaluation, apply @var{handler} to the\n"
322 "arguments to the throw, just as @code{throw} would. If this happens,\n"
323 "@var{handler} is called outside the scope of the new root -- it is\n"
324 "called in the same dynamic context in which\n"
325 "@code{call-with-dynamic-root} was evaluated.\n\n"
326 "If @var{thunk} captures a continuation, the continuation is rooted at\n"
327 "the call to @var{thunk}. In particular, the call to\n"
328 "@code{call-with-dynamic-root} is not captured. Therefore,\n"
329 "@code{call-with-dynamic-root} always returns at most one time.\n\n"
330 "Before calling @var{thunk}, the dynamic-wind chain is un-wound back to\n"
331 "the root and a new chain started for @var{thunk}. Therefore, this call\n"
332 "may not do what you expect:\n\n"
1e6808ea 333 "@lisp\n"
b380b885
MD
334 ";; Almost certainly a bug:\n"
335 "(with-output-to-port\n"
336 " some-port\n\n"
337 " (lambda ()\n"
338 " (call-with-dynamic-root\n"
339 " (lambda ()\n"
340 " (display 'fnord)\n"
341 " (newline))\n"
342 " (lambda (errcode) errcode))))\n"
1e6808ea 343 "@end lisp\n\n"
2a2a730b 344 "The problem is, on what port will @samp{fnord} be displayed? You\n"
b380b885
MD
345 "might expect that because of the @code{with-output-to-port} that\n"
346 "it will be displayed on the port bound to @code{some-port}. But it\n"
347 "probably won't -- before evaluating the thunk, dynamic winds are\n"
348 "unwound, including those created by @code{with-output-to-port}.\n"
349 "So, the standard output port will have been re-set to its default value\n"
350 "before @code{display} is evaluated.\n\n"
351 "(This function was added to Guile mostly to help calls to functions in C\n"
352 "libraries that can not tolerate non-local exits or calls that return\n"
353 "multiple times. If such functions call back to the interpreter, it should\n"
354 "be under a new dynamic root.)")
1bbd0b84 355#define FUNC_NAME s_scm_call_with_dynamic_root
d564d753
MD
356{
357 SCM_STACKITEM stack_place;
8938d022 358 return cwdr (thunk, SCM_EOL, SCM_EOL, handler, &stack_place);
d564d753 359}
1bbd0b84 360#undef FUNC_NAME
d564d753 361
3b3b36dd 362SCM_DEFINE (scm_dynamic_root, "dynamic-root", 0, 0, 0,
1bbd0b84 363 (),
b380b885
MD
364 "Return an object representing the current dynamic root.\n\n"
365 "These objects are only useful for comparison using @code{eq?}.\n"
366 "They are currently represented as numbers, but your code should\n"
367 "in no way depend on this.")
1bbd0b84 368#define FUNC_NAME s_scm_dynamic_root
d564d753
MD
369{
370 return scm_ulong2num (SCM_SEQ (scm_root->rootcont));
371}
1bbd0b84 372#undef FUNC_NAME
d564d753 373
d564d753 374SCM
1bbd0b84 375scm_apply_with_dynamic_root (SCM proc, SCM a1, SCM args, SCM handler)
d564d753
MD
376{
377 SCM_STACKITEM stack_place;
8938d022 378 return cwdr (proc, a1, args, handler, &stack_place);
d564d753 379}
0f2d19dd
JB
380
381\f
382
d564d753
MD
383void
384scm_init_root ()
385{
cc4feeca 386 scm_tc16_root = scm_make_smob_type ("root", sizeof (struct scm_root_state));
e841c3e0
KN
387 scm_set_smob_mark (scm_tc16_root, root_mark);
388 scm_set_smob_print (scm_tc16_root, root_print);
cc4feeca 389
a0599745 390#include "libguile/root.x"
d564d753 391}
89e00824
ML
392
393/*
394 Local Variables:
395 c-file-style: "gnu"
396 End:
397*/