summaryrefslogtreecommitdiff
path: root/doc/ref/scheme-scheduling.texi
blob: ddd24bc901c986a0112dfe5860e005256a13b4a3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
@page
@node Scheduling
@chapter Threads, Mutexes, Asyncs and Dynamic Roots

[FIXME: This is pasted in from Tom Lord's original guile.texi chapter
plus the Cygnus programmer's manual; it should be *very* carefully
reviewed and largely reorganized.]

@menu
* Arbiters::                    Synchronization primitives.
* Asyncs::                      Asynchronous procedure invocation.
* Dynamic Roots::               Root frames of execution.
* Threads::                     Multiple threads of execution.
* Fluids::                      Thread-local variables.
@end menu


@node Arbiters
@section Arbiters

@cindex arbiters

@c FIXME::martin: Review me!

Arbiters are synchronization objects.  They are created with
@code{make-arbiter}.  Two or more threads can synchronize on an arbiter
by trying to lock it using @code{try-arbiter}.  This call will succeed
if no other thread has called @code{try-arbiter} on the arbiter yet,
otherwise it will fail and return @code{#f}.  Once an arbiter is
successfully locked, it cannot be locked by another thread until the
thread holding the arbiter calls @code{release-arbiter} to unlock it.

@deffn {Scheme Procedure} make-arbiter name
@deffnx {C Function} scm_make_arbiter (name)
Return an object of type arbiter and name @var{name}. Its
state is initially unlocked.  Arbiters are a way to achieve
process synchronization.
@end deffn

@deffn {Scheme Procedure} try-arbiter arb
@deffnx {C Function} scm_try_arbiter (arb)
Return @code{#t} and lock the arbiter @var{arb} if the arbiter
was unlocked. Otherwise, return @code{#f}.
@end deffn

@deffn {Scheme Procedure} release-arbiter arb
@deffnx {C Function} scm_release_arbiter (arb)
Return @code{#t} and unlock the arbiter @var{arb} if the
arbiter was locked. Otherwise, return @code{#f}.
@end deffn


@node Asyncs
@section Asyncs

@cindex asyncs
@cindex user asyncs
@cindex system asyncs

Asyncs are a means of deferring the excution of Scheme code until it is
safe to do so.

Guile provides two kinds of asyncs that share the basic concept but are
otherwise quite different: system asyncs and user asyncs.  System asyncs
are integrated into the core of Guile and are executed automatically
when the system is in a state to allow the execution of Scheme code.
For example, it is not possible to execute Scheme code in a POSIX signal
handler, but such a signal handler can queue a system async to be
executed in the near future, when it is safe to do so.

System asyncs can also be queued for threads other than the current one.
This way, you can cause threads to asynchronously execute arbitrary
code.

User asyncs offer a convenient means of queueing procedures for future
execution and triggering this execution.  They will not be executed
automatically.

@menu
* System asyncs::               
* User asyncs::                 
@end menu

@node System asyncs
@subsection System asyncs

To cause the future asynchronous execution of a procedure in a given
thread, use @code{system-async-mark}.

Automatic invocation of system asyncs can be temporarily disabled by
calling @code{call-with-blocked-asyncs}.  This function works by
temporarily increasing the @emph{async blocking level} of the current
thread while a given procedure is running.  The blocking level starts
out at zero, and whenever a safe point is reached, a blocking level
greater than zero will prevent the execution of queued asyncs.

Analogously, the procedure @code{call-with-unblocked-asyncs} will
temporarily decrease the blocking level of the current thread.  You
can use it when you want to disable asyncs by default and only allow
them temporarily.

@deffn {Scheme Procedure} system-async-mark proc [thread]
@deffnx {C Function} scm_system_async_mark (proc)
@deffnx {C Function} scm_system_async_mark_for_thread (proc, thread)
Mark @var{proc} (a procedure with zero arguments) for future execution
in @var{thread}.  When @var{proc} has already been marked for
@var{thread} but has not been executed yet, this call has no effect.
When @var{thread} is omitted, the thread that called
@code{system-async-mark} is used.

This procedure is not safe to be called from signal handlers.  Use
@code{scm_sigaction} or @code{scm_sigaction_for_thread} to install
signal handlers.
@end deffn

@deffn {Scheme Procedure} call-with-blocked-asyncs proc
@deffnx {C Function} scm_call_with_blocked_asyncs (proc)
@deffnx {C Function} void *scm_c_call_with_blocked_asyncs (void * (*proc) (void *data), void *data)
Call @var{proc} and block the execution of system asyncs by one level
for the current thread while it is running.  Return the value returned
by @var{proc}.  For the first two variants, call @var{proc} with no
arguments; for the third, call it with @var{data}.
@end deffn

@deffn {Scheme Procedure} call-with-unblocked-asyncs proc
@deffnx {C Function} scm_call_with_unblocked_asyncs (proc)
@deffnx {C Function} void *scm_c_call_with_unblocked_asyncs (void *(*p) (void *d), void *d)
Call @var{proc} and unblock the execution of system asyncs by one
level for the current thread while it is running.  Return the value
returned by @var{proc}.  For the first two variants, call @var{proc}
with no arguments; for the third, call it with @var{data}.
@end deffn

@node User asyncs
@subsection User asyncs

A user async is a pair of a thunk (a parameterless procedure) and a
mark.  Setting the mark on a user async will cause the thunk to be
executed when the user async is passed to @code{run-asyncs}.  Setting
the mark more than once is satisfied by one execution of the thunk.

User asyncs are created with @code{async}.  They are marked with
@code{async-mark}.

@deffn {Scheme Procedure} async thunk
@deffnx {C Function} scm_async (thunk)
Create a new user async for the procedure @var{thunk}.
@end deffn

@deffn {Scheme Procedure} async-mark a
@deffnx {C Function} scm_async_mark (a)
Mark the user async @var{a} for future execution.
@end deffn

@deffn {Scheme Procedure} run-asyncs list_of_a
@deffnx {C Function} scm_run_asyncs (list_of_a)
Execute all thunks from the marked asyncs of the list @var{list_of_a}.
@end deffn


@node Dynamic Roots
@section Dynamic Roots
@cindex dynamic roots

A @dfn{dynamic root} is a root frame of Scheme evaluation.
The top-level repl, for example, is an instance of a dynamic root.

Each dynamic root has its own chain of dynamic-wind information.  Each
has its own set of continuations, jump-buffers, and pending CATCH
statements which are inaccessible from the dynamic scope of any
other dynamic root.

In a thread-based system, each thread has its own dynamic root.  Therefore,
continuations created by one thread may not be invoked by another.

Even in a single-threaded system, it is sometimes useful to create a new
dynamic root.  For example, if you want to apply a procedure, but to
not allow that procedure to capture the current continuation, calling
the procedure under a new dynamic root will do the job.

@deffn {Scheme Procedure} call-with-dynamic-root thunk handler
@deffnx {C Function} scm_call_with_dynamic_root (thunk, handler)
Evaluate @code{(thunk)} in a new dynamic context, returning its value.

If an error occurs during evaluation, apply @var{handler} to the
arguments to the throw, just as @code{throw} would.  If this happens,
@var{handler} is called outside the scope of the new root -- it is
called in the same dynamic context in which
@code{call-with-dynamic-root} was evaluated.

If @var{thunk} captures a continuation, the continuation is rooted at
the call to @var{thunk}.  In particular, the call to
@code{call-with-dynamic-root} is not captured.  Therefore,
@code{call-with-dynamic-root} always returns at most one time.

Before calling @var{thunk}, the dynamic-wind chain is un-wound back to
the root and a new chain started for @var{thunk}.  Therefore, this call
may not do what you expect:

@lisp
;; Almost certainly a bug:
(with-output-to-port
 some-port

 (lambda ()
   (call-with-dynamic-root
    (lambda ()
      (display 'fnord)
      (newline))
    (lambda (errcode) errcode))))
@end lisp

The problem is, on what port will @samp{fnord} be displayed?  You
might expect that because of the @code{with-output-to-port} that
it will be displayed on the port bound to @code{some-port}.  But it
probably won't -- before evaluating the thunk, dynamic winds are
unwound, including those created by @code{with-output-to-port}.
So, the standard output port will have been re-set to its default value
before @code{display} is evaluated.

(This function was added to Guile mostly to help calls to functions in C
libraries that can not tolerate non-local exits or calls that return
multiple times.  If such functions call back to the interpreter, it should
be under a new dynamic root.)
@end deffn


@deffn {Scheme Procedure} dynamic-root
@deffnx {C Function} scm_dynamic_root ()
Return an object representing the current dynamic root.

These objects are only useful for comparison using @code{eq?}.
They are currently represented as numbers, but your code should
in no way depend on this.
@end deffn

@c begin (scm-doc-string "boot-9.scm" "quit")
@deffn {Scheme Procedure} quit [exit_val]
Throw back to the error handler of the current dynamic root.

If integer @var{exit_val} is specified and if Guile is being used
stand-alone and if quit is called from the initial dynamic-root,
@var{exit_val} becomes the exit status of the Guile process and the
process exits.
@end deffn

When Guile is run interactively, errors are caught from within the
read-eval-print loop.  An error message will be printed and @code{abort}
called.  A default set of signal handlers is installed, e.g., to allow
user interrupt of the interpreter.

It is possible to switch to a "batch mode", in which the interpreter
will terminate after an error and in which all signals cause their
default actions.  Switching to batch mode causes any handlers installed
from Scheme code to be removed.  An example of where this is useful is
after forking a new process intended to run non-interactively.

@c begin (scm-doc-string "boot-9.scm" "batch-mode?")
@deffn {Scheme Procedure} batch-mode?
Returns a boolean indicating whether the interpreter is in batch mode.
@end deffn

@c begin (scm-doc-string "boot-9.scm" "set-batch-mode?!")
@deffn {Scheme Procedure} set-batch-mode?! arg
If @var{arg} is true, switches the interpreter to batch mode.
The @code{#f} case has not been implemented.
@end deffn

@node Threads
@section Threads
@cindex threads
@cindex Guile threads

@strong{[NOTE: this chapter was written for Cygnus Guile and has not yet
been updated for the Guile 1.x release.]}

Here is a the reference for Guile's threads.  In this chapter I simply
quote verbatim Tom Lord's description of the low-level primitives
written in C (basically an interface to the POSIX threads library) and
Anthony Green's description of the higher-level thread procedures
written in scheme.
@cindex posix threads
@cindex Lord, Tom
@cindex Green, Anthony

When using Guile threads, keep in mind that each guile thread is
executed in a new dynamic root.

@menu
* Low level thread primitives::  
* Higher level thread procedures::  
@end menu


@node Low level thread primitives
@subsection Low level thread primitives

@c NJFIXME no current mechanism for making sure that these docstrings
@c are in sync.

@c begin (texi-doc-string "guile" "call-with-new-thread")
@deffn {Scheme Procedure} call-with-new-thread thunk error-handler
Evaluate @code{(thunk)} in a new thread, and new dynamic context,
returning a new thread object representing the thread.

If an error occurs during evaluation, call error-handler, passing it an
error code describing the condition.  [Error codes are currently
meaningless integers.  In the future, real values will be specified.]
If this happens, the error-handler is called outside the scope of the new
root -- it is called in the same dynamic context in which
with-new-thread was evaluated, but not in the caller's thread.

All the evaluation rules for dynamic roots apply to threads.
@end deffn

@c begin (texi-doc-string "guile" "join-thread")
@deffn {Scheme Procedure} join-thread thread
Suspend execution of the calling thread until the target @var{thread}
terminates, unless the target @var{thread} has already terminated.
@end deffn

@c begin (texi-doc-string "guile" "yield")
@deffn {Scheme Procedure} yield
If one or more threads are waiting to execute, calling yield forces an
immediate context switch to one of them. Otherwise, yield has no effect.
@end deffn

@c begin (texi-doc-string "guile" "make-mutex")
@deffn {Scheme Procedure} make-mutex
Create a new mutex object.
@end deffn

@c begin (texi-doc-string "guile" "lock-mutex")
@deffn {Scheme Procedure} lock-mutex mutex
Lock @var{mutex}. If the mutex is already locked, the calling thread
blocks until the mutex becomes available. The function returns when
the calling thread owns the lock on @var{mutex}.  Locking a mutex that
a thread already owns will succeed right away and will not block the
thread.  That is, Guile's mutexes are @emph{recursive}.
@end deffn

@deffn {Scheme Procedure} try-mutex mutex
Try to lock @var{mutex}. If the mutex is already locked by someone
else, return @code{#f}.  Else lock the mutex and return @code{#t}.
@end deffn

@c begin (texi-doc-string "guile" "unlock-mutex")
@deffn {Scheme Procedure} unlock-mutex mutex
Unlocks @var{mutex} if the calling thread owns the lock on
@var{mutex}.  Calling unlock-mutex on a mutex not owned by the current
thread results in undefined behaviour. Once a mutex has been unlocked,
one thread blocked on @var{mutex} is awakened and grabs the mutex
lock.  Every call to @code{lock-mutex} by this thread must be matched
with a call to @code{unlock-mutex}.  Only the last call to
@code{unlock-mutex} will actually unlock the mutex.
@end deffn

@c begin (texi-doc-string "guile" "make-condition-variable")
@deffn {Scheme Procedure} make-condition-variable
@end deffn

@c begin (texi-doc-string "guile" "wait-condition-variable")
@deffn {Scheme Procedure} wait-condition-variable cond-var mutex [time]
Wait until @var{cond-var} has been signalled.  While waiting,
@var{mutex} is atomically unlocked (as with @code{unlock-mutex}) and
is locked again when this function returns.  When @var{time} is given,
it specifies a point in time where the waiting should be aborted.  It
can be either a integer as returned by @code{current-time} or a pair
as returned by @code{gettimeofday}.  When the waiting is aborted the
mutex is locked and @code{#f} is returned.  When the condition
variable is in fact signalled, the mutex is also locked and @code{#t}
is returned.
@end deffn

@c begin (texi-doc-string "guile" "signal-condition-variable")
@deffn {Scheme Procedure} signal-condition-variable cond-var
@end deffn

@c begin (texi-doc-string "guile" "broadcast-condition-variable")
@deffn {Scheme Procedure} signal-condition-variable cond-var
@end deffn

@node Higher level thread procedures
@subsection Higher level thread procedures

@c new by ttn, needs review

Higher level thread procedures are available by loading the
@code{(ice-9 threads)} module.  These provide standardized
thread creation and mutex interaction.

@deffn {Scheme Procedure} %thread-handler tag args@dots{}

This procedure is specified as the standard error-handler for
@code{make-thread} and @code{begin-thread}.  If the number of @var{args}
is three or more, use @code{display-error}, otherwise display a message
"uncaught throw to @var{tag}".  All output is sent to the port specified
by @code{current-error-port}.

Before display, global var @code{the-last-stack} is set to @code{#f}
and signals are unmasked with @code{unmask-signals}.

[FIXME: Why distinguish based on number of args?!  Cue voodoo music here.]
@end deffn

@deffn macro make-thread proc [args@dots{}]
Apply @var{proc} to @var{args} in a new thread formed by
@code{call-with-new-thread} using @code{%thread-handler} as the error
handler.
@end deffn

@deffn macro begin-thread first [rest@dots{}]
Evaluate forms @var{first} and @var{rest} in a new thread formed by
@code{call-with-new-thread} using @code{%thread-handler} as the error
handler.
@end deffn

@deffn macro with-mutex m [body@dots{}]
Lock mutex @var{m}, evaluate @var{body}, and then unlock @var{m}.
These sub-operations form the branches of a @code{dynamic-wind}.
@end deffn

@deffn macro monitor first [rest@dots{}]
Evaluate forms @var{first} and @var{rest} under a newly created
anonymous mutex, using @code{with-mutex}.

[FIXME: Is there any way to access the mutex?]
@end deffn


@node Fluids
@section Fluids

@cindex fluids

@c FIXME::martin: Review me!

Fluids are objects to store values in.  They have a few properties which
make them useful in certain situations: Fluids can have one value per
dynamic root (@pxref{Dynamic Roots}), so that changes to the value in a
fluid are only visible in the same dynamic root.  Since threads are
executed in separate dynamic roots, fluids can be used for thread local
storage (@pxref{Threads}).

Fluids can be used to simulate the desirable effects of dynamically
scoped variables.  Dynamically scoped variables are useful when you
want to set a variable to a value during some dynamic extent in the
execution of your program and have them revert to their original value
when the control flow is outside of this dynamic extent.  See the
description of @code{with-fluids} below for details.

New fluids are created with @code{make-fluid} and @code{fluid?} is
used for testing whether an object is actually a fluid.  The values
stored in a fluid can be accessed with @code{fluid-ref} and
@code{fluid-set!}.

@deffn {Scheme Procedure} make-fluid
@deffnx {C Function} scm_make_fluid ()
Return a newly created fluid.
Fluids are objects of a certain type (a smob) that can hold one SCM
value per dynamic root.  That is, modifications to this value are
only visible to code that executes within the same dynamic root as
the modifying code.  When a new dynamic root is constructed, it
inherits the values from its parent.  Because each thread executes
in its own dynamic root, you can use fluids for thread local storage.
@end deffn

@deffn {Scheme Procedure} fluid? obj
@deffnx {C Function} scm_fluid_p (obj)
Return @code{#t} iff @var{obj} is a fluid; otherwise, return
@code{#f}.
@end deffn

@deffn {Scheme Procedure} fluid-ref fluid
@deffnx {C Function} scm_fluid_ref (fluid)
Return the value associated with @var{fluid} in the current
dynamic root.  If @var{fluid} has not been set, then return
@code{#f}.
@end deffn

@deffn {Scheme Procedure} fluid-set! fluid value
@deffnx {C Function} scm_fluid_set_x (fluid, value)
Set the value associated with @var{fluid} in the current dynamic root.
@end deffn

@code{with-fluids*} temporarily changes the values of one or more fluids,
so that the given procedure and each procedure called by it access the
given values.  After the procedure returns, the old values are restored.

@deffn {Scheme Procedure} with-fluids* fluids values thunk
@deffnx {C Function} scm_with_fluids (fluids, values, thunk)
Set @var{fluids} to @var{values} temporary, and call @var{thunk}.
@var{fluids} must be a list of fluids and @var{values} must be the
same number of their values to be applied.  Each substitution is done
in the order given.  @var{thunk} must be a procedure with no argument.
it is called inside a @code{dynamic-wind} and the fluids are
set/restored when control enter or leaves the established dynamic
extent.
@end deffn

@deffn {Scheme Macro} with-fluids ((fluid value) ...) body...
Execute @var{body...} while each @var{fluid} is set to the
corresponding @var{value}.  Both @var{fluid} and @var{value} are
evaluated and @var{fluid} must yield a fluid.  @var{body...} is
executed inside a @code{dynamic-wind} and the fluids are set/restored
when control enter or leaves the established dynamic extent.
@end deffn

@c Local Variables:
@c TeX-master: "guile.texi"
@c End: