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