Merge remote-tracking branch 'origin/stable-2.0'
[bpt/guile.git] / libguile / fluids.c
CommitLineData
d223c3fc 1/* Copyright (C) 1996,1997,2000,2001, 2004, 2006, 2007, 2008, 2009, 2010, 2011 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],
47ed8656 163 SCM_HEAP_OBJECT_BASE (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),
ed4d7cee 182 "Return a newly created fluid.\n"
9de87eea
MV
183 "Fluids are objects that can hold one\n"
184 "value per dynamic state. That is, modifications to this value are\n"
185 "only visible to code that executes with the same dynamic state as\n"
186 "the modifying code. When a new dynamic state is constructed, it\n"
187 "inherits the values from its parent. Because each thread normally executes\n"
188 "with its own dynamic state, you can use fluids for thread local storage.")
aafb4ed7 189#define FUNC_NAME s_scm_make_fluid_with_default
9482a297 190{
aafb4ed7 191 return new_fluid (SCM_UNBNDP (dflt) ? SCM_BOOL_F : dflt);
9482a297 192}
1bbd0b84 193#undef FUNC_NAME
9482a297 194
e01163b5 195SCM_DEFINE (scm_make_unbound_fluid, "make-unbound-fluid", 0, 0, 0,
ef94624e 196 (),
e01163b5
AW
197 "Make a fluid that is initially unbound.")
198#define FUNC_NAME s_scm_make_unbound_fluid
ef94624e 199{
aafb4ed7 200 return new_fluid (SCM_UNDEFINED);
ef94624e
BT
201}
202#undef FUNC_NAME
203
a1ec6916 204SCM_DEFINE (scm_fluid_p, "fluid?", 1, 0, 0,
ed4d7cee 205 (SCM obj),
1e6808ea
MG
206 "Return @code{#t} iff @var{obj} is a fluid; otherwise, return\n"
207 "@code{#f}.")
1bbd0b84 208#define FUNC_NAME s_scm_fluid_p
b3460a50 209{
9de87eea 210 return scm_from_bool (IS_FLUID (obj));
b3460a50 211}
1bbd0b84 212#undef FUNC_NAME
b3460a50 213
9de87eea
MV
214int
215scm_is_fluid (SCM obj)
216{
217 return IS_FLUID (obj);
218}
219
ef94624e
BT
220/* Does not check type of `fluid'! */
221static SCM
222fluid_ref (SCM fluid)
9482a297 223{
aafb4ed7 224 SCM ret;
9de87eea 225 SCM fluids = DYNAMIC_STATE_FLUIDS (SCM_I_CURRENT_THREAD->dynamic_state);
9482a297 226
8b039053
LC
227 if (SCM_UNLIKELY (FLUID_NUM (fluid) >= SCM_SIMPLE_VECTOR_LENGTH (fluids)))
228 {
8b039053
LC
229 /* Lazily grow the current thread's dynamic state. */
230 grow_dynamic_state (SCM_I_CURRENT_THREAD->dynamic_state);
231
232 fluids = DYNAMIC_STATE_FLUIDS (SCM_I_CURRENT_THREAD->dynamic_state);
233 }
234
aafb4ed7
AW
235 ret = SCM_SIMPLE_VECTOR_REF (fluids, FLUID_NUM (fluid));
236 if (SCM_UNBNDP (ret))
237 return SCM_I_FLUID_DEFAULT (fluid);
238 else
239 return ret;
9482a297 240}
ef94624e
BT
241
242SCM_DEFINE (scm_fluid_ref, "fluid-ref", 1, 0, 0,
243 (SCM fluid),
244 "Return the value associated with @var{fluid} in the current\n"
245 "dynamic root. If @var{fluid} has not been set, then return\n"
246 "@code{#f}.")
247#define FUNC_NAME s_scm_fluid_ref
248{
249 SCM val;
250 SCM_VALIDATE_FLUID (1, fluid);
251 val = fluid_ref (fluid);
252 if (SCM_UNBNDP (val))
253 SCM_MISC_ERROR ("unbound fluid: ~S",
254 scm_list_1 (fluid));
255 return val;
256}
1bbd0b84 257#undef FUNC_NAME
9482a297 258
a1ec6916 259SCM_DEFINE (scm_fluid_set_x, "fluid-set!", 2, 0, 0,
ed4d7cee
GB
260 (SCM fluid, SCM value),
261 "Set the value associated with @var{fluid} in the current dynamic root.")
1bbd0b84 262#define FUNC_NAME s_scm_fluid_set_x
9482a297 263{
9de87eea 264 SCM fluids = DYNAMIC_STATE_FLUIDS (SCM_I_CURRENT_THREAD->dynamic_state);
9482a297 265
ed4d7cee 266 SCM_VALIDATE_FLUID (1, fluid);
8b039053
LC
267
268 if (SCM_UNLIKELY (FLUID_NUM (fluid) >= SCM_SIMPLE_VECTOR_LENGTH (fluids)))
269 {
8b039053
LC
270 /* Lazily grow the current thread's dynamic state. */
271 grow_dynamic_state (SCM_I_CURRENT_THREAD->dynamic_state);
272
273 fluids = DYNAMIC_STATE_FLUIDS (SCM_I_CURRENT_THREAD->dynamic_state);
274 }
275
9de87eea 276 SCM_SIMPLE_VECTOR_SET (fluids, FLUID_NUM (fluid), value);
86f9f9ae 277 return SCM_UNSPECIFIED;
9482a297 278}
1bbd0b84 279#undef FUNC_NAME
9482a297 280
ef94624e
BT
281SCM_DEFINE (scm_fluid_unset_x, "fluid-unset!", 1, 0, 0,
282 (SCM fluid),
283 "Unset the value associated with @var{fluid}.")
284#define FUNC_NAME s_scm_fluid_unset_x
285{
aafb4ed7
AW
286 /* FIXME: really unset the default value, too? The current test
287 suite demands it, but I would prefer not to. */
288 SCM_SET_CELL_OBJECT_1 (fluid, SCM_UNDEFINED);
ef94624e
BT
289 return scm_fluid_set_x (fluid, SCM_UNDEFINED);
290}
291#undef FUNC_NAME
292
293SCM_DEFINE (scm_fluid_bound_p, "fluid-bound?", 1, 0, 0,
294 (SCM fluid),
295 "Return @code{#t} iff @var{fluid} is bound to a value.\n"
296 "Throw an error if @var{fluid} is not a fluid.")
297#define FUNC_NAME s_scm_fluid_bound_p
298{
299 SCM val;
300 SCM_VALIDATE_FLUID (1, fluid);
301 val = fluid_ref (fluid);
302 return scm_from_bool (! (SCM_UNBNDP (val)));
303}
304#undef FUNC_NAME
305
bb0229b5
AW
306static SCM
307apply_thunk (void *thunk)
b3460a50 308{
bb0229b5
AW
309 return scm_call_0 (SCM_PACK (thunk));
310}
311
312SCM
313scm_i_make_with_fluids (size_t n, SCM *fluids, SCM *vals)
314{
315 SCM ret;
316
317 /* Ensure that there are no duplicates in the fluids set -- an N^2 operation,
318 but N will usually be small, so perhaps that's OK. */
319 {
320 size_t i, j = n;
321
322 while (j--)
323 for (i = 0; i < j; i++)
d223c3fc 324 if (scm_is_eq (fluids[i], fluids[j]))
bb0229b5
AW
325 {
326 vals[i] = vals[j]; /* later bindings win */
327 n--;
328 break;
329 }
330 }
331
332 ret = scm_words (scm_tc7_with_fluids | (n << 8), 1 + n*2);
333 SCM_SET_CELL_WORD_1 (ret, n);
334
335 while (n--)
b3460a50 336 {
bb0229b5
AW
337 if (SCM_UNLIKELY (!IS_FLUID (fluids[n])))
338 scm_wrong_type_arg ("with-fluids", 0, fluids[n]);
339 SCM_SET_CELL_OBJECT (ret, 1 + n * 2, fluids[n]);
340 SCM_SET_CELL_OBJECT (ret, 2 + n * 2, vals[n]);
b3460a50 341 }
bb0229b5
AW
342
343 return ret;
b3460a50 344}
bb0229b5
AW
345
346void
347scm_i_swap_with_fluids (SCM wf, SCM dynstate)
348{
349 SCM fluids;
350 size_t i, max = 0;
b3460a50 351
bb0229b5 352 fluids = DYNAMIC_STATE_FLUIDS (dynstate);
b3460a50 353
bb0229b5
AW
354 /* We could cache the max in the with-fluids, but that would take more mem,
355 and we're touching all the fluids anyway, so this per-swap traversal should
356 be OK. */
357 for (i = 0; i < SCM_WITH_FLUIDS_LEN (wf); i++)
b3460a50 358 {
bb0229b5
AW
359 size_t num = FLUID_NUM (SCM_WITH_FLUIDS_NTH_FLUID (wf, i));
360 max = (max > num) ? max : num;
b3460a50 361 }
b3460a50 362
bb0229b5
AW
363 if (SCM_UNLIKELY (max >= SCM_SIMPLE_VECTOR_LENGTH (fluids)))
364 {
bb0229b5
AW
365 /* Lazily grow the current thread's dynamic state. */
366 grow_dynamic_state (dynstate);
367
368 fluids = DYNAMIC_STATE_FLUIDS (dynstate);
369 }
1bbd0b84 370
bb0229b5
AW
371 /* Bind the fluids. Order doesn't matter, as all fluids are distinct. */
372 for (i = 0; i < SCM_WITH_FLUIDS_LEN (wf); i++)
373 {
374 size_t fluid_num;
375 SCM x;
376
377 fluid_num = FLUID_NUM (SCM_WITH_FLUIDS_NTH_FLUID (wf, i));
378 x = SCM_SIMPLE_VECTOR_REF (fluids, fluid_num);
379 SCM_SIMPLE_VECTOR_SET (fluids, fluid_num,
380 SCM_WITH_FLUIDS_NTH_VAL (wf, i));
381 SCM_WITH_FLUIDS_SET_NTH_VAL (wf, i, x);
382 }
383}
384
a1ec6916 385SCM_DEFINE (scm_with_fluids, "with-fluids*", 3, 0, 0,
ed4d7cee
GB
386 (SCM fluids, SCM values, SCM thunk),
387 "Set @var{fluids} to @var{values} temporary, and call @var{thunk}.\n"
388 "@var{fluids} must be a list of fluids and @var{values} must be the same\n"
389 "number of their values to be applied. Each substitution is done\n"
390 "one after another. @var{thunk} must be a procedure with no argument.")
1bbd0b84
GB
391#define FUNC_NAME s_scm_with_fluids
392{
bebd3fba
MV
393 return scm_c_with_fluids (fluids, values,
394 apply_thunk, (void *) SCM_UNPACK (thunk));
1bbd0b84
GB
395}
396#undef FUNC_NAME
b3460a50
MV
397
398SCM
143e0902
MV
399scm_c_with_fluids (SCM fluids, SCM values, SCM (*cproc) (), void *cdata)
400#define FUNC_NAME "scm_c_with_fluids"
b3460a50 401{
bb0229b5
AW
402 SCM wf, ans;
403 long flen, vlen, i;
404 SCM *fluidsv, *valuesv;
b3460a50 405
c1bfcf60 406 SCM_VALIDATE_LIST_COPYLEN (1, fluids, flen);
ed4d7cee 407 SCM_VALIDATE_LIST_COPYLEN (2, values, vlen);
b3460a50 408 if (flen != vlen)
ed4d7cee 409 scm_out_of_range (s_scm_with_fluids, values);
b3460a50 410
bb0229b5
AW
411 if (SCM_UNLIKELY (flen == 0))
412 return cproc (cdata);
413
414 fluidsv = alloca (sizeof(SCM)*flen);
415 valuesv = alloca (sizeof(SCM)*flen);
bebd3fba 416
bb0229b5
AW
417 for (i = 0; i < flen; i++)
418 {
419 fluidsv[i] = SCM_CAR (fluids);
420 fluids = SCM_CDR (fluids);
421 valuesv[i] = SCM_CAR (values);
422 values = SCM_CDR (values);
423 }
424
425 wf = scm_i_make_with_fluids (flen, fluidsv, valuesv);
426 scm_i_swap_with_fluids (wf, SCM_I_CURRENT_THREAD->dynamic_state);
427 scm_i_set_dynwinds (scm_cons (wf, scm_i_dynwinds ()));
b3460a50 428 ans = cproc (cdata);
bb0229b5
AW
429 scm_i_swap_with_fluids (wf, SCM_I_CURRENT_THREAD->dynamic_state);
430 scm_i_set_dynwinds (scm_cdr (scm_i_dynwinds ()));
431
b3460a50
MV
432 return ans;
433}
c1bfcf60 434#undef FUNC_NAME
b3460a50 435
bebd3fba
MV
436SCM_DEFINE (scm_with_fluid, "with-fluid*", 3, 0, 0,
437 (SCM fluid, SCM value, SCM thunk),
438 "Set @var{fluid} to @var{value} temporarily, and call @var{thunk}.\n"
439 "@var{thunk} must be a procedure with no argument.")
440#define FUNC_NAME s_scm_with_fluid
441{
442 return scm_c_with_fluid (fluid, value,
443 apply_thunk, (void *) SCM_UNPACK (thunk));
444}
445#undef FUNC_NAME
446
143e0902
MV
447SCM
448scm_c_with_fluid (SCM fluid, SCM value, SCM (*cproc) (), void *cdata)
449#define FUNC_NAME "scm_c_with_fluid"
450{
bb0229b5 451 SCM ans, wf;
bebd3fba 452
bb0229b5
AW
453 wf = scm_i_make_with_fluids (1, &fluid, &value);
454 scm_i_swap_with_fluids (wf, SCM_I_CURRENT_THREAD->dynamic_state);
455 scm_i_set_dynwinds (scm_cons (wf, scm_i_dynwinds ()));
bebd3fba 456 ans = cproc (cdata);
bb0229b5
AW
457 scm_i_swap_with_fluids (wf, SCM_I_CURRENT_THREAD->dynamic_state);
458 scm_i_set_dynwinds (scm_cdr (scm_i_dynwinds ()));
459
bebd3fba 460 return ans;
143e0902
MV
461}
462#undef FUNC_NAME
b3460a50 463
ef20bf70
MV
464static void
465swap_fluid (SCM data)
466{
467 SCM f = SCM_CAR (data);
ef94624e 468 SCM t = fluid_ref (f);
ef20bf70
MV
469 scm_fluid_set_x (f, SCM_CDR (data));
470 SCM_SETCDR (data, t);
471}
472
473void
661ae7ab 474scm_dynwind_fluid (SCM fluid, SCM value)
ef20bf70
MV
475{
476 SCM data = scm_cons (fluid, value);
661ae7ab
MV
477 scm_dynwind_rewind_handler_with_scm (swap_fluid, data, SCM_F_WIND_EXPLICITLY);
478 scm_dynwind_unwind_handler_with_scm (swap_fluid, data, SCM_F_WIND_EXPLICITLY);
ef20bf70
MV
479}
480
9de87eea
MV
481SCM
482scm_i_make_initial_dynamic_state ()
483{
484 SCM fluids = scm_c_make_vector (allocated_fluids_len, SCM_BOOL_F);
9ea31741 485 return scm_cell (scm_tc7_dynamic_state, SCM_UNPACK (fluids));
9de87eea
MV
486}
487
488SCM_DEFINE (scm_make_dynamic_state, "make-dynamic-state", 0, 1, 0,
489 (SCM parent),
490 "Return a copy of the dynamic state object @var{parent}\n"
491 "or of the current dynamic state when @var{parent} is omitted.")
492#define FUNC_NAME s_scm_make_dynamic_state
493{
9ea31741 494 SCM fluids;
9de87eea
MV
495
496 if (SCM_UNBNDP (parent))
497 parent = scm_current_dynamic_state ();
498
9ea31741 499 SCM_ASSERT (IS_DYNAMIC_STATE (parent), parent, SCM_ARG1, FUNC_NAME);
9de87eea 500 fluids = scm_vector_copy (DYNAMIC_STATE_FLUIDS (parent));
9ea31741 501 return scm_cell (scm_tc7_dynamic_state, SCM_UNPACK (fluids));
9de87eea
MV
502}
503#undef FUNC_NAME
504
505SCM_DEFINE (scm_dynamic_state_p, "dynamic-state?", 1, 0, 0,
506 (SCM obj),
507 "Return @code{#t} if @var{obj} is a dynamic state object;\n"
508 "return @code{#f} otherwise")
509#define FUNC_NAME s_scm_dynamic_state_p
510{
511 return scm_from_bool (IS_DYNAMIC_STATE (obj));
512}
513#undef FUNC_NAME
514
515int
516scm_is_dynamic_state (SCM obj)
517{
518 return IS_DYNAMIC_STATE (obj);
519}
520
521SCM_DEFINE (scm_current_dynamic_state, "current-dynamic-state", 0, 0, 0,
522 (),
523 "Return the current dynamic state object.")
524#define FUNC_NAME s_scm_current_dynamic_state
525{
526 return SCM_I_CURRENT_THREAD->dynamic_state;
527}
528#undef FUNC_NAME
529
530SCM_DEFINE (scm_set_current_dynamic_state, "set-current-dynamic-state", 1,0,0,
531 (SCM state),
532 "Set the current dynamic state object to @var{state}\n"
533 "and return the previous current dynamic state object.")
534#define FUNC_NAME s_scm_set_current_dynamic_state
535{
536 scm_i_thread *t = SCM_I_CURRENT_THREAD;
537 SCM old = t->dynamic_state;
9ea31741 538 SCM_ASSERT (IS_DYNAMIC_STATE (state), state, SCM_ARG1, FUNC_NAME);
9de87eea
MV
539 t->dynamic_state = state;
540 return old;
541}
542#undef FUNC_NAME
543
544static void
545swap_dynamic_state (SCM loc)
546{
547 SCM_SETCAR (loc, scm_set_current_dynamic_state (SCM_CAR (loc)));
548}
549
550void
661ae7ab 551scm_dynwind_current_dynamic_state (SCM state)
9de87eea
MV
552{
553 SCM loc = scm_cons (state, SCM_EOL);
9ea31741 554 SCM_ASSERT (IS_DYNAMIC_STATE (state), state, SCM_ARG1, NULL);
661ae7ab 555 scm_dynwind_rewind_handler_with_scm (swap_dynamic_state, loc,
9de87eea 556 SCM_F_WIND_EXPLICITLY);
661ae7ab 557 scm_dynwind_unwind_handler_with_scm (swap_dynamic_state, loc,
9de87eea
MV
558 SCM_F_WIND_EXPLICITLY);
559}
560
561void *
562scm_c_with_dynamic_state (SCM state, void *(*func)(void *), void *data)
563{
564 void *result;
661ae7ab
MV
565 scm_dynwind_begin (SCM_F_DYNWIND_REWINDABLE);
566 scm_dynwind_current_dynamic_state (state);
9de87eea 567 result = func (data);
661ae7ab 568 scm_dynwind_end ();
9de87eea
MV
569 return result;
570}
571
572SCM_DEFINE (scm_with_dynamic_state, "with-dynamic-state", 2, 0, 0,
573 (SCM state, SCM proc),
574 "Call @var{proc} while @var{state} is the current dynamic\n"
575 "state object.")
576#define FUNC_NAME s_scm_with_dynamic_state
577{
578 SCM result;
661ae7ab
MV
579 scm_dynwind_begin (SCM_F_DYNWIND_REWINDABLE);
580 scm_dynwind_current_dynamic_state (state);
9de87eea 581 result = scm_call_0 (proc);
661ae7ab 582 scm_dynwind_end ();
9de87eea
MV
583 return result;
584}
585#undef FUNC_NAME
586
9de87eea 587
9482a297
MV
588void
589scm_init_fluids ()
590{
a0599745 591#include "libguile/fluids.x"
9482a297 592}
89e00824
ML
593
594/*
595 Local Variables:
596 c-file-style: "gnu"
597 End:
598*/