1
Fork 0
mirror of https://git.savannah.gnu.org/git/guile.git synced 2025-05-28 07:50:20 +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
instance @code{(@var{cont} @var{x} @var{y} @var{z})}.
@var{cont} may only be used from the dynamic root in which it was
created (@pxref{Dynamic Roots}), and in a multi-threaded program only
from the thread in which it was created, since each thread is a
separate dynamic root.
@var{cont} may only be used from the same side of a continuation
barrier as it was created (@pxref{Continuation Barriers}), and in a
multi-threaded program only from the thread in which it was created.
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

View file

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

View file

@ -8,50 +8,92 @@
@node Initialization
@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})
Initialize the Guile Scheme interpreter. Then call @var{main_func},
passing it @var{data}, @var{argc}, and @var{argv} as indicated. The
function @var{main_func} should do all the work of the program
(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.
Each thread that wants to use functions from the Guile API needs to
put itself into guile mode with either @code{scm_with_guile} or
@code{scm_init_guile}. The global state of Guile is initialized
automatically when the first thread enters guile mode.
@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.
When a thread wants to block outside of a Guile API function, it should
leave guile mode temporarily with either @code{scm_without_guile} or
@code{scm_leave_guile}, @xref{Threads}.
Why must the caller do all the real work from @var{main_func}? Guile's
garbage collector scans the stack to find all local variables that
reference Scheme objects. To do this, it needs to know the bounds of
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.
Threads that are created by @code{call-with-new-thread} or
@code{scm_spawn_thread} start out in guile mode so you don't need to
initialize them.
See @code{scm_init_guile}, below, for a function that can find the real
base of the stack, but not in a portable way.
@deftypefn {C Function} void *scm_with_guile (void *(*func)(void *), void *data)
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
@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
the true base of the stack and thus does not need to usurp the control
flow of your program. However, since finding the stack base can not be
done portably, this function might not be available in all installations
of Guile. If you can, you should use @code{scm_boot_guile} instead.
When @code{scm_init_guile} is called from a thread that already has been
in guile mode once, nothing happens. This behavior matters when you
call @code{scm_init_guile} while the thread has only temporarily left
guile mode: in that case the thread will not be in guile mode after
@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
line arguments that should be returned by the Scheme function
@code{command-line}. You can use @code{scm_set_program_arguments} to do
this.
When a uncaught throw happens in a thread that has been put into guile
mode via @code{scm_init_guile}, a short message is printed to the
current error port and the thread is exited via @code{scm_pthread_exit
(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
@deftypefn {C Function} void scm_shell (int @var{argc}, char **@var{argv})

View file

@ -15,12 +15,13 @@ reviewed and largely reorganized.]
@menu
* Arbiters:: Synchronization primitives.
* Asyncs:: Asynchronous procedure invocation.
* Dynamic Roots:: Root frames of execution.
* Continuation Barriers:: Protection from non-local control flow.
* 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.
* Parallel Forms:: Parallel execution of forms.
* Mutexes:: Synchronization primitives.
* Mutexes and Condition Variables:: Synchronization primitives.
@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
indicate a resource is in use, and unlocked when done.
An arbiter is like a light-weight mutex (@pxref{Mutexes}). It uses
less memory and may be faster, but there's no way for a thread to
block waiting on an arbiter, it can only test and get the status
returned.
An arbiter is like a light-weight mutex (@pxref{Mutexes and Condition
Variables}). It uses less memory and may be faster, but there's no
way for a thread to block waiting on an arbiter, it can only test and
get the status returned.
@deffn {Scheme Procedure} 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
@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
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}.
@end deffn
@node Continuation Barriers
@subsection Continuation Barriers
@node Dynamic Roots
@subsection Dynamic Roots
@cindex dynamic roots
The non-local flow of control caused by continuations might sometimes
not be wanted. You can use @code{with-continuation-barrier} etc to
errect fences that continuations can not pass.
A @dfn{dynamic root} is a root frame of Scheme evaluation.
The top-level repl, for example, is an instance of a dynamic root.
@deffn {Sheme Procedure} with-continuation-barrier proc
@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
has its own set of continuations, jump-buffers, and pending CATCH
statements which are inaccessible from the dynamic scope of any
other dynamic root.
Throws (such as errors) that are not caught from within @var{proc} are
caught by @code{with-continuation-barrier}. In that case, a short
message is printed to the current error port and @code{#f} is returned.
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.)
Thus, @code{with-continuation-barrier} returns exactly once.
@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
@deftypefn {C Function} void *scm_c_with_continuation_barrier (void *(*func) (void *), void *data)
Like @code{scm_with_continuation_barrier} but call @var{func} on
@var{data}. When an error is caught, @code{NULL} is returned.
@end deftypefn
@node Threads
@subsection Threads
@ -311,21 +229,6 @@ The @code{#f} case has not been implemented.
@cindex Guile 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
@deffnx {C Function} scm_all_threads ()
Return a list of all threads.
@ -337,23 +240,38 @@ Return the thread that called this function.
@end deffn
@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.
@deffn {Scheme Procedure} call-with-new-thread thunk handler
Call @code{thunk} in a new thread and with a new dynamic state,
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
an error code. 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.
When @var{handler} is specified, then @var{thunk} is called from
within a @code{catch} with tag @code{#t} that has @var{handler} as its
handler. This catch is established inside the continuation barrier.
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
@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")
@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.
Wait for @var{thread} to terminate and return its exit value. Threads
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
@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.
@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
@code{(ice-9 threads)} module. These provide standardized
thread creation.
@ -417,7 +292,8 @@ thread creation.
@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 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
@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.
@end deffn
@node C level thread interface
@subsubsection C level thread interface
@node Blocking
@subsection Blocking in Guile Mode
You can create and manage threads
with the C versions of the primitives above.
These
functions and data types are only available from C and can not be
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.
A thread must not block outside of a libguile function while it is in
guile mode. The following functions can be used to temporily leave
guile mode or to perform some common blocking operations in a supported
way.
Furthermore, they are the primitives that Guile relies on for its own
higher level threads. By reimplementing them, you can adapt Guile to
different low-level thread implementations.
@deftypefn {C Function} scm_t_guile_ticket scm_leave_guile ()
Leave guile mode and return a ticket that can be used with
@code{scm_enter_guile} to enter it again.
C code in a thread must call a libguile function periodically. When
one thread finds garbage collection is required, it waits for all
threads to rendezvous before doing that GC. Such a rendezvous is
checked within libguile functions. If C code wants to sleep or block
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.
While a thread has left guile mode, it must not call any libguile
functions except @code{scm_enter_guile} and must not use any libguile
macros. Also, local variables of type @code{SCM} that are allocated
while not in guile mode are not protected from the garbage collector.
@end deftypefn
@deftypefn {C Function} void scm_thread_detach (scm_t_thread t)
Detach the thread @var{t}. See @code{scm_thread_create}.
@deftypefn {C Function} void scm_enter_guile (scm_t_guile_ticket ticket)
Enter guile mode again.
@end deftypefn
@deftypefn {C Function} void scm_thread_join (scm_t_thread t)
Wait for thread @var{t} to terminate. The thread must not have been
detached at the time that @code{scm_thread_join} is called, but it
might have been detached by the time it terminates.
@deftypefn {C Function} void *scm_without_guile (void *(*func) (void *), void *data)
Leave guile mode, call @var{func} on @var{data}, enter guile mode and
return the result of calling @var{func}.
@end deftypefn
@deftypefn {C Function} scm_t_thread scm_thread_self ()
Return the handle of the calling thread.
@deftypefn {C Function} int scm_pthread_mutex_lock (pthread_mutex_t *mutex)
Like @code{pthread_mutex_lock}, but leaves guile mode while waiting for
the mutex.
@end deftypefn
@deftp {C Data Type} scm_t_cond
This data type represents a condition variable, to be used with
scm_cond_init, etc.
@end deftp
@deftypefn {C Function} void scm_cond_init (scm_t_cond *c)
Initialize the condition variable structure pointed to by @var{c}.
@deftypefn {C Function} int scm_pthread_cond_wait (pthread_cond_t *cond, pthread_mutex_t *mutex)
@deftypefnx {C Function} int scm_pthread_cond_timedwait (pthread_cond_t *cond, pthread_mutex_t *mutex, struct timespec *abstime)
Like @code{pthread_cond_wait} and @code{pthread_cond_timedwait}, but
leaves guile mode while waiting for the condition variable.
@end deftypefn
@deftypefn {C Function} void scm_cond_destroy (scm_t_cond *c)
Deallocate all resources associated with @var{c}.
@deftypefn {C Function} int scm_std_select (int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout)
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
@deftypefn {C Function} void scm_cond_wait (scm_t_cond *c, scm_t_mutex *m)
Wait for @var{c} to be signalled. While waiting @var{m} is unlocked
and locked again before @code{scm_cond_wait} returns.
@deftypefn {C Function} {unsigned int} scm_std_sleep ({unsigned int} seconds)
Like @code{sleep}, but leaves guile mode while sleeping. Also, the
delivery of a system async causes this function to be interrupted.
@end deftypefn
@deftypefn {C Function} void scm_cond_timedwait (scm_t_cond *c, scm_t_mutex *m, timespec *abstime)
Wait for @var{c} to be signalled as with @code{scm_cond_wait} but
don't wait longer than the point in time specified by @var{abstime}.
when the waiting is aborted, zero is returned; non-zero else.
@deftypefn {C Function} {unsigned long} scm_std_usleep ({unsigned long} usecs)
Like @code{usleep}, but leaves guile mode while sleeping. Also, the
delivery of a system async causes this function to be interrupted.
@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)
Signal the condition variable @var{c}. When there are threads waiting
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
@node Fluids and Dynamic States
@subsection Fluids and Dynamic States
@cindex fluids
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}).
A @emph{fluid} is an object that can store one value per @emph{dynamic
state}. Each thread has a current dynamic state, and when accessing a
fluid, this current dynamic state is used to provide the actual value.
In this way, fluids can be used for thread local storage, but they are
in fact more flexible: dynamic states are objects of their own and can
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
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.
Fluids can also 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
@ -600,12 +385,12 @@ stored in a fluid can be accessed with @code{fluid-ref} and
@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.
Fluids are objects that can hold one
value per dynamic state. That is, modifications to this value are
only visible to code that executes with the same dynamic state as
the modifying code. When a new dynamic state is constructed, it
inherits the values from its parent. Because each thread normally executes
with its own dynamic state, you can use fluids for thread local storage.
@end deffn
@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.
@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
@subsection Futures
@cindex futures
@ -798,9 +627,10 @@ completed, it doesn't need to wait for all to finish.
@end deffn
@node Mutexes
@subsection Mutexes
@node Mutexes and Condition Variables
@subsection Mutexes and Condition Variables
@cindex mutex
@cindex condition variable
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
@ -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
if not available). ``Mutex'' is short for ``mutual exclusion''.
There are two types of mutexes, ``standard'' and ``fair''. They're
created by @code{make-mutex} and @code{make-fair-mutex} respectively,
the operation functions are then common to both.
There are two types of mutexes in Guile, ``standard'' and
``recursive''. They're created by @code{make-mutex} and
@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
``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
@deffn {Scheme Procedure} make-mutex
@deffnx {Scheme Procedure} make-fair-mutex
Return a new mutex object.
Return a new standard mutex. It is initially unlocked.
@end deffn
@code{make-mutex} creates a standard mutex. This is fast, but its
features are restricted. Recursive locking (multiple lock calls by
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.
@deffn {Scheme Procedure} make-recursive-mutex
Return a new recursive mutex. It is initialloy unlocked.
@end deffn
@deffn {Scheme Procedure} lock-mutex mutex
Lock @var{mutex}. If the mutex is already locked by another thread
then block and return only when @var{mutex} has been acquired.
For standard mutexes (@code{make-mutex}), if the thread has itself
already locked @var{mutex} it must not call @code{lock-mutex} on it a
further time. Behaviour is unspecified if this is done.
For standard mutexes (@code{make-mutex}), and error is signalled if
the thread has itself already locked @var{mutex}.
For a fair mutex (@code{make-fair-mutex}), if the thread has itself
already locked @var{mutex}, then a further @code{lock-mutex} call
increments the lock count. An additional @code{unlock-mutex} will be
required to finally release.
For a recursive mutex (@code{make-recursive-mutex}), if the thread has
itself already locked @var{mutex}, then a further @code{lock-mutex}
call increments the lock count. An additional @code{unlock-mutex}
will be required to finally release.
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
executed. When the async returns the wait resumes.
executed. When the async returns, the wait resumes.
@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
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
@ -865,13 +684,43 @@ the return is @code{#f}.
@end deffn
@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
by the calling thread then behaviour is unspecified.
@c begin (texi-doc-string "guile" "make-condition-variable")
@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
locked by the calling thread then an error is thrown.
@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. 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
@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.
@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 TeX-master: "guile.texi"

View file

@ -1,6 +1,6 @@
@c -*-texinfo-*-
@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 See the file guile.texi for copying conditions.
@ -8,12 +8,12 @@
@node General Libguile Concepts
@section General concepts for using libguile
When you want to embed the Guile Scheme interpreter into your program,
you need to link it against the @file{libguile} library (@pxref{Linking
Programs With Guile}). Once you have done this, your C code has access
to a number of data types and functions that can be used to invoke the
interpreter, or make new functions that you have written in C available
to be called from Scheme code, among other things.
When you want to embed the Guile Scheme interpreter into your program or
library, you need to link it against the @file{libguile} library
(@pxref{Linking Programs With Guile}). Once you have done this, your C
code has access to a number of data types and functions that can be used
to invoke the interpreter, or make new functions that you have written
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
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
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
* Dynamic Types:: Dynamic Types.
* Garbage Collection:: Garbage Collection.
* Control Flow:: Control Flow.
* Asynchronous Signals:: Asynchronous Signals
* Multi-Threading:: Multi-Threading
@end menu
@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,
(@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]
@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
initialize the elements, otherwise the contents of the vector
is unspecified.
@ -40,18 +40,235 @@ is unspecified.
@deffn {Scheme Procedure} 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.
@end deffn
@deffn {Scheme Procedure} list->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
@deffn {Scheme Procedure} any->u8vector obj
@deffnx {C Function} scm_any_to_u8vector (obj)
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.
@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*}.
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
@sp 1
Parameter objects are implemented using fluids (@pxref{Fluids}), so
each dynamic root has it's own parameter locations. That includes the
separate locations when outside any @code{parameterize} form. When a
parameter is created it gets a separate initial location in each
dynamic root, all initialized to the given @var{init} value.
Parameter objects are implemented using fluids (@pxref{Fluids and
Dynamic States}), so each dynamic state has it's own parameter
locations. That includes the separate locations when outside any
@code{parameterize} form. When a parameter is created it gets a
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,
each thread has it's own locations behind parameter objects, and
changes in one thread are not visible to any other. When a new
dynamic root or thread is created, the values of parameters in the
originating context are copied, into new locations.
As alluded to above, because each thread usually has a separate
dynamic state, each thread has it's own locations behind parameter
objects, and changes in one thread are not visible to any other. When
a new dynamic state or thread is created, the values of parameters in
the originating context are copied, into new locations.
SRFI-39 doesn't specify the interaction between parameter objects and
threads, so the threading behaviour described here should be regarded