1
Fork 0
mirror of https://git.savannah.gnu.org/git/guile.git synced 2025-05-30 08:50:23 +02:00

Updates for the new thread stuff.

This commit is contained in:
Marius Vollmer 2005-03-02 20:46:41 +00:00
parent 9de87eea47
commit b4fddbbeda
7 changed files with 742 additions and 457 deletions

View file

@ -372,10 +372,9 @@ location resumed is expecting multiple values (@pxref{Multiple
Values}) then they should be passed as multiple arguments, for Values}) then they should be passed as multiple arguments, for
instance @code{(@var{cont} @var{x} @var{y} @var{z})}. instance @code{(@var{cont} @var{x} @var{y} @var{z})}.
@var{cont} may only be used from the dynamic root in which it was @var{cont} may only be used from the same side of a continuation
created (@pxref{Dynamic Roots}), and in a multi-threaded program only barrier as it was created (@pxref{Continuation Barriers}), and in a
from the thread in which it was created, since each thread is a multi-threaded program only from the thread in which it was created.
separate dynamic root.
The call to @var{proc} is not part of the continuation captured, it runs The call to @var{proc} is not part of the continuation captured, it runs
only when the continuation is created. Often a program will want to only when the continuation is created. Often a program will want to

View file

@ -326,13 +326,15 @@ this procedure directly, use the procedures @code{read-enable},
@rnindex eval @rnindex eval
@c ARGFIXME environment/environment specifier @c ARGFIXME environment/environment specifier
@deffn {Scheme Procedure} eval exp module @deffn {Scheme Procedure} eval exp module_or_state
@deffnx {C Function} scm_eval (exp, module) @deffnx {C Function} scm_eval (exp, module_or_state)
Evaluate @var{exp}, a list representing a Scheme expression, Evaluate @var{exp}, a list representing a Scheme expression,
in the top-level environment specified by @var{module}. in the top-level environment specified by @var{module}.
While @var{exp} is evaluated (using @code{primitive-eval}), While @var{exp} is evaluated (using @code{primitive-eval}),
@var{module} is made the current module. The current module @var{module} is made the current module. The current module
is reset to its previous value when @var{eval} returns. is reset to its previous value when @var{eval} returns.
XXX - dynamic states.
Example: (eval '(+ 1 2) (interaction-environment))
@end deffn @end deffn
@rnindex interaction-environment @rnindex interaction-environment

View file

@ -8,50 +8,92 @@
@node Initialization @node Initialization
@section Initializing Guile @section Initializing Guile
@deftypefn {C Function} void scm_boot_guile (int @var{argc}, char **@var{argv}, void (*@var{main_func}) (void *@var{data}, int @var{argc}, char **@var{argv}), void *@var{data}) Each thread that wants to use functions from the Guile API needs to
Initialize the Guile Scheme interpreter. Then call @var{main_func}, put itself into guile mode with either @code{scm_with_guile} or
passing it @var{data}, @var{argc}, and @var{argv} as indicated. The @code{scm_init_guile}. The global state of Guile is initialized
function @var{main_func} should do all the work of the program automatically when the first thread enters guile mode.
(initializing other packages, defining application-specific functions,
reading user input, and so on) before returning. When @var{main_func}
returns, @code{scm_boot_guile} calls @code{exit (0)};
@code{scm_boot_guile} never returns. If you want some other exit
value, have @var{main_func} call @code{exit} itself.
@code{scm_boot_guile} arranges for the Scheme @code{command-line} When a thread wants to block outside of a Guile API function, it should
function to return the strings given by @var{argc} and @var{argv}. If leave guile mode temporarily with either @code{scm_without_guile} or
@var{main_func} modifies @var{argc} or @var{argv}, it should call @code{scm_leave_guile}, @xref{Threads}.
@code{scm_set_program_arguments} with the final list, so Scheme code
will know which arguments have been processed.
Why must the caller do all the real work from @var{main_func}? Guile's Threads that are created by @code{call-with-new-thread} or
garbage collector scans the stack to find all local variables that @code{scm_spawn_thread} start out in guile mode so you don't need to
reference Scheme objects. To do this, it needs to know the bounds of initialize them.
the stack that might contain such references. Because there is no
portable way in C to find the base of the stack, @code{scm_boot_guile}
assumes that all references are above its own stack frame. If you try
to manipulate Scheme objects after this function returns, it's the luck
of the draw whether Guile's storage manager will be able to find the
objects you allocate. So, @code{scm_boot_guile} function exits, rather
than returning, to discourage you from making that mistake.
See @code{scm_init_guile}, below, for a function that can find the real @deftypefn {C Function} void *scm_with_guile (void *(*func)(void *), void *data)
base of the stack, but not in a portable way. Call @var{func}, passing it @var{data} and return what @var{func}
returns. While @var{func} is running, the current thread is in guile
mode and can thus use the Guile API.
When @code{scm_with_guile} is called from guile mode, the thread remains
in guile mode when @code{scm_with_guile} returns.
Otherwise, it puts the current thread into guile mode and, if needed,
gives it a Scheme representation that is contained in the list returned
by @code{all-threads}, for example. This Scheme representation is not
removed when @code{scm_with_guile} returns so that a given thread is
always represented by the same Scheme value during its lifetime, if at
all.
When this is the first thread that enters guile mode, the global state
of Guile is initialized before calling @code{func}.
The function @var{func} is called via
@code{scm_with_continuation_barrier}; thus, @code{scm_with_guile}
returns exactly once.
When @code{scm_with_guile} returns, the thread is no longer in guile
mode (except when @code{scm_with_guile} was called from guile mode, see
above). Thus, only @code{func} can store @code{SCM} variables on the
stack and be sure that they are protected from the garbage collector.
See @code{scm_init_guile} for another approach at initializing Guile
that does not have this restriction.
It is OK to call @code{scm_with_guile} while a thread has temporarily
left guile mode via @code{scm_without_guile} or @code{scm_leave_guile}.
It will then simply temporarily enter guile mode again.
@end deftypefn @end deftypefn
@deftypefn {C Function} void scm_init_guile () @deftypefn {C Function} void scm_init_guile ()
Initialize the Guile Scheme interpreter. Arrange things so that all of the code in the current thread executes as
if from within a call to @code{scm_with_guile}. That is, all functions
called by the current thread can assume that @code{SCM} values on their
stack frames are protected from the garbage collector (except when the
thread has explicitely left guile mode, of course).
In contrast to @code{scm_boot_guile}, this function knows how to find When @code{scm_init_guile} is called from a thread that already has been
the true base of the stack and thus does not need to usurp the control in guile mode once, nothing happens. This behavior matters when you
flow of your program. However, since finding the stack base can not be call @code{scm_init_guile} while the thread has only temporarily left
done portably, this function might not be available in all installations guile mode: in that case the thread will not be in guile mode after
of Guile. If you can, you should use @code{scm_boot_guile} instead. @code{scm_init_guile} returns. Thus, you should not use
@code{scm_init_guile} in such a scenario.
Note that @code{scm_init_guile} does not inform Guile about the command When a uncaught throw happens in a thread that has been put into guile
line arguments that should be returned by the Scheme function mode via @code{scm_init_guile}, a short message is printed to the
@code{command-line}. You can use @code{scm_set_program_arguments} to do current error port and the thread is exited via @code{scm_pthread_exit
this. (NULL)}. No restrictions are placed on continuations.
The function @code{scm_init_guile} might not be available on all
platforms since it requires some stack-bounds-finding magic that might
not have been ported to all platforms that Guile runs on. Thus, if you
can, it is better to use @code{scm_with_guile} or its variation
@code{scm_boot_guile} instead of this function.
@end deftypefn
@deftypefn {C Function} void scm_boot_guile (int @var{argc}, char **@var{argv}, void (*@var{main_func}) (void *@var{data}, int @var{argc}, char **@var{argv}), void *@var{data})
Enter guile mode as with @code{scm_with_guile} and call @var{main_func},
passing it @var{data}, @var{argc}, and @var{argv} as indicated. When
@var{main_func} returns, @code{scm_boot_guile} calls @code{exit (0)};
@code{scm_boot_guile} never returns. If you want some other exit value,
have @var{main_func} call @code{exit} itself. If you don't want to exit
at all, use @code{scm_with_guile} instead of @code{scm_boot_guile}.
The function @code{scm_boot_guile} arranges for the Scheme
@code{command-line} function to return the strings given by @var{argc}
and @var{argv}. If @var{main_func} modifies @var{argc} or @var{argv},
it should call @code{scm_set_program_arguments} with the final list, so
Scheme code will know which arguments have been processed.
@end deftypefn @end deftypefn
@deftypefn {C Function} void scm_shell (int @var{argc}, char **@var{argv}) @deftypefn {C Function} void scm_shell (int @var{argc}, char **@var{argv})

View file

@ -15,12 +15,13 @@ reviewed and largely reorganized.]
@menu @menu
* Arbiters:: Synchronization primitives. * Arbiters:: Synchronization primitives.
* Asyncs:: Asynchronous procedure invocation. * Asyncs:: Asynchronous procedure invocation.
* Dynamic Roots:: Root frames of execution. * Continuation Barriers:: Protection from non-local control flow.
* Threads:: Multiple threads of execution. * Threads:: Multiple threads of execution.
* Fluids:: Thread-local variables. * Blocking:: How to block properly in guile mode.
* Fluids and Dynamic States:: Thread-local variables, etc.
* Futures:: Delayed execution in new threads. * Futures:: Delayed execution in new threads.
* Parallel Forms:: Parallel execution of forms. * Parallel Forms:: Parallel execution of forms.
* Mutexes:: Synchronization primitives. * Mutexes and Condition Variables:: Synchronization primitives.
@end menu @end menu
@ -32,10 +33,10 @@ Arbiters are synchronization objects, they can be used by threads to
control access to a shared resource. An arbiter can be locked to control access to a shared resource. An arbiter can be locked to
indicate a resource is in use, and unlocked when done. indicate a resource is in use, and unlocked when done.
An arbiter is like a light-weight mutex (@pxref{Mutexes}). It uses An arbiter is like a light-weight mutex (@pxref{Mutexes and Condition
less memory and may be faster, but there's no way for a thread to Variables}). It uses less memory and may be faster, but there's no
block waiting on an arbiter, it can only test and get the status way for a thread to block waiting on an arbiter, it can only test and
returned. get the status returned.
@deffn {Scheme Procedure} make-arbiter name @deffn {Scheme Procedure} make-arbiter name
@deffnx {C Function} scm_make_arbiter (name) @deffnx {C Function} scm_make_arbiter (name)
@ -113,7 +114,7 @@ them temporarily.
In addition to the C versions of @code{call-with-blocked-asyncs} and In addition to the C versions of @code{call-with-blocked-asyncs} and
@code{call-with-unblocked-asyncs}, C code can use @code{call-with-unblocked-asyncs}, C code can use
@code{scm_with_blocked_asyncs} and @code{scm_with_unblocked_asyncs} @code{scm_frame_block_asyncs} and @code{scm_frame_unblock_asyncs}
inside a @dfn{frame} (@pxref{Frames}) to block or unblock system asyncs inside a @dfn{frame} (@pxref{Frames}) to block or unblock system asyncs
temporarily. temporarily.
@ -196,114 +197,31 @@ Mark the user async @var{a} for future execution.
Execute all thunks from the marked asyncs of the list @var{list_of_a}. Execute all thunks from the marked asyncs of the list @var{list_of_a}.
@end deffn @end deffn
@node Continuation Barriers
@subsection Continuation Barriers
@node Dynamic Roots The non-local flow of control caused by continuations might sometimes
@subsection Dynamic Roots not be wanted. You can use @code{with-continuation-barrier} etc to
@cindex dynamic roots errect fences that continuations can not pass.
A @dfn{dynamic root} is a root frame of Scheme evaluation. @deffn {Sheme Procedure} with-continuation-barrier proc
The top-level repl, for example, is an instance of a dynamic root. @deffnx {C Function} scm_with_continuation_barrier (proc)
Call @var{proc} and return its result. Do not allow the invocation of
continuations that would leave or enter the dynamic extent of the call
to @code{with-continuation-barrier}. Such an attempt causes an error
to be signaled.
Each dynamic root has its own chain of dynamic-wind information. Each Throws (such as errors) that are not caught from within @var{proc} are
has its own set of continuations, jump-buffers, and pending CATCH caught by @code{with-continuation-barrier}. In that case, a short
statements which are inaccessible from the dynamic scope of any message is printed to the current error port and @code{#f} is returned.
other dynamic root.
In a thread-based system, each thread has its own dynamic root. Therefore, Thus, @code{with-continuation-barrier} returns exactly once.
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 @end deffn
@deftypefn {C Function} void *scm_c_with_continuation_barrier (void *(*func) (void *), void *data)
@deffn {Scheme Procedure} dynamic-root Like @code{scm_with_continuation_barrier} but call @var{func} on
@deffnx {C Function} scm_dynamic_root () @var{data}. When an error is caught, @code{NULL} is returned.
Return an object representing the current dynamic root. @end deftypefn
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 @node Threads
@subsection Threads @subsection Threads
@ -311,21 +229,6 @@ The @code{#f} case has not been implemented.
@cindex Guile threads @cindex Guile threads
@cindex POSIX threads @cindex POSIX threads
Guile threads are implemented using POSIX threads, they run
pre-emptively and concurrently through both Scheme code and system
calls. The only exception is for garbage collection, where all
threads must rendezvous.
@menu
* Low level thread primitives::
* Higher level thread procedures::
* C level thread interface::
@end menu
@node Low level thread primitives
@subsubsection Low level thread primitives
@deffn {Scheme Procedure} all-threads @deffn {Scheme Procedure} all-threads
@deffnx {C Function} scm_all_threads () @deffnx {C Function} scm_all_threads ()
Return a list of all threads. Return a list of all threads.
@ -337,23 +240,38 @@ Return the thread that called this function.
@end deffn @end deffn
@c begin (texi-doc-string "guile" "call-with-new-thread") @c begin (texi-doc-string "guile" "call-with-new-thread")
@deffn {Scheme Procedure} call-with-new-thread thunk error-handler @deffn {Scheme Procedure} call-with-new-thread thunk handler
Evaluate @code{(thunk)} in a new thread, and new dynamic context, Call @code{thunk} in a new thread and with a new dynamic state,
returning a new thread object representing the thread. returning the new thread. The procedure @var{thunk} is called via
@code{with-continuation-barrier}.
If an error occurs during evaluation, call error-handler, passing it When @var{handler} is specified, then @var{thunk} is called from
an error code. If this happens, the error-handler is called outside within a @code{catch} with tag @code{#t} that has @var{handler} as its
the scope of the new root -- it is called in the same dynamic context handler. This catch is established inside the continuation barrier.
in which with-new-thread was evaluated, but not in the caller's
thread.
All the evaluation rules for dynamic roots apply to threads. Once @var{thunk} or @var{handler} returns, the return value is made
the @emph{exit value} of the thread and the thread is terminated.
@end deffn @end deffn
@deftypefn {C Function} SCM scm_spawn_thread (scm_t_catch_body body, void *body_data, scm_t_catch_handler handler, void *handler_data)
Call @var{body} in a new thread, passing it @var{body_data}, returning
the new thread. The function @var{body} is called via
@code{scm_c_with_continuation_barrier}.
When @var{handler} is non-@code{NULL}, @var{body} is called via
@code{scm_internal_catch} with tag @code{SCM_BOOL_T} that has
@var{handler} and @var{handler_data} as the handler and its data. This
catch is established inside the continuation barrier.
Once @var{body} or @var{handler} returns, the return value is made the
@emph{exit value} of the thread and the thread is terminated.
@end deftypefn
@c begin (texi-doc-string "guile" "join-thread") @c begin (texi-doc-string "guile" "join-thread")
@deffn {Scheme Procedure} join-thread thread @deffn {Scheme Procedure} join-thread thread
Suspend execution of the calling thread until the target @var{thread} Wait for @var{thread} to terminate and return its exit value. Threads
terminates, unless the target @var{thread} has already terminated. that have not been created with @code{call-with-new-thread} or
@code{scm_spawn_thread} have an exit value of @code{#f}.
@end deffn @end deffn
@deffn {Scheme Procedure} thread-exited? thread @deffn {Scheme Procedure} thread-exited? thread
@ -367,49 +285,6 @@ 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. immediate context switch to one of them. Otherwise, yield has no effect.
@end deffn @end deffn
@c begin (texi-doc-string "guile" "make-condition-variable")
@deffn {Scheme Procedure} make-condition-variable
Make a new condition variable.
@end deffn
@deffn {Scheme Procedure} make-fair-condition-variable
@deffnx {C Function} scm_make_fair_condition_variable ()
Make a new fair 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,
@code{#f} is returned. When the condition variable has in fact been
signalled, @code{#t} is returned. The mutex is re-locked in any case
before @code{wait-condition-variable} returns.
When a system async is activated for a thread that is blocked in a
call to @code{wait-condition-variable}, the waiting is interrupted,
the mutex is locked, and the async is executed. When the async
returns, the mutex is unlocked again and the waiting is resumed.
@end deffn
@c begin (texi-doc-string "guile" "signal-condition-variable")
@deffn {Scheme Procedure} signal-condition-variable cond-var
Wake up one thread that is waiting for @var{cv}.
@end deffn
@c begin (texi-doc-string "guile" "broadcast-condition-variable")
@deffn {Scheme Procedure} broadcast-condition-variable cond-var
Wake up all threads that are waiting for @var{cv}.
@end deffn
@node Higher level thread procedures
@subsubsection Higher level thread procedures
@c new by ttn, needs review
Higher level thread procedures are available by loading the Higher level thread procedures are available by loading the
@code{(ice-9 threads)} module. These provide standardized @code{(ice-9 threads)} module. These provide standardized
thread creation. thread creation.
@ -417,7 +292,8 @@ thread creation.
@deffn macro make-thread proc [args@dots{}] @deffn macro make-thread proc [args@dots{}]
Apply @var{proc} to @var{args} in a new thread formed by Apply @var{proc} to @var{args} in a new thread formed by
@code{call-with-new-thread} using a default error handler that display @code{call-with-new-thread} using a default error handler that display
the error to the current error port. the error to the current error port. The @var{args@dots{}}
expressions are evaluated in the new thread.
@end deffn @end deffn
@deffn macro begin-thread first [rest@dots{}] @deffn macro begin-thread first [rest@dots{}]
@ -426,171 +302,80 @@ Evaluate forms @var{first} and @var{rest} in a new thread formed by
the error to the current error port. the error to the current error port.
@end deffn @end deffn
@node C level thread interface @node Blocking
@subsubsection C level thread interface @subsection Blocking in Guile Mode
You can create and manage threads A thread must not block outside of a libguile function while it is in
with the C versions of the primitives above. guile mode. The following functions can be used to temporily leave
These guile mode or to perform some common blocking operations in a supported
functions and data types are only available from C and can not be way.
mixed with the first set from above. However, they might be more
efficient and can be used in situations where Scheme data types are
not allowed or are inconvenient to use.
Furthermore, they are the primitives that Guile relies on for its own @deftypefn {C Function} scm_t_guile_ticket scm_leave_guile ()
higher level threads. By reimplementing them, you can adapt Guile to Leave guile mode and return a ticket that can be used with
different low-level thread implementations. @code{scm_enter_guile} to enter it again.
C code in a thread must call a libguile function periodically. When While a thread has left guile mode, it must not call any libguile
one thread finds garbage collection is required, it waits for all functions except @code{scm_enter_guile} and must not use any libguile
threads to rendezvous before doing that GC. Such a rendezvous is macros. Also, local variables of type @code{SCM} that are allocated
checked within libguile functions. If C code wants to sleep or block while not in guile mode are not protected from the garbage collector.
in a thread it should use one of the libguile functions provided.
Only threads created by Guile can use the libguile functions. Threads
created directly with say @code{pthread_create} are unknown to Guile
and they cannot call libguile. The stack in such foreign threads is
not scanned during GC, so @code{SCM} values generally cannot be held
there.
@c FIXME:
@c
@c Describe SCM_TICK which can be called if no other libguile
@c function is being used by a C function.
@c
@c Describe "Guile mode", which a thread can enter and exit. There
@c are no functions for doing this yet.
@c
@c When in guile mode a thread can call libguile, is subject to the
@c tick rule, and its stack is scanned. When not in guile mode it
@c cannot call libguile, it doesn't have to tick, and its stack is
@c not scanned. The strange guile control flow things like
@c exceptions, continuations and asyncs only occur when in guile
@c mode.
@c
@c When guile mode is exited, the portion of the stack allocated
@c while it was in guile mode is still scanned. This portion may not
@c be modified when outside guile mode. The stack ends up
@c partitioned into alternating guile and non-guile regions.
@c
@c Leaving guile mode is convenient when running an extended
@c calculation not involving guile, since one doesn't need to worry
@c about SCM_TICK calls.
@deftp {C Data Type} scm_t_thread
This data type represents a thread, to be used with scm_thread_create,
etc.
@end deftp
@deftypefn {C Function} int scm_thread_create (scm_t_thread *t, void (*proc)(void *), void *data)
Create a new thread that will start by calling @var{proc}, passing it
@var{data}. A handle for the new thread is stored in @var{t}, which
must be non-NULL. The thread terminated when @var{proc} returns.
When the thread has not been detached, its handle remains valid after
is has terminated so that it can be used with @var{scm_thread_join},
for example. When it has been detached, the handle becomes invalid as
soon as the thread terminates.
@end deftypefn @end deftypefn
@deftypefn {C Function} void scm_thread_detach (scm_t_thread t) @deftypefn {C Function} void scm_enter_guile (scm_t_guile_ticket ticket)
Detach the thread @var{t}. See @code{scm_thread_create}. Enter guile mode again.
@end deftypefn @end deftypefn
@deftypefn {C Function} void scm_thread_join (scm_t_thread t) @deftypefn {C Function} void *scm_without_guile (void *(*func) (void *), void *data)
Wait for thread @var{t} to terminate. The thread must not have been Leave guile mode, call @var{func} on @var{data}, enter guile mode and
detached at the time that @code{scm_thread_join} is called, but it return the result of calling @var{func}.
might have been detached by the time it terminates.
@end deftypefn @end deftypefn
@deftypefn {C Function} scm_t_thread scm_thread_self () @deftypefn {C Function} int scm_pthread_mutex_lock (pthread_mutex_t *mutex)
Return the handle of the calling thread. Like @code{pthread_mutex_lock}, but leaves guile mode while waiting for
the mutex.
@end deftypefn @end deftypefn
@deftp {C Data Type} scm_t_cond @deftypefn {C Function} int scm_pthread_cond_wait (pthread_cond_t *cond, pthread_mutex_t *mutex)
This data type represents a condition variable, to be used with @deftypefnx {C Function} int scm_pthread_cond_timedwait (pthread_cond_t *cond, pthread_mutex_t *mutex, struct timespec *abstime)
scm_cond_init, etc. Like @code{pthread_cond_wait} and @code{pthread_cond_timedwait}, but
@end deftp leaves guile mode while waiting for the condition variable.
@deftypefn {C Function} void scm_cond_init (scm_t_cond *c)
Initialize the condition variable structure pointed to by @var{c}.
@end deftypefn @end deftypefn
@deftypefn {C Function} void scm_cond_destroy (scm_t_cond *c) @deftypefn {C Function} int scm_std_select (int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout)
Deallocate all resources associated with @var{c}. Like @code{select} but leaves guile mode while waiting. Also, the
delivery of a system async causes this function to be interrupted with
error code @code{EINTR}.
@end deftypefn @end deftypefn
@deftypefn {C Function} void scm_cond_wait (scm_t_cond *c, scm_t_mutex *m) @deftypefn {C Function} {unsigned int} scm_std_sleep ({unsigned int} seconds)
Wait for @var{c} to be signalled. While waiting @var{m} is unlocked Like @code{sleep}, but leaves guile mode while sleeping. Also, the
and locked again before @code{scm_cond_wait} returns. delivery of a system async causes this function to be interrupted.
@end deftypefn @end deftypefn
@deftypefn {C Function} void scm_cond_timedwait (scm_t_cond *c, scm_t_mutex *m, timespec *abstime) @deftypefn {C Function} {unsigned long} scm_std_usleep ({unsigned long} usecs)
Wait for @var{c} to be signalled as with @code{scm_cond_wait} but Like @code{usleep}, but leaves guile mode while sleeping. Also, the
don't wait longer than the point in time specified by @var{abstime}. delivery of a system async causes this function to be interrupted.
when the waiting is aborted, zero is returned; non-zero else.
@end deftypefn @end deftypefn
@deftypefn {C Function} void scm_cond_signal (scm_t_cond *c)
Signal the condition variable @var{c}. When one or more threads are
waiting for it to be signalled, select one arbitrarily and let its
wait succeed.
@end deftypefn
@deftypefn {C Function} void scm_cond_broadcast (scm_t_cond *c) @node Fluids and Dynamic States
Signal the condition variable @var{c}. When there are threads waiting @subsection Fluids and Dynamic States
for it to be signalled, wake them all up and make all their waits
succeed.
@end deftypefn
@deftp {C Type} scm_t_key
This type represents a key for a thread-specific value.
@end deftp
@deftypefn {C Function} void scm_key_create (scm_t_key *keyp)
Create a new key for a thread-specific value. Each thread has its own
value associated to such a handle. The new handle is stored into
@var{keyp}, which must be non-NULL.
@end deftypefn
@deftypefn {C Function} void scm_key_delete (scm_t_key key)
This function makes @var{key} invalid as a key for thread-specific data.
@end deftypefn
@deftypefn {C Function} void scm_key_setspecific (scm_t_key key, const void *value)
Associate @var{value} with @var{key} in the calling thread.
@end deftypefn
@deftypefn {C Function} int scm_key_getspecific (scm_t_key key)
Return the value currently associated with @var{key} in the calling
thread. When @code{scm_key_setspecific} has not yet been called in
this thread with this key, @code{NULL} is returned.
@end deftypefn
@deftypefn {C Function} int scm_thread_select (...)
This function does the same thing as the system's @code{select}
function, but in a way that is friendly to the thread implementation.
You should call it in preference to the system @code{select}.
@end deftypefn
@node Fluids
@subsection Fluids
@cindex fluids @cindex fluids
Fluids are objects to store values in. They have a few properties A @emph{fluid} is an object that can store one value per @emph{dynamic
which make them useful in certain situations: Fluids can have one state}. Each thread has a current dynamic state, and when accessing a
value per dynamic root (@pxref{Dynamic Roots}), so that changes to the fluid, this current dynamic state is used to provide the actual value.
value in a fluid are only visible in the same dynamic root. Since In this way, fluids can be used for thread local storage, but they are
threads are executed in separate dynamic roots, fluids can be used for in fact more flexible: dynamic states are objects of their own and can
thread local storage (@pxref{Threads}). be made current for more than one thread at the same time, or only be
made current temporarily, for example.
Fluids can be used to simulate the desirable effects of dynamically Fluids can also be used to simulate the desirable effects of
scoped variables. Dynamically scoped variables are useful when you dynamically scoped variables. Dynamically scoped variables are useful
want to set a variable to a value during some dynamic extent in the when you want to set a variable to a value during some dynamic extent
execution of your program and have them revert to their original value in the execution of your program and have them revert to their
when the control flow is outside of this dynamic extent. See the original value when the control flow is outside of this dynamic
description of @code{with-fluids} below for details. extent. See the description of @code{with-fluids} below for details.
New fluids are created with @code{make-fluid} and @code{fluid?} is New fluids are created with @code{make-fluid} and @code{fluid?} is
used for testing whether an object is actually a fluid. The values used for testing whether an object is actually a fluid. The values
@ -600,12 +385,12 @@ stored in a fluid can be accessed with @code{fluid-ref} and
@deffn {Scheme Procedure} make-fluid @deffn {Scheme Procedure} make-fluid
@deffnx {C Function} scm_make_fluid () @deffnx {C Function} scm_make_fluid ()
Return a newly created fluid. Return a newly created fluid.
Fluids are objects of a certain type (a smob) that can hold one SCM Fluids are objects that can hold one
value per dynamic root. That is, modifications to this value are value per dynamic state. That is, modifications to this value are
only visible to code that executes within the same dynamic root as only visible to code that executes with the same dynamic state as
the modifying code. When a new dynamic root is constructed, it the modifying code. When a new dynamic state is constructed, it
inherits the values from its parent. Because each thread executes inherits the values from its parent. Because each thread normally executes
in its own dynamic root, you can use fluids for thread local storage. with its own dynamic state, you can use fluids for thread local storage.
@end deffn @end deffn
@deffn {Scheme Procedure} fluid? obj @deffn {Scheme Procedure} fluid? obj
@ -675,6 +460,50 @@ value whenever the frame is entered or left. The backup value is
initialized with the @var{val} argument. initialized with the @var{val} argument.
@end deftypefn @end deftypefn
@deffn {Scheme Procedure} make-dynamic-state [parent]
@deffnx {C Function} scm_make_dynamic_state (parent)
Return a copy of the dynamic state object @var{parent}
or of the current dynamic state when @var{parent} is omitted.
@end deffn
@deffn {Scheme Procedure} dynamic-state? obj
@deffnx {C Function} scm_dynamic_state_p (obj)
Return @code{#t} if @var{obj} is a dynamic state object;
return @code{#f} otherwise.
@end deffn
@deftypefn {C Procedure} int scm_is_dynamic_state (SCM obj)
Return non-zero if @var{obj} is a dynamic state object;
return zero otherwise.
@end deftypefn
@deffn {Scheme Procedure} current-dynamic-state
@deffnx {C Function} scm_current_dynamic_state ()
Return the current dynamic state object.
@end deffn
@deffn {Scheme Procedure} set-current-dynamic-state state
@deffnx {C Function} scm_set_current_dynamic_state (state)
Set the current dynamic state object to @var{state}
and return the previous current dynamic state object.
@end deffn
@deffn {Scheme Procedure} with-dynamic-state state proc
@deffnx {C Function} scm_with_dynamic_state (state, proc)
Call @var{proc} while @var{state} is the current dynamic
state object.
@end deffn
@deftypefn {C Procedure} void scm_frame_current_dynamic_state (SCM state)
Set the current dynamic state to @var{state} for the dynamic extent of
the current frame.
@end deftypefn
@deftypefn {C Procedure} void *scm_c_with_dynamic_state (SCM state, void *(*func)(void *), void *data)
Like @code{scm_with_dynamic_state}, but call @var{func} with
@var{data}.
@end deftypefn
@node Futures @node Futures
@subsection Futures @subsection Futures
@cindex futures @cindex futures
@ -798,9 +627,10 @@ completed, it doesn't need to wait for all to finish.
@end deffn @end deffn
@node Mutexes @node Mutexes and Condition Variables
@subsection Mutexes @subsection Mutexes and Condition Variables
@cindex mutex @cindex mutex
@cindex condition variable
A mutex is a thread synchronization object, it can be used by threads A mutex is a thread synchronization object, it can be used by threads
to control access to a shared resource. A mutex can be locked to to control access to a shared resource. A mutex can be locked to
@ -808,9 +638,10 @@ indicate a resource is in use, and other threads can then block on the
mutex to wait for the resource (or can just test and do something else mutex to wait for the resource (or can just test and do something else
if not available). ``Mutex'' is short for ``mutual exclusion''. if not available). ``Mutex'' is short for ``mutual exclusion''.
There are two types of mutexes, ``standard'' and ``fair''. They're There are two types of mutexes in Guile, ``standard'' and
created by @code{make-mutex} and @code{make-fair-mutex} respectively, ``recursive''. They're created by @code{make-mutex} and
the operation functions are then common to both. @code{make-recursive-mutex} respectively, the operation functions are
then common to both.
Note that for both types of mutex there's no protection against a Note that for both types of mutex there's no protection against a
``deadly embrace''. For instance if one thread has locked mutex A and ``deadly embrace''. For instance if one thread has locked mutex A and
@ -821,43 +652,31 @@ in all threads is one way to avoid such problems.
@sp 1 @sp 1
@deffn {Scheme Procedure} make-mutex @deffn {Scheme Procedure} make-mutex
@deffnx {Scheme Procedure} make-fair-mutex Return a new standard mutex. It is initially unlocked.
Return a new mutex object. @end deffn
@code{make-mutex} creates a standard mutex. This is fast, but its @deffn {Scheme Procedure} make-recursive-mutex
features are restricted. Recursive locking (multiple lock calls by Return a new recursive mutex. It is initialloy unlocked.
one thread) is not permitted, and an unlock can be done only when
already locked and only by the owning thread. When multiple threads
are blocked waiting to acquire the mutex, it's unspecified which will
get it next.
@code{make-fair-mutex} creates a fair mutex. This has more features
and error checking. Recursive locking is allowed, a given thread can
make multiple lock calls and the mutex is released when a balancing
number of unlocks are done. Other threads blocked waiting to acquire
the mutex form a queue and the one waiting longest will be the next to
acquire it.
@end deffn @end deffn
@deffn {Scheme Procedure} lock-mutex mutex @deffn {Scheme Procedure} lock-mutex mutex
Lock @var{mutex}. If the mutex is already locked by another thread Lock @var{mutex}. If the mutex is already locked by another thread
then block and return only when @var{mutex} has been acquired. then block and return only when @var{mutex} has been acquired.
For standard mutexes (@code{make-mutex}), if the thread has itself For standard mutexes (@code{make-mutex}), and error is signalled if
already locked @var{mutex} it must not call @code{lock-mutex} on it a the thread has itself already locked @var{mutex}.
further time. Behaviour is unspecified if this is done.
For a fair mutex (@code{make-fair-mutex}), if the thread has itself For a recursive mutex (@code{make-recursive-mutex}), if the thread has
already locked @var{mutex}, then a further @code{lock-mutex} call itself already locked @var{mutex}, then a further @code{lock-mutex}
increments the lock count. An additional @code{unlock-mutex} will be call increments the lock count. An additional @code{unlock-mutex}
required to finally release. will be required to finally release.
When a system async (@pxref{System asyncs}) is activated for a thread When a system async (@pxref{System asyncs}) is activated for a thread
blocked in @code{lock-mutex}, the wait is interrupted and the async is blocked in @code{lock-mutex}, the wait is interrupted and the async is
executed. When the async returns the wait resumes. executed. When the async returns, the wait resumes.
@end deffn @end deffn
@deffn {Scheme Procedure} try-mutex mutex @deffn {Scheme Procedure} try-mutex mutex
Try to lock @var{mutex} as per @code{lock-mutex}. If @var{mutex} can Try to lock @var{mutex} as per @code{lock-mutex}. If @var{mutex} can
be acquired immediately then this is done and the return is @code{#t}. be acquired immediately then this is done and the return is @code{#t}.
If @var{mutex} is locked by some other thread then nothing is done and If @var{mutex} is locked by some other thread then nothing is done and
@ -865,13 +684,43 @@ the return is @code{#f}.
@end deffn @end deffn
@deffn {Scheme Procedure} unlock-mutex mutex @deffn {Scheme Procedure} unlock-mutex mutex
Unlock @var{mutex}. Unlock @var{mutex}. An error is signalled if @var{mutex} is not
locked by the calling thread.
@end deffn
For a standard mutex (@code{make-mutex}), if @var{mutex} is not locked @c begin (texi-doc-string "guile" "make-condition-variable")
by the calling thread then behaviour is unspecified. @deffn {Scheme Procedure} make-condition-variable
Return a new condition variable.
@end deffn
For a fair mutex (@code{make-fair-mutex}), if @var{mutex} is not @c begin (texi-doc-string "guile" "wait-condition-variable")
locked by the calling thread then an error is thrown. @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,
@code{#f} is returned. When the condition variable has in fact been
signalled, @code{#t} is returned. The mutex is re-locked in any case
before @code{wait-condition-variable} returns.
When a system async is activated for a thread that is blocked in a
call to @code{wait-condition-variable}, the waiting is interrupted,
the mutex is locked, and the async is executed. When the async
returns, the mutex is unlocked again and the waiting is resumed. When
the thread block while re-acquiring the mutex, execution of asyncs is
blocked.
@end deffn
@c begin (texi-doc-string "guile" "signal-condition-variable")
@deffn {Scheme Procedure} signal-condition-variable cond-var
Wake up one thread that is waiting for @var{cv}.
@end deffn
@c begin (texi-doc-string "guile" "broadcast-condition-variable")
@deffn {Scheme Procedure} broadcast-condition-variable cond-var
Wake up all threads that are waiting for @var{cv}.
@end deffn @end deffn
@sp 1 @sp 1
@ -908,38 +757,6 @@ means a particular bit of code managing access to some resource and
which only ever executes on behalf of one process at any one time. which only ever executes on behalf of one process at any one time.
@end deffn @end deffn
@sp 1
The following provide access to standard mutexes from C code.
@deftp {C Data Type} scm_t_mutex
A mutex, to be used with @code{scm_mutex_init}, etc.
@end deftp
@deftypefn {C Function} void scm_mutex_init (scm_t_mutex *m)
Initialize the mutex structure pointed to by @var{m}.
@end deftypefn
@deftypefn {C Function} void scm_mutex_destroy (scm_t_mutex *m)
Free all resources associated with @var{m}.
@end deftypefn
@deftypefn {C Function} void scm_mutex_lock (scm_t_mutex *m)
Lock the mutex @var{m}. This is as per @code{lock-mutex} above on a
standard mutex.
@end deftypefn
@deftypefn {C Function} int scm_mutex_trylock (scm_t_mutex *m)
Attempt to lock mutex @var{m}, as per @code{scm_mutex_lock}. If
@var{m} is unlocked then this is done and the return is non-zero. If
@var{m} is already locked by another thread then do nothing and return
zero.
@end deftypefn
@deftypefn {C Function} void scm_mutex_unlock (scm_t_mutex *m)
Unlock the mutex @var{m}. The mutex must have been locked by the
current thread, otherwise the behavior is undefined.
@end deftypefn
@c Local Variables: @c Local Variables:
@c TeX-master: "guile.texi" @c TeX-master: "guile.texi"

View file

@ -1,6 +1,6 @@
@c -*-texinfo-*- @c -*-texinfo-*-
@c This is part of the GNU Guile Reference Manual. @c This is part of the GNU Guile Reference Manual.
@c Copyright (C) 1996, 1997, 2000, 2001, 2002, 2003, 2004 @c Copyright (C) 1996, 1997, 2000, 2001, 2002, 2003, 2004, 2005
@c Free Software Foundation, Inc. @c Free Software Foundation, Inc.
@c See the file guile.texi for copying conditions. @c See the file guile.texi for copying conditions.
@ -8,12 +8,12 @@
@node General Libguile Concepts @node General Libguile Concepts
@section General concepts for using libguile @section General concepts for using libguile
When you want to embed the Guile Scheme interpreter into your program, When you want to embed the Guile Scheme interpreter into your program or
you need to link it against the @file{libguile} library (@pxref{Linking library, you need to link it against the @file{libguile} library
Programs With Guile}). Once you have done this, your C code has access (@pxref{Linking Programs With Guile}). Once you have done this, your C
to a number of data types and functions that can be used to invoke the code has access to a number of data types and functions that can be used
interpreter, or make new functions that you have written in C available to invoke the interpreter, or make new functions that you have written
to be called from Scheme code, among other things. in C available to be called from Scheme code, among other things.
Scheme is different from C in a number of significant ways, and Guile Scheme is different from C in a number of significant ways, and Guile
tries to make the advantages of Scheme available to C as well. Thus, in tries to make the advantages of Scheme available to C as well. Thus, in
@ -26,10 +26,16 @@ You need to understand how libguile offers them to C programs in order
to use the rest of libguile. Also, the more general control flow of to use the rest of libguile. Also, the more general control flow of
Scheme caused by continuations needs to be dealt with. Scheme caused by continuations needs to be dealt with.
Running asynchronous signal handlers and multi-threading is known to C
code already, but there are of course a few additional rules when using
them together with libguile.
@menu @menu
* Dynamic Types:: Dynamic Types. * Dynamic Types:: Dynamic Types.
* Garbage Collection:: Garbage Collection. * Garbage Collection:: Garbage Collection.
* Control Flow:: Control Flow. * Control Flow:: Control Flow.
* Asynchronous Signals:: Asynchronous Signals
* Multi-Threading:: Multi-Threading
@end menu @end menu
@node Dynamic Types @node Dynamic Types
@ -377,3 +383,204 @@ corresponding @code{scm_internal_dynamic_wind} function, but it might
prefer to use the @dfn{frames} concept that is more natural for C code, prefer to use the @dfn{frames} concept that is more natural for C code,
(@pxref{Frames}). (@pxref{Frames}).
@node Asynchronous Signals
@subsection Asynchronous Signals
You can not call libguile functions from handlers for POSIX signals, but
you can register Scheme handlers for POSIX signals such as
@code{SIGINT}. These handlers do not run during the actual signal
delivery. Instead, they are run when the program (more precisely, the
thread that the handler has been registered for) reaches the next
@emph{safe point}.
The libguile functions themselves have many such safe points.
Consequently, you must be prepared for arbitrary actions anytime you
call a libguile function. For example, even @code{scm_cons} can contain
a safe point and when a signal handler is pending for your thread,
calling @code{scm_cons} will run this handler and anything might happen,
including a non-local exit although @code{scm_cons} would not ordinarily
do such a thing on its own.
If you do not want to allow the running of asynchronous signal handlers,
you can block them temporarily with @code{scm_frame_block_asyncs}, for
example. See @xref{System asyncs}.
Since signal handling in Guile relies on safe points, you need to make
sure that your functions do offer enough of them. Normally, calling
libguile functions in the normal course of action is all that is needed.
But when a thread might spent a long time in a code section that calls
no libguile function, it is good to include explicit safe points. This
can allow the user to interrupt your code with @key{C-c}, for example.
You can do this with the macro @code{SCM_TICK}. This macro is
syntactically a statement. That is, you could use it like this:
@example
while (1)
@{
SCM_TICK;
do_some_work ();
@}
@end example
Frequent execution of a safe point is even more important in multi
threaded programs, @xref{Multi-Threading}.
@node Multi-Threading
@subsection Multi-Threading
Guile can be used in multi-threaded programs just as well as in
single-threaded ones.
Each thread that wants to use functions from libguile must put itself
into @emph{guile mode} and must then follow a few rules. If it doesn't
want to honor these rules in certain situations, a thread can
temporarily leave guile mode (but can no longer use libguile functions
during that time, of course).
Threads enter guile mode by calling @code{scm_with_guile},
@code{scm_boot_guile}, or @code{scm_init_guile}. As explained in the
reference documentation for these functions, Guile will then learn about
the stack bounds of the thread and can protect the @code{SCM} values
that are stored in local variables. When a thread puts itself into
guile mode for the first time, it gets a Scheme representation and is
listed by @code{all-threads}, for example.
While in guile mode, a thread promises to reach a safe point reasonably
frequently (@pxref{Asynchronous Signals}). In addition to running
signal handlers, these points are also potential rendezvous points of
all guile mode threads where Guile can orchestrate global things like
garbage collection. Consequently, when a thread in guile mode blocks
and does no longer frequent safe points, it might cause all other guile
mode threads to block as well. To prevent this from happening, a guile
mode thread should either only block in libguile functions (who know how
to do it right), or should temporarily leave guile mode with
@code{scm_without_guile} or
@code{scm_leave_guile}/@code{scm_enter_guile}.
For some common blocking operations, Guile provides convenience
functions. For example, if you want to lock a pthread mutex while in
guile mode, you might want to use @code{scm_pthread_mutex_lock} which is
just like @code{pthread_mutex_lock} except that it leaves guile mode
while blocking.
All libguile functions are (intended to be) robust in the face of
multiple threads using them concurrently. This means that there is no
risk of the internal data structures of libguile becoming corrupted in
such a way that the process crashes.
A program might still produce non-sensical results, though. Taking
hashtables as an example, Guile guarantees that you can use them from
multiple threads concurrently and a hashtable will always remain a valid
hashtable and Guile will not crash when you access it. It does not
guarantee, however, that inserting into it concurrently from two threads
will give useful results: only one insertion might actually happen, none
might happen, or the table might in general be modified in a totally
arbitrary manner. (It will still be a valid hashtable, but not the one
that you might have expected.) Guile might also signal an error when it
detects a harmful race condition.
Thus, you need to put in additional synchronizations when multiple
threads want to use a single hashtable, or any other mutable Scheme
object.
When writing C code for use with libguile, you should try to make it
robust as well. An example that converts a list into a vector will help
to illustrate. Here is a correct version:
@example
SCM
my_list_to_vector (SCM list)
@{
SCM vector = scm_make_vector (scm_length (list), SCM_UNDEFINED);
size_t len, i;
len = SCM_SIMPLE_VECTOR_LENGTH (vector);
i = 0;
while (i < len && scm_is_pair (list))
@{
SCM_SIMPLE_VECTOR_SET (vector, i, SCM_CAR (list));
list = SCM_CDR (list);
i++;
@}
return vector;
@}
@end example
The first thing to note is that storing into a @code{SCM} location
concurrently from multiple threads is guaranteed to be robust: you don't
know which value wins but it will in any case be a valid @code{SCM}
value.
But there is no guarantee that the list referenced by @var{list} is not
modified in another thread while the loop iterates over it. Thus, while
copying its elements into the vector, the list might get longer or
shorter. For this reason, the loop must check both that it doesn't
overrun the vector (@code{SCM_SIMPLE_VECTOR_SET} does no range-checking)
and that it doesn't overrung the list (@code{SCM_CAR} and @code{SCM_CDR}
likewise do no type checking).
It is safe to use @code{SCM_CAR} and @code{SCM_CDR} on the local
variable @var{list} once it is known that the variable contains a pair.
The contents of the pair might change spontaneously, but it will always
stay a valid pair (and a local variable will of course not spontaneously
point to a different Scheme object).
Likewise, a simple vector such as the one returned by
@code{scm_make_vector} is guaranteed to always stay the same length so
that it is safe to only use SCM_SIMPLE_VECTOR_LENGTH once and store the
result. (In the example, @var{vector} is safe anyway since it is a
fresh object that no other thread can possibly know about until it is
returned from @code{my_list_to_vector}.)
Of course the behavior of @code{my_list_to_vector} is suboptimal when
@var{list} does indeed gets asynchronously lengthened or shortened in
another thread. But it is robust: it will always return a valid vector.
That vector might be shorter than expected, or its last elements might
be unspecified, but it is a valid vector and if a program wants to rule
out these cases, it must avoid modifying the list asynchronously.
Here is another version that is also correct:
@example
SCM
my_pedantic_list_to_vector (SCM list)
@{
SCM vector = scm_make_vector (scm_length (list), SCM_UNDEFINED);
size_t len, i;
len = SCM_SIMPLE_VECTOR_LENGTH (vector);
i = 0;
while (i < len)
@{
SCM_SIMPLE_VECTOR_SET (vector, i, scm_car (list));
list = scm_cdr (list);
i++;
@}
return vector;
@}
@end example
This version uses the type-checking and thread-robust functions
@code{scm_car} and @code{scm_cdr} instead of the faster, but less robust
macros @code{SCM_CAR} and @code{SCM_CDR}. When the list is shortened
(that is, when @var{list} holds a non-pair), @code{scm_car} will throw
an error. This might be preferable to just returning a half-initialized
vector.
The API for accessing vectors and arrays of various kinds from C takes a
slightly different approach to thread-robustness. In order to get at
the raw memory that stores the elements of an array, you need to
@emph{reserve} that array as long as you need the raw memory. During
the time an array is reserved, its elements can still spontaneously
change their values, but the memory itself and other things like the
size of the array are guaranteed to stay fixed. Any operation that
would change these parameters of an array that is currently reserved
will signal an error. In order to avoid these errors, a program should
of course put suitable synchronization mechanisms in place. As you can
see, Guile itself is again only concerned about robustness, not about
correctness: without proper synchronization, your program will likely
not be correct, but the worst consequence is an error message.

View file

@ -32,7 +32,7 @@ Convert the homogeneous numeric vector @var{uvec} to a list.
@deffn {Scheme Procedure} make-u8vector len [fill] @deffn {Scheme Procedure} make-u8vector len [fill]
@deffnx {C Function} scm_make_u8vector (len, fill) @deffnx {C Function} scm_make_u8vector (len, fill)
Return a newly allocated homogeneous numeric vector which can Return a newly allocated uniform numeric vector which can
hold @var{len} elements. If @var{fill} is given, it is used to hold @var{len} elements. If @var{fill} is given, it is used to
initialize the elements, otherwise the contents of the vector initialize the elements, otherwise the contents of the vector
is unspecified. is unspecified.
@ -40,18 +40,235 @@ is unspecified.
@deffn {Scheme Procedure} u8vector . l @deffn {Scheme Procedure} u8vector . l
@deffnx {C Function} scm_u8vector (l) @deffnx {C Function} scm_u8vector (l)
Return a newly allocated homogeneous numeric vector containing Return a newly allocated uniform numeric vector containing
all argument values. all argument values.
@end deffn @end deffn
@deffn {Scheme Procedure} list->u8vector l @deffn {Scheme Procedure} list->u8vector l
@deffnx {C Function} scm_list_to_u8vector (l) @deffnx {C Function} scm_list_to_u8vector (l)
Convert the list @var{l} to a numeric homogeneous vector. Convert the list @var{l} to a numeric uniform vector.
@end deffn @end deffn
@deffn {Scheme Procedure} any->u8vector obj @deffn {Scheme Procedure} any->u8vector obj
@deffnx {C Function} scm_any_to_u8vector (obj) @deffnx {C Function} scm_any_to_u8vector (obj)
Convert @var{obj}, which can be a list, vector, or Convert @var{obj}, which can be a list, vector, or
homogenous vector, to a numeric homogenous vector of uniform vector, to a numeric uniform vector of
type u8. type u8.
@end deffn @end deffn
@deffn {Scheme Procedure} with-continuation-barrier proc
@deffnx {C Function} scm_with_continuation_barrier (proc)
Call @var{proc} and return the returned value but do not allow the invocation of continuations that would exit or reenter the dynamic extent of the call to @var{proc}. When a uncaught throw happens during the call to @var{proc}, a message is printed to the current error port and @code{#f} is returned.
@end deffn
@deffn {Scheme Procedure} dynamic-state? obj
@deffnx {C Function} scm_dynamic_state_p (obj)
Return @code{#t} if @var{obj} is a dynamic state object;
return @code{#f} otherwise
@end deffn
@deffn {Scheme Procedure} current-dynamic-state
@deffnx {C Function} scm_current_dynamic_state ()
Return the current dynamic state object.
@end deffn
@deffn {Scheme Procedure} set-current-dynamic-state state
@deffnx {C Function} scm_set_current_dynamic_state (state)
Set the current dynamic state object to @var{state}
and return the previous current dynamic state object.
@end deffn
@deffn {Scheme Procedure} with-dynamic-state state proc
@deffnx {C Function} scm_with_dynamic_state (state, proc)
Call @var{proc} while @var{state} is the current dynamic
state object.
@end deffn
@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?}.
@end deffn
@deffn {Scheme Procedure} uniform-vector-ref v idx
@deffnx {C Function} scm_uniform_vector_ref (v, idx)
Return the element at index @var{idx} of the
homogenous numeric vector @var{v}.
@end deffn
@deffn {Scheme Procedure} uniform-vector-length v
@deffnx {C Function} scm_uniform_vector_length (v)
Return the number of elements in the uniform vector @var{v}.
@end deffn
@deffn {Scheme Procedure} uniform-vector-read! uvec [port_or_fd [start [end]]]
@deffnx {C Function} scm_uniform_vector_read_x (uvec, port_or_fd, start, end)
Fill the elements of @var{uvec} by reading
raw bytes from @var{port-or-fdes}, using host byte order.
The optional arguments @var{start} (inclusive) and @var{end}
(exclusive) allow a specified region to be read,
leaving the remainder of the vector unchanged.
When @var{port-or-fdes} is a port, all specified elements
of @var{uvec} are attempted to be read, potentially blocking
while waiting formore input or end-of-file.
When @var{port-or-fd} is an integer, a single call to
read(2) is made.
An error is signalled when the last element has only
been partially filled before reaching end-of-file or in
the single call to read(2).
@code{uniform-vector-read!} returns the number of elements
read.
@var{port-or-fdes} may be omitted, in which case it defaults
to the value returned by @code{(current-input-port)}.
@end deffn
@deffn {Scheme Procedure} uniform-vector-write uvec [port_or_fd [start [end]]]
@deffnx {C Function} scm_uniform_vector_write (uvec, port_or_fd, start, end)
Write the elements of @var{uvec} as raw bytes to
@var{port-or-fdes}, in the host byte order.
The optional arguments @var{start} (inclusive)
and @var{end} (exclusive) allow
a specified region to be written.
When @var{port-or-fdes} is a port, all specified elements
of @var{uvec} are attempted to be written, potentially blocking
while waiting for more room.
When @var{port-or-fd} is an integer, a single call to
write(2) is made.
An error is signalled when the last element has only
been partially written in the single call to write(2).
The number of objects actually written is returned.
@var{port-or-fdes} may be
omitted, in which case it defaults to the value returned by
@code{(current-output-port)}.
@end deffn
@deffn {Scheme Procedure} string-any-c-code char_pred s [start [end]]
@deffnx {C Function} scm_string_any (char_pred, s, start, end)
Check if the predicate @var{pred} is true for any character in
the string @var{s}.
Calls to @var{pred} are made from left to right across @var{s}.
When it returns true (ie.@: non-@code{#f}), that return value
is the return from @code{string-any}.
The SRFI-13 specification requires that the call to @var{pred}
on the last character of @var{s} (assuming that point is
reached) be a tail call, but currently in Guile this is not the
case.
@end deffn
@deffn {Scheme Procedure} string-every-c-code char_pred s [start [end]]
@deffnx {C Function} scm_string_every (char_pred, s, start, end)
Check if the predicate @var{pred} is true for every character
in the string @var{s}.
Calls to @var{pred} are made from left to right across @var{s}.
If the predicate is true for every character then the return
value from the last @var{pred} call is the return from
@code{string-every}.
If there are no characters in @var{s} (ie.@: @var{start} equals
@var{end}) then the return is @code{#t}.
The SRFI-13 specification requires that the call to @var{pred}
on the last character of @var{s} (assuming that point is
reached) be a tail call, but currently in Guile this is not the
case.
@end deffn
@deffn {Scheme Procedure} make-recursive-mutex
@deffnx {C Function} scm_make_recursive_mutex ()
Create a new recursive mutex.
@end deffn
@deffn {Scheme Procedure} vector-copy vec
@deffnx {C Function} scm_vector_copy (vec)
Return a copy of @var{vec}.
@end deffn
@deffn {Scheme Procedure} dimensions->uniform-array dims prot [fill]
@deffnx {Scheme Procedure} make-uniform-vector length prototype [fill]
@deffnx {C Function} scm_dimensions_to_uniform_array (dims, prot, fill)
Create and return a uniform array or vector of type
corresponding to @var{prototype} with dimensions @var{dims} or
length @var{length}. If @var{fill} is supplied, it's used to
fill the array, otherwise @var{prototype} is used.
@end deffn
@deffn {Scheme Procedure} list->uniform-array ndim prot lst
@deffnx {C Function} scm_list_to_uniform_array (ndim, prot, lst)
Return a uniform array of the type indicated by prototype
@var{prot} with elements the same as those of @var{lst}.
Elements must be of the appropriate type, no coercions are
done.
The argument @var{ndim} determines the number of dimensions
of the array. It is either an exact integer, giving the
number directly, or a list of exact integers, whose length
specifies the number of dimensions and each element is the
lower index bound of its dimension.
@end deffn
@deffn {Scheme Procedure} array-prototype ra
@deffnx {C Function} scm_array_prototype (ra)
Return an object that would produce an array of the same type
as @var{array}, if used as the @var{prototype} for
@code{make-uniform-array}.
@end deffn

View file

@ -2356,22 +2356,23 @@ scope and the result from that @var{thunk} is the return from
@code{with-parameters*}. @code{with-parameters*}.
This function is a Guile-specific addition to the SRFI, it's similar This function is a Guile-specific addition to the SRFI, it's similar
to the core @code{with-fluids*} (@pxref{Fluids}). to the core @code{with-fluids*} (@pxref{Fluids and Dynamic States}).
@end defun @end defun
@sp 1 @sp 1
Parameter objects are implemented using fluids (@pxref{Fluids}), so Parameter objects are implemented using fluids (@pxref{Fluids and
each dynamic root has it's own parameter locations. That includes the Dynamic States}), so each dynamic state has it's own parameter
separate locations when outside any @code{parameterize} form. When a locations. That includes the separate locations when outside any
parameter is created it gets a separate initial location in each @code{parameterize} form. When a parameter is created it gets a
dynamic root, all initialized to the given @var{init} value. separate initial location in each dynamic state, all initialized to
the given @var{init} value.
As alluded to above, because each thread is a separate dynamic root, As alluded to above, because each thread usually has a separate
each thread has it's own locations behind parameter objects, and dynamic state, each thread has it's own locations behind parameter
changes in one thread are not visible to any other. When a new objects, and changes in one thread are not visible to any other. When
dynamic root or thread is created, the values of parameters in the a new dynamic state or thread is created, the values of parameters in
originating context are copied, into new locations. the originating context are copied, into new locations.
SRFI-39 doesn't specify the interaction between parameter objects and SRFI-39 doesn't specify the interaction between parameter objects and
threads, so the threading behaviour described here should be regarded threads, so the threading behaviour described here should be regarded