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