Updates for the new thread stuff.
authorMarius Vollmer <mvo@zagadka.de>
Wed, 2 Mar 2005 20:46:41 +0000 (20:46 +0000)
committerMarius Vollmer <mvo@zagadka.de>
Wed, 2 Mar 2005 20:46:41 +0000 (20:46 +0000)
doc/ref/api-control.texi
doc/ref/api-evaluation.texi
doc/ref/api-init.texi
doc/ref/api-scheduling.texi
doc/ref/libguile-concepts.texi
doc/ref/new-docstrings.texi
doc/ref/srfi-modules.texi

index e778eb3..57cd786 100644 (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
index c6934df..b41e88a 100644 (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
dissimilarity index 64%
index 9440711..4e668ce 100644 (file)
-@c -*-texinfo-*-
-@c This is part of the GNU Guile Reference Manual.
-@c Copyright (C)  1996, 1997, 2000, 2001, 2002, 2003, 2004
-@c   Free Software Foundation, Inc.
-@c See the file guile.texi for copying conditions.
-
-
-@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.
-
-@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.
-
-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.
-
-See @code{scm_init_guile}, below, for a function that can find the real
-base of the stack, but not in a portable way.
-@end deftypefn
-
-@deftypefn {C Function} void scm_init_guile ()
-Initialize the Guile Scheme interpreter.
-
-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.
-
-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.
-@end deftypefn
-
-@deftypefn {C Function} void scm_shell (int @var{argc}, char **@var{argv})
-Process command-line arguments in the manner of the @code{guile}
-executable.  This includes loading the normal Guile initialization
-files, interacting with the user or running any scripts or expressions
-specified by @code{-s} or @code{-e} options, and then exiting.
-@xref{Invoking Guile}, for more details.
-
-Since this function does not return, you must do all
-application-specific initialization before calling this function.
-@end deftypefn
+@c -*-texinfo-*-
+@c This is part of the GNU Guile Reference Manual.
+@c Copyright (C)  1996, 1997, 2000, 2001, 2002, 2003, 2004
+@c   Free Software Foundation, Inc.
+@c See the file guile.texi for copying conditions.
+
+
+@node Initialization
+@section Initializing Guile
+
+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.
+
+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}.
+
+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.
+
+@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 ()
+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).
+
+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.
+
+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})
+Process command-line arguments in the manner of the @code{guile}
+executable.  This includes loading the normal Guile initialization
+files, interacting with the user or running any scripts or expressions
+specified by @code{-s} or @code{-e} options, and then exiting.
+@xref{Invoking Guile}, for more details.
+
+Since this function does not return, you must do all
+application-specific initialization before calling this function.
+@end deftypefn
index dd830fa..be3fd64 100644 (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.)
-@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.
+Thus, @code{with-continuation-barrier} returns exactly once.
 @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
-
-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.
-
-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.
-
-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.
-@end deftypefn
+@node Blocking
+@subsection Blocking in Guile Mode
 
-@deftypefn {C Function} void scm_thread_detach (scm_t_thread t)
-Detach the thread @var{t}.  See @code{scm_thread_create}.
-@end deftypefn
+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.
 
-@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.
-@end deftypefn
+@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.
 
-@deftypefn {C Function} scm_t_thread scm_thread_self ()
-Return the handle of the calling thread.
+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
 
-@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} void scm_enter_guile (scm_t_guile_ticket ticket)
+Enter guile mode again.
 @end deftypefn
 
-@deftypefn {C Function} void scm_cond_destroy (scm_t_cond *c)
-Deallocate all resources associated with @var{c}.
+@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} 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} 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
 
-@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} 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_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.
+@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_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.
+@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
 
-@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.
+@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_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}).
-
-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.
+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 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.
-
-@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.
+Return a new standard mutex.  It is initially unlocked.
+@end deffn
 
-@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
+
+@c begin (texi-doc-string "guile" "make-condition-variable")
+@deffn {Scheme Procedure} make-condition-variable
+Return a new 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.
 
-For a standard mutex (@code{make-mutex}), if @var{mutex} is not locked
-by the calling thread then behaviour is unspecified.
+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
 
-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" "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"
index 6ae0041..a9151ee 100644 (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.
index 0f134df..7f3bb6f 100644 (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
index c02840a..e24cce3 100644 (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.
-
-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.
+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 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