the dynamic stack is really a stack now, instead of a list
[bpt/guile.git] / libguile / fluids.c
CommitLineData
f43622a2 1/* Copyright (C) 1996,1997,2000,2001, 2004, 2006, 2007, 2008, 2009, 2010, 2011, 2012 Free Software Foundation, Inc.
9482a297 2 *
73be1d9e 3 * This library is free software; you can redistribute it and/or
53befeb7
NJ
4 * modify it under the terms of the GNU Lesser General Public License
5 * as published by the Free Software Foundation; either version 3 of
6 * the License, or (at your option) any later version.
9482a297 7 *
53befeb7
NJ
8 * This library is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of
73be1d9e
MV
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Lesser General Public License for more details.
9482a297 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
53befeb7
NJ
15 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
16 * 02110-1301 USA
73be1d9e 17 */
9482a297 18
dbb605f5
LC
19#ifdef HAVE_CONFIG_H
20# include <config.h>
21#endif
22
9de87eea
MV
23#include <stdio.h>
24#include <string.h>
1bbd0b84 25
a0599745
MD
26#include "libguile/_scm.h"
27#include "libguile/print.h"
a0599745
MD
28#include "libguile/dynwind.h"
29#include "libguile/fluids.h"
30#include "libguile/alist.h"
31#include "libguile/eval.h"
32#include "libguile/ports.h"
143e0902 33#include "libguile/deprecation.h"
a0599745 34#include "libguile/validate.h"
bd5a75dc 35#include "libguile/bdw-gc.h"
9482a297 36
bd5a75dc
LC
37/* Number of additional slots to allocate when ALLOCATED_FLUIDS is full. */
38#define FLUID_GROW 128
9de87eea 39
bd5a75dc
LC
40/* Vector of allocated fluids indexed by fluid numbers. Access is protected by
41 FLUID_ADMIN_MUTEX. */
42static void **allocated_fluids = NULL;
43static size_t allocated_fluids_len = 0;
9482a297 44
9de87eea
MV
45static scm_i_pthread_mutex_t fluid_admin_mutex = SCM_I_PTHREAD_MUTEX_INITIALIZER;
46
6f8d7b12 47#define IS_FLUID(x) SCM_FLUID_P (x)
5ef71027 48#define FLUID_NUM(x) SCM_I_FLUID_NUM (x)
9de87eea 49
5ef71027
AW
50#define IS_DYNAMIC_STATE(x) SCM_I_DYNAMIC_STATE_P (x)
51#define DYNAMIC_STATE_FLUIDS(x) SCM_I_DYNAMIC_STATE_FLUIDS (x)
9ea31741 52#define SET_DYNAMIC_STATE_FLUIDS(x, y) SCM_SET_CELL_WORD_1 ((x), (SCM_UNPACK (y)))
9de87eea 53
9de87eea 54
8b039053 55\f
bd5a75dc
LC
56/* Grow STATE so that it can hold up to ALLOCATED_FLUIDS_LEN fluids. This may
57 be more than necessary since ALLOCATED_FLUIDS is sparse and the current
58 thread may not access all the fluids anyway. Memory usage could be improved
59 by using a 2-level array as is done in glibc for pthread keys (TODO). */
9482a297 60static void
8b039053 61grow_dynamic_state (SCM state)
9de87eea 62{
8b039053
LC
63 SCM new_fluids;
64 SCM old_fluids = DYNAMIC_STATE_FLUIDS (state);
bd5a75dc 65 size_t i, len, old_len = SCM_SIMPLE_VECTOR_LENGTH (old_fluids);
9de87eea 66
bd5a75dc
LC
67 /* Assume the assignment below is atomic. */
68 len = allocated_fluids_len;
9de87eea 69
aafb4ed7 70 new_fluids = scm_c_make_vector (len, SCM_UNDEFINED);
8b039053
LC
71
72 for (i = 0; i < old_len; i++)
73 SCM_SIMPLE_VECTOR_SET (new_fluids, i,
74 SCM_SIMPLE_VECTOR_REF (old_fluids, i));
75 SET_DYNAMIC_STATE_FLUIDS (state, new_fluids);
9482a297
MV
76}
77
9ea31741
AW
78void
79scm_i_fluid_print (SCM exp, SCM port, scm_print_state *pstate SCM_UNUSED)
9482a297 80{
0607ebbf 81 scm_puts_unlocked ("#<fluid ", port);
9de87eea 82 scm_intprint ((int) FLUID_NUM (exp), 10, port);
0607ebbf 83 scm_putc_unlocked ('>', port);
9482a297
MV
84}
85
45cf2428
AW
86void
87scm_i_dynamic_state_print (SCM exp, SCM port, scm_print_state *pstate SCM_UNUSED)
88{
0607ebbf 89 scm_puts_unlocked ("#<dynamic-state ", port);
45cf2428 90 scm_intprint (SCM_UNPACK (exp), 16, port);
0607ebbf 91 scm_putc_unlocked ('>', port);
45cf2428
AW
92}
93
bd5a75dc
LC
94\f
95/* Return a new fluid. */
96static SCM
aafb4ed7 97new_fluid (SCM init)
9482a297 98{
bd5a75dc
LC
99 SCM fluid;
100 size_t trial, n;
101
aafb4ed7
AW
102 /* Fluids hold the type tag and the fluid number in the first word,
103 and the default value in the second word. */
104 fluid = scm_cell (scm_tc7_fluid, SCM_UNPACK (init));
bd5a75dc 105 SCM_SET_CELL_TYPE (fluid, scm_tc7_fluid);
9de87eea 106
661ae7ab
MV
107 scm_dynwind_begin (0);
108 scm_i_dynwind_pthread_mutex_lock (&fluid_admin_mutex);
9de87eea 109
bd5a75dc 110 for (trial = 0; trial < 2; trial++)
9de87eea 111 {
bd5a75dc 112 /* Look for a free fluid number. */
9de87eea 113 for (n = 0; n < allocated_fluids_len; n++)
bd5a75dc
LC
114 /* TODO: Use `__sync_bool_compare_and_swap' where available. */
115 if (allocated_fluids[n] == NULL)
9de87eea 116 break;
bd5a75dc
LC
117
118 if (trial == 0 && n >= allocated_fluids_len)
119 /* All fluid numbers are in use. Run a GC and retry. Explicitly
120 running the GC is costly and bad-style. We only do this because
121 dynamic state fluid vectors would grow unreasonably if fluid numbers
122 weren't reused. */
123 scm_i_gc ("fluids");
9de87eea 124 }
bd5a75dc
LC
125
126 if (n >= allocated_fluids_len)
9de87eea 127 {
8b039053 128 /* Grow the vector of allocated fluids. */
bd5a75dc
LC
129 void **new_allocated_fluids =
130 scm_gc_malloc_pointerless ((allocated_fluids_len + FLUID_GROW)
131 * sizeof (*allocated_fluids),
132 "allocated fluids");
9de87eea
MV
133
134 /* Copy over old values and initialize rest. GC can not run
135 during these two operations since there is no safe point in
bd5a75dc
LC
136 them. */
137 memcpy (new_allocated_fluids, allocated_fluids,
138 allocated_fluids_len * sizeof (*allocated_fluids));
139 memset (new_allocated_fluids + allocated_fluids_len, 0,
140 FLUID_GROW * sizeof (*allocated_fluids));
9de87eea 141 n = allocated_fluids_len;
d3075c52 142
8b039053
LC
143 /* Update the vector of allocated fluids. Dynamic states will
144 eventually be lazily grown to accomodate the new value of
145 ALLOCATED_FLUIDS_LEN in `fluid-ref' and `fluid-set!'. */
9de87eea
MV
146 allocated_fluids = new_allocated_fluids;
147 allocated_fluids_len += FLUID_GROW;
9de87eea 148 }
bd5a75dc 149
21041372 150 allocated_fluids[n] = SCM_UNPACK_POINTER (fluid);
aafb4ed7 151 SCM_SET_CELL_WORD_0 (fluid, (scm_tc7_fluid | (n << 8)));
bd5a75dc
LC
152
153 GC_GENERAL_REGISTER_DISAPPEARING_LINK (&allocated_fluids[n],
0aed71aa 154 SCM2PTR (fluid));
bd5a75dc 155
661ae7ab 156 scm_dynwind_end ();
0b77014f
AW
157
158 /* Now null out values. We could (and probably should) do this when
159 the fluid is collected instead of now. */
aafb4ed7 160 scm_i_reset_fluid (n);
0b77014f 161
bd5a75dc 162 return fluid;
9482a297
MV
163}
164
aafb4ed7
AW
165SCM
166scm_make_fluid (void)
167{
168 return new_fluid (SCM_BOOL_F);
169}
170
171SCM_DEFINE (scm_make_fluid_with_default, "make-fluid", 0, 1, 0,
172 (SCM dflt),
f43622a2
AW
173 "Return a newly created fluid, whose initial value is @var{dflt},\n"
174 "or @code{#f} if @var{dflt} is not given.\n"
9de87eea
MV
175 "Fluids are objects that can hold one\n"
176 "value per dynamic state. That is, modifications to this value are\n"
177 "only visible to code that executes with the same dynamic state as\n"
178 "the modifying code. When a new dynamic state is constructed, it\n"
179 "inherits the values from its parent. Because each thread normally executes\n"
180 "with its own dynamic state, you can use fluids for thread local storage.")
aafb4ed7 181#define FUNC_NAME s_scm_make_fluid_with_default
9482a297 182{
aafb4ed7 183 return new_fluid (SCM_UNBNDP (dflt) ? SCM_BOOL_F : dflt);
9482a297 184}
1bbd0b84 185#undef FUNC_NAME
9482a297 186
e01163b5 187SCM_DEFINE (scm_make_unbound_fluid, "make-unbound-fluid", 0, 0, 0,
ef94624e 188 (),
e01163b5
AW
189 "Make a fluid that is initially unbound.")
190#define FUNC_NAME s_scm_make_unbound_fluid
ef94624e 191{
aafb4ed7 192 return new_fluid (SCM_UNDEFINED);
ef94624e
BT
193}
194#undef FUNC_NAME
195
a1ec6916 196SCM_DEFINE (scm_fluid_p, "fluid?", 1, 0, 0,
ed4d7cee 197 (SCM obj),
1e6808ea
MG
198 "Return @code{#t} iff @var{obj} is a fluid; otherwise, return\n"
199 "@code{#f}.")
1bbd0b84 200#define FUNC_NAME s_scm_fluid_p
b3460a50 201{
9de87eea 202 return scm_from_bool (IS_FLUID (obj));
b3460a50 203}
1bbd0b84 204#undef FUNC_NAME
b3460a50 205
9de87eea
MV
206int
207scm_is_fluid (SCM obj)
208{
209 return IS_FLUID (obj);
210}
211
ef94624e
BT
212/* Does not check type of `fluid'! */
213static SCM
214fluid_ref (SCM fluid)
9482a297 215{
aafb4ed7 216 SCM ret;
9de87eea 217 SCM fluids = DYNAMIC_STATE_FLUIDS (SCM_I_CURRENT_THREAD->dynamic_state);
9482a297 218
8b039053
LC
219 if (SCM_UNLIKELY (FLUID_NUM (fluid) >= SCM_SIMPLE_VECTOR_LENGTH (fluids)))
220 {
8b039053
LC
221 /* Lazily grow the current thread's dynamic state. */
222 grow_dynamic_state (SCM_I_CURRENT_THREAD->dynamic_state);
223
224 fluids = DYNAMIC_STATE_FLUIDS (SCM_I_CURRENT_THREAD->dynamic_state);
225 }
226
aafb4ed7
AW
227 ret = SCM_SIMPLE_VECTOR_REF (fluids, FLUID_NUM (fluid));
228 if (SCM_UNBNDP (ret))
229 return SCM_I_FLUID_DEFAULT (fluid);
230 else
231 return ret;
9482a297 232}
ef94624e
BT
233
234SCM_DEFINE (scm_fluid_ref, "fluid-ref", 1, 0, 0,
235 (SCM fluid),
236 "Return the value associated with @var{fluid} in the current\n"
237 "dynamic root. If @var{fluid} has not been set, then return\n"
238 "@code{#f}.")
239#define FUNC_NAME s_scm_fluid_ref
240{
241 SCM val;
242 SCM_VALIDATE_FLUID (1, fluid);
243 val = fluid_ref (fluid);
244 if (SCM_UNBNDP (val))
245 SCM_MISC_ERROR ("unbound fluid: ~S",
246 scm_list_1 (fluid));
247 return val;
248}
1bbd0b84 249#undef FUNC_NAME
9482a297 250
a1ec6916 251SCM_DEFINE (scm_fluid_set_x, "fluid-set!", 2, 0, 0,
ed4d7cee
GB
252 (SCM fluid, SCM value),
253 "Set the value associated with @var{fluid} in the current dynamic root.")
1bbd0b84 254#define FUNC_NAME s_scm_fluid_set_x
9482a297 255{
9de87eea 256 SCM fluids = DYNAMIC_STATE_FLUIDS (SCM_I_CURRENT_THREAD->dynamic_state);
9482a297 257
ed4d7cee 258 SCM_VALIDATE_FLUID (1, fluid);
8b039053
LC
259
260 if (SCM_UNLIKELY (FLUID_NUM (fluid) >= SCM_SIMPLE_VECTOR_LENGTH (fluids)))
261 {
8b039053
LC
262 /* Lazily grow the current thread's dynamic state. */
263 grow_dynamic_state (SCM_I_CURRENT_THREAD->dynamic_state);
264
265 fluids = DYNAMIC_STATE_FLUIDS (SCM_I_CURRENT_THREAD->dynamic_state);
266 }
267
9de87eea 268 SCM_SIMPLE_VECTOR_SET (fluids, FLUID_NUM (fluid), value);
86f9f9ae 269 return SCM_UNSPECIFIED;
9482a297 270}
1bbd0b84 271#undef FUNC_NAME
9482a297 272
ef94624e
BT
273SCM_DEFINE (scm_fluid_unset_x, "fluid-unset!", 1, 0, 0,
274 (SCM fluid),
275 "Unset the value associated with @var{fluid}.")
276#define FUNC_NAME s_scm_fluid_unset_x
277{
aafb4ed7
AW
278 /* FIXME: really unset the default value, too? The current test
279 suite demands it, but I would prefer not to. */
280 SCM_SET_CELL_OBJECT_1 (fluid, SCM_UNDEFINED);
ef94624e
BT
281 return scm_fluid_set_x (fluid, SCM_UNDEFINED);
282}
283#undef FUNC_NAME
284
285SCM_DEFINE (scm_fluid_bound_p, "fluid-bound?", 1, 0, 0,
286 (SCM fluid),
287 "Return @code{#t} iff @var{fluid} is bound to a value.\n"
288 "Throw an error if @var{fluid} is not a fluid.")
289#define FUNC_NAME s_scm_fluid_bound_p
290{
291 SCM val;
292 SCM_VALIDATE_FLUID (1, fluid);
293 val = fluid_ref (fluid);
294 return scm_from_bool (! (SCM_UNBNDP (val)));
295}
296#undef FUNC_NAME
297
bb0229b5
AW
298static SCM
299apply_thunk (void *thunk)
b3460a50 300{
bb0229b5
AW
301 return scm_call_0 (SCM_PACK (thunk));
302}
303
9ede013f
AW
304size_t
305scm_prepare_fluids (size_t n, SCM *fluids, SCM *values)
bb0229b5 306{
9ede013f 307 size_t j = n;
bb0229b5
AW
308
309 /* Ensure that there are no duplicates in the fluids set -- an N^2 operation,
310 but N will usually be small, so perhaps that's OK. */
9ede013f
AW
311 while (j--)
312 {
313 size_t i;
314
315 if (SCM_UNLIKELY (!IS_FLUID (fluids[j])))
316 scm_wrong_type_arg ("with-fluids", 0, fluids[j]);
bb0229b5 317
bb0229b5 318 for (i = 0; i < j; i++)
d223c3fc 319 if (scm_is_eq (fluids[i], fluids[j]))
bb0229b5 320 {
9ede013f 321 values[i] = values[j]; /* later bindings win */
bb0229b5
AW
322 n--;
323 break;
324 }
b3460a50 325 }
bb0229b5 326
9ede013f 327 return n;
b3460a50 328}
bb0229b5
AW
329
330void
9ede013f 331scm_swap_fluids (size_t n, SCM *fluids, SCM *values, SCM dynstate)
bb0229b5 332{
9ede013f 333 SCM fluid_vector;
bb0229b5 334 size_t i, max = 0;
b3460a50 335
9ede013f 336 fluid_vector = DYNAMIC_STATE_FLUIDS (dynstate);
b3460a50 337
bb0229b5
AW
338 /* We could cache the max in the with-fluids, but that would take more mem,
339 and we're touching all the fluids anyway, so this per-swap traversal should
340 be OK. */
9ede013f 341 for (i = 0; i < n; i++)
b3460a50 342 {
9ede013f 343 size_t num = FLUID_NUM (fluids[i]);
bb0229b5 344 max = (max > num) ? max : num;
b3460a50 345 }
b3460a50 346
9ede013f 347 if (SCM_UNLIKELY (max >= SCM_SIMPLE_VECTOR_LENGTH (fluid_vector)))
bb0229b5 348 {
bb0229b5
AW
349 /* Lazily grow the current thread's dynamic state. */
350 grow_dynamic_state (dynstate);
351
9ede013f 352 fluid_vector = DYNAMIC_STATE_FLUIDS (dynstate);
bb0229b5 353 }
1bbd0b84 354
bb0229b5 355 /* Bind the fluids. Order doesn't matter, as all fluids are distinct. */
9ede013f 356 for (i = 0; i < n; i++)
bb0229b5
AW
357 {
358 size_t fluid_num;
359 SCM x;
360
9ede013f
AW
361 fluid_num = FLUID_NUM (fluids[i]);
362 x = SCM_SIMPLE_VECTOR_REF (fluid_vector, fluid_num);
363 SCM_SIMPLE_VECTOR_SET (fluid_vector, fluid_num, values[i]);
364 values[i] = x;
bb0229b5
AW
365 }
366}
367
a1ec6916 368SCM_DEFINE (scm_with_fluids, "with-fluids*", 3, 0, 0,
ed4d7cee
GB
369 (SCM fluids, SCM values, SCM thunk),
370 "Set @var{fluids} to @var{values} temporary, and call @var{thunk}.\n"
371 "@var{fluids} must be a list of fluids and @var{values} must be the same\n"
372 "number of their values to be applied. Each substitution is done\n"
373 "one after another. @var{thunk} must be a procedure with no argument.")
1bbd0b84
GB
374#define FUNC_NAME s_scm_with_fluids
375{
bebd3fba
MV
376 return scm_c_with_fluids (fluids, values,
377 apply_thunk, (void *) SCM_UNPACK (thunk));
1bbd0b84
GB
378}
379#undef FUNC_NAME
b3460a50
MV
380
381SCM
143e0902
MV
382scm_c_with_fluids (SCM fluids, SCM values, SCM (*cproc) (), void *cdata)
383#define FUNC_NAME "scm_c_with_fluids"
b3460a50 384{
9ede013f 385 SCM ans;
bb0229b5
AW
386 long flen, vlen, i;
387 SCM *fluidsv, *valuesv;
9ede013f 388 scm_i_thread *thread = SCM_I_CURRENT_THREAD;
b3460a50 389
c1bfcf60 390 SCM_VALIDATE_LIST_COPYLEN (1, fluids, flen);
ed4d7cee 391 SCM_VALIDATE_LIST_COPYLEN (2, values, vlen);
b3460a50 392 if (flen != vlen)
ed4d7cee 393 scm_out_of_range (s_scm_with_fluids, values);
b3460a50 394
bb0229b5
AW
395 if (SCM_UNLIKELY (flen == 0))
396 return cproc (cdata);
397
398 fluidsv = alloca (sizeof(SCM)*flen);
399 valuesv = alloca (sizeof(SCM)*flen);
bebd3fba 400
bb0229b5
AW
401 for (i = 0; i < flen; i++)
402 {
403 fluidsv[i] = SCM_CAR (fluids);
404 fluids = SCM_CDR (fluids);
405 valuesv[i] = SCM_CAR (values);
406 values = SCM_CDR (values);
407 }
408
9ede013f
AW
409 scm_dynstack_push_fluids (&thread->dynstack, flen, fluidsv, valuesv,
410 thread->dynamic_state);
b3460a50 411 ans = cproc (cdata);
9ede013f 412 scm_dynstack_unwind_fluids (&thread->dynstack, thread->dynamic_state);
bb0229b5 413
b3460a50
MV
414 return ans;
415}
c1bfcf60 416#undef FUNC_NAME
b3460a50 417
bebd3fba
MV
418SCM_DEFINE (scm_with_fluid, "with-fluid*", 3, 0, 0,
419 (SCM fluid, SCM value, SCM thunk),
420 "Set @var{fluid} to @var{value} temporarily, and call @var{thunk}.\n"
421 "@var{thunk} must be a procedure with no argument.")
422#define FUNC_NAME s_scm_with_fluid
423{
424 return scm_c_with_fluid (fluid, value,
425 apply_thunk, (void *) SCM_UNPACK (thunk));
426}
427#undef FUNC_NAME
428
143e0902
MV
429SCM
430scm_c_with_fluid (SCM fluid, SCM value, SCM (*cproc) (), void *cdata)
431#define FUNC_NAME "scm_c_with_fluid"
432{
9ede013f
AW
433 SCM ans;
434 scm_i_thread *thread = SCM_I_CURRENT_THREAD;
bebd3fba 435
9ede013f
AW
436 scm_dynstack_push_fluids (&thread->dynstack, 1, &fluid, &value,
437 thread->dynamic_state);
bebd3fba 438 ans = cproc (cdata);
9ede013f 439 scm_dynstack_unwind_fluids (&thread->dynstack, thread->dynamic_state);
bb0229b5 440
bebd3fba 441 return ans;
143e0902
MV
442}
443#undef FUNC_NAME
b3460a50 444
ef20bf70
MV
445static void
446swap_fluid (SCM data)
447{
448 SCM f = SCM_CAR (data);
ef94624e 449 SCM t = fluid_ref (f);
ef20bf70
MV
450 scm_fluid_set_x (f, SCM_CDR (data));
451 SCM_SETCDR (data, t);
452}
453
454void
661ae7ab 455scm_dynwind_fluid (SCM fluid, SCM value)
ef20bf70
MV
456{
457 SCM data = scm_cons (fluid, value);
661ae7ab
MV
458 scm_dynwind_rewind_handler_with_scm (swap_fluid, data, SCM_F_WIND_EXPLICITLY);
459 scm_dynwind_unwind_handler_with_scm (swap_fluid, data, SCM_F_WIND_EXPLICITLY);
ef20bf70
MV
460}
461
9de87eea
MV
462SCM
463scm_i_make_initial_dynamic_state ()
464{
465 SCM fluids = scm_c_make_vector (allocated_fluids_len, SCM_BOOL_F);
9ea31741 466 return scm_cell (scm_tc7_dynamic_state, SCM_UNPACK (fluids));
9de87eea
MV
467}
468
469SCM_DEFINE (scm_make_dynamic_state, "make-dynamic-state", 0, 1, 0,
470 (SCM parent),
471 "Return a copy of the dynamic state object @var{parent}\n"
472 "or of the current dynamic state when @var{parent} is omitted.")
473#define FUNC_NAME s_scm_make_dynamic_state
474{
9ea31741 475 SCM fluids;
9de87eea
MV
476
477 if (SCM_UNBNDP (parent))
478 parent = scm_current_dynamic_state ();
479
9ea31741 480 SCM_ASSERT (IS_DYNAMIC_STATE (parent), parent, SCM_ARG1, FUNC_NAME);
9de87eea 481 fluids = scm_vector_copy (DYNAMIC_STATE_FLUIDS (parent));
9ea31741 482 return scm_cell (scm_tc7_dynamic_state, SCM_UNPACK (fluids));
9de87eea
MV
483}
484#undef FUNC_NAME
485
486SCM_DEFINE (scm_dynamic_state_p, "dynamic-state?", 1, 0, 0,
487 (SCM obj),
488 "Return @code{#t} if @var{obj} is a dynamic state object;\n"
489 "return @code{#f} otherwise")
490#define FUNC_NAME s_scm_dynamic_state_p
491{
492 return scm_from_bool (IS_DYNAMIC_STATE (obj));
493}
494#undef FUNC_NAME
495
496int
497scm_is_dynamic_state (SCM obj)
498{
499 return IS_DYNAMIC_STATE (obj);
500}
501
502SCM_DEFINE (scm_current_dynamic_state, "current-dynamic-state", 0, 0, 0,
503 (),
504 "Return the current dynamic state object.")
505#define FUNC_NAME s_scm_current_dynamic_state
506{
507 return SCM_I_CURRENT_THREAD->dynamic_state;
508}
509#undef FUNC_NAME
510
511SCM_DEFINE (scm_set_current_dynamic_state, "set-current-dynamic-state", 1,0,0,
512 (SCM state),
513 "Set the current dynamic state object to @var{state}\n"
514 "and return the previous current dynamic state object.")
515#define FUNC_NAME s_scm_set_current_dynamic_state
516{
517 scm_i_thread *t = SCM_I_CURRENT_THREAD;
518 SCM old = t->dynamic_state;
9ea31741 519 SCM_ASSERT (IS_DYNAMIC_STATE (state), state, SCM_ARG1, FUNC_NAME);
9de87eea
MV
520 t->dynamic_state = state;
521 return old;
522}
523#undef FUNC_NAME
524
525static void
526swap_dynamic_state (SCM loc)
527{
528 SCM_SETCAR (loc, scm_set_current_dynamic_state (SCM_CAR (loc)));
529}
530
531void
661ae7ab 532scm_dynwind_current_dynamic_state (SCM state)
9de87eea
MV
533{
534 SCM loc = scm_cons (state, SCM_EOL);
9ea31741 535 SCM_ASSERT (IS_DYNAMIC_STATE (state), state, SCM_ARG1, NULL);
661ae7ab 536 scm_dynwind_rewind_handler_with_scm (swap_dynamic_state, loc,
9de87eea 537 SCM_F_WIND_EXPLICITLY);
661ae7ab 538 scm_dynwind_unwind_handler_with_scm (swap_dynamic_state, loc,
9de87eea
MV
539 SCM_F_WIND_EXPLICITLY);
540}
541
542void *
543scm_c_with_dynamic_state (SCM state, void *(*func)(void *), void *data)
544{
545 void *result;
661ae7ab
MV
546 scm_dynwind_begin (SCM_F_DYNWIND_REWINDABLE);
547 scm_dynwind_current_dynamic_state (state);
9de87eea 548 result = func (data);
661ae7ab 549 scm_dynwind_end ();
9de87eea
MV
550 return result;
551}
552
553SCM_DEFINE (scm_with_dynamic_state, "with-dynamic-state", 2, 0, 0,
554 (SCM state, SCM proc),
555 "Call @var{proc} while @var{state} is the current dynamic\n"
556 "state object.")
557#define FUNC_NAME s_scm_with_dynamic_state
558{
559 SCM result;
661ae7ab
MV
560 scm_dynwind_begin (SCM_F_DYNWIND_REWINDABLE);
561 scm_dynwind_current_dynamic_state (state);
9de87eea 562 result = scm_call_0 (proc);
661ae7ab 563 scm_dynwind_end ();
9de87eea
MV
564 return result;
565}
566#undef FUNC_NAME
567
9de87eea 568
9482a297
MV
569void
570scm_init_fluids ()
571{
a0599745 572#include "libguile/fluids.x"
9482a297 573}
89e00824
ML
574
575/*
576 Local Variables:
577 c-file-style: "gnu"
578 End:
579*/