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