mirror of
https://git.savannah.gnu.org/git/guile.git
synced 2025-05-30 08:50:23 +02:00
Updates for the new thread stuff.
This commit is contained in:
parent
9de87eea47
commit
b4fddbbeda
7 changed files with 742 additions and 457 deletions
|
@ -372,10 +372,9 @@ location resumed is expecting multiple values (@pxref{Multiple
|
||||||
Values}) then they should be passed as multiple arguments, for
|
Values}) then they should be passed as multiple arguments, for
|
||||||
instance @code{(@var{cont} @var{x} @var{y} @var{z})}.
|
instance @code{(@var{cont} @var{x} @var{y} @var{z})}.
|
||||||
|
|
||||||
@var{cont} may only be used from the dynamic root in which it was
|
@var{cont} may only be used from the same side of a continuation
|
||||||
created (@pxref{Dynamic Roots}), and in a multi-threaded program only
|
barrier as it was created (@pxref{Continuation Barriers}), and in a
|
||||||
from the thread in which it was created, since each thread is a
|
multi-threaded program only from the thread in which it was created.
|
||||||
separate dynamic root.
|
|
||||||
|
|
||||||
The call to @var{proc} is not part of the continuation captured, it runs
|
The call to @var{proc} is not part of the continuation captured, it runs
|
||||||
only when the continuation is created. Often a program will want to
|
only when the continuation is created. Often a program will want to
|
||||||
|
|
|
@ -326,13 +326,15 @@ this procedure directly, use the procedures @code{read-enable},
|
||||||
|
|
||||||
@rnindex eval
|
@rnindex eval
|
||||||
@c ARGFIXME environment/environment specifier
|
@c ARGFIXME environment/environment specifier
|
||||||
@deffn {Scheme Procedure} eval exp module
|
@deffn {Scheme Procedure} eval exp module_or_state
|
||||||
@deffnx {C Function} scm_eval (exp, module)
|
@deffnx {C Function} scm_eval (exp, module_or_state)
|
||||||
Evaluate @var{exp}, a list representing a Scheme expression,
|
Evaluate @var{exp}, a list representing a Scheme expression,
|
||||||
in the top-level environment specified by @var{module}.
|
in the top-level environment specified by @var{module}.
|
||||||
While @var{exp} is evaluated (using @code{primitive-eval}),
|
While @var{exp} is evaluated (using @code{primitive-eval}),
|
||||||
@var{module} is made the current module. The current module
|
@var{module} is made the current module. The current module
|
||||||
is reset to its previous value when @var{eval} returns.
|
is reset to its previous value when @var{eval} returns.
|
||||||
|
XXX - dynamic states.
|
||||||
|
Example: (eval '(+ 1 2) (interaction-environment))
|
||||||
@end deffn
|
@end deffn
|
||||||
|
|
||||||
@rnindex interaction-environment
|
@rnindex interaction-environment
|
||||||
|
|
|
@ -8,50 +8,92 @@
|
||||||
@node Initialization
|
@node Initialization
|
||||||
@section Initializing Guile
|
@section Initializing Guile
|
||||||
|
|
||||||
@deftypefn {C Function} void scm_boot_guile (int @var{argc}, char **@var{argv}, void (*@var{main_func}) (void *@var{data}, int @var{argc}, char **@var{argv}), void *@var{data})
|
Each thread that wants to use functions from the Guile API needs to
|
||||||
Initialize the Guile Scheme interpreter. Then call @var{main_func},
|
put itself into guile mode with either @code{scm_with_guile} or
|
||||||
passing it @var{data}, @var{argc}, and @var{argv} as indicated. The
|
@code{scm_init_guile}. The global state of Guile is initialized
|
||||||
function @var{main_func} should do all the work of the program
|
automatically when the first thread enters guile mode.
|
||||||
(initializing other packages, defining application-specific functions,
|
|
||||||
reading user input, and so on) before returning. When @var{main_func}
|
|
||||||
returns, @code{scm_boot_guile} calls @code{exit (0)};
|
|
||||||
@code{scm_boot_guile} never returns. If you want some other exit
|
|
||||||
value, have @var{main_func} call @code{exit} itself.
|
|
||||||
|
|
||||||
@code{scm_boot_guile} arranges for the Scheme @code{command-line}
|
When a thread wants to block outside of a Guile API function, it should
|
||||||
function to return the strings given by @var{argc} and @var{argv}. If
|
leave guile mode temporarily with either @code{scm_without_guile} or
|
||||||
@var{main_func} modifies @var{argc} or @var{argv}, it should call
|
@code{scm_leave_guile}, @xref{Threads}.
|
||||||
@code{scm_set_program_arguments} with the final list, so Scheme code
|
|
||||||
will know which arguments have been processed.
|
|
||||||
|
|
||||||
Why must the caller do all the real work from @var{main_func}? Guile's
|
Threads that are created by @code{call-with-new-thread} or
|
||||||
garbage collector scans the stack to find all local variables that
|
@code{scm_spawn_thread} start out in guile mode so you don't need to
|
||||||
reference Scheme objects. To do this, it needs to know the bounds of
|
initialize them.
|
||||||
the stack that might contain such references. Because there is no
|
|
||||||
portable way in C to find the base of the stack, @code{scm_boot_guile}
|
|
||||||
assumes that all references are above its own stack frame. If you try
|
|
||||||
to manipulate Scheme objects after this function returns, it's the luck
|
|
||||||
of the draw whether Guile's storage manager will be able to find the
|
|
||||||
objects you allocate. So, @code{scm_boot_guile} function exits, rather
|
|
||||||
than returning, to discourage you from making that mistake.
|
|
||||||
|
|
||||||
See @code{scm_init_guile}, below, for a function that can find the real
|
@deftypefn {C Function} void *scm_with_guile (void *(*func)(void *), void *data)
|
||||||
base of the stack, but not in a portable way.
|
Call @var{func}, passing it @var{data} and return what @var{func}
|
||||||
|
returns. While @var{func} is running, the current thread is in guile
|
||||||
|
mode and can thus use the Guile API.
|
||||||
|
|
||||||
|
When @code{scm_with_guile} is called from guile mode, the thread remains
|
||||||
|
in guile mode when @code{scm_with_guile} returns.
|
||||||
|
|
||||||
|
Otherwise, it puts the current thread into guile mode and, if needed,
|
||||||
|
gives it a Scheme representation that is contained in the list returned
|
||||||
|
by @code{all-threads}, for example. This Scheme representation is not
|
||||||
|
removed when @code{scm_with_guile} returns so that a given thread is
|
||||||
|
always represented by the same Scheme value during its lifetime, if at
|
||||||
|
all.
|
||||||
|
|
||||||
|
When this is the first thread that enters guile mode, the global state
|
||||||
|
of Guile is initialized before calling @code{func}.
|
||||||
|
|
||||||
|
The function @var{func} is called via
|
||||||
|
@code{scm_with_continuation_barrier}; thus, @code{scm_with_guile}
|
||||||
|
returns exactly once.
|
||||||
|
|
||||||
|
When @code{scm_with_guile} returns, the thread is no longer in guile
|
||||||
|
mode (except when @code{scm_with_guile} was called from guile mode, see
|
||||||
|
above). Thus, only @code{func} can store @code{SCM} variables on the
|
||||||
|
stack and be sure that they are protected from the garbage collector.
|
||||||
|
See @code{scm_init_guile} for another approach at initializing Guile
|
||||||
|
that does not have this restriction.
|
||||||
|
|
||||||
|
It is OK to call @code{scm_with_guile} while a thread has temporarily
|
||||||
|
left guile mode via @code{scm_without_guile} or @code{scm_leave_guile}.
|
||||||
|
It will then simply temporarily enter guile mode again.
|
||||||
@end deftypefn
|
@end deftypefn
|
||||||
|
|
||||||
@deftypefn {C Function} void scm_init_guile ()
|
@deftypefn {C Function} void scm_init_guile ()
|
||||||
Initialize the Guile Scheme interpreter.
|
Arrange things so that all of the code in the current thread executes as
|
||||||
|
if from within a call to @code{scm_with_guile}. That is, all functions
|
||||||
|
called by the current thread can assume that @code{SCM} values on their
|
||||||
|
stack frames are protected from the garbage collector (except when the
|
||||||
|
thread has explicitely left guile mode, of course).
|
||||||
|
|
||||||
In contrast to @code{scm_boot_guile}, this function knows how to find
|
When @code{scm_init_guile} is called from a thread that already has been
|
||||||
the true base of the stack and thus does not need to usurp the control
|
in guile mode once, nothing happens. This behavior matters when you
|
||||||
flow of your program. However, since finding the stack base can not be
|
call @code{scm_init_guile} while the thread has only temporarily left
|
||||||
done portably, this function might not be available in all installations
|
guile mode: in that case the thread will not be in guile mode after
|
||||||
of Guile. If you can, you should use @code{scm_boot_guile} instead.
|
@code{scm_init_guile} returns. Thus, you should not use
|
||||||
|
@code{scm_init_guile} in such a scenario.
|
||||||
|
|
||||||
Note that @code{scm_init_guile} does not inform Guile about the command
|
When a uncaught throw happens in a thread that has been put into guile
|
||||||
line arguments that should be returned by the Scheme function
|
mode via @code{scm_init_guile}, a short message is printed to the
|
||||||
@code{command-line}. You can use @code{scm_set_program_arguments} to do
|
current error port and the thread is exited via @code{scm_pthread_exit
|
||||||
this.
|
(NULL)}. No restrictions are placed on continuations.
|
||||||
|
|
||||||
|
The function @code{scm_init_guile} might not be available on all
|
||||||
|
platforms since it requires some stack-bounds-finding magic that might
|
||||||
|
not have been ported to all platforms that Guile runs on. Thus, if you
|
||||||
|
can, it is better to use @code{scm_with_guile} or its variation
|
||||||
|
@code{scm_boot_guile} instead of this function.
|
||||||
|
@end deftypefn
|
||||||
|
|
||||||
|
@deftypefn {C Function} void scm_boot_guile (int @var{argc}, char **@var{argv}, void (*@var{main_func}) (void *@var{data}, int @var{argc}, char **@var{argv}), void *@var{data})
|
||||||
|
Enter guile mode as with @code{scm_with_guile} and call @var{main_func},
|
||||||
|
passing it @var{data}, @var{argc}, and @var{argv} as indicated. When
|
||||||
|
@var{main_func} returns, @code{scm_boot_guile} calls @code{exit (0)};
|
||||||
|
@code{scm_boot_guile} never returns. If you want some other exit value,
|
||||||
|
have @var{main_func} call @code{exit} itself. If you don't want to exit
|
||||||
|
at all, use @code{scm_with_guile} instead of @code{scm_boot_guile}.
|
||||||
|
|
||||||
|
The function @code{scm_boot_guile} arranges for the Scheme
|
||||||
|
@code{command-line} function to return the strings given by @var{argc}
|
||||||
|
and @var{argv}. If @var{main_func} modifies @var{argc} or @var{argv},
|
||||||
|
it should call @code{scm_set_program_arguments} with the final list, so
|
||||||
|
Scheme code will know which arguments have been processed.
|
||||||
@end deftypefn
|
@end deftypefn
|
||||||
|
|
||||||
@deftypefn {C Function} void scm_shell (int @var{argc}, char **@var{argv})
|
@deftypefn {C Function} void scm_shell (int @var{argc}, char **@var{argv})
|
||||||
|
|
|
@ -15,12 +15,13 @@ reviewed and largely reorganized.]
|
||||||
@menu
|
@menu
|
||||||
* Arbiters:: Synchronization primitives.
|
* Arbiters:: Synchronization primitives.
|
||||||
* Asyncs:: Asynchronous procedure invocation.
|
* Asyncs:: Asynchronous procedure invocation.
|
||||||
* Dynamic Roots:: Root frames of execution.
|
* Continuation Barriers:: Protection from non-local control flow.
|
||||||
* Threads:: Multiple threads of execution.
|
* Threads:: Multiple threads of execution.
|
||||||
* Fluids:: Thread-local variables.
|
* Blocking:: How to block properly in guile mode.
|
||||||
|
* Fluids and Dynamic States:: Thread-local variables, etc.
|
||||||
* Futures:: Delayed execution in new threads.
|
* Futures:: Delayed execution in new threads.
|
||||||
* Parallel Forms:: Parallel execution of forms.
|
* Parallel Forms:: Parallel execution of forms.
|
||||||
* Mutexes:: Synchronization primitives.
|
* Mutexes and Condition Variables:: Synchronization primitives.
|
||||||
@end menu
|
@end menu
|
||||||
|
|
||||||
|
|
||||||
|
@ -32,10 +33,10 @@ Arbiters are synchronization objects, they can be used by threads to
|
||||||
control access to a shared resource. An arbiter can be locked to
|
control access to a shared resource. An arbiter can be locked to
|
||||||
indicate a resource is in use, and unlocked when done.
|
indicate a resource is in use, and unlocked when done.
|
||||||
|
|
||||||
An arbiter is like a light-weight mutex (@pxref{Mutexes}). It uses
|
An arbiter is like a light-weight mutex (@pxref{Mutexes and Condition
|
||||||
less memory and may be faster, but there's no way for a thread to
|
Variables}). It uses less memory and may be faster, but there's no
|
||||||
block waiting on an arbiter, it can only test and get the status
|
way for a thread to block waiting on an arbiter, it can only test and
|
||||||
returned.
|
get the status returned.
|
||||||
|
|
||||||
@deffn {Scheme Procedure} make-arbiter name
|
@deffn {Scheme Procedure} make-arbiter name
|
||||||
@deffnx {C Function} scm_make_arbiter (name)
|
@deffnx {C Function} scm_make_arbiter (name)
|
||||||
|
@ -113,7 +114,7 @@ them temporarily.
|
||||||
|
|
||||||
In addition to the C versions of @code{call-with-blocked-asyncs} and
|
In addition to the C versions of @code{call-with-blocked-asyncs} and
|
||||||
@code{call-with-unblocked-asyncs}, C code can use
|
@code{call-with-unblocked-asyncs}, C code can use
|
||||||
@code{scm_with_blocked_asyncs} and @code{scm_with_unblocked_asyncs}
|
@code{scm_frame_block_asyncs} and @code{scm_frame_unblock_asyncs}
|
||||||
inside a @dfn{frame} (@pxref{Frames}) to block or unblock system asyncs
|
inside a @dfn{frame} (@pxref{Frames}) to block or unblock system asyncs
|
||||||
temporarily.
|
temporarily.
|
||||||
|
|
||||||
|
@ -196,114 +197,31 @@ Mark the user async @var{a} for future execution.
|
||||||
Execute all thunks from the marked asyncs of the list @var{list_of_a}.
|
Execute all thunks from the marked asyncs of the list @var{list_of_a}.
|
||||||
@end deffn
|
@end deffn
|
||||||
|
|
||||||
|
@node Continuation Barriers
|
||||||
|
@subsection Continuation Barriers
|
||||||
|
|
||||||
@node Dynamic Roots
|
The non-local flow of control caused by continuations might sometimes
|
||||||
@subsection Dynamic Roots
|
not be wanted. You can use @code{with-continuation-barrier} etc to
|
||||||
@cindex dynamic roots
|
errect fences that continuations can not pass.
|
||||||
|
|
||||||
A @dfn{dynamic root} is a root frame of Scheme evaluation.
|
@deffn {Sheme Procedure} with-continuation-barrier proc
|
||||||
The top-level repl, for example, is an instance of a dynamic root.
|
@deffnx {C Function} scm_with_continuation_barrier (proc)
|
||||||
|
Call @var{proc} and return its result. Do not allow the invocation of
|
||||||
|
continuations that would leave or enter the dynamic extent of the call
|
||||||
|
to @code{with-continuation-barrier}. Such an attempt causes an error
|
||||||
|
to be signaled.
|
||||||
|
|
||||||
Each dynamic root has its own chain of dynamic-wind information. Each
|
Throws (such as errors) that are not caught from within @var{proc} are
|
||||||
has its own set of continuations, jump-buffers, and pending CATCH
|
caught by @code{with-continuation-barrier}. In that case, a short
|
||||||
statements which are inaccessible from the dynamic scope of any
|
message is printed to the current error port and @code{#f} is returned.
|
||||||
other dynamic root.
|
|
||||||
|
|
||||||
In a thread-based system, each thread has its own dynamic root. Therefore,
|
Thus, @code{with-continuation-barrier} returns exactly once.
|
||||||
continuations created by one thread may not be invoked by another.
|
|
||||||
|
|
||||||
Even in a single-threaded system, it is sometimes useful to create a new
|
|
||||||
dynamic root. For example, if you want to apply a procedure, but to
|
|
||||||
not allow that procedure to capture the current continuation, calling
|
|
||||||
the procedure under a new dynamic root will do the job.
|
|
||||||
|
|
||||||
@deffn {Scheme Procedure} call-with-dynamic-root thunk handler
|
|
||||||
@deffnx {C Function} scm_call_with_dynamic_root (thunk, handler)
|
|
||||||
Evaluate @code{(thunk)} in a new dynamic context, returning its value.
|
|
||||||
|
|
||||||
If an error occurs during evaluation, apply @var{handler} to the
|
|
||||||
arguments to the throw, just as @code{throw} would. If this happens,
|
|
||||||
@var{handler} is called outside the scope of the new root -- it is
|
|
||||||
called in the same dynamic context in which
|
|
||||||
@code{call-with-dynamic-root} was evaluated.
|
|
||||||
|
|
||||||
If @var{thunk} captures a continuation, the continuation is rooted at
|
|
||||||
the call to @var{thunk}. In particular, the call to
|
|
||||||
@code{call-with-dynamic-root} is not captured. Therefore,
|
|
||||||
@code{call-with-dynamic-root} always returns at most one time.
|
|
||||||
|
|
||||||
Before calling @var{thunk}, the dynamic-wind chain is un-wound back to
|
|
||||||
the root and a new chain started for @var{thunk}. Therefore, this call
|
|
||||||
may not do what you expect:
|
|
||||||
|
|
||||||
@lisp
|
|
||||||
;; Almost certainly a bug:
|
|
||||||
(with-output-to-port
|
|
||||||
some-port
|
|
||||||
|
|
||||||
(lambda ()
|
|
||||||
(call-with-dynamic-root
|
|
||||||
(lambda ()
|
|
||||||
(display 'fnord)
|
|
||||||
(newline))
|
|
||||||
(lambda (errcode) errcode))))
|
|
||||||
@end lisp
|
|
||||||
|
|
||||||
The problem is, on what port will @samp{fnord} be displayed? You
|
|
||||||
might expect that because of the @code{with-output-to-port} that
|
|
||||||
it will be displayed on the port bound to @code{some-port}. But it
|
|
||||||
probably won't -- before evaluating the thunk, dynamic winds are
|
|
||||||
unwound, including those created by @code{with-output-to-port}.
|
|
||||||
So, the standard output port will have been re-set to its default value
|
|
||||||
before @code{display} is evaluated.
|
|
||||||
|
|
||||||
(This function was added to Guile mostly to help calls to functions in C
|
|
||||||
libraries that can not tolerate non-local exits or calls that return
|
|
||||||
multiple times. If such functions call back to the interpreter, it should
|
|
||||||
be under a new dynamic root.)
|
|
||||||
@end deffn
|
@end deffn
|
||||||
|
|
||||||
|
@deftypefn {C Function} void *scm_c_with_continuation_barrier (void *(*func) (void *), void *data)
|
||||||
@deffn {Scheme Procedure} dynamic-root
|
Like @code{scm_with_continuation_barrier} but call @var{func} on
|
||||||
@deffnx {C Function} scm_dynamic_root ()
|
@var{data}. When an error is caught, @code{NULL} is returned.
|
||||||
Return an object representing the current dynamic root.
|
@end deftypefn
|
||||||
|
|
||||||
These objects are only useful for comparison using @code{eq?}.
|
|
||||||
They are currently represented as numbers, but your code should
|
|
||||||
in no way depend on this.
|
|
||||||
@end deffn
|
|
||||||
|
|
||||||
@c begin (scm-doc-string "boot-9.scm" "quit")
|
|
||||||
@deffn {Scheme Procedure} quit [exit_val]
|
|
||||||
Throw back to the error handler of the current dynamic root.
|
|
||||||
|
|
||||||
If integer @var{exit_val} is specified and if Guile is being used
|
|
||||||
stand-alone and if quit is called from the initial dynamic-root,
|
|
||||||
@var{exit_val} becomes the exit status of the Guile process and the
|
|
||||||
process exits.
|
|
||||||
@end deffn
|
|
||||||
|
|
||||||
When Guile is run interactively, errors are caught from within the
|
|
||||||
read-eval-print loop. An error message will be printed and @code{abort}
|
|
||||||
called. A default set of signal handlers is installed, e.g., to allow
|
|
||||||
user interrupt of the interpreter.
|
|
||||||
|
|
||||||
It is possible to switch to a "batch mode", in which the interpreter
|
|
||||||
will terminate after an error and in which all signals cause their
|
|
||||||
default actions. Switching to batch mode causes any handlers installed
|
|
||||||
from Scheme code to be removed. An example of where this is useful is
|
|
||||||
after forking a new process intended to run non-interactively.
|
|
||||||
|
|
||||||
@c begin (scm-doc-string "boot-9.scm" "batch-mode?")
|
|
||||||
@deffn {Scheme Procedure} batch-mode?
|
|
||||||
Returns a boolean indicating whether the interpreter is in batch mode.
|
|
||||||
@end deffn
|
|
||||||
|
|
||||||
@c begin (scm-doc-string "boot-9.scm" "set-batch-mode?!")
|
|
||||||
@deffn {Scheme Procedure} set-batch-mode?! arg
|
|
||||||
If @var{arg} is true, switches the interpreter to batch mode.
|
|
||||||
The @code{#f} case has not been implemented.
|
|
||||||
@end deffn
|
|
||||||
|
|
||||||
@node Threads
|
@node Threads
|
||||||
@subsection Threads
|
@subsection Threads
|
||||||
|
@ -311,21 +229,6 @@ The @code{#f} case has not been implemented.
|
||||||
@cindex Guile threads
|
@cindex Guile threads
|
||||||
@cindex POSIX threads
|
@cindex POSIX threads
|
||||||
|
|
||||||
Guile threads are implemented using POSIX threads, they run
|
|
||||||
pre-emptively and concurrently through both Scheme code and system
|
|
||||||
calls. The only exception is for garbage collection, where all
|
|
||||||
threads must rendezvous.
|
|
||||||
|
|
||||||
@menu
|
|
||||||
* Low level thread primitives::
|
|
||||||
* Higher level thread procedures::
|
|
||||||
* C level thread interface::
|
|
||||||
@end menu
|
|
||||||
|
|
||||||
|
|
||||||
@node Low level thread primitives
|
|
||||||
@subsubsection Low level thread primitives
|
|
||||||
|
|
||||||
@deffn {Scheme Procedure} all-threads
|
@deffn {Scheme Procedure} all-threads
|
||||||
@deffnx {C Function} scm_all_threads ()
|
@deffnx {C Function} scm_all_threads ()
|
||||||
Return a list of all threads.
|
Return a list of all threads.
|
||||||
|
@ -337,23 +240,38 @@ Return the thread that called this function.
|
||||||
@end deffn
|
@end deffn
|
||||||
|
|
||||||
@c begin (texi-doc-string "guile" "call-with-new-thread")
|
@c begin (texi-doc-string "guile" "call-with-new-thread")
|
||||||
@deffn {Scheme Procedure} call-with-new-thread thunk error-handler
|
@deffn {Scheme Procedure} call-with-new-thread thunk handler
|
||||||
Evaluate @code{(thunk)} in a new thread, and new dynamic context,
|
Call @code{thunk} in a new thread and with a new dynamic state,
|
||||||
returning a new thread object representing the thread.
|
returning the new thread. The procedure @var{thunk} is called via
|
||||||
|
@code{with-continuation-barrier}.
|
||||||
|
|
||||||
If an error occurs during evaluation, call error-handler, passing it
|
When @var{handler} is specified, then @var{thunk} is called from
|
||||||
an error code. If this happens, the error-handler is called outside
|
within a @code{catch} with tag @code{#t} that has @var{handler} as its
|
||||||
the scope of the new root -- it is called in the same dynamic context
|
handler. This catch is established inside the continuation barrier.
|
||||||
in which with-new-thread was evaluated, but not in the caller's
|
|
||||||
thread.
|
|
||||||
|
|
||||||
All the evaluation rules for dynamic roots apply to threads.
|
Once @var{thunk} or @var{handler} returns, the return value is made
|
||||||
|
the @emph{exit value} of the thread and the thread is terminated.
|
||||||
@end deffn
|
@end deffn
|
||||||
|
|
||||||
|
@deftypefn {C Function} SCM scm_spawn_thread (scm_t_catch_body body, void *body_data, scm_t_catch_handler handler, void *handler_data)
|
||||||
|
Call @var{body} in a new thread, passing it @var{body_data}, returning
|
||||||
|
the new thread. The function @var{body} is called via
|
||||||
|
@code{scm_c_with_continuation_barrier}.
|
||||||
|
|
||||||
|
When @var{handler} is non-@code{NULL}, @var{body} is called via
|
||||||
|
@code{scm_internal_catch} with tag @code{SCM_BOOL_T} that has
|
||||||
|
@var{handler} and @var{handler_data} as the handler and its data. This
|
||||||
|
catch is established inside the continuation barrier.
|
||||||
|
|
||||||
|
Once @var{body} or @var{handler} returns, the return value is made the
|
||||||
|
@emph{exit value} of the thread and the thread is terminated.
|
||||||
|
@end deftypefn
|
||||||
|
|
||||||
@c begin (texi-doc-string "guile" "join-thread")
|
@c begin (texi-doc-string "guile" "join-thread")
|
||||||
@deffn {Scheme Procedure} join-thread thread
|
@deffn {Scheme Procedure} join-thread thread
|
||||||
Suspend execution of the calling thread until the target @var{thread}
|
Wait for @var{thread} to terminate and return its exit value. Threads
|
||||||
terminates, unless the target @var{thread} has already terminated.
|
that have not been created with @code{call-with-new-thread} or
|
||||||
|
@code{scm_spawn_thread} have an exit value of @code{#f}.
|
||||||
@end deffn
|
@end deffn
|
||||||
|
|
||||||
@deffn {Scheme Procedure} thread-exited? thread
|
@deffn {Scheme Procedure} thread-exited? thread
|
||||||
|
@ -367,49 +285,6 @@ If one or more threads are waiting to execute, calling yield forces an
|
||||||
immediate context switch to one of them. Otherwise, yield has no effect.
|
immediate context switch to one of them. Otherwise, yield has no effect.
|
||||||
@end deffn
|
@end deffn
|
||||||
|
|
||||||
@c begin (texi-doc-string "guile" "make-condition-variable")
|
|
||||||
@deffn {Scheme Procedure} make-condition-variable
|
|
||||||
Make a new condition variable.
|
|
||||||
@end deffn
|
|
||||||
|
|
||||||
@deffn {Scheme Procedure} make-fair-condition-variable
|
|
||||||
@deffnx {C Function} scm_make_fair_condition_variable ()
|
|
||||||
Make a new fair condition variable.
|
|
||||||
@end deffn
|
|
||||||
|
|
||||||
@c begin (texi-doc-string "guile" "wait-condition-variable")
|
|
||||||
@deffn {Scheme Procedure} wait-condition-variable cond-var mutex [time]
|
|
||||||
Wait until @var{cond-var} has been signalled. While waiting,
|
|
||||||
@var{mutex} is atomically unlocked (as with @code{unlock-mutex}) and
|
|
||||||
is locked again when this function returns. When @var{time} is given,
|
|
||||||
it specifies a point in time where the waiting should be aborted. It
|
|
||||||
can be either a integer as returned by @code{current-time} or a pair
|
|
||||||
as returned by @code{gettimeofday}. When the waiting is aborted,
|
|
||||||
@code{#f} is returned. When the condition variable has in fact been
|
|
||||||
signalled, @code{#t} is returned. The mutex is re-locked in any case
|
|
||||||
before @code{wait-condition-variable} returns.
|
|
||||||
|
|
||||||
When a system async is activated for a thread that is blocked in a
|
|
||||||
call to @code{wait-condition-variable}, the waiting is interrupted,
|
|
||||||
the mutex is locked, and the async is executed. When the async
|
|
||||||
returns, the mutex is unlocked again and the waiting is resumed.
|
|
||||||
@end deffn
|
|
||||||
|
|
||||||
@c begin (texi-doc-string "guile" "signal-condition-variable")
|
|
||||||
@deffn {Scheme Procedure} signal-condition-variable cond-var
|
|
||||||
Wake up one thread that is waiting for @var{cv}.
|
|
||||||
@end deffn
|
|
||||||
|
|
||||||
@c begin (texi-doc-string "guile" "broadcast-condition-variable")
|
|
||||||
@deffn {Scheme Procedure} broadcast-condition-variable cond-var
|
|
||||||
Wake up all threads that are waiting for @var{cv}.
|
|
||||||
@end deffn
|
|
||||||
|
|
||||||
@node Higher level thread procedures
|
|
||||||
@subsubsection Higher level thread procedures
|
|
||||||
|
|
||||||
@c new by ttn, needs review
|
|
||||||
|
|
||||||
Higher level thread procedures are available by loading the
|
Higher level thread procedures are available by loading the
|
||||||
@code{(ice-9 threads)} module. These provide standardized
|
@code{(ice-9 threads)} module. These provide standardized
|
||||||
thread creation.
|
thread creation.
|
||||||
|
@ -417,7 +292,8 @@ thread creation.
|
||||||
@deffn macro make-thread proc [args@dots{}]
|
@deffn macro make-thread proc [args@dots{}]
|
||||||
Apply @var{proc} to @var{args} in a new thread formed by
|
Apply @var{proc} to @var{args} in a new thread formed by
|
||||||
@code{call-with-new-thread} using a default error handler that display
|
@code{call-with-new-thread} using a default error handler that display
|
||||||
the error to the current error port.
|
the error to the current error port. The @var{args@dots{}}
|
||||||
|
expressions are evaluated in the new thread.
|
||||||
@end deffn
|
@end deffn
|
||||||
|
|
||||||
@deffn macro begin-thread first [rest@dots{}]
|
@deffn macro begin-thread first [rest@dots{}]
|
||||||
|
@ -426,171 +302,80 @@ Evaluate forms @var{first} and @var{rest} in a new thread formed by
|
||||||
the error to the current error port.
|
the error to the current error port.
|
||||||
@end deffn
|
@end deffn
|
||||||
|
|
||||||
@node C level thread interface
|
@node Blocking
|
||||||
@subsubsection C level thread interface
|
@subsection Blocking in Guile Mode
|
||||||
|
|
||||||
You can create and manage threads
|
A thread must not block outside of a libguile function while it is in
|
||||||
with the C versions of the primitives above.
|
guile mode. The following functions can be used to temporily leave
|
||||||
These
|
guile mode or to perform some common blocking operations in a supported
|
||||||
functions and data types are only available from C and can not be
|
way.
|
||||||
mixed with the first set from above. However, they might be more
|
|
||||||
efficient and can be used in situations where Scheme data types are
|
|
||||||
not allowed or are inconvenient to use.
|
|
||||||
|
|
||||||
Furthermore, they are the primitives that Guile relies on for its own
|
@deftypefn {C Function} scm_t_guile_ticket scm_leave_guile ()
|
||||||
higher level threads. By reimplementing them, you can adapt Guile to
|
Leave guile mode and return a ticket that can be used with
|
||||||
different low-level thread implementations.
|
@code{scm_enter_guile} to enter it again.
|
||||||
|
|
||||||
C code in a thread must call a libguile function periodically. When
|
While a thread has left guile mode, it must not call any libguile
|
||||||
one thread finds garbage collection is required, it waits for all
|
functions except @code{scm_enter_guile} and must not use any libguile
|
||||||
threads to rendezvous before doing that GC. Such a rendezvous is
|
macros. Also, local variables of type @code{SCM} that are allocated
|
||||||
checked within libguile functions. If C code wants to sleep or block
|
while not in guile mode are not protected from the garbage collector.
|
||||||
in a thread it should use one of the libguile functions provided.
|
|
||||||
|
|
||||||
Only threads created by Guile can use the libguile functions. Threads
|
|
||||||
created directly with say @code{pthread_create} are unknown to Guile
|
|
||||||
and they cannot call libguile. The stack in such foreign threads is
|
|
||||||
not scanned during GC, so @code{SCM} values generally cannot be held
|
|
||||||
there.
|
|
||||||
|
|
||||||
@c FIXME:
|
|
||||||
@c
|
|
||||||
@c Describe SCM_TICK which can be called if no other libguile
|
|
||||||
@c function is being used by a C function.
|
|
||||||
@c
|
|
||||||
@c Describe "Guile mode", which a thread can enter and exit. There
|
|
||||||
@c are no functions for doing this yet.
|
|
||||||
@c
|
|
||||||
@c When in guile mode a thread can call libguile, is subject to the
|
|
||||||
@c tick rule, and its stack is scanned. When not in guile mode it
|
|
||||||
@c cannot call libguile, it doesn't have to tick, and its stack is
|
|
||||||
@c not scanned. The strange guile control flow things like
|
|
||||||
@c exceptions, continuations and asyncs only occur when in guile
|
|
||||||
@c mode.
|
|
||||||
@c
|
|
||||||
@c When guile mode is exited, the portion of the stack allocated
|
|
||||||
@c while it was in guile mode is still scanned. This portion may not
|
|
||||||
@c be modified when outside guile mode. The stack ends up
|
|
||||||
@c partitioned into alternating guile and non-guile regions.
|
|
||||||
@c
|
|
||||||
@c Leaving guile mode is convenient when running an extended
|
|
||||||
@c calculation not involving guile, since one doesn't need to worry
|
|
||||||
@c about SCM_TICK calls.
|
|
||||||
|
|
||||||
|
|
||||||
@deftp {C Data Type} scm_t_thread
|
|
||||||
This data type represents a thread, to be used with scm_thread_create,
|
|
||||||
etc.
|
|
||||||
@end deftp
|
|
||||||
|
|
||||||
@deftypefn {C Function} int scm_thread_create (scm_t_thread *t, void (*proc)(void *), void *data)
|
|
||||||
Create a new thread that will start by calling @var{proc}, passing it
|
|
||||||
@var{data}. A handle for the new thread is stored in @var{t}, which
|
|
||||||
must be non-NULL. The thread terminated when @var{proc} returns.
|
|
||||||
When the thread has not been detached, its handle remains valid after
|
|
||||||
is has terminated so that it can be used with @var{scm_thread_join},
|
|
||||||
for example. When it has been detached, the handle becomes invalid as
|
|
||||||
soon as the thread terminates.
|
|
||||||
@end deftypefn
|
@end deftypefn
|
||||||
|
|
||||||
@deftypefn {C Function} void scm_thread_detach (scm_t_thread t)
|
@deftypefn {C Function} void scm_enter_guile (scm_t_guile_ticket ticket)
|
||||||
Detach the thread @var{t}. See @code{scm_thread_create}.
|
Enter guile mode again.
|
||||||
@end deftypefn
|
@end deftypefn
|
||||||
|
|
||||||
@deftypefn {C Function} void scm_thread_join (scm_t_thread t)
|
@deftypefn {C Function} void *scm_without_guile (void *(*func) (void *), void *data)
|
||||||
Wait for thread @var{t} to terminate. The thread must not have been
|
Leave guile mode, call @var{func} on @var{data}, enter guile mode and
|
||||||
detached at the time that @code{scm_thread_join} is called, but it
|
return the result of calling @var{func}.
|
||||||
might have been detached by the time it terminates.
|
|
||||||
@end deftypefn
|
@end deftypefn
|
||||||
|
|
||||||
@deftypefn {C Function} scm_t_thread scm_thread_self ()
|
@deftypefn {C Function} int scm_pthread_mutex_lock (pthread_mutex_t *mutex)
|
||||||
Return the handle of the calling thread.
|
Like @code{pthread_mutex_lock}, but leaves guile mode while waiting for
|
||||||
|
the mutex.
|
||||||
@end deftypefn
|
@end deftypefn
|
||||||
|
|
||||||
@deftp {C Data Type} scm_t_cond
|
@deftypefn {C Function} int scm_pthread_cond_wait (pthread_cond_t *cond, pthread_mutex_t *mutex)
|
||||||
This data type represents a condition variable, to be used with
|
@deftypefnx {C Function} int scm_pthread_cond_timedwait (pthread_cond_t *cond, pthread_mutex_t *mutex, struct timespec *abstime)
|
||||||
scm_cond_init, etc.
|
Like @code{pthread_cond_wait} and @code{pthread_cond_timedwait}, but
|
||||||
@end deftp
|
leaves guile mode while waiting for the condition variable.
|
||||||
|
|
||||||
@deftypefn {C Function} void scm_cond_init (scm_t_cond *c)
|
|
||||||
Initialize the condition variable structure pointed to by @var{c}.
|
|
||||||
@end deftypefn
|
@end deftypefn
|
||||||
|
|
||||||
@deftypefn {C Function} void scm_cond_destroy (scm_t_cond *c)
|
@deftypefn {C Function} int scm_std_select (int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout)
|
||||||
Deallocate all resources associated with @var{c}.
|
Like @code{select} but leaves guile mode while waiting. Also, the
|
||||||
|
delivery of a system async causes this function to be interrupted with
|
||||||
|
error code @code{EINTR}.
|
||||||
@end deftypefn
|
@end deftypefn
|
||||||
|
|
||||||
@deftypefn {C Function} void scm_cond_wait (scm_t_cond *c, scm_t_mutex *m)
|
@deftypefn {C Function} {unsigned int} scm_std_sleep ({unsigned int} seconds)
|
||||||
Wait for @var{c} to be signalled. While waiting @var{m} is unlocked
|
Like @code{sleep}, but leaves guile mode while sleeping. Also, the
|
||||||
and locked again before @code{scm_cond_wait} returns.
|
delivery of a system async causes this function to be interrupted.
|
||||||
@end deftypefn
|
@end deftypefn
|
||||||
|
|
||||||
@deftypefn {C Function} void scm_cond_timedwait (scm_t_cond *c, scm_t_mutex *m, timespec *abstime)
|
@deftypefn {C Function} {unsigned long} scm_std_usleep ({unsigned long} usecs)
|
||||||
Wait for @var{c} to be signalled as with @code{scm_cond_wait} but
|
Like @code{usleep}, but leaves guile mode while sleeping. Also, the
|
||||||
don't wait longer than the point in time specified by @var{abstime}.
|
delivery of a system async causes this function to be interrupted.
|
||||||
when the waiting is aborted, zero is returned; non-zero else.
|
|
||||||
@end deftypefn
|
@end deftypefn
|
||||||
|
|
||||||
@deftypefn {C Function} void scm_cond_signal (scm_t_cond *c)
|
|
||||||
Signal the condition variable @var{c}. When one or more threads are
|
|
||||||
waiting for it to be signalled, select one arbitrarily and let its
|
|
||||||
wait succeed.
|
|
||||||
@end deftypefn
|
|
||||||
|
|
||||||
@deftypefn {C Function} void scm_cond_broadcast (scm_t_cond *c)
|
@node Fluids and Dynamic States
|
||||||
Signal the condition variable @var{c}. When there are threads waiting
|
@subsection Fluids and Dynamic States
|
||||||
for it to be signalled, wake them all up and make all their waits
|
|
||||||
succeed.
|
|
||||||
@end deftypefn
|
|
||||||
|
|
||||||
@deftp {C Type} scm_t_key
|
|
||||||
This type represents a key for a thread-specific value.
|
|
||||||
@end deftp
|
|
||||||
|
|
||||||
@deftypefn {C Function} void scm_key_create (scm_t_key *keyp)
|
|
||||||
Create a new key for a thread-specific value. Each thread has its own
|
|
||||||
value associated to such a handle. The new handle is stored into
|
|
||||||
@var{keyp}, which must be non-NULL.
|
|
||||||
@end deftypefn
|
|
||||||
|
|
||||||
@deftypefn {C Function} void scm_key_delete (scm_t_key key)
|
|
||||||
This function makes @var{key} invalid as a key for thread-specific data.
|
|
||||||
@end deftypefn
|
|
||||||
|
|
||||||
@deftypefn {C Function} void scm_key_setspecific (scm_t_key key, const void *value)
|
|
||||||
Associate @var{value} with @var{key} in the calling thread.
|
|
||||||
@end deftypefn
|
|
||||||
|
|
||||||
@deftypefn {C Function} int scm_key_getspecific (scm_t_key key)
|
|
||||||
Return the value currently associated with @var{key} in the calling
|
|
||||||
thread. When @code{scm_key_setspecific} has not yet been called in
|
|
||||||
this thread with this key, @code{NULL} is returned.
|
|
||||||
@end deftypefn
|
|
||||||
|
|
||||||
@deftypefn {C Function} int scm_thread_select (...)
|
|
||||||
This function does the same thing as the system's @code{select}
|
|
||||||
function, but in a way that is friendly to the thread implementation.
|
|
||||||
You should call it in preference to the system @code{select}.
|
|
||||||
@end deftypefn
|
|
||||||
|
|
||||||
@node Fluids
|
|
||||||
@subsection Fluids
|
|
||||||
|
|
||||||
@cindex fluids
|
@cindex fluids
|
||||||
|
|
||||||
Fluids are objects to store values in. They have a few properties
|
A @emph{fluid} is an object that can store one value per @emph{dynamic
|
||||||
which make them useful in certain situations: Fluids can have one
|
state}. Each thread has a current dynamic state, and when accessing a
|
||||||
value per dynamic root (@pxref{Dynamic Roots}), so that changes to the
|
fluid, this current dynamic state is used to provide the actual value.
|
||||||
value in a fluid are only visible in the same dynamic root. Since
|
In this way, fluids can be used for thread local storage, but they are
|
||||||
threads are executed in separate dynamic roots, fluids can be used for
|
in fact more flexible: dynamic states are objects of their own and can
|
||||||
thread local storage (@pxref{Threads}).
|
be made current for more than one thread at the same time, or only be
|
||||||
|
made current temporarily, for example.
|
||||||
|
|
||||||
Fluids can be used to simulate the desirable effects of dynamically
|
Fluids can also be used to simulate the desirable effects of
|
||||||
scoped variables. Dynamically scoped variables are useful when you
|
dynamically scoped variables. Dynamically scoped variables are useful
|
||||||
want to set a variable to a value during some dynamic extent in the
|
when you want to set a variable to a value during some dynamic extent
|
||||||
execution of your program and have them revert to their original value
|
in the execution of your program and have them revert to their
|
||||||
when the control flow is outside of this dynamic extent. See the
|
original value when the control flow is outside of this dynamic
|
||||||
description of @code{with-fluids} below for details.
|
extent. See the description of @code{with-fluids} below for details.
|
||||||
|
|
||||||
New fluids are created with @code{make-fluid} and @code{fluid?} is
|
New fluids are created with @code{make-fluid} and @code{fluid?} is
|
||||||
used for testing whether an object is actually a fluid. The values
|
used for testing whether an object is actually a fluid. The values
|
||||||
|
@ -600,12 +385,12 @@ stored in a fluid can be accessed with @code{fluid-ref} and
|
||||||
@deffn {Scheme Procedure} make-fluid
|
@deffn {Scheme Procedure} make-fluid
|
||||||
@deffnx {C Function} scm_make_fluid ()
|
@deffnx {C Function} scm_make_fluid ()
|
||||||
Return a newly created fluid.
|
Return a newly created fluid.
|
||||||
Fluids are objects of a certain type (a smob) that can hold one SCM
|
Fluids are objects that can hold one
|
||||||
value per dynamic root. That is, modifications to this value are
|
value per dynamic state. That is, modifications to this value are
|
||||||
only visible to code that executes within the same dynamic root as
|
only visible to code that executes with the same dynamic state as
|
||||||
the modifying code. When a new dynamic root is constructed, it
|
the modifying code. When a new dynamic state is constructed, it
|
||||||
inherits the values from its parent. Because each thread executes
|
inherits the values from its parent. Because each thread normally executes
|
||||||
in its own dynamic root, you can use fluids for thread local storage.
|
with its own dynamic state, you can use fluids for thread local storage.
|
||||||
@end deffn
|
@end deffn
|
||||||
|
|
||||||
@deffn {Scheme Procedure} fluid? obj
|
@deffn {Scheme Procedure} fluid? obj
|
||||||
|
@ -675,6 +460,50 @@ value whenever the frame is entered or left. The backup value is
|
||||||
initialized with the @var{val} argument.
|
initialized with the @var{val} argument.
|
||||||
@end deftypefn
|
@end deftypefn
|
||||||
|
|
||||||
|
@deffn {Scheme Procedure} make-dynamic-state [parent]
|
||||||
|
@deffnx {C Function} scm_make_dynamic_state (parent)
|
||||||
|
Return a copy of the dynamic state object @var{parent}
|
||||||
|
or of the current dynamic state when @var{parent} is omitted.
|
||||||
|
@end deffn
|
||||||
|
|
||||||
|
@deffn {Scheme Procedure} dynamic-state? obj
|
||||||
|
@deffnx {C Function} scm_dynamic_state_p (obj)
|
||||||
|
Return @code{#t} if @var{obj} is a dynamic state object;
|
||||||
|
return @code{#f} otherwise.
|
||||||
|
@end deffn
|
||||||
|
|
||||||
|
@deftypefn {C Procedure} int scm_is_dynamic_state (SCM obj)
|
||||||
|
Return non-zero if @var{obj} is a dynamic state object;
|
||||||
|
return zero otherwise.
|
||||||
|
@end deftypefn
|
||||||
|
|
||||||
|
@deffn {Scheme Procedure} current-dynamic-state
|
||||||
|
@deffnx {C Function} scm_current_dynamic_state ()
|
||||||
|
Return the current dynamic state object.
|
||||||
|
@end deffn
|
||||||
|
|
||||||
|
@deffn {Scheme Procedure} set-current-dynamic-state state
|
||||||
|
@deffnx {C Function} scm_set_current_dynamic_state (state)
|
||||||
|
Set the current dynamic state object to @var{state}
|
||||||
|
and return the previous current dynamic state object.
|
||||||
|
@end deffn
|
||||||
|
|
||||||
|
@deffn {Scheme Procedure} with-dynamic-state state proc
|
||||||
|
@deffnx {C Function} scm_with_dynamic_state (state, proc)
|
||||||
|
Call @var{proc} while @var{state} is the current dynamic
|
||||||
|
state object.
|
||||||
|
@end deffn
|
||||||
|
|
||||||
|
@deftypefn {C Procedure} void scm_frame_current_dynamic_state (SCM state)
|
||||||
|
Set the current dynamic state to @var{state} for the dynamic extent of
|
||||||
|
the current frame.
|
||||||
|
@end deftypefn
|
||||||
|
|
||||||
|
@deftypefn {C Procedure} void *scm_c_with_dynamic_state (SCM state, void *(*func)(void *), void *data)
|
||||||
|
Like @code{scm_with_dynamic_state}, but call @var{func} with
|
||||||
|
@var{data}.
|
||||||
|
@end deftypefn
|
||||||
|
|
||||||
@node Futures
|
@node Futures
|
||||||
@subsection Futures
|
@subsection Futures
|
||||||
@cindex futures
|
@cindex futures
|
||||||
|
@ -798,9 +627,10 @@ completed, it doesn't need to wait for all to finish.
|
||||||
@end deffn
|
@end deffn
|
||||||
|
|
||||||
|
|
||||||
@node Mutexes
|
@node Mutexes and Condition Variables
|
||||||
@subsection Mutexes
|
@subsection Mutexes and Condition Variables
|
||||||
@cindex mutex
|
@cindex mutex
|
||||||
|
@cindex condition variable
|
||||||
|
|
||||||
A mutex is a thread synchronization object, it can be used by threads
|
A mutex is a thread synchronization object, it can be used by threads
|
||||||
to control access to a shared resource. A mutex can be locked to
|
to control access to a shared resource. A mutex can be locked to
|
||||||
|
@ -808,9 +638,10 @@ indicate a resource is in use, and other threads can then block on the
|
||||||
mutex to wait for the resource (or can just test and do something else
|
mutex to wait for the resource (or can just test and do something else
|
||||||
if not available). ``Mutex'' is short for ``mutual exclusion''.
|
if not available). ``Mutex'' is short for ``mutual exclusion''.
|
||||||
|
|
||||||
There are two types of mutexes, ``standard'' and ``fair''. They're
|
There are two types of mutexes in Guile, ``standard'' and
|
||||||
created by @code{make-mutex} and @code{make-fair-mutex} respectively,
|
``recursive''. They're created by @code{make-mutex} and
|
||||||
the operation functions are then common to both.
|
@code{make-recursive-mutex} respectively, the operation functions are
|
||||||
|
then common to both.
|
||||||
|
|
||||||
Note that for both types of mutex there's no protection against a
|
Note that for both types of mutex there's no protection against a
|
||||||
``deadly embrace''. For instance if one thread has locked mutex A and
|
``deadly embrace''. For instance if one thread has locked mutex A and
|
||||||
|
@ -821,43 +652,31 @@ in all threads is one way to avoid such problems.
|
||||||
|
|
||||||
@sp 1
|
@sp 1
|
||||||
@deffn {Scheme Procedure} make-mutex
|
@deffn {Scheme Procedure} make-mutex
|
||||||
@deffnx {Scheme Procedure} make-fair-mutex
|
Return a new standard mutex. It is initially unlocked.
|
||||||
Return a new mutex object.
|
@end deffn
|
||||||
|
|
||||||
@code{make-mutex} creates a standard mutex. This is fast, but its
|
@deffn {Scheme Procedure} make-recursive-mutex
|
||||||
features are restricted. Recursive locking (multiple lock calls by
|
Return a new recursive mutex. It is initialloy unlocked.
|
||||||
one thread) is not permitted, and an unlock can be done only when
|
|
||||||
already locked and only by the owning thread. When multiple threads
|
|
||||||
are blocked waiting to acquire the mutex, it's unspecified which will
|
|
||||||
get it next.
|
|
||||||
|
|
||||||
@code{make-fair-mutex} creates a fair mutex. This has more features
|
|
||||||
and error checking. Recursive locking is allowed, a given thread can
|
|
||||||
make multiple lock calls and the mutex is released when a balancing
|
|
||||||
number of unlocks are done. Other threads blocked waiting to acquire
|
|
||||||
the mutex form a queue and the one waiting longest will be the next to
|
|
||||||
acquire it.
|
|
||||||
@end deffn
|
@end deffn
|
||||||
|
|
||||||
@deffn {Scheme Procedure} lock-mutex mutex
|
@deffn {Scheme Procedure} lock-mutex mutex
|
||||||
Lock @var{mutex}. If the mutex is already locked by another thread
|
Lock @var{mutex}. If the mutex is already locked by another thread
|
||||||
then block and return only when @var{mutex} has been acquired.
|
then block and return only when @var{mutex} has been acquired.
|
||||||
|
|
||||||
For standard mutexes (@code{make-mutex}), if the thread has itself
|
For standard mutexes (@code{make-mutex}), and error is signalled if
|
||||||
already locked @var{mutex} it must not call @code{lock-mutex} on it a
|
the thread has itself already locked @var{mutex}.
|
||||||
further time. Behaviour is unspecified if this is done.
|
|
||||||
|
|
||||||
For a fair mutex (@code{make-fair-mutex}), if the thread has itself
|
For a recursive mutex (@code{make-recursive-mutex}), if the thread has
|
||||||
already locked @var{mutex}, then a further @code{lock-mutex} call
|
itself already locked @var{mutex}, then a further @code{lock-mutex}
|
||||||
increments the lock count. An additional @code{unlock-mutex} will be
|
call increments the lock count. An additional @code{unlock-mutex}
|
||||||
required to finally release.
|
will be required to finally release.
|
||||||
|
|
||||||
When a system async (@pxref{System asyncs}) is activated for a thread
|
When a system async (@pxref{System asyncs}) is activated for a thread
|
||||||
blocked in @code{lock-mutex}, the wait is interrupted and the async is
|
blocked in @code{lock-mutex}, the wait is interrupted and the async is
|
||||||
executed. When the async returns the wait resumes.
|
executed. When the async returns, the wait resumes.
|
||||||
@end deffn
|
@end deffn
|
||||||
|
|
||||||
@deffn {Scheme Procedure} try-mutex mutex
|
@deffn {Scheme Procedure} try-mutex mutex
|
||||||
Try to lock @var{mutex} as per @code{lock-mutex}. If @var{mutex} can
|
Try to lock @var{mutex} as per @code{lock-mutex}. If @var{mutex} can
|
||||||
be acquired immediately then this is done and the return is @code{#t}.
|
be acquired immediately then this is done and the return is @code{#t}.
|
||||||
If @var{mutex} is locked by some other thread then nothing is done and
|
If @var{mutex} is locked by some other thread then nothing is done and
|
||||||
|
@ -865,13 +684,43 @@ the return is @code{#f}.
|
||||||
@end deffn
|
@end deffn
|
||||||
|
|
||||||
@deffn {Scheme Procedure} unlock-mutex mutex
|
@deffn {Scheme Procedure} unlock-mutex mutex
|
||||||
Unlock @var{mutex}.
|
Unlock @var{mutex}. An error is signalled if @var{mutex} is not
|
||||||
|
locked by the calling thread.
|
||||||
|
@end deffn
|
||||||
|
|
||||||
For a standard mutex (@code{make-mutex}), if @var{mutex} is not locked
|
@c begin (texi-doc-string "guile" "make-condition-variable")
|
||||||
by the calling thread then behaviour is unspecified.
|
@deffn {Scheme Procedure} make-condition-variable
|
||||||
|
Return a new condition variable.
|
||||||
|
@end deffn
|
||||||
|
|
||||||
For a fair mutex (@code{make-fair-mutex}), if @var{mutex} is not
|
@c begin (texi-doc-string "guile" "wait-condition-variable")
|
||||||
locked by the calling thread then an error is thrown.
|
@deffn {Scheme Procedure} wait-condition-variable cond-var mutex [time]
|
||||||
|
Wait until @var{cond-var} has been signalled. While waiting,
|
||||||
|
@var{mutex} is atomically unlocked (as with @code{unlock-mutex}) and
|
||||||
|
is locked again when this function returns. When @var{time} is given,
|
||||||
|
it specifies a point in time where the waiting should be aborted. It
|
||||||
|
can be either a integer as returned by @code{current-time} or a pair
|
||||||
|
as returned by @code{gettimeofday}. When the waiting is aborted,
|
||||||
|
@code{#f} is returned. When the condition variable has in fact been
|
||||||
|
signalled, @code{#t} is returned. The mutex is re-locked in any case
|
||||||
|
before @code{wait-condition-variable} returns.
|
||||||
|
|
||||||
|
When a system async is activated for a thread that is blocked in a
|
||||||
|
call to @code{wait-condition-variable}, the waiting is interrupted,
|
||||||
|
the mutex is locked, and the async is executed. When the async
|
||||||
|
returns, the mutex is unlocked again and the waiting is resumed. When
|
||||||
|
the thread block while re-acquiring the mutex, execution of asyncs is
|
||||||
|
blocked.
|
||||||
|
@end deffn
|
||||||
|
|
||||||
|
@c begin (texi-doc-string "guile" "signal-condition-variable")
|
||||||
|
@deffn {Scheme Procedure} signal-condition-variable cond-var
|
||||||
|
Wake up one thread that is waiting for @var{cv}.
|
||||||
|
@end deffn
|
||||||
|
|
||||||
|
@c begin (texi-doc-string "guile" "broadcast-condition-variable")
|
||||||
|
@deffn {Scheme Procedure} broadcast-condition-variable cond-var
|
||||||
|
Wake up all threads that are waiting for @var{cv}.
|
||||||
@end deffn
|
@end deffn
|
||||||
|
|
||||||
@sp 1
|
@sp 1
|
||||||
|
@ -908,38 +757,6 @@ means a particular bit of code managing access to some resource and
|
||||||
which only ever executes on behalf of one process at any one time.
|
which only ever executes on behalf of one process at any one time.
|
||||||
@end deffn
|
@end deffn
|
||||||
|
|
||||||
@sp 1
|
|
||||||
The following provide access to standard mutexes from C code.
|
|
||||||
|
|
||||||
@deftp {C Data Type} scm_t_mutex
|
|
||||||
A mutex, to be used with @code{scm_mutex_init}, etc.
|
|
||||||
@end deftp
|
|
||||||
|
|
||||||
@deftypefn {C Function} void scm_mutex_init (scm_t_mutex *m)
|
|
||||||
Initialize the mutex structure pointed to by @var{m}.
|
|
||||||
@end deftypefn
|
|
||||||
|
|
||||||
@deftypefn {C Function} void scm_mutex_destroy (scm_t_mutex *m)
|
|
||||||
Free all resources associated with @var{m}.
|
|
||||||
@end deftypefn
|
|
||||||
|
|
||||||
@deftypefn {C Function} void scm_mutex_lock (scm_t_mutex *m)
|
|
||||||
Lock the mutex @var{m}. This is as per @code{lock-mutex} above on a
|
|
||||||
standard mutex.
|
|
||||||
@end deftypefn
|
|
||||||
|
|
||||||
@deftypefn {C Function} int scm_mutex_trylock (scm_t_mutex *m)
|
|
||||||
Attempt to lock mutex @var{m}, as per @code{scm_mutex_lock}. If
|
|
||||||
@var{m} is unlocked then this is done and the return is non-zero. If
|
|
||||||
@var{m} is already locked by another thread then do nothing and return
|
|
||||||
zero.
|
|
||||||
@end deftypefn
|
|
||||||
|
|
||||||
@deftypefn {C Function} void scm_mutex_unlock (scm_t_mutex *m)
|
|
||||||
Unlock the mutex @var{m}. The mutex must have been locked by the
|
|
||||||
current thread, otherwise the behavior is undefined.
|
|
||||||
@end deftypefn
|
|
||||||
|
|
||||||
|
|
||||||
@c Local Variables:
|
@c Local Variables:
|
||||||
@c TeX-master: "guile.texi"
|
@c TeX-master: "guile.texi"
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
@c -*-texinfo-*-
|
@c -*-texinfo-*-
|
||||||
@c This is part of the GNU Guile Reference Manual.
|
@c This is part of the GNU Guile Reference Manual.
|
||||||
@c Copyright (C) 1996, 1997, 2000, 2001, 2002, 2003, 2004
|
@c Copyright (C) 1996, 1997, 2000, 2001, 2002, 2003, 2004, 2005
|
||||||
@c Free Software Foundation, Inc.
|
@c Free Software Foundation, Inc.
|
||||||
@c See the file guile.texi for copying conditions.
|
@c See the file guile.texi for copying conditions.
|
||||||
|
|
||||||
|
@ -8,12 +8,12 @@
|
||||||
@node General Libguile Concepts
|
@node General Libguile Concepts
|
||||||
@section General concepts for using libguile
|
@section General concepts for using libguile
|
||||||
|
|
||||||
When you want to embed the Guile Scheme interpreter into your program,
|
When you want to embed the Guile Scheme interpreter into your program or
|
||||||
you need to link it against the @file{libguile} library (@pxref{Linking
|
library, you need to link it against the @file{libguile} library
|
||||||
Programs With Guile}). Once you have done this, your C code has access
|
(@pxref{Linking Programs With Guile}). Once you have done this, your C
|
||||||
to a number of data types and functions that can be used to invoke the
|
code has access to a number of data types and functions that can be used
|
||||||
interpreter, or make new functions that you have written in C available
|
to invoke the interpreter, or make new functions that you have written
|
||||||
to be called from Scheme code, among other things.
|
in C available to be called from Scheme code, among other things.
|
||||||
|
|
||||||
Scheme is different from C in a number of significant ways, and Guile
|
Scheme is different from C in a number of significant ways, and Guile
|
||||||
tries to make the advantages of Scheme available to C as well. Thus, in
|
tries to make the advantages of Scheme available to C as well. Thus, in
|
||||||
|
@ -26,10 +26,16 @@ You need to understand how libguile offers them to C programs in order
|
||||||
to use the rest of libguile. Also, the more general control flow of
|
to use the rest of libguile. Also, the more general control flow of
|
||||||
Scheme caused by continuations needs to be dealt with.
|
Scheme caused by continuations needs to be dealt with.
|
||||||
|
|
||||||
|
Running asynchronous signal handlers and multi-threading is known to C
|
||||||
|
code already, but there are of course a few additional rules when using
|
||||||
|
them together with libguile.
|
||||||
|
|
||||||
@menu
|
@menu
|
||||||
* Dynamic Types:: Dynamic Types.
|
* Dynamic Types:: Dynamic Types.
|
||||||
* Garbage Collection:: Garbage Collection.
|
* Garbage Collection:: Garbage Collection.
|
||||||
* Control Flow:: Control Flow.
|
* Control Flow:: Control Flow.
|
||||||
|
* Asynchronous Signals:: Asynchronous Signals
|
||||||
|
* Multi-Threading:: Multi-Threading
|
||||||
@end menu
|
@end menu
|
||||||
|
|
||||||
@node Dynamic Types
|
@node Dynamic Types
|
||||||
|
@ -377,3 +383,204 @@ corresponding @code{scm_internal_dynamic_wind} function, but it might
|
||||||
prefer to use the @dfn{frames} concept that is more natural for C code,
|
prefer to use the @dfn{frames} concept that is more natural for C code,
|
||||||
(@pxref{Frames}).
|
(@pxref{Frames}).
|
||||||
|
|
||||||
|
@node Asynchronous Signals
|
||||||
|
@subsection Asynchronous Signals
|
||||||
|
|
||||||
|
You can not call libguile functions from handlers for POSIX signals, but
|
||||||
|
you can register Scheme handlers for POSIX signals such as
|
||||||
|
@code{SIGINT}. These handlers do not run during the actual signal
|
||||||
|
delivery. Instead, they are run when the program (more precisely, the
|
||||||
|
thread that the handler has been registered for) reaches the next
|
||||||
|
@emph{safe point}.
|
||||||
|
|
||||||
|
The libguile functions themselves have many such safe points.
|
||||||
|
Consequently, you must be prepared for arbitrary actions anytime you
|
||||||
|
call a libguile function. For example, even @code{scm_cons} can contain
|
||||||
|
a safe point and when a signal handler is pending for your thread,
|
||||||
|
calling @code{scm_cons} will run this handler and anything might happen,
|
||||||
|
including a non-local exit although @code{scm_cons} would not ordinarily
|
||||||
|
do such a thing on its own.
|
||||||
|
|
||||||
|
If you do not want to allow the running of asynchronous signal handlers,
|
||||||
|
you can block them temporarily with @code{scm_frame_block_asyncs}, for
|
||||||
|
example. See @xref{System asyncs}.
|
||||||
|
|
||||||
|
Since signal handling in Guile relies on safe points, you need to make
|
||||||
|
sure that your functions do offer enough of them. Normally, calling
|
||||||
|
libguile functions in the normal course of action is all that is needed.
|
||||||
|
But when a thread might spent a long time in a code section that calls
|
||||||
|
no libguile function, it is good to include explicit safe points. This
|
||||||
|
can allow the user to interrupt your code with @key{C-c}, for example.
|
||||||
|
|
||||||
|
You can do this with the macro @code{SCM_TICK}. This macro is
|
||||||
|
syntactically a statement. That is, you could use it like this:
|
||||||
|
|
||||||
|
@example
|
||||||
|
while (1)
|
||||||
|
@{
|
||||||
|
SCM_TICK;
|
||||||
|
do_some_work ();
|
||||||
|
@}
|
||||||
|
@end example
|
||||||
|
|
||||||
|
Frequent execution of a safe point is even more important in multi
|
||||||
|
threaded programs, @xref{Multi-Threading}.
|
||||||
|
|
||||||
|
@node Multi-Threading
|
||||||
|
@subsection Multi-Threading
|
||||||
|
|
||||||
|
Guile can be used in multi-threaded programs just as well as in
|
||||||
|
single-threaded ones.
|
||||||
|
|
||||||
|
Each thread that wants to use functions from libguile must put itself
|
||||||
|
into @emph{guile mode} and must then follow a few rules. If it doesn't
|
||||||
|
want to honor these rules in certain situations, a thread can
|
||||||
|
temporarily leave guile mode (but can no longer use libguile functions
|
||||||
|
during that time, of course).
|
||||||
|
|
||||||
|
Threads enter guile mode by calling @code{scm_with_guile},
|
||||||
|
@code{scm_boot_guile}, or @code{scm_init_guile}. As explained in the
|
||||||
|
reference documentation for these functions, Guile will then learn about
|
||||||
|
the stack bounds of the thread and can protect the @code{SCM} values
|
||||||
|
that are stored in local variables. When a thread puts itself into
|
||||||
|
guile mode for the first time, it gets a Scheme representation and is
|
||||||
|
listed by @code{all-threads}, for example.
|
||||||
|
|
||||||
|
While in guile mode, a thread promises to reach a safe point reasonably
|
||||||
|
frequently (@pxref{Asynchronous Signals}). In addition to running
|
||||||
|
signal handlers, these points are also potential rendezvous points of
|
||||||
|
all guile mode threads where Guile can orchestrate global things like
|
||||||
|
garbage collection. Consequently, when a thread in guile mode blocks
|
||||||
|
and does no longer frequent safe points, it might cause all other guile
|
||||||
|
mode threads to block as well. To prevent this from happening, a guile
|
||||||
|
mode thread should either only block in libguile functions (who know how
|
||||||
|
to do it right), or should temporarily leave guile mode with
|
||||||
|
@code{scm_without_guile} or
|
||||||
|
@code{scm_leave_guile}/@code{scm_enter_guile}.
|
||||||
|
|
||||||
|
For some common blocking operations, Guile provides convenience
|
||||||
|
functions. For example, if you want to lock a pthread mutex while in
|
||||||
|
guile mode, you might want to use @code{scm_pthread_mutex_lock} which is
|
||||||
|
just like @code{pthread_mutex_lock} except that it leaves guile mode
|
||||||
|
while blocking.
|
||||||
|
|
||||||
|
|
||||||
|
All libguile functions are (intended to be) robust in the face of
|
||||||
|
multiple threads using them concurrently. This means that there is no
|
||||||
|
risk of the internal data structures of libguile becoming corrupted in
|
||||||
|
such a way that the process crashes.
|
||||||
|
|
||||||
|
A program might still produce non-sensical results, though. Taking
|
||||||
|
hashtables as an example, Guile guarantees that you can use them from
|
||||||
|
multiple threads concurrently and a hashtable will always remain a valid
|
||||||
|
hashtable and Guile will not crash when you access it. It does not
|
||||||
|
guarantee, however, that inserting into it concurrently from two threads
|
||||||
|
will give useful results: only one insertion might actually happen, none
|
||||||
|
might happen, or the table might in general be modified in a totally
|
||||||
|
arbitrary manner. (It will still be a valid hashtable, but not the one
|
||||||
|
that you might have expected.) Guile might also signal an error when it
|
||||||
|
detects a harmful race condition.
|
||||||
|
|
||||||
|
Thus, you need to put in additional synchronizations when multiple
|
||||||
|
threads want to use a single hashtable, or any other mutable Scheme
|
||||||
|
object.
|
||||||
|
|
||||||
|
When writing C code for use with libguile, you should try to make it
|
||||||
|
robust as well. An example that converts a list into a vector will help
|
||||||
|
to illustrate. Here is a correct version:
|
||||||
|
|
||||||
|
@example
|
||||||
|
SCM
|
||||||
|
my_list_to_vector (SCM list)
|
||||||
|
@{
|
||||||
|
SCM vector = scm_make_vector (scm_length (list), SCM_UNDEFINED);
|
||||||
|
size_t len, i;
|
||||||
|
|
||||||
|
len = SCM_SIMPLE_VECTOR_LENGTH (vector);
|
||||||
|
i = 0;
|
||||||
|
while (i < len && scm_is_pair (list))
|
||||||
|
@{
|
||||||
|
SCM_SIMPLE_VECTOR_SET (vector, i, SCM_CAR (list));
|
||||||
|
list = SCM_CDR (list);
|
||||||
|
i++;
|
||||||
|
@}
|
||||||
|
|
||||||
|
return vector;
|
||||||
|
@}
|
||||||
|
@end example
|
||||||
|
|
||||||
|
The first thing to note is that storing into a @code{SCM} location
|
||||||
|
concurrently from multiple threads is guaranteed to be robust: you don't
|
||||||
|
know which value wins but it will in any case be a valid @code{SCM}
|
||||||
|
value.
|
||||||
|
|
||||||
|
But there is no guarantee that the list referenced by @var{list} is not
|
||||||
|
modified in another thread while the loop iterates over it. Thus, while
|
||||||
|
copying its elements into the vector, the list might get longer or
|
||||||
|
shorter. For this reason, the loop must check both that it doesn't
|
||||||
|
overrun the vector (@code{SCM_SIMPLE_VECTOR_SET} does no range-checking)
|
||||||
|
and that it doesn't overrung the list (@code{SCM_CAR} and @code{SCM_CDR}
|
||||||
|
likewise do no type checking).
|
||||||
|
|
||||||
|
It is safe to use @code{SCM_CAR} and @code{SCM_CDR} on the local
|
||||||
|
variable @var{list} once it is known that the variable contains a pair.
|
||||||
|
The contents of the pair might change spontaneously, but it will always
|
||||||
|
stay a valid pair (and a local variable will of course not spontaneously
|
||||||
|
point to a different Scheme object).
|
||||||
|
|
||||||
|
Likewise, a simple vector such as the one returned by
|
||||||
|
@code{scm_make_vector} is guaranteed to always stay the same length so
|
||||||
|
that it is safe to only use SCM_SIMPLE_VECTOR_LENGTH once and store the
|
||||||
|
result. (In the example, @var{vector} is safe anyway since it is a
|
||||||
|
fresh object that no other thread can possibly know about until it is
|
||||||
|
returned from @code{my_list_to_vector}.)
|
||||||
|
|
||||||
|
Of course the behavior of @code{my_list_to_vector} is suboptimal when
|
||||||
|
@var{list} does indeed gets asynchronously lengthened or shortened in
|
||||||
|
another thread. But it is robust: it will always return a valid vector.
|
||||||
|
That vector might be shorter than expected, or its last elements might
|
||||||
|
be unspecified, but it is a valid vector and if a program wants to rule
|
||||||
|
out these cases, it must avoid modifying the list asynchronously.
|
||||||
|
|
||||||
|
Here is another version that is also correct:
|
||||||
|
|
||||||
|
@example
|
||||||
|
SCM
|
||||||
|
my_pedantic_list_to_vector (SCM list)
|
||||||
|
@{
|
||||||
|
SCM vector = scm_make_vector (scm_length (list), SCM_UNDEFINED);
|
||||||
|
size_t len, i;
|
||||||
|
|
||||||
|
len = SCM_SIMPLE_VECTOR_LENGTH (vector);
|
||||||
|
i = 0;
|
||||||
|
while (i < len)
|
||||||
|
@{
|
||||||
|
SCM_SIMPLE_VECTOR_SET (vector, i, scm_car (list));
|
||||||
|
list = scm_cdr (list);
|
||||||
|
i++;
|
||||||
|
@}
|
||||||
|
|
||||||
|
return vector;
|
||||||
|
@}
|
||||||
|
@end example
|
||||||
|
|
||||||
|
This version uses the type-checking and thread-robust functions
|
||||||
|
@code{scm_car} and @code{scm_cdr} instead of the faster, but less robust
|
||||||
|
macros @code{SCM_CAR} and @code{SCM_CDR}. When the list is shortened
|
||||||
|
(that is, when @var{list} holds a non-pair), @code{scm_car} will throw
|
||||||
|
an error. This might be preferable to just returning a half-initialized
|
||||||
|
vector.
|
||||||
|
|
||||||
|
The API for accessing vectors and arrays of various kinds from C takes a
|
||||||
|
slightly different approach to thread-robustness. In order to get at
|
||||||
|
the raw memory that stores the elements of an array, you need to
|
||||||
|
@emph{reserve} that array as long as you need the raw memory. During
|
||||||
|
the time an array is reserved, its elements can still spontaneously
|
||||||
|
change their values, but the memory itself and other things like the
|
||||||
|
size of the array are guaranteed to stay fixed. Any operation that
|
||||||
|
would change these parameters of an array that is currently reserved
|
||||||
|
will signal an error. In order to avoid these errors, a program should
|
||||||
|
of course put suitable synchronization mechanisms in place. As you can
|
||||||
|
see, Guile itself is again only concerned about robustness, not about
|
||||||
|
correctness: without proper synchronization, your program will likely
|
||||||
|
not be correct, but the worst consequence is an error message.
|
||||||
|
|
|
@ -32,7 +32,7 @@ Convert the homogeneous numeric vector @var{uvec} to a list.
|
||||||
|
|
||||||
@deffn {Scheme Procedure} make-u8vector len [fill]
|
@deffn {Scheme Procedure} make-u8vector len [fill]
|
||||||
@deffnx {C Function} scm_make_u8vector (len, fill)
|
@deffnx {C Function} scm_make_u8vector (len, fill)
|
||||||
Return a newly allocated homogeneous numeric vector which can
|
Return a newly allocated uniform numeric vector which can
|
||||||
hold @var{len} elements. If @var{fill} is given, it is used to
|
hold @var{len} elements. If @var{fill} is given, it is used to
|
||||||
initialize the elements, otherwise the contents of the vector
|
initialize the elements, otherwise the contents of the vector
|
||||||
is unspecified.
|
is unspecified.
|
||||||
|
@ -40,18 +40,235 @@ is unspecified.
|
||||||
|
|
||||||
@deffn {Scheme Procedure} u8vector . l
|
@deffn {Scheme Procedure} u8vector . l
|
||||||
@deffnx {C Function} scm_u8vector (l)
|
@deffnx {C Function} scm_u8vector (l)
|
||||||
Return a newly allocated homogeneous numeric vector containing
|
Return a newly allocated uniform numeric vector containing
|
||||||
all argument values.
|
all argument values.
|
||||||
@end deffn
|
@end deffn
|
||||||
|
|
||||||
@deffn {Scheme Procedure} list->u8vector l
|
@deffn {Scheme Procedure} list->u8vector l
|
||||||
@deffnx {C Function} scm_list_to_u8vector (l)
|
@deffnx {C Function} scm_list_to_u8vector (l)
|
||||||
Convert the list @var{l} to a numeric homogeneous vector.
|
Convert the list @var{l} to a numeric uniform vector.
|
||||||
@end deffn
|
@end deffn
|
||||||
|
|
||||||
@deffn {Scheme Procedure} any->u8vector obj
|
@deffn {Scheme Procedure} any->u8vector obj
|
||||||
@deffnx {C Function} scm_any_to_u8vector (obj)
|
@deffnx {C Function} scm_any_to_u8vector (obj)
|
||||||
Convert @var{obj}, which can be a list, vector, or
|
Convert @var{obj}, which can be a list, vector, or
|
||||||
homogenous vector, to a numeric homogenous vector of
|
uniform vector, to a numeric uniform vector of
|
||||||
type u8.
|
type u8.
|
||||||
@end deffn
|
@end deffn
|
||||||
|
|
||||||
|
@deffn {Scheme Procedure} with-continuation-barrier proc
|
||||||
|
@deffnx {C Function} scm_with_continuation_barrier (proc)
|
||||||
|
Call @var{proc} and return the returned value but do not allow the invocation of continuations that would exit or reenter the dynamic extent of the call to @var{proc}. When a uncaught throw happens during the call to @var{proc}, a message is printed to the current error port and @code{#f} is returned.
|
||||||
|
@end deffn
|
||||||
|
|
||||||
|
@deffn {Scheme Procedure} dynamic-state? obj
|
||||||
|
@deffnx {C Function} scm_dynamic_state_p (obj)
|
||||||
|
Return @code{#t} if @var{obj} is a dynamic state object;
|
||||||
|
return @code{#f} otherwise
|
||||||
|
@end deffn
|
||||||
|
|
||||||
|
@deffn {Scheme Procedure} current-dynamic-state
|
||||||
|
@deffnx {C Function} scm_current_dynamic_state ()
|
||||||
|
Return the current dynamic state object.
|
||||||
|
@end deffn
|
||||||
|
|
||||||
|
@deffn {Scheme Procedure} set-current-dynamic-state state
|
||||||
|
@deffnx {C Function} scm_set_current_dynamic_state (state)
|
||||||
|
Set the current dynamic state object to @var{state}
|
||||||
|
and return the previous current dynamic state object.
|
||||||
|
@end deffn
|
||||||
|
|
||||||
|
@deffn {Scheme Procedure} with-dynamic-state state proc
|
||||||
|
@deffnx {C Function} scm_with_dynamic_state (state, proc)
|
||||||
|
Call @var{proc} while @var{state} is the current dynamic
|
||||||
|
state object.
|
||||||
|
@end deffn
|
||||||
|
|
||||||
|
@deffn {Scheme Procedure} call-with-dynamic-root thunk handler
|
||||||
|
@deffnx {C Function} scm_call_with_dynamic_root (thunk, handler)
|
||||||
|
Evaluate @code{(thunk)} in a new dynamic context, returning its value.
|
||||||
|
|
||||||
|
If an error occurs during evaluation, apply @var{handler} to the
|
||||||
|
arguments to the throw, just as @code{throw} would. If this happens,
|
||||||
|
@var{handler} is called outside the scope of the new root -- it is
|
||||||
|
called in the same dynamic context in which
|
||||||
|
@code{call-with-dynamic-root} was evaluated.
|
||||||
|
|
||||||
|
If @var{thunk} captures a continuation, the continuation is rooted at
|
||||||
|
the call to @var{thunk}. In particular, the call to
|
||||||
|
@code{call-with-dynamic-root} is not captured. Therefore,
|
||||||
|
@code{call-with-dynamic-root} always returns at most one time.
|
||||||
|
|
||||||
|
Before calling @var{thunk}, the dynamic-wind chain is un-wound back to
|
||||||
|
the root and a new chain started for @var{thunk}. Therefore, this call
|
||||||
|
may not do what you expect:
|
||||||
|
|
||||||
|
@lisp
|
||||||
|
;; Almost certainly a bug:
|
||||||
|
(with-output-to-port
|
||||||
|
some-port
|
||||||
|
|
||||||
|
(lambda ()
|
||||||
|
(call-with-dynamic-root
|
||||||
|
(lambda ()
|
||||||
|
(display 'fnord)
|
||||||
|
(newline))
|
||||||
|
(lambda (errcode) errcode))))
|
||||||
|
@end lisp
|
||||||
|
|
||||||
|
The problem is, on what port will @samp{fnord} be displayed? You
|
||||||
|
might expect that because of the @code{with-output-to-port} that
|
||||||
|
it will be displayed on the port bound to @code{some-port}. But it
|
||||||
|
probably won't -- before evaluating the thunk, dynamic winds are
|
||||||
|
unwound, including those created by @code{with-output-to-port}.
|
||||||
|
So, the standard output port will have been re-set to its default value
|
||||||
|
before @code{display} is evaluated.
|
||||||
|
|
||||||
|
(This function was added to Guile mostly to help calls to functions in C
|
||||||
|
libraries that can not tolerate non-local exits or calls that return
|
||||||
|
multiple times. If such functions call back to the interpreter, it should
|
||||||
|
be under a new dynamic root.)
|
||||||
|
@end deffn
|
||||||
|
|
||||||
|
@deffn {Scheme Procedure} dynamic-root
|
||||||
|
@deffnx {C Function} scm_dynamic_root ()
|
||||||
|
Return an object representing the current dynamic root.
|
||||||
|
|
||||||
|
These objects are only useful for comparison using @code{eq?}.
|
||||||
|
|
||||||
|
@end deffn
|
||||||
|
|
||||||
|
@deffn {Scheme Procedure} uniform-vector-ref v idx
|
||||||
|
@deffnx {C Function} scm_uniform_vector_ref (v, idx)
|
||||||
|
Return the element at index @var{idx} of the
|
||||||
|
homogenous numeric vector @var{v}.
|
||||||
|
@end deffn
|
||||||
|
|
||||||
|
@deffn {Scheme Procedure} uniform-vector-length v
|
||||||
|
@deffnx {C Function} scm_uniform_vector_length (v)
|
||||||
|
Return the number of elements in the uniform vector @var{v}.
|
||||||
|
@end deffn
|
||||||
|
|
||||||
|
@deffn {Scheme Procedure} uniform-vector-read! uvec [port_or_fd [start [end]]]
|
||||||
|
@deffnx {C Function} scm_uniform_vector_read_x (uvec, port_or_fd, start, end)
|
||||||
|
Fill the elements of @var{uvec} by reading
|
||||||
|
raw bytes from @var{port-or-fdes}, using host byte order.
|
||||||
|
|
||||||
|
The optional arguments @var{start} (inclusive) and @var{end}
|
||||||
|
(exclusive) allow a specified region to be read,
|
||||||
|
leaving the remainder of the vector unchanged.
|
||||||
|
|
||||||
|
When @var{port-or-fdes} is a port, all specified elements
|
||||||
|
of @var{uvec} are attempted to be read, potentially blocking
|
||||||
|
while waiting formore input or end-of-file.
|
||||||
|
When @var{port-or-fd} is an integer, a single call to
|
||||||
|
read(2) is made.
|
||||||
|
|
||||||
|
An error is signalled when the last element has only
|
||||||
|
been partially filled before reaching end-of-file or in
|
||||||
|
the single call to read(2).
|
||||||
|
|
||||||
|
@code{uniform-vector-read!} returns the number of elements
|
||||||
|
read.
|
||||||
|
|
||||||
|
@var{port-or-fdes} may be omitted, in which case it defaults
|
||||||
|
to the value returned by @code{(current-input-port)}.
|
||||||
|
@end deffn
|
||||||
|
|
||||||
|
@deffn {Scheme Procedure} uniform-vector-write uvec [port_or_fd [start [end]]]
|
||||||
|
@deffnx {C Function} scm_uniform_vector_write (uvec, port_or_fd, start, end)
|
||||||
|
Write the elements of @var{uvec} as raw bytes to
|
||||||
|
@var{port-or-fdes}, in the host byte order.
|
||||||
|
|
||||||
|
The optional arguments @var{start} (inclusive)
|
||||||
|
and @var{end} (exclusive) allow
|
||||||
|
a specified region to be written.
|
||||||
|
|
||||||
|
When @var{port-or-fdes} is a port, all specified elements
|
||||||
|
of @var{uvec} are attempted to be written, potentially blocking
|
||||||
|
while waiting for more room.
|
||||||
|
When @var{port-or-fd} is an integer, a single call to
|
||||||
|
write(2) is made.
|
||||||
|
|
||||||
|
An error is signalled when the last element has only
|
||||||
|
been partially written in the single call to write(2).
|
||||||
|
|
||||||
|
The number of objects actually written is returned.
|
||||||
|
@var{port-or-fdes} may be
|
||||||
|
omitted, in which case it defaults to the value returned by
|
||||||
|
@code{(current-output-port)}.
|
||||||
|
@end deffn
|
||||||
|
|
||||||
|
@deffn {Scheme Procedure} string-any-c-code char_pred s [start [end]]
|
||||||
|
@deffnx {C Function} scm_string_any (char_pred, s, start, end)
|
||||||
|
Check if the predicate @var{pred} is true for any character in
|
||||||
|
the string @var{s}.
|
||||||
|
|
||||||
|
Calls to @var{pred} are made from left to right across @var{s}.
|
||||||
|
When it returns true (ie.@: non-@code{#f}), that return value
|
||||||
|
is the return from @code{string-any}.
|
||||||
|
|
||||||
|
The SRFI-13 specification requires that the call to @var{pred}
|
||||||
|
on the last character of @var{s} (assuming that point is
|
||||||
|
reached) be a tail call, but currently in Guile this is not the
|
||||||
|
case.
|
||||||
|
@end deffn
|
||||||
|
|
||||||
|
@deffn {Scheme Procedure} string-every-c-code char_pred s [start [end]]
|
||||||
|
@deffnx {C Function} scm_string_every (char_pred, s, start, end)
|
||||||
|
Check if the predicate @var{pred} is true for every character
|
||||||
|
in the string @var{s}.
|
||||||
|
|
||||||
|
Calls to @var{pred} are made from left to right across @var{s}.
|
||||||
|
If the predicate is true for every character then the return
|
||||||
|
value from the last @var{pred} call is the return from
|
||||||
|
@code{string-every}.
|
||||||
|
|
||||||
|
If there are no characters in @var{s} (ie.@: @var{start} equals
|
||||||
|
@var{end}) then the return is @code{#t}.
|
||||||
|
|
||||||
|
The SRFI-13 specification requires that the call to @var{pred}
|
||||||
|
on the last character of @var{s} (assuming that point is
|
||||||
|
reached) be a tail call, but currently in Guile this is not the
|
||||||
|
case.
|
||||||
|
@end deffn
|
||||||
|
|
||||||
|
@deffn {Scheme Procedure} make-recursive-mutex
|
||||||
|
@deffnx {C Function} scm_make_recursive_mutex ()
|
||||||
|
Create a new recursive mutex.
|
||||||
|
@end deffn
|
||||||
|
|
||||||
|
@deffn {Scheme Procedure} vector-copy vec
|
||||||
|
@deffnx {C Function} scm_vector_copy (vec)
|
||||||
|
Return a copy of @var{vec}.
|
||||||
|
@end deffn
|
||||||
|
|
||||||
|
@deffn {Scheme Procedure} dimensions->uniform-array dims prot [fill]
|
||||||
|
@deffnx {Scheme Procedure} make-uniform-vector length prototype [fill]
|
||||||
|
@deffnx {C Function} scm_dimensions_to_uniform_array (dims, prot, fill)
|
||||||
|
Create and return a uniform array or vector of type
|
||||||
|
corresponding to @var{prototype} with dimensions @var{dims} or
|
||||||
|
length @var{length}. If @var{fill} is supplied, it's used to
|
||||||
|
fill the array, otherwise @var{prototype} is used.
|
||||||
|
@end deffn
|
||||||
|
|
||||||
|
@deffn {Scheme Procedure} list->uniform-array ndim prot lst
|
||||||
|
@deffnx {C Function} scm_list_to_uniform_array (ndim, prot, lst)
|
||||||
|
Return a uniform array of the type indicated by prototype
|
||||||
|
@var{prot} with elements the same as those of @var{lst}.
|
||||||
|
Elements must be of the appropriate type, no coercions are
|
||||||
|
done.
|
||||||
|
|
||||||
|
The argument @var{ndim} determines the number of dimensions
|
||||||
|
of the array. It is either an exact integer, giving the
|
||||||
|
number directly, or a list of exact integers, whose length
|
||||||
|
specifies the number of dimensions and each element is the
|
||||||
|
lower index bound of its dimension.
|
||||||
|
@end deffn
|
||||||
|
|
||||||
|
@deffn {Scheme Procedure} array-prototype ra
|
||||||
|
@deffnx {C Function} scm_array_prototype (ra)
|
||||||
|
Return an object that would produce an array of the same type
|
||||||
|
as @var{array}, if used as the @var{prototype} for
|
||||||
|
@code{make-uniform-array}.
|
||||||
|
@end deffn
|
||||||
|
|
|
@ -2356,22 +2356,23 @@ scope and the result from that @var{thunk} is the return from
|
||||||
@code{with-parameters*}.
|
@code{with-parameters*}.
|
||||||
|
|
||||||
This function is a Guile-specific addition to the SRFI, it's similar
|
This function is a Guile-specific addition to the SRFI, it's similar
|
||||||
to the core @code{with-fluids*} (@pxref{Fluids}).
|
to the core @code{with-fluids*} (@pxref{Fluids and Dynamic States}).
|
||||||
@end defun
|
@end defun
|
||||||
|
|
||||||
|
|
||||||
@sp 1
|
@sp 1
|
||||||
Parameter objects are implemented using fluids (@pxref{Fluids}), so
|
Parameter objects are implemented using fluids (@pxref{Fluids and
|
||||||
each dynamic root has it's own parameter locations. That includes the
|
Dynamic States}), so each dynamic state has it's own parameter
|
||||||
separate locations when outside any @code{parameterize} form. When a
|
locations. That includes the separate locations when outside any
|
||||||
parameter is created it gets a separate initial location in each
|
@code{parameterize} form. When a parameter is created it gets a
|
||||||
dynamic root, all initialized to the given @var{init} value.
|
separate initial location in each dynamic state, all initialized to
|
||||||
|
the given @var{init} value.
|
||||||
|
|
||||||
As alluded to above, because each thread is a separate dynamic root,
|
As alluded to above, because each thread usually has a separate
|
||||||
each thread has it's own locations behind parameter objects, and
|
dynamic state, each thread has it's own locations behind parameter
|
||||||
changes in one thread are not visible to any other. When a new
|
objects, and changes in one thread are not visible to any other. When
|
||||||
dynamic root or thread is created, the values of parameters in the
|
a new dynamic state or thread is created, the values of parameters in
|
||||||
originating context are copied, into new locations.
|
the originating context are copied, into new locations.
|
||||||
|
|
||||||
SRFI-39 doesn't specify the interaction between parameter objects and
|
SRFI-39 doesn't specify the interaction between parameter objects and
|
||||||
threads, so the threading behaviour described here should be regarded
|
threads, so the threading behaviour described here should be regarded
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue