diff options
author | Marius Vollmer <mvo@zagadka.de> | 2005-03-02 20:46:41 +0000 |
---|---|---|
committer | Marius Vollmer <mvo@zagadka.de> | 2005-03-02 20:46:41 +0000 |
commit | b4fddbbeda8368b705daabb6a32202d1b9ba8b8e (patch) | |
tree | ec2851b20d5215eaa2bb6a0402bc0abd5cdf8856 | |
parent | 9de87eea47536e25ef99bc25f07afdd759ee3575 (diff) | |
download | guile-b4fddbbeda8368b705daabb6a32202d1b9ba8b8e.tar.gz |
Updates for the new thread stuff.
-rw-r--r-- | doc/ref/api-control.texi | 7 | ||||
-rw-r--r-- | doc/ref/api-evaluation.texi | 6 | ||||
-rw-r--r-- | doc/ref/api-init.texi | 124 | ||||
-rw-r--r-- | doc/ref/api-scheduling.texi | 605 | ||||
-rw-r--r-- | doc/ref/libguile-concepts.texi | 221 | ||||
-rw-r--r-- | doc/ref/new-docstrings.texi | 225 | ||||
-rw-r--r-- | doc/ref/srfi-modules.texi | 25 |
7 files changed, 749 insertions, 464 deletions
diff --git a/doc/ref/api-control.texi b/doc/ref/api-control.texi index e778eb391..57cd7866f 100644 --- a/doc/ref/api-control.texi +++ b/doc/ref/api-control.texi @@ -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 diff --git a/doc/ref/api-evaluation.texi b/doc/ref/api-evaluation.texi index c6934df18..b41e88a0a 100644 --- a/doc/ref/api-evaluation.texi +++ b/doc/ref/api-evaluation.texi @@ -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 diff --git a/doc/ref/api-init.texi b/doc/ref/api-init.texi index 94407114b..4e668ce44 100644 --- a/doc/ref/api-init.texi +++ b/doc/ref/api-init.texi @@ -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. - -@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. +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 () -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. +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}) diff --git a/doc/ref/api-scheduling.texi b/doc/ref/api-scheduling.texi index dd830fa34..be3fd6440 100644 --- a/doc/ref/api-scheduling.texi +++ b/doc/ref/api-scheduling.texi @@ -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" diff --git a/doc/ref/libguile-concepts.texi b/doc/ref/libguile-concepts.texi index 6ae004146..a9151ee0f 100644 --- a/doc/ref/libguile-concepts.texi +++ b/doc/ref/libguile-concepts.texi @@ -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. diff --git a/doc/ref/new-docstrings.texi b/doc/ref/new-docstrings.texi index 0f134df9d..7f3bb6f73 100644 --- a/doc/ref/new-docstrings.texi +++ b/doc/ref/new-docstrings.texi @@ -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 diff --git a/doc/ref/srfi-modules.texi b/doc/ref/srfi-modules.texi index c02840acc..e24cce34f 100644 --- a/doc/ref/srfi-modules.texi +++ b/doc/ref/srfi-modules.texi @@ -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 |