Use immutable cells for vectors.
[bpt/guile.git] / libguile / fluids.c
CommitLineData
dbb605f5 1/* Copyright (C) 1996,1997,2000,2001, 2004, 2006, 2007, 2008 Free Software Foundation, Inc.
9482a297 2 *
73be1d9e
MV
3 * This library is free software; you can redistribute it and/or
4 * modify it under the terms of the GNU Lesser General Public
5 * License as published by the Free Software Foundation; either
6 * version 2.1 of the License, or (at your option) any later version.
9482a297 7 *
73be1d9e
MV
8 * This library is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
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
92205699 15 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
73be1d9e 16 */
9482a297 17
dbb605f5
LC
18#ifdef HAVE_CONFIG_H
19# include <config.h>
20#endif
21
9de87eea
MV
22#include <stdio.h>
23#include <string.h>
1bbd0b84 24
a0599745
MD
25#include "libguile/_scm.h"
26#include "libguile/print.h"
27#include "libguile/smob.h"
28#include "libguile/dynwind.h"
29#include "libguile/fluids.h"
30#include "libguile/alist.h"
31#include "libguile/eval.h"
32#include "libguile/ports.h"
143e0902 33#include "libguile/deprecation.h"
c96d76b8 34#include "libguile/lang.h"
a0599745 35#include "libguile/validate.h"
9482a297 36
9de87eea
MV
37#define FLUID_GROW 20
38
39/* A lot of the complexity below stems from the desire to reuse fluid
40 slots. Normally, fluids should be pretty global and long-lived
41 things, so that reusing their slots should not be overly critical,
42 but it is the right thing to do nevertheless. The code therefore
43 puts the burdon on allocating and collection fluids and keeps
44 accessing fluids lock free. This is achieved by manipulating the
45 global state of the fluid machinery mostly in single threaded
46 sections.
47
48 Reusing a fluid slot means that it must be reset to #f in all
49 dynamic states. We do this by maintaining a weak list of all
50 dynamic states, which is used after a GC to do the resetting.
51
52 Also, the fluid vectors in the dynamic states need to grow from
53 time to time when more fluids are created. We do this in a single
54 threaded section so that threads do not need to lock when accessing
55 a fluid in the normal way.
56*/
9482a297 57
9de87eea
MV
58static scm_i_pthread_mutex_t fluid_admin_mutex = SCM_I_PTHREAD_MUTEX_INITIALIZER;
59
60/* Protected by fluid_admin_mutex, but also accessed during GC. See
61 next_fluid_num for a discussion of this.
62 */
63static size_t allocated_fluids_len = 0;
64static size_t allocated_fluids_num = 0;
65static char *allocated_fluids = NULL;
66
67static scm_t_bits tc16_fluid;
68
69#define IS_FLUID(x) SCM_SMOB_PREDICATE(tc16_fluid, (x))
70#define FLUID_NUM(x) ((size_t)SCM_SMOB_DATA(x))
71#define FLUID_NEXT(x) SCM_SMOB_OBJECT_2(x)
645dd3fc 72#define FLUID_NEXT_LOC(x) SCM_SMOB_OBJECT_2_LOC(x)
9de87eea
MV
73#define SET_FLUID_NEXT(x,y) SCM_SET_SMOB_OBJECT_2((x), (y))
74
75static scm_t_bits tc16_dynamic_state;
76
77#define IS_DYNAMIC_STATE(x) SCM_SMOB_PREDICATE(tc16_dynamic_state, (x))
78#define DYNAMIC_STATE_FLUIDS(x) SCM_SMOB_OBJECT(x)
79#define SET_DYNAMIC_STATE_FLUIDS(x, y) SCM_SET_SMOB_OBJECT((x), (y))
80#define DYNAMIC_STATE_NEXT(x) SCM_SMOB_OBJECT_2(x)
645dd3fc 81#define DYNAMIC_STATE_NEXT_LOC(x) SCM_SMOB_OBJECT_2_LOC(x)
9de87eea
MV
82#define SET_DYNAMIC_STATE_NEXT(x, y) SCM_SET_SMOB_OBJECT_2((x), (y))
83
84/* Weak lists of all dynamic states and all fluids.
85 */
86static SCM all_dynamic_states = SCM_EOL;
87static SCM all_fluids = SCM_EOL;
88
9de87eea
MV
89/* Make sure that all states have the right size. This must be called
90 while fluid_admin_mutex is held.
91*/
9482a297 92static void
b5fa979c 93resize_all_states ()
9de87eea 94{
b5fa979c
MV
95 SCM new_vectors, state;
96
97 /* Replacing the vector of a dynamic state must be done atomically:
98 the old values must be copied into the new vector and the new
99 vector must be installed without someone modifying the old vector
100 concurrently. Since accessing a fluid should be lock-free, we
101 need to put all threads to sleep when replacing a vector.
102 However, when being single threaded, it is best not to do much.
103 Therefore, we allocate the new vectors before going single
104 threaded.
105 */
9de87eea 106
b5fa979c
MV
107 new_vectors = SCM_EOL;
108 for (state = all_dynamic_states; !scm_is_null (state);
109 state = DYNAMIC_STATE_NEXT (state))
110 new_vectors = scm_cons (scm_c_make_vector (allocated_fluids_len,
111 SCM_BOOL_F),
112 new_vectors);
9de87eea 113
b5fa979c 114 scm_i_thread_put_to_sleep ();
9de87eea
MV
115 for (state = all_dynamic_states; !scm_is_null (state);
116 state = DYNAMIC_STATE_NEXT (state))
b5fa979c
MV
117 {
118 SCM old_fluids = DYNAMIC_STATE_FLUIDS (state);
119 SCM new_fluids = SCM_CAR (new_vectors);
120 size_t i, old_len = SCM_SIMPLE_VECTOR_LENGTH (old_fluids);
9de87eea 121
b5fa979c
MV
122 for (i = 0; i < old_len; i++)
123 SCM_SIMPLE_VECTOR_SET (new_fluids, i,
124 SCM_SIMPLE_VECTOR_REF (old_fluids, i));
125 SET_DYNAMIC_STATE_FLUIDS (state, new_fluids);
126 new_vectors = SCM_CDR (new_vectors);
127 }
128 scm_i_thread_wake_up ();
9de87eea
MV
129}
130
131/* This is called during GC, that is, while being single threaded.
132 See next_fluid_num for a discussion why it is safe to access
133 allocated_fluids here.
134 */
135static void *
136scan_dynamic_states_and_fluids (void *dummy1 SCM_UNUSED,
137 void *dummy2 SCM_UNUSED,
138 void *dummy3 SCM_UNUSED)
9482a297 139{
26224b3f
LC
140 /* FIXME: What to do here? */
141#if 0
9de87eea 142 SCM *statep, *fluidp;
9482a297 143
9de87eea
MV
144 /* Scan all fluids and deallocate the unmarked ones.
145 */
146 fluidp = &all_fluids;
147 while (!scm_is_null (*fluidp))
9482a297 148 {
9de87eea
MV
149 if (!SCM_GC_MARK_P (*fluidp))
150 {
151 allocated_fluids_num -= 1;
152 allocated_fluids[FLUID_NUM (*fluidp)] = 0;
153 *fluidp = FLUID_NEXT (*fluidp);
154 }
155 else
645dd3fc 156 fluidp = FLUID_NEXT_LOC (*fluidp);
9482a297 157 }
9de87eea
MV
158
159 /* Scan all dynamic states and remove the unmarked ones. The live
160 ones are updated for unallocated fluids.
161 */
162 statep = &all_dynamic_states;
163 while (!scm_is_null (*statep))
9482a297 164 {
9de87eea
MV
165 if (!SCM_GC_MARK_P (*statep))
166 *statep = DYNAMIC_STATE_NEXT (*statep);
167 else
168 {
169 SCM fluids = DYNAMIC_STATE_FLUIDS (*statep);
170 size_t len, i;
171
172 len = SCM_SIMPLE_VECTOR_LENGTH (fluids);
173 for (i = 0; i < len && i < allocated_fluids_len; i++)
174 if (allocated_fluids[i] == 0)
175 SCM_SIMPLE_VECTOR_SET (fluids, i, SCM_BOOL_F);
176
645dd3fc 177 statep = DYNAMIC_STATE_NEXT_LOC (*statep);
9de87eea 178 }
9482a297
MV
179 }
180
26224b3f 181#endif
9de87eea 182 return NULL;
9482a297
MV
183}
184
9482a297 185static int
e81d98ec 186fluid_print (SCM exp, SCM port, scm_print_state *pstate SCM_UNUSED)
9482a297 187{
ed4d7cee 188 scm_puts ("#<fluid ", port);
9de87eea 189 scm_intprint ((int) FLUID_NUM (exp), 10, port);
ed4d7cee
GB
190 scm_putc ('>', port);
191 return 1;
9482a297
MV
192}
193
9de87eea 194static size_t
ed4d7cee 195next_fluid_num ()
9482a297 196{
9de87eea
MV
197 size_t n;
198
661ae7ab
MV
199 scm_dynwind_begin (0);
200 scm_i_dynwind_pthread_mutex_lock (&fluid_admin_mutex);
9de87eea 201
29295b0c
NJ
202 if ((allocated_fluids_len > 0) &&
203 (allocated_fluids_num == allocated_fluids_len))
9de87eea
MV
204 {
205 /* All fluid numbers are in use. Run a GC to try to free some
206 up.
207 */
208 scm_gc ();
209 }
210
211 if (allocated_fluids_num < allocated_fluids_len)
212 {
213 for (n = 0; n < allocated_fluids_len; n++)
214 if (allocated_fluids[n] == 0)
215 break;
216 }
217 else
218 {
219 /* During the following call, the GC might run and elements of
220 allocated_fluids might bet set to zero. Also,
221 allocated_fluids and allocated_fluids_len are used to scan
222 all dynamic states during GC. Thus we need to make sure that
223 no GC can run while updating these two variables.
224 */
225
d3075c52
LC
226 char *prev_allocated_fluids;
227 char *new_allocated_fluids =
9de87eea
MV
228 scm_malloc (allocated_fluids_len + FLUID_GROW);
229
230 /* Copy over old values and initialize rest. GC can not run
231 during these two operations since there is no safe point in
232 them.
233 */
234 memcpy (new_allocated_fluids, allocated_fluids, allocated_fluids_len);
235 memset (new_allocated_fluids + allocated_fluids_len, 0, FLUID_GROW);
236 n = allocated_fluids_len;
d3075c52
LC
237
238 prev_allocated_fluids = allocated_fluids;
9de87eea
MV
239 allocated_fluids = new_allocated_fluids;
240 allocated_fluids_len += FLUID_GROW;
d3075c52
LC
241
242 if (prev_allocated_fluids != NULL)
243 free (prev_allocated_fluids);
244
9de87eea
MV
245 /* Now allocated_fluids and allocated_fluids_len are valid again
246 and we can allow GCs to occur.
247 */
b5fa979c 248 resize_all_states ();
9de87eea
MV
249 }
250
251 allocated_fluids_num += 1;
252 allocated_fluids[n] = 1;
253
661ae7ab 254 scm_dynwind_end ();
9482a297
MV
255 return n;
256}
257
a1ec6916 258SCM_DEFINE (scm_make_fluid, "make-fluid", 0, 0, 0,
ed4d7cee
GB
259 (),
260 "Return a newly created fluid.\n"
9de87eea
MV
261 "Fluids are objects that can hold one\n"
262 "value per dynamic state. That is, modifications to this value are\n"
263 "only visible to code that executes with the same dynamic state as\n"
264 "the modifying code. When a new dynamic state is constructed, it\n"
265 "inherits the values from its parent. Because each thread normally executes\n"
266 "with its own dynamic state, you can use fluids for thread local storage.")
1bbd0b84 267#define FUNC_NAME s_scm_make_fluid
9482a297 268{
9de87eea 269 SCM fluid;
9482a297 270
9de87eea
MV
271 SCM_NEWSMOB2 (fluid, tc16_fluid,
272 (scm_t_bits) next_fluid_num (), SCM_UNPACK (SCM_EOL));
273
274 /* The GC must not run until the fluid is properly entered into the
275 list.
276 */
b5fa979c 277 scm_i_scm_pthread_mutex_lock (&fluid_admin_mutex);
9de87eea
MV
278 SET_FLUID_NEXT (fluid, all_fluids);
279 all_fluids = fluid;
b5fa979c 280 scm_i_pthread_mutex_unlock (&fluid_admin_mutex);
9de87eea
MV
281
282 return fluid;
9482a297 283}
1bbd0b84 284#undef FUNC_NAME
9482a297 285
a1ec6916 286SCM_DEFINE (scm_fluid_p, "fluid?", 1, 0, 0,
ed4d7cee 287 (SCM obj),
1e6808ea
MG
288 "Return @code{#t} iff @var{obj} is a fluid; otherwise, return\n"
289 "@code{#f}.")
1bbd0b84 290#define FUNC_NAME s_scm_fluid_p
b3460a50 291{
9de87eea 292 return scm_from_bool (IS_FLUID (obj));
b3460a50 293}
1bbd0b84 294#undef FUNC_NAME
b3460a50 295
9de87eea
MV
296int
297scm_is_fluid (SCM obj)
298{
299 return IS_FLUID (obj);
300}
301
302size_t
303scm_i_fluid_num (SCM fluid)
304{
305 return FLUID_NUM (fluid);
306}
307
a1ec6916 308SCM_DEFINE (scm_fluid_ref, "fluid-ref", 1, 0, 0,
ed4d7cee 309 (SCM fluid),
1e6808ea
MG
310 "Return the value associated with @var{fluid} in the current\n"
311 "dynamic root. If @var{fluid} has not been set, then return\n"
312 "@code{#f}.")
1bbd0b84 313#define FUNC_NAME s_scm_fluid_ref
9482a297 314{
9de87eea 315 SCM fluids = DYNAMIC_STATE_FLUIDS (SCM_I_CURRENT_THREAD->dynamic_state);
9482a297 316
ed4d7cee 317 SCM_VALIDATE_FLUID (1, fluid);
9de87eea 318 return SCM_SIMPLE_VECTOR_REF (fluids, FLUID_NUM (fluid));
9482a297 319}
1bbd0b84 320#undef FUNC_NAME
9482a297 321
9de87eea
MV
322SCM
323scm_i_fast_fluid_ref (size_t n)
324{
325 SCM fluids = DYNAMIC_STATE_FLUIDS (SCM_I_CURRENT_THREAD->dynamic_state);
326 return SCM_SIMPLE_VECTOR_REF (fluids, n);
327}
328
a1ec6916 329SCM_DEFINE (scm_fluid_set_x, "fluid-set!", 2, 0, 0,
ed4d7cee
GB
330 (SCM fluid, SCM value),
331 "Set the value associated with @var{fluid} in the current dynamic root.")
1bbd0b84 332#define FUNC_NAME s_scm_fluid_set_x
9482a297 333{
9de87eea 334 SCM fluids = DYNAMIC_STATE_FLUIDS (SCM_I_CURRENT_THREAD->dynamic_state);
9482a297 335
ed4d7cee 336 SCM_VALIDATE_FLUID (1, fluid);
9de87eea 337 SCM_SIMPLE_VECTOR_SET (fluids, FLUID_NUM (fluid), value);
86f9f9ae 338 return SCM_UNSPECIFIED;
9482a297 339}
1bbd0b84 340#undef FUNC_NAME
9482a297 341
9de87eea
MV
342void
343scm_i_fast_fluid_set_x (size_t n, SCM value)
344{
345 SCM fluids = DYNAMIC_STATE_FLUIDS (SCM_I_CURRENT_THREAD->dynamic_state);
346 SCM_SIMPLE_VECTOR_SET (fluids, n, value);
347}
348
bebd3fba
MV
349static void
350swap_fluids (SCM data)
b3460a50 351{
bebd3fba
MV
352 SCM fluids = SCM_CAR (data), vals = SCM_CDR (data);
353
c96d76b8 354 while (!SCM_NULL_OR_NIL_P (fluids))
b3460a50
MV
355 {
356 SCM fl = SCM_CAR (fluids);
357 SCM old_val = scm_fluid_ref (fl);
358 scm_fluid_set_x (fl, SCM_CAR (vals));
359 SCM_SETCAR (vals, old_val);
360 fluids = SCM_CDR (fluids);
361 vals = SCM_CDR (vals);
362 }
363}
364
365/* Swap the fluid values in reverse order. This is important when the
9de87eea
MV
366 same fluid appears multiple times in the fluids list.
367*/
b3460a50 368
bebd3fba
MV
369static void
370swap_fluids_reverse_aux (SCM fluids, SCM vals)
b3460a50 371{
c96d76b8 372 if (!SCM_NULL_OR_NIL_P (fluids))
b3460a50
MV
373 {
374 SCM fl, old_val;
375
bebd3fba 376 swap_fluids_reverse_aux (SCM_CDR (fluids), SCM_CDR (vals));
b3460a50
MV
377 fl = SCM_CAR (fluids);
378 old_val = scm_fluid_ref (fl);
379 scm_fluid_set_x (fl, SCM_CAR (vals));
380 SCM_SETCAR (vals, old_val);
381 }
382}
383
bebd3fba
MV
384static void
385swap_fluids_reverse (SCM data)
386{
387 swap_fluids_reverse_aux (SCM_CAR (data), SCM_CDR (data));
388}
1bbd0b84
GB
389
390static SCM
391apply_thunk (void *thunk)
392{
fdc28395 393 return scm_call_0 (SCM_PACK (thunk));
1bbd0b84
GB
394}
395
a1ec6916 396SCM_DEFINE (scm_with_fluids, "with-fluids*", 3, 0, 0,
ed4d7cee
GB
397 (SCM fluids, SCM values, SCM thunk),
398 "Set @var{fluids} to @var{values} temporary, and call @var{thunk}.\n"
399 "@var{fluids} must be a list of fluids and @var{values} must be the same\n"
400 "number of their values to be applied. Each substitution is done\n"
401 "one after another. @var{thunk} must be a procedure with no argument.")
1bbd0b84
GB
402#define FUNC_NAME s_scm_with_fluids
403{
bebd3fba
MV
404 return scm_c_with_fluids (fluids, values,
405 apply_thunk, (void *) SCM_UNPACK (thunk));
1bbd0b84
GB
406}
407#undef FUNC_NAME
b3460a50
MV
408
409SCM
143e0902
MV
410scm_c_with_fluids (SCM fluids, SCM values, SCM (*cproc) (), void *cdata)
411#define FUNC_NAME "scm_c_with_fluids"
b3460a50 412{
bebd3fba 413 SCM ans, data;
c014a02e 414 long flen, vlen;
b3460a50 415
c1bfcf60 416 SCM_VALIDATE_LIST_COPYLEN (1, fluids, flen);
ed4d7cee 417 SCM_VALIDATE_LIST_COPYLEN (2, values, vlen);
b3460a50 418 if (flen != vlen)
ed4d7cee 419 scm_out_of_range (s_scm_with_fluids, values);
b3460a50 420
bebd3fba
MV
421 if (flen == 1)
422 return scm_c_with_fluid (SCM_CAR (fluids), SCM_CAR (values),
423 cproc, cdata);
424
425 data = scm_cons (fluids, values);
661ae7ab
MV
426 scm_dynwind_begin (SCM_F_DYNWIND_REWINDABLE);
427 scm_dynwind_rewind_handler_with_scm (swap_fluids, data,
16c5cac2 428 SCM_F_WIND_EXPLICITLY);
661ae7ab 429 scm_dynwind_unwind_handler_with_scm (swap_fluids_reverse, data,
16c5cac2 430 SCM_F_WIND_EXPLICITLY);
b3460a50 431 ans = cproc (cdata);
661ae7ab 432 scm_dynwind_end ();
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{
bebd3fba
MV
452 SCM ans;
453
661ae7ab
MV
454 scm_dynwind_begin (SCM_F_DYNWIND_REWINDABLE);
455 scm_dynwind_fluid (fluid, value);
bebd3fba 456 ans = cproc (cdata);
661ae7ab 457 scm_dynwind_end ();
bebd3fba 458 return ans;
143e0902
MV
459}
460#undef FUNC_NAME
b3460a50 461
ef20bf70
MV
462static void
463swap_fluid (SCM data)
464{
465 SCM f = SCM_CAR (data);
466 SCM t = scm_fluid_ref (f);
467 scm_fluid_set_x (f, SCM_CDR (data));
468 SCM_SETCDR (data, t);
469}
470
471void
661ae7ab 472scm_dynwind_fluid (SCM fluid, SCM value)
ef20bf70
MV
473{
474 SCM data = scm_cons (fluid, value);
661ae7ab
MV
475 scm_dynwind_rewind_handler_with_scm (swap_fluid, data, SCM_F_WIND_EXPLICITLY);
476 scm_dynwind_unwind_handler_with_scm (swap_fluid, data, SCM_F_WIND_EXPLICITLY);
ef20bf70
MV
477}
478
9de87eea
MV
479SCM
480scm_i_make_initial_dynamic_state ()
481{
482 SCM fluids = scm_c_make_vector (allocated_fluids_len, SCM_BOOL_F);
483 SCM state;
484 SCM_NEWSMOB2 (state, tc16_dynamic_state,
485 SCM_UNPACK (fluids), SCM_UNPACK (SCM_EOL));
486 all_dynamic_states = state;
487 return state;
488}
489
490SCM_DEFINE (scm_make_dynamic_state, "make-dynamic-state", 0, 1, 0,
491 (SCM parent),
492 "Return a copy of the dynamic state object @var{parent}\n"
493 "or of the current dynamic state when @var{parent} is omitted.")
494#define FUNC_NAME s_scm_make_dynamic_state
495{
496 SCM fluids, state;
497
498 if (SCM_UNBNDP (parent))
499 parent = scm_current_dynamic_state ();
500
501 scm_assert_smob_type (tc16_dynamic_state, parent);
502 fluids = scm_vector_copy (DYNAMIC_STATE_FLUIDS (parent));
503 SCM_NEWSMOB2 (state, tc16_dynamic_state,
504 SCM_UNPACK (fluids), SCM_UNPACK (SCM_EOL));
505
506 /* The GC must not run until the state is properly entered into the
507 list.
508 */
b5fa979c 509 scm_i_scm_pthread_mutex_lock (&fluid_admin_mutex);
9de87eea
MV
510 SET_DYNAMIC_STATE_NEXT (state, all_dynamic_states);
511 all_dynamic_states = state;
b5fa979c 512 scm_i_pthread_mutex_unlock (&fluid_admin_mutex);
9de87eea 513
9de87eea
MV
514 return state;
515}
516#undef FUNC_NAME
517
518SCM_DEFINE (scm_dynamic_state_p, "dynamic-state?", 1, 0, 0,
519 (SCM obj),
520 "Return @code{#t} if @var{obj} is a dynamic state object;\n"
521 "return @code{#f} otherwise")
522#define FUNC_NAME s_scm_dynamic_state_p
523{
524 return scm_from_bool (IS_DYNAMIC_STATE (obj));
525}
526#undef FUNC_NAME
527
528int
529scm_is_dynamic_state (SCM obj)
530{
531 return IS_DYNAMIC_STATE (obj);
532}
533
534SCM_DEFINE (scm_current_dynamic_state, "current-dynamic-state", 0, 0, 0,
535 (),
536 "Return the current dynamic state object.")
537#define FUNC_NAME s_scm_current_dynamic_state
538{
539 return SCM_I_CURRENT_THREAD->dynamic_state;
540}
541#undef FUNC_NAME
542
543SCM_DEFINE (scm_set_current_dynamic_state, "set-current-dynamic-state", 1,0,0,
544 (SCM state),
545 "Set the current dynamic state object to @var{state}\n"
546 "and return the previous current dynamic state object.")
547#define FUNC_NAME s_scm_set_current_dynamic_state
548{
549 scm_i_thread *t = SCM_I_CURRENT_THREAD;
550 SCM old = t->dynamic_state;
551 scm_assert_smob_type (tc16_dynamic_state, state);
552 t->dynamic_state = state;
553 return old;
554}
555#undef FUNC_NAME
556
557static void
558swap_dynamic_state (SCM loc)
559{
560 SCM_SETCAR (loc, scm_set_current_dynamic_state (SCM_CAR (loc)));
561}
562
563void
661ae7ab 564scm_dynwind_current_dynamic_state (SCM state)
9de87eea
MV
565{
566 SCM loc = scm_cons (state, SCM_EOL);
567 scm_assert_smob_type (tc16_dynamic_state, state);
661ae7ab 568 scm_dynwind_rewind_handler_with_scm (swap_dynamic_state, loc,
9de87eea 569 SCM_F_WIND_EXPLICITLY);
661ae7ab 570 scm_dynwind_unwind_handler_with_scm (swap_dynamic_state, loc,
9de87eea
MV
571 SCM_F_WIND_EXPLICITLY);
572}
573
574void *
575scm_c_with_dynamic_state (SCM state, void *(*func)(void *), void *data)
576{
577 void *result;
661ae7ab
MV
578 scm_dynwind_begin (SCM_F_DYNWIND_REWINDABLE);
579 scm_dynwind_current_dynamic_state (state);
9de87eea 580 result = func (data);
661ae7ab 581 scm_dynwind_end ();
9de87eea
MV
582 return result;
583}
584
585SCM_DEFINE (scm_with_dynamic_state, "with-dynamic-state", 2, 0, 0,
586 (SCM state, SCM proc),
587 "Call @var{proc} while @var{state} is the current dynamic\n"
588 "state object.")
589#define FUNC_NAME s_scm_with_dynamic_state
590{
591 SCM result;
661ae7ab
MV
592 scm_dynwind_begin (SCM_F_DYNWIND_REWINDABLE);
593 scm_dynwind_current_dynamic_state (state);
9de87eea 594 result = scm_call_0 (proc);
661ae7ab 595 scm_dynwind_end ();
9de87eea
MV
596 return result;
597}
598#undef FUNC_NAME
599
600void
601scm_fluids_prehistory ()
602{
603 tc16_fluid = scm_make_smob_type ("fluid", 0);
9de87eea
MV
604 scm_set_smob_print (tc16_fluid, fluid_print);
605
606 tc16_dynamic_state = scm_make_smob_type ("dynamic-state", 0);
9de87eea
MV
607
608 scm_c_hook_add (&scm_after_sweep_c_hook, scan_dynamic_states_and_fluids,
609 0, 0);
610}
611
9482a297
MV
612void
613scm_init_fluids ()
614{
a0599745 615#include "libguile/fluids.x"
9482a297 616}
89e00824
ML
617
618/*
619 Local Variables:
620 c-file-style: "gnu"
621 End:
622*/