Commit | Line | Data |
---|---|---|
a0e07ba4 NJ |
1 | @page |
2 | @node Scheduling | |
3 | @chapter Threads, Mutexes, Asyncs and Dynamic Roots | |
4 | ||
5 | [FIXME: This is pasted in from Tom Lord's original guile.texi chapter | |
6 | plus the Cygnus programmer's manual; it should be *very* carefully | |
7 | reviewed and largely reorganized.] | |
8 | ||
9 | @menu | |
b6506f45 MV |
10 | * Arbiters:: Synchronization primitives. |
11 | * Asyncs:: Asynchronous procedure invocation. | |
12 | * Dynamic Roots:: Root frames of execution. | |
13 | * Threads:: Multiple threads of execution. | |
14 | * Fluids:: Thread-local variables. | |
a0e07ba4 NJ |
15 | @end menu |
16 | ||
17 | ||
18 | @node Arbiters | |
19 | @section Arbiters | |
20 | ||
21 | @cindex arbiters | |
22 | ||
23 | @c FIXME::martin: Review me! | |
24 | ||
25 | Arbiters are synchronization objects. They are created with | |
26 | @code{make-arbiter}. Two or more threads can synchronize on an arbiter | |
27 | by trying to lock it using @code{try-arbiter}. This call will succeed | |
28 | if no other thread has called @code{try-arbiter} on the arbiter yet, | |
29 | otherwise it will fail and return @code{#f}. Once an arbiter is | |
30 | successfully locked, it cannot be locked by another thread until the | |
31 | thread holding the arbiter calls @code{release-arbiter} to unlock it. | |
32 | ||
8f85c0c6 NJ |
33 | @deffn {Scheme Procedure} make-arbiter name |
34 | @deffnx {C Function} scm_make_arbiter (name) | |
a0e07ba4 NJ |
35 | Return an object of type arbiter and name @var{name}. Its |
36 | state is initially unlocked. Arbiters are a way to achieve | |
37 | process synchronization. | |
38 | @end deffn | |
39 | ||
8f85c0c6 NJ |
40 | @deffn {Scheme Procedure} try-arbiter arb |
41 | @deffnx {C Function} scm_try_arbiter (arb) | |
a0e07ba4 NJ |
42 | Return @code{#t} and lock the arbiter @var{arb} if the arbiter |
43 | was unlocked. Otherwise, return @code{#f}. | |
44 | @end deffn | |
45 | ||
8f85c0c6 NJ |
46 | @deffn {Scheme Procedure} release-arbiter arb |
47 | @deffnx {C Function} scm_release_arbiter (arb) | |
a0e07ba4 NJ |
48 | Return @code{#t} and unlock the arbiter @var{arb} if the |
49 | arbiter was locked. Otherwise, return @code{#f}. | |
50 | @end deffn | |
51 | ||
52 | ||
53 | @node Asyncs | |
54 | @section Asyncs | |
55 | ||
56 | @cindex asyncs | |
b6506f45 | 57 | @cindex user asyncs |
a0e07ba4 NJ |
58 | @cindex system asyncs |
59 | ||
b6506f45 MV |
60 | Asyncs are a means of deferring the excution of Scheme code until it is |
61 | safe to do so. | |
a0e07ba4 | 62 | |
b6506f45 MV |
63 | Guile provides two kinds of asyncs that share the basic concept but are |
64 | otherwise quite different: system asyncs and user asyncs. System asyncs | |
65 | are integrated into the core of Guile and are executed automatically | |
66 | when the system is in a state to allow the execution of Scheme code. | |
67 | For example, it is not possible to execute Scheme code in a POSIX signal | |
68 | handler, but such a signal handler can queue a system async to be | |
69 | executed in the near future, when it is safe to do so. | |
a0e07ba4 | 70 | |
b6506f45 MV |
71 | System asyncs can also be queued for threads other than the current one. |
72 | This way, you can cause threads to asynchronously execute arbitrary | |
73 | code. | |
a0e07ba4 | 74 | |
b6506f45 MV |
75 | User asyncs offer a convenient means of queueing procedures for future |
76 | execution and triggering this execution. They will not be executed | |
77 | automatically. | |
a0e07ba4 | 78 | |
b6506f45 MV |
79 | @menu |
80 | * System asyncs:: | |
81 | * User asyncs:: | |
82 | @end menu | |
a0e07ba4 | 83 | |
b6506f45 MV |
84 | @node System asyncs |
85 | @subsection System asyncs | |
a0e07ba4 | 86 | |
b6506f45 MV |
87 | To cause the future asynchronous execution of a procedure in a given |
88 | thread, use @code{system-async-mark}. | |
a0e07ba4 NJ |
89 | |
90 | Automatic invocation of system asyncs can be temporarily disabled by | |
a6c10671 MV |
91 | calling @code{call-with-blocked-asyncs}. This function works by |
92 | temporarily increasing the @emph{async blocking level} of the current | |
93 | thread while a given procedure is running. The blocking level starts | |
94 | out at zero, and whenever a safe point is reached, a blocking level | |
95 | greater than zero will prevent the execution of queued asyncs. | |
96 | ||
97 | Analogously, the procedure @code{call-with-unblocked-asyncs} will | |
98 | temporarily decrease the blocking level of the current thread. You | |
99 | can use it when you want to disable asyncs by default and only allow | |
100 | them temporarily. | |
a0e07ba4 | 101 | |
0a50eeaa | 102 | @deffn {Scheme Procedure} system-async-mark proc [thread] |
b6506f45 MV |
103 | @deffnx {C Function} scm_system_async_mark (proc) |
104 | @deffnx {C Function} scm_system_async_mark_for_thread (proc, thread) | |
105 | Mark @var{proc} (a procedure with zero arguments) for future execution | |
106 | in @var{thread}. When @var{proc} has already been marked for | |
107 | @var{thread} but has not been executed yet, this call has no effect. | |
108 | When @var{thread} is omitted, the thread that called | |
109 | @code{system-async-mark} is used. | |
110 | ||
111 | This procedure is not safe to be called from signal handlers. Use | |
112 | @code{scm_sigaction} or @code{scm_sigaction_for_thread} to install | |
113 | signal handlers. | |
114 | @end deffn | |
115 | ||
a6c10671 MV |
116 | @deffn {Scheme Procedure} call-with-blocked-asyncs proc |
117 | @deffnx {C Function} scm_call_with_blocked_asyncs (proc) | |
0a50eeaa | 118 | @deffnx {C Function} void *scm_c_call_with_blocked_asyncs (void * (*proc) (void *data), void *data) |
a6c10671 MV |
119 | Call @var{proc} and block the execution of system asyncs by one level |
120 | for the current thread while it is running. Return the value returned | |
121 | by @var{proc}. For the first two variants, call @var{proc} with no | |
122 | arguments; for the third, call it with @var{data}. | |
a0e07ba4 NJ |
123 | @end deffn |
124 | ||
a6c10671 MV |
125 | @deffn {Scheme Procedure} call-with-unblocked-asyncs proc |
126 | @deffnx {C Function} scm_call_with_unblocked_asyncs (proc) | |
127 | @deffnx {C Function} void *scm_c_call_with_unblocked_asyncs (void *(*p) (void *d), void *d) | |
128 | Call @var{proc} and unblock the execution of system asyncs by one | |
129 | level for the current thread while it is running. Return the value | |
130 | returned by @var{proc}. For the first two variants, call @var{proc} | |
131 | with no arguments; for the third, call it with @var{data}. | |
a0e07ba4 NJ |
132 | @end deffn |
133 | ||
b6506f45 MV |
134 | @node User asyncs |
135 | @subsection User asyncs | |
136 | ||
137 | A user async is a pair of a thunk (a parameterless procedure) and a | |
138 | mark. Setting the mark on a user async will cause the thunk to be | |
139 | executed when the user async is passed to @code{run-asyncs}. Setting | |
140 | the mark more than once is satisfied by one execution of the thunk. | |
141 | ||
142 | User asyncs are created with @code{async}. They are marked with | |
143 | @code{async-mark}. | |
144 | ||
145 | @deffn {Scheme Procedure} async thunk | |
146 | @deffnx {C Function} scm_async (thunk) | |
147 | Create a new user async for the procedure @var{thunk}. | |
148 | @end deffn | |
149 | ||
150 | @deffn {Scheme Procedure} async-mark a | |
151 | @deffnx {C Function} scm_async_mark (a) | |
152 | Mark the user async @var{a} for future execution. | |
153 | @end deffn | |
a0e07ba4 | 154 | |
b6506f45 MV |
155 | @deffn {Scheme Procedure} run-asyncs list_of_a |
156 | @deffnx {C Function} scm_run_asyncs (list_of_a) | |
157 | Execute all thunks from the marked asyncs of the list @var{list_of_a}. | |
a0e07ba4 NJ |
158 | @end deffn |
159 | ||
160 | ||
161 | @node Dynamic Roots | |
162 | @section Dynamic Roots | |
163 | @cindex dynamic roots | |
164 | ||
165 | A @dfn{dynamic root} is a root frame of Scheme evaluation. | |
166 | The top-level repl, for example, is an instance of a dynamic root. | |
167 | ||
168 | Each dynamic root has its own chain of dynamic-wind information. Each | |
169 | has its own set of continuations, jump-buffers, and pending CATCH | |
170 | statements which are inaccessible from the dynamic scope of any | |
171 | other dynamic root. | |
172 | ||
173 | In a thread-based system, each thread has its own dynamic root. Therefore, | |
174 | continuations created by one thread may not be invoked by another. | |
175 | ||
176 | Even in a single-threaded system, it is sometimes useful to create a new | |
177 | dynamic root. For example, if you want to apply a procedure, but to | |
178 | not allow that procedure to capture the current continuation, calling | |
179 | the procedure under a new dynamic root will do the job. | |
180 | ||
8f85c0c6 NJ |
181 | @deffn {Scheme Procedure} call-with-dynamic-root thunk handler |
182 | @deffnx {C Function} scm_call_with_dynamic_root (thunk, handler) | |
a0e07ba4 NJ |
183 | Evaluate @code{(thunk)} in a new dynamic context, returning its value. |
184 | ||
185 | If an error occurs during evaluation, apply @var{handler} to the | |
186 | arguments to the throw, just as @code{throw} would. If this happens, | |
187 | @var{handler} is called outside the scope of the new root -- it is | |
188 | called in the same dynamic context in which | |
189 | @code{call-with-dynamic-root} was evaluated. | |
190 | ||
191 | If @var{thunk} captures a continuation, the continuation is rooted at | |
192 | the call to @var{thunk}. In particular, the call to | |
193 | @code{call-with-dynamic-root} is not captured. Therefore, | |
194 | @code{call-with-dynamic-root} always returns at most one time. | |
195 | ||
196 | Before calling @var{thunk}, the dynamic-wind chain is un-wound back to | |
197 | the root and a new chain started for @var{thunk}. Therefore, this call | |
198 | may not do what you expect: | |
199 | ||
200 | @lisp | |
201 | ;; Almost certainly a bug: | |
202 | (with-output-to-port | |
203 | some-port | |
204 | ||
205 | (lambda () | |
206 | (call-with-dynamic-root | |
207 | (lambda () | |
208 | (display 'fnord) | |
209 | (newline)) | |
210 | (lambda (errcode) errcode)))) | |
211 | @end lisp | |
212 | ||
213 | The problem is, on what port will @samp{fnord} be displayed? You | |
214 | might expect that because of the @code{with-output-to-port} that | |
215 | it will be displayed on the port bound to @code{some-port}. But it | |
216 | probably won't -- before evaluating the thunk, dynamic winds are | |
217 | unwound, including those created by @code{with-output-to-port}. | |
218 | So, the standard output port will have been re-set to its default value | |
219 | before @code{display} is evaluated. | |
220 | ||
221 | (This function was added to Guile mostly to help calls to functions in C | |
222 | libraries that can not tolerate non-local exits or calls that return | |
223 | multiple times. If such functions call back to the interpreter, it should | |
224 | be under a new dynamic root.) | |
225 | @end deffn | |
226 | ||
227 | ||
8f85c0c6 NJ |
228 | @deffn {Scheme Procedure} dynamic-root |
229 | @deffnx {C Function} scm_dynamic_root () | |
a0e07ba4 NJ |
230 | Return an object representing the current dynamic root. |
231 | ||
232 | These objects are only useful for comparison using @code{eq?}. | |
233 | They are currently represented as numbers, but your code should | |
234 | in no way depend on this. | |
235 | @end deffn | |
236 | ||
237 | @c begin (scm-doc-string "boot-9.scm" "quit") | |
8f85c0c6 | 238 | @deffn {Scheme Procedure} quit [exit_val] |
a0e07ba4 NJ |
239 | Throw back to the error handler of the current dynamic root. |
240 | ||
241 | If integer @var{exit_val} is specified and if Guile is being used | |
242 | stand-alone and if quit is called from the initial dynamic-root, | |
243 | @var{exit_val} becomes the exit status of the Guile process and the | |
244 | process exits. | |
245 | @end deffn | |
246 | ||
247 | When Guile is run interactively, errors are caught from within the | |
248 | read-eval-print loop. An error message will be printed and @code{abort} | |
249 | called. A default set of signal handlers is installed, e.g., to allow | |
250 | user interrupt of the interpreter. | |
251 | ||
252 | It is possible to switch to a "batch mode", in which the interpreter | |
253 | will terminate after an error and in which all signals cause their | |
254 | default actions. Switching to batch mode causes any handlers installed | |
255 | from Scheme code to be removed. An example of where this is useful is | |
256 | after forking a new process intended to run non-interactively. | |
257 | ||
258 | @c begin (scm-doc-string "boot-9.scm" "batch-mode?") | |
8f85c0c6 | 259 | @deffn {Scheme Procedure} batch-mode? |
a0e07ba4 NJ |
260 | Returns a boolean indicating whether the interpreter is in batch mode. |
261 | @end deffn | |
262 | ||
263 | @c begin (scm-doc-string "boot-9.scm" "set-batch-mode?!") | |
8f85c0c6 | 264 | @deffn {Scheme Procedure} set-batch-mode?! arg |
a0e07ba4 NJ |
265 | If @var{arg} is true, switches the interpreter to batch mode. |
266 | The @code{#f} case has not been implemented. | |
267 | @end deffn | |
268 | ||
269 | @node Threads | |
270 | @section Threads | |
271 | @cindex threads | |
272 | @cindex Guile threads | |
273 | ||
274 | @strong{[NOTE: this chapter was written for Cygnus Guile and has not yet | |
275 | been updated for the Guile 1.x release.]} | |
276 | ||
277 | Here is a the reference for Guile's threads. In this chapter I simply | |
278 | quote verbatim Tom Lord's description of the low-level primitives | |
279 | written in C (basically an interface to the POSIX threads library) and | |
280 | Anthony Green's description of the higher-level thread procedures | |
281 | written in scheme. | |
282 | @cindex posix threads | |
283 | @cindex Lord, Tom | |
284 | @cindex Green, Anthony | |
285 | ||
286 | When using Guile threads, keep in mind that each guile thread is | |
287 | executed in a new dynamic root. | |
288 | ||
289 | @menu | |
b6506f45 MV |
290 | * Low level thread primitives:: |
291 | * Higher level thread procedures:: | |
a0e07ba4 NJ |
292 | @end menu |
293 | ||
294 | ||
295 | @node Low level thread primitives | |
296 | @subsection Low level thread primitives | |
297 | ||
298 | @c NJFIXME no current mechanism for making sure that these docstrings | |
299 | @c are in sync. | |
300 | ||
301 | @c begin (texi-doc-string "guile" "call-with-new-thread") | |
8f85c0c6 | 302 | @deffn {Scheme Procedure} call-with-new-thread thunk error-handler |
a0e07ba4 NJ |
303 | Evaluate @code{(thunk)} in a new thread, and new dynamic context, |
304 | returning a new thread object representing the thread. | |
305 | ||
306 | If an error occurs during evaluation, call error-handler, passing it an | |
307 | error code describing the condition. [Error codes are currently | |
308 | meaningless integers. In the future, real values will be specified.] | |
309 | If this happens, the error-handler is called outside the scope of the new | |
310 | root -- it is called in the same dynamic context in which | |
311 | with-new-thread was evaluated, but not in the caller's thread. | |
312 | ||
313 | All the evaluation rules for dynamic roots apply to threads. | |
314 | @end deffn | |
315 | ||
316 | @c begin (texi-doc-string "guile" "join-thread") | |
8f85c0c6 | 317 | @deffn {Scheme Procedure} join-thread thread |
a0e07ba4 NJ |
318 | Suspend execution of the calling thread until the target @var{thread} |
319 | terminates, unless the target @var{thread} has already terminated. | |
320 | @end deffn | |
321 | ||
322 | @c begin (texi-doc-string "guile" "yield") | |
8f85c0c6 | 323 | @deffn {Scheme Procedure} yield |
a0e07ba4 NJ |
324 | If one or more threads are waiting to execute, calling yield forces an |
325 | immediate context switch to one of them. Otherwise, yield has no effect. | |
326 | @end deffn | |
327 | ||
328 | @c begin (texi-doc-string "guile" "make-mutex") | |
8f85c0c6 | 329 | @deffn {Scheme Procedure} make-mutex |
a0e07ba4 NJ |
330 | Create a new mutex object. |
331 | @end deffn | |
332 | ||
333 | @c begin (texi-doc-string "guile" "lock-mutex") | |
8f85c0c6 | 334 | @deffn {Scheme Procedure} lock-mutex mutex |
a0e07ba4 NJ |
335 | Lock @var{mutex}. If the mutex is already locked, the calling thread |
336 | blocks until the mutex becomes available. The function returns when | |
337 | the calling thread owns the lock on @var{mutex}. | |
338 | @end deffn | |
339 | ||
340 | @c begin (texi-doc-string "guile" "unlock-mutex") | |
8f85c0c6 | 341 | @deffn {Scheme Procedure} unlock-mutex mutex |
a0e07ba4 NJ |
342 | Unlocks @var{mutex} if the calling thread owns the lock on @var{mutex}. |
343 | Calling unlock-mutex on a mutex not owned by the current thread results | |
344 | in undefined behaviour. Once a mutex has been unlocked, one thread | |
345 | blocked on @var{mutex} is awakened and grabs the mutex lock. | |
346 | @end deffn | |
347 | ||
348 | @c begin (texi-doc-string "guile" "make-condition-variable") | |
8f85c0c6 | 349 | @deffn {Scheme Procedure} make-condition-variable |
a0e07ba4 NJ |
350 | @end deffn |
351 | ||
352 | @c begin (texi-doc-string "guile" "wait-condition-variable") | |
8f85c0c6 | 353 | @deffn {Scheme Procedure} wait-condition-variable cond-var mutex |
a0e07ba4 NJ |
354 | @end deffn |
355 | ||
356 | @c begin (texi-doc-string "guile" "signal-condition-variable") | |
8f85c0c6 | 357 | @deffn {Scheme Procedure} signal-condition-variable cond-var |
a0e07ba4 NJ |
358 | @end deffn |
359 | ||
360 | ||
361 | @node Higher level thread procedures | |
362 | @subsection Higher level thread procedures | |
363 | ||
364 | @c new by ttn, needs review | |
365 | ||
366 | Higher level thread procedures are available by loading the | |
367 | @code{(ice-9 threads)} module. These provide standardized | |
368 | thread creation and mutex interaction. | |
369 | ||
8f85c0c6 | 370 | @deffn {Scheme Procedure} %thread-handler tag args@dots{} |
a0e07ba4 NJ |
371 | |
372 | This procedure is specified as the standard error-handler for | |
373 | @code{make-thread} and @code{begin-thread}. If the number of @var{args} | |
374 | is three or more, use @code{display-error}, otherwise display a message | |
375 | "uncaught throw to @var{tag}". All output is sent to the port specified | |
376 | by @code{current-error-port}. | |
377 | ||
378 | Before display, global var @code{the-last-stack} is set to @code{#f} | |
379 | and signals are unmasked with @code{unmask-signals}. | |
380 | ||
381 | [FIXME: Why distinguish based on number of args?! Cue voodoo music here.] | |
382 | @end deffn | |
383 | ||
384 | @deffn macro make-thread proc [args@dots{}] | |
385 | Apply @var{proc} to @var{args} in a new thread formed by | |
386 | @code{call-with-new-thread} using @code{%thread-handler} as the error | |
387 | handler. | |
388 | @end deffn | |
389 | ||
390 | @deffn macro begin-thread first [rest@dots{}] | |
391 | Evaluate forms @var{first} and @var{rest} in a new thread formed by | |
392 | @code{call-with-new-thread} using @code{%thread-handler} as the error | |
393 | handler. | |
394 | @end deffn | |
395 | ||
396 | @deffn macro with-mutex m [body@dots{}] | |
397 | Lock mutex @var{m}, evaluate @var{body}, and then unlock @var{m}. | |
398 | These sub-operations form the branches of a @code{dynamic-wind}. | |
399 | @end deffn | |
400 | ||
401 | @deffn macro monitor first [rest@dots{}] | |
402 | Evaluate forms @var{first} and @var{rest} under a newly created | |
403 | anonymous mutex, using @code{with-mutex}. | |
404 | ||
405 | [FIXME: Is there any way to access the mutex?] | |
406 | @end deffn | |
407 | ||
408 | ||
409 | @node Fluids | |
410 | @section Fluids | |
411 | ||
412 | @cindex fluids | |
413 | ||
414 | @c FIXME::martin: Review me! | |
415 | ||
416 | Fluids are objects to store values in. They have a few properties which | |
417 | make them useful in certain situations: Fluids can have one value per | |
418 | dynamic root (@pxref{Dynamic Roots}), so that changes to the value in a | |
419 | fluid are only visible in the same dynamic root. Since threads are | |
420 | executed in separate dynamic roots, fluids can be used for thread local | |
421 | storage (@pxref{Threads}). | |
422 | ||
a05a88b3 MV |
423 | Fluids can be used to simulate the desirable effects of dynamically |
424 | scoped variables. Dynamically scoped variables are useful when you | |
425 | want to set a variable to a value during some dynamic extent in the | |
426 | execution of your program and have them revert to their original value | |
427 | when the control flow is outside of this dynamic extent. See the | |
428 | description of @code{with-fluids} below for details. | |
a0e07ba4 | 429 | |
a05a88b3 MV |
430 | New fluids are created with @code{make-fluid} and @code{fluid?} is |
431 | used for testing whether an object is actually a fluid. The values | |
432 | stored in a fluid can be accessed with @code{fluid-ref} and | |
433 | @code{fluid-set!}. | |
a0e07ba4 | 434 | |
8f85c0c6 NJ |
435 | @deffn {Scheme Procedure} make-fluid |
436 | @deffnx {C Function} scm_make_fluid () | |
a0e07ba4 NJ |
437 | Return a newly created fluid. |
438 | Fluids are objects of a certain type (a smob) that can hold one SCM | |
439 | value per dynamic root. That is, modifications to this value are | |
440 | only visible to code that executes within the same dynamic root as | |
441 | the modifying code. When a new dynamic root is constructed, it | |
442 | inherits the values from its parent. Because each thread executes | |
443 | in its own dynamic root, you can use fluids for thread local storage. | |
444 | @end deffn | |
445 | ||
8f85c0c6 NJ |
446 | @deffn {Scheme Procedure} fluid? obj |
447 | @deffnx {C Function} scm_fluid_p (obj) | |
a0e07ba4 NJ |
448 | Return @code{#t} iff @var{obj} is a fluid; otherwise, return |
449 | @code{#f}. | |
450 | @end deffn | |
451 | ||
8f85c0c6 NJ |
452 | @deffn {Scheme Procedure} fluid-ref fluid |
453 | @deffnx {C Function} scm_fluid_ref (fluid) | |
a0e07ba4 NJ |
454 | Return the value associated with @var{fluid} in the current |
455 | dynamic root. If @var{fluid} has not been set, then return | |
456 | @code{#f}. | |
457 | @end deffn | |
458 | ||
8f85c0c6 NJ |
459 | @deffn {Scheme Procedure} fluid-set! fluid value |
460 | @deffnx {C Function} scm_fluid_set_x (fluid, value) | |
a0e07ba4 NJ |
461 | Set the value associated with @var{fluid} in the current dynamic root. |
462 | @end deffn | |
463 | ||
464 | @code{with-fluids*} temporarily changes the values of one or more fluids, | |
465 | so that the given procedure and each procedure called by it access the | |
466 | given values. After the procedure returns, the old values are restored. | |
467 | ||
8f85c0c6 NJ |
468 | @deffn {Scheme Procedure} with-fluids* fluids values thunk |
469 | @deffnx {C Function} scm_with_fluids (fluids, values, thunk) | |
a0e07ba4 | 470 | Set @var{fluids} to @var{values} temporary, and call @var{thunk}. |
a05a88b3 MV |
471 | @var{fluids} must be a list of fluids and @var{values} must be the |
472 | same number of their values to be applied. Each substitution is done | |
473 | in the order given. @var{thunk} must be a procedure with no argument. | |
474 | it is called inside a @code{dynamic-wind} and the fluids are | |
475 | set/restored when control enter or leaves the established dynamic | |
476 | extent. | |
a0e07ba4 NJ |
477 | @end deffn |
478 | ||
a05a88b3 MV |
479 | @deffn {Scheme Macro} with-fluids ((fluid value) ...) body... |
480 | Execute @var{body...} while each @var{fluid} is set to the | |
481 | corresponding @var{value}. Both @var{fluid} and @var{value} are | |
482 | evaluated and @var{fluid} must yield a fluid. @var{body...} is | |
483 | executed inside a @code{dynamic-wind} and the fluids are set/restored | |
484 | when control enter or leaves the established dynamic extent. | |
485 | @end deffn | |
a0e07ba4 NJ |
486 | |
487 | @c Local Variables: | |
488 | @c TeX-master: "guile.texi" | |
489 | @c End: |