Merge remote-tracking branch 'origin/stable-2.0'
[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
cdd47ec7 23#include <alloca.h>
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
bbb2ecd1
AW
95void
96scm_i_with_fluids_print (SCM exp, SCM port, scm_print_state *pstate SCM_UNUSED)
97{
0607ebbf 98 scm_puts_unlocked ("#<with-fluids ", port);
bbb2ecd1 99 scm_intprint (SCM_UNPACK (exp), 16, port);
0607ebbf 100 scm_putc_unlocked ('>', port);
bbb2ecd1
AW
101}
102
bd5a75dc
LC
103\f
104/* Return a new fluid. */
105static SCM
aafb4ed7 106new_fluid (SCM init)
9482a297 107{
bd5a75dc
LC
108 SCM fluid;
109 size_t trial, n;
110
aafb4ed7
AW
111 /* Fluids hold the type tag and the fluid number in the first word,
112 and the default value in the second word. */
113 fluid = scm_cell (scm_tc7_fluid, SCM_UNPACK (init));
bd5a75dc 114 SCM_SET_CELL_TYPE (fluid, scm_tc7_fluid);
9de87eea 115
661ae7ab
MV
116 scm_dynwind_begin (0);
117 scm_i_dynwind_pthread_mutex_lock (&fluid_admin_mutex);
9de87eea 118
bd5a75dc 119 for (trial = 0; trial < 2; trial++)
9de87eea 120 {
bd5a75dc 121 /* Look for a free fluid number. */
9de87eea 122 for (n = 0; n < allocated_fluids_len; n++)
bd5a75dc
LC
123 /* TODO: Use `__sync_bool_compare_and_swap' where available. */
124 if (allocated_fluids[n] == NULL)
9de87eea 125 break;
bd5a75dc
LC
126
127 if (trial == 0 && n >= allocated_fluids_len)
128 /* All fluid numbers are in use. Run a GC and retry. Explicitly
129 running the GC is costly and bad-style. We only do this because
130 dynamic state fluid vectors would grow unreasonably if fluid numbers
131 weren't reused. */
132 scm_i_gc ("fluids");
9de87eea 133 }
bd5a75dc
LC
134
135 if (n >= allocated_fluids_len)
9de87eea 136 {
8b039053 137 /* Grow the vector of allocated fluids. */
bd5a75dc
LC
138 void **new_allocated_fluids =
139 scm_gc_malloc_pointerless ((allocated_fluids_len + FLUID_GROW)
140 * sizeof (*allocated_fluids),
141 "allocated fluids");
9de87eea
MV
142
143 /* Copy over old values and initialize rest. GC can not run
144 during these two operations since there is no safe point in
bd5a75dc
LC
145 them. */
146 memcpy (new_allocated_fluids, allocated_fluids,
147 allocated_fluids_len * sizeof (*allocated_fluids));
148 memset (new_allocated_fluids + allocated_fluids_len, 0,
149 FLUID_GROW * sizeof (*allocated_fluids));
9de87eea 150 n = allocated_fluids_len;
d3075c52 151
8b039053
LC
152 /* Update the vector of allocated fluids. Dynamic states will
153 eventually be lazily grown to accomodate the new value of
154 ALLOCATED_FLUIDS_LEN in `fluid-ref' and `fluid-set!'. */
9de87eea
MV
155 allocated_fluids = new_allocated_fluids;
156 allocated_fluids_len += FLUID_GROW;
9de87eea 157 }
bd5a75dc 158
21041372 159 allocated_fluids[n] = SCM_UNPACK_POINTER (fluid);
aafb4ed7 160 SCM_SET_CELL_WORD_0 (fluid, (scm_tc7_fluid | (n << 8)));
bd5a75dc
LC
161
162 GC_GENERAL_REGISTER_DISAPPEARING_LINK (&allocated_fluids[n],
0aed71aa 163 SCM2PTR (fluid));
bd5a75dc 164
661ae7ab 165 scm_dynwind_end ();
0b77014f
AW
166
167 /* Now null out values. We could (and probably should) do this when
168 the fluid is collected instead of now. */
aafb4ed7 169 scm_i_reset_fluid (n);
0b77014f 170
bd5a75dc 171 return fluid;
9482a297
MV
172}
173
aafb4ed7
AW
174SCM
175scm_make_fluid (void)
176{
177 return new_fluid (SCM_BOOL_F);
178}
179
180SCM_DEFINE (scm_make_fluid_with_default, "make-fluid", 0, 1, 0,
181 (SCM dflt),
f43622a2
AW
182 "Return a newly created fluid, whose initial value is @var{dflt},\n"
183 "or @code{#f} if @var{dflt} is not given.\n"
9de87eea
MV
184 "Fluids are objects that can hold one\n"
185 "value per dynamic state. That is, modifications to this value are\n"
186 "only visible to code that executes with the same dynamic state as\n"
187 "the modifying code. When a new dynamic state is constructed, it\n"
188 "inherits the values from its parent. Because each thread normally executes\n"
189 "with its own dynamic state, you can use fluids for thread local storage.")
aafb4ed7 190#define FUNC_NAME s_scm_make_fluid_with_default
9482a297 191{
aafb4ed7 192 return new_fluid (SCM_UNBNDP (dflt) ? SCM_BOOL_F : dflt);
9482a297 193}
1bbd0b84 194#undef FUNC_NAME
9482a297 195
e01163b5 196SCM_DEFINE (scm_make_unbound_fluid, "make-unbound-fluid", 0, 0, 0,
ef94624e 197 (),
e01163b5
AW
198 "Make a fluid that is initially unbound.")
199#define FUNC_NAME s_scm_make_unbound_fluid
ef94624e 200{
aafb4ed7 201 return new_fluid (SCM_UNDEFINED);
ef94624e
BT
202}
203#undef FUNC_NAME
204
a1ec6916 205SCM_DEFINE (scm_fluid_p, "fluid?", 1, 0, 0,
ed4d7cee 206 (SCM obj),
1e6808ea
MG
207 "Return @code{#t} iff @var{obj} is a fluid; otherwise, return\n"
208 "@code{#f}.")
1bbd0b84 209#define FUNC_NAME s_scm_fluid_p
b3460a50 210{
9de87eea 211 return scm_from_bool (IS_FLUID (obj));
b3460a50 212}
1bbd0b84 213#undef FUNC_NAME
b3460a50 214
9de87eea
MV
215int
216scm_is_fluid (SCM obj)
217{
218 return IS_FLUID (obj);
219}
220
ef94624e
BT
221/* Does not check type of `fluid'! */
222static SCM
223fluid_ref (SCM fluid)
9482a297 224{
aafb4ed7 225 SCM ret;
9de87eea 226 SCM fluids = DYNAMIC_STATE_FLUIDS (SCM_I_CURRENT_THREAD->dynamic_state);
9482a297 227
8b039053
LC
228 if (SCM_UNLIKELY (FLUID_NUM (fluid) >= SCM_SIMPLE_VECTOR_LENGTH (fluids)))
229 {
8b039053
LC
230 /* Lazily grow the current thread's dynamic state. */
231 grow_dynamic_state (SCM_I_CURRENT_THREAD->dynamic_state);
232
233 fluids = DYNAMIC_STATE_FLUIDS (SCM_I_CURRENT_THREAD->dynamic_state);
234 }
235
aafb4ed7
AW
236 ret = SCM_SIMPLE_VECTOR_REF (fluids, FLUID_NUM (fluid));
237 if (SCM_UNBNDP (ret))
238 return SCM_I_FLUID_DEFAULT (fluid);
239 else
240 return ret;
9482a297 241}
ef94624e
BT
242
243SCM_DEFINE (scm_fluid_ref, "fluid-ref", 1, 0, 0,
244 (SCM fluid),
245 "Return the value associated with @var{fluid} in the current\n"
246 "dynamic root. If @var{fluid} has not been set, then return\n"
247 "@code{#f}.")
248#define FUNC_NAME s_scm_fluid_ref
249{
250 SCM val;
251 SCM_VALIDATE_FLUID (1, fluid);
252 val = fluid_ref (fluid);
253 if (SCM_UNBNDP (val))
254 SCM_MISC_ERROR ("unbound fluid: ~S",
255 scm_list_1 (fluid));
256 return val;
257}
1bbd0b84 258#undef FUNC_NAME
9482a297 259
a1ec6916 260SCM_DEFINE (scm_fluid_set_x, "fluid-set!", 2, 0, 0,
ed4d7cee
GB
261 (SCM fluid, SCM value),
262 "Set the value associated with @var{fluid} in the current dynamic root.")
1bbd0b84 263#define FUNC_NAME s_scm_fluid_set_x
9482a297 264{
9de87eea 265 SCM fluids = DYNAMIC_STATE_FLUIDS (SCM_I_CURRENT_THREAD->dynamic_state);
9482a297 266
ed4d7cee 267 SCM_VALIDATE_FLUID (1, fluid);
8b039053
LC
268
269 if (SCM_UNLIKELY (FLUID_NUM (fluid) >= SCM_SIMPLE_VECTOR_LENGTH (fluids)))
270 {
8b039053
LC
271 /* Lazily grow the current thread's dynamic state. */
272 grow_dynamic_state (SCM_I_CURRENT_THREAD->dynamic_state);
273
274 fluids = DYNAMIC_STATE_FLUIDS (SCM_I_CURRENT_THREAD->dynamic_state);
275 }
276
9de87eea 277 SCM_SIMPLE_VECTOR_SET (fluids, FLUID_NUM (fluid), value);
86f9f9ae 278 return SCM_UNSPECIFIED;
9482a297 279}
1bbd0b84 280#undef FUNC_NAME
9482a297 281
ef94624e
BT
282SCM_DEFINE (scm_fluid_unset_x, "fluid-unset!", 1, 0, 0,
283 (SCM fluid),
284 "Unset the value associated with @var{fluid}.")
285#define FUNC_NAME s_scm_fluid_unset_x
286{
aafb4ed7
AW
287 /* FIXME: really unset the default value, too? The current test
288 suite demands it, but I would prefer not to. */
289 SCM_SET_CELL_OBJECT_1 (fluid, SCM_UNDEFINED);
ef94624e
BT
290 return scm_fluid_set_x (fluid, SCM_UNDEFINED);
291}
292#undef FUNC_NAME
293
294SCM_DEFINE (scm_fluid_bound_p, "fluid-bound?", 1, 0, 0,
295 (SCM fluid),
296 "Return @code{#t} iff @var{fluid} is bound to a value.\n"
297 "Throw an error if @var{fluid} is not a fluid.")
298#define FUNC_NAME s_scm_fluid_bound_p
299{
300 SCM val;
301 SCM_VALIDATE_FLUID (1, fluid);
302 val = fluid_ref (fluid);
303 return scm_from_bool (! (SCM_UNBNDP (val)));
304}
305#undef FUNC_NAME
306
bb0229b5
AW
307static SCM
308apply_thunk (void *thunk)
b3460a50 309{
bb0229b5
AW
310 return scm_call_0 (SCM_PACK (thunk));
311}
312
313SCM
314scm_i_make_with_fluids (size_t n, SCM *fluids, SCM *vals)
315{
316 SCM ret;
317
318 /* Ensure that there are no duplicates in the fluids set -- an N^2 operation,
319 but N will usually be small, so perhaps that's OK. */
320 {
321 size_t i, j = n;
322
323 while (j--)
324 for (i = 0; i < j; i++)
d223c3fc 325 if (scm_is_eq (fluids[i], fluids[j]))
bb0229b5
AW
326 {
327 vals[i] = vals[j]; /* later bindings win */
328 n--;
329 break;
330 }
331 }
332
333 ret = scm_words (scm_tc7_with_fluids | (n << 8), 1 + n*2);
334 SCM_SET_CELL_WORD_1 (ret, n);
335
336 while (n--)
b3460a50 337 {
bb0229b5
AW
338 if (SCM_UNLIKELY (!IS_FLUID (fluids[n])))
339 scm_wrong_type_arg ("with-fluids", 0, fluids[n]);
340 SCM_SET_CELL_OBJECT (ret, 1 + n * 2, fluids[n]);
341 SCM_SET_CELL_OBJECT (ret, 2 + n * 2, vals[n]);
b3460a50 342 }
bb0229b5
AW
343
344 return ret;
b3460a50 345}
bb0229b5
AW
346
347void
348scm_i_swap_with_fluids (SCM wf, SCM dynstate)
349{
350 SCM fluids;
351 size_t i, max = 0;
b3460a50 352
bb0229b5 353 fluids = DYNAMIC_STATE_FLUIDS (dynstate);
b3460a50 354
bb0229b5
AW
355 /* We could cache the max in the with-fluids, but that would take more mem,
356 and we're touching all the fluids anyway, so this per-swap traversal should
357 be OK. */
358 for (i = 0; i < SCM_WITH_FLUIDS_LEN (wf); i++)
b3460a50 359 {
bb0229b5
AW
360 size_t num = FLUID_NUM (SCM_WITH_FLUIDS_NTH_FLUID (wf, i));
361 max = (max > num) ? max : num;
b3460a50 362 }
b3460a50 363
bb0229b5
AW
364 if (SCM_UNLIKELY (max >= SCM_SIMPLE_VECTOR_LENGTH (fluids)))
365 {
bb0229b5
AW
366 /* Lazily grow the current thread's dynamic state. */
367 grow_dynamic_state (dynstate);
368
369 fluids = DYNAMIC_STATE_FLUIDS (dynstate);
370 }
1bbd0b84 371
bb0229b5
AW
372 /* Bind the fluids. Order doesn't matter, as all fluids are distinct. */
373 for (i = 0; i < SCM_WITH_FLUIDS_LEN (wf); i++)
374 {
375 size_t fluid_num;
376 SCM x;
377
378 fluid_num = FLUID_NUM (SCM_WITH_FLUIDS_NTH_FLUID (wf, i));
379 x = SCM_SIMPLE_VECTOR_REF (fluids, fluid_num);
380 SCM_SIMPLE_VECTOR_SET (fluids, fluid_num,
381 SCM_WITH_FLUIDS_NTH_VAL (wf, i));
382 SCM_WITH_FLUIDS_SET_NTH_VAL (wf, i, x);
383 }
384}
385
a1ec6916 386SCM_DEFINE (scm_with_fluids, "with-fluids*", 3, 0, 0,
ed4d7cee
GB
387 (SCM fluids, SCM values, SCM thunk),
388 "Set @var{fluids} to @var{values} temporary, and call @var{thunk}.\n"
389 "@var{fluids} must be a list of fluids and @var{values} must be the same\n"
390 "number of their values to be applied. Each substitution is done\n"
391 "one after another. @var{thunk} must be a procedure with no argument.")
1bbd0b84
GB
392#define FUNC_NAME s_scm_with_fluids
393{
bebd3fba
MV
394 return scm_c_with_fluids (fluids, values,
395 apply_thunk, (void *) SCM_UNPACK (thunk));
1bbd0b84
GB
396}
397#undef FUNC_NAME
b3460a50
MV
398
399SCM
143e0902
MV
400scm_c_with_fluids (SCM fluids, SCM values, SCM (*cproc) (), void *cdata)
401#define FUNC_NAME "scm_c_with_fluids"
b3460a50 402{
bb0229b5
AW
403 SCM wf, ans;
404 long flen, vlen, i;
405 SCM *fluidsv, *valuesv;
b3460a50 406
c1bfcf60 407 SCM_VALIDATE_LIST_COPYLEN (1, fluids, flen);
ed4d7cee 408 SCM_VALIDATE_LIST_COPYLEN (2, values, vlen);
b3460a50 409 if (flen != vlen)
ed4d7cee 410 scm_out_of_range (s_scm_with_fluids, values);
b3460a50 411
bb0229b5
AW
412 if (SCM_UNLIKELY (flen == 0))
413 return cproc (cdata);
414
415 fluidsv = alloca (sizeof(SCM)*flen);
416 valuesv = alloca (sizeof(SCM)*flen);
bebd3fba 417
bb0229b5
AW
418 for (i = 0; i < flen; i++)
419 {
420 fluidsv[i] = SCM_CAR (fluids);
421 fluids = SCM_CDR (fluids);
422 valuesv[i] = SCM_CAR (values);
423 values = SCM_CDR (values);
424 }
425
426 wf = scm_i_make_with_fluids (flen, fluidsv, valuesv);
427 scm_i_swap_with_fluids (wf, SCM_I_CURRENT_THREAD->dynamic_state);
428 scm_i_set_dynwinds (scm_cons (wf, scm_i_dynwinds ()));
b3460a50 429 ans = cproc (cdata);
bb0229b5
AW
430 scm_i_swap_with_fluids (wf, SCM_I_CURRENT_THREAD->dynamic_state);
431 scm_i_set_dynwinds (scm_cdr (scm_i_dynwinds ()));
432
b3460a50
MV
433 return ans;
434}
c1bfcf60 435#undef FUNC_NAME
b3460a50 436
bebd3fba
MV
437SCM_DEFINE (scm_with_fluid, "with-fluid*", 3, 0, 0,
438 (SCM fluid, SCM value, SCM thunk),
439 "Set @var{fluid} to @var{value} temporarily, and call @var{thunk}.\n"
440 "@var{thunk} must be a procedure with no argument.")
441#define FUNC_NAME s_scm_with_fluid
442{
443 return scm_c_with_fluid (fluid, value,
444 apply_thunk, (void *) SCM_UNPACK (thunk));
445}
446#undef FUNC_NAME
447
143e0902
MV
448SCM
449scm_c_with_fluid (SCM fluid, SCM value, SCM (*cproc) (), void *cdata)
450#define FUNC_NAME "scm_c_with_fluid"
451{
bb0229b5 452 SCM ans, wf;
bebd3fba 453
bb0229b5
AW
454 wf = scm_i_make_with_fluids (1, &fluid, &value);
455 scm_i_swap_with_fluids (wf, SCM_I_CURRENT_THREAD->dynamic_state);
456 scm_i_set_dynwinds (scm_cons (wf, scm_i_dynwinds ()));
bebd3fba 457 ans = cproc (cdata);
bb0229b5
AW
458 scm_i_swap_with_fluids (wf, SCM_I_CURRENT_THREAD->dynamic_state);
459 scm_i_set_dynwinds (scm_cdr (scm_i_dynwinds ()));
460
bebd3fba 461 return ans;
143e0902
MV
462}
463#undef FUNC_NAME
b3460a50 464
ef20bf70
MV
465static void
466swap_fluid (SCM data)
467{
468 SCM f = SCM_CAR (data);
ef94624e 469 SCM t = fluid_ref (f);
ef20bf70
MV
470 scm_fluid_set_x (f, SCM_CDR (data));
471 SCM_SETCDR (data, t);
472}
473
474void
661ae7ab 475scm_dynwind_fluid (SCM fluid, SCM value)
ef20bf70
MV
476{
477 SCM data = scm_cons (fluid, value);
661ae7ab
MV
478 scm_dynwind_rewind_handler_with_scm (swap_fluid, data, SCM_F_WIND_EXPLICITLY);
479 scm_dynwind_unwind_handler_with_scm (swap_fluid, data, SCM_F_WIND_EXPLICITLY);
ef20bf70
MV
480}
481
9de87eea
MV
482SCM
483scm_i_make_initial_dynamic_state ()
484{
485 SCM fluids = scm_c_make_vector (allocated_fluids_len, SCM_BOOL_F);
9ea31741 486 return scm_cell (scm_tc7_dynamic_state, SCM_UNPACK (fluids));
9de87eea
MV
487}
488
489SCM_DEFINE (scm_make_dynamic_state, "make-dynamic-state", 0, 1, 0,
490 (SCM parent),
491 "Return a copy of the dynamic state object @var{parent}\n"
492 "or of the current dynamic state when @var{parent} is omitted.")
493#define FUNC_NAME s_scm_make_dynamic_state
494{
9ea31741 495 SCM fluids;
9de87eea
MV
496
497 if (SCM_UNBNDP (parent))
498 parent = scm_current_dynamic_state ();
499
9ea31741 500 SCM_ASSERT (IS_DYNAMIC_STATE (parent), parent, SCM_ARG1, FUNC_NAME);
9de87eea 501 fluids = scm_vector_copy (DYNAMIC_STATE_FLUIDS (parent));
9ea31741 502 return scm_cell (scm_tc7_dynamic_state, SCM_UNPACK (fluids));
9de87eea
MV
503}
504#undef FUNC_NAME
505
506SCM_DEFINE (scm_dynamic_state_p, "dynamic-state?", 1, 0, 0,
507 (SCM obj),
508 "Return @code{#t} if @var{obj} is a dynamic state object;\n"
509 "return @code{#f} otherwise")
510#define FUNC_NAME s_scm_dynamic_state_p
511{
512 return scm_from_bool (IS_DYNAMIC_STATE (obj));
513}
514#undef FUNC_NAME
515
516int
517scm_is_dynamic_state (SCM obj)
518{
519 return IS_DYNAMIC_STATE (obj);
520}
521
522SCM_DEFINE (scm_current_dynamic_state, "current-dynamic-state", 0, 0, 0,
523 (),
524 "Return the current dynamic state object.")
525#define FUNC_NAME s_scm_current_dynamic_state
526{
527 return SCM_I_CURRENT_THREAD->dynamic_state;
528}
529#undef FUNC_NAME
530
531SCM_DEFINE (scm_set_current_dynamic_state, "set-current-dynamic-state", 1,0,0,
532 (SCM state),
533 "Set the current dynamic state object to @var{state}\n"
534 "and return the previous current dynamic state object.")
535#define FUNC_NAME s_scm_set_current_dynamic_state
536{
537 scm_i_thread *t = SCM_I_CURRENT_THREAD;
538 SCM old = t->dynamic_state;
9ea31741 539 SCM_ASSERT (IS_DYNAMIC_STATE (state), state, SCM_ARG1, FUNC_NAME);
9de87eea
MV
540 t->dynamic_state = state;
541 return old;
542}
543#undef FUNC_NAME
544
545static void
546swap_dynamic_state (SCM loc)
547{
548 SCM_SETCAR (loc, scm_set_current_dynamic_state (SCM_CAR (loc)));
549}
550
551void
661ae7ab 552scm_dynwind_current_dynamic_state (SCM state)
9de87eea
MV
553{
554 SCM loc = scm_cons (state, SCM_EOL);
9ea31741 555 SCM_ASSERT (IS_DYNAMIC_STATE (state), state, SCM_ARG1, NULL);
661ae7ab 556 scm_dynwind_rewind_handler_with_scm (swap_dynamic_state, loc,
9de87eea 557 SCM_F_WIND_EXPLICITLY);
661ae7ab 558 scm_dynwind_unwind_handler_with_scm (swap_dynamic_state, loc,
9de87eea
MV
559 SCM_F_WIND_EXPLICITLY);
560}
561
562void *
563scm_c_with_dynamic_state (SCM state, void *(*func)(void *), void *data)
564{
565 void *result;
661ae7ab
MV
566 scm_dynwind_begin (SCM_F_DYNWIND_REWINDABLE);
567 scm_dynwind_current_dynamic_state (state);
9de87eea 568 result = func (data);
661ae7ab 569 scm_dynwind_end ();
9de87eea
MV
570 return result;
571}
572
573SCM_DEFINE (scm_with_dynamic_state, "with-dynamic-state", 2, 0, 0,
574 (SCM state, SCM proc),
575 "Call @var{proc} while @var{state} is the current dynamic\n"
576 "state object.")
577#define FUNC_NAME s_scm_with_dynamic_state
578{
579 SCM result;
661ae7ab
MV
580 scm_dynwind_begin (SCM_F_DYNWIND_REWINDABLE);
581 scm_dynwind_current_dynamic_state (state);
9de87eea 582 result = scm_call_0 (proc);
661ae7ab 583 scm_dynwind_end ();
9de87eea
MV
584 return result;
585}
586#undef FUNC_NAME
587
9de87eea 588
9482a297
MV
589void
590scm_init_fluids ()
591{
a0599745 592#include "libguile/fluids.x"
9482a297 593}
89e00824
ML
594
595/*
596 Local Variables:
597 c-file-style: "gnu"
598 End:
599*/