mirror of
https://git.savannah.gnu.org/git/guile.git
synced 2025-04-30 03:40:34 +02:00
Reverted changed from 2005/01/24 19:14:54, which was a commit to the
wrong branch. Sorry.
This commit is contained in:
parent
a54a94b397
commit
76da80e788
34 changed files with 1125 additions and 1296 deletions
|
@ -8,96 +8,50 @@
|
|||
@node Initialization
|
||||
@section Initializing Guile
|
||||
|
||||
Each thread that wants to use function 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.
|
||||
@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.
|
||||
|
||||
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}.
|
||||
@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.
|
||||
|
||||
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.
|
||||
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.
|
||||
|
||||
@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}.
|
||||
|
||||
When a throw happens while @var{func} runs (such as a signalled error)
|
||||
that is not caught, a short message is printed to the current error port
|
||||
and @code{scm_with_guile} returns @code{NULL}. When a continuation is
|
||||
invoked that would make the control flow cross this call to
|
||||
@code{scm_with_guile}, an error will be signalled at the point of
|
||||
continuation invokation. Thus, @code{scm_with_guile} guaranteed to
|
||||
return 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.
|
||||
See @code{scm_init_guile}, below, for a function that can find the real
|
||||
base of the stack, but not in a portable way.
|
||||
@end deftypefn
|
||||
|
||||
@deftypefn {C Function} void scm_init_guile ()
|
||||
Arrange things so as if all of the code of the current thread would be
|
||||
executed 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).
|
||||
Initialize the Guile Scheme interpreter.
|
||||
|
||||
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.
|
||||
In contrast to @code{scm_boot_guile}, this function knows how to find
|
||||
the true base of the stack and thus does not need to usurp the control
|
||||
flow of your program. However, since finding the stack base can not be
|
||||
done portably, this function might not be available in all installations
|
||||
of Guile. If you can, you should use @code{scm_boot_guile} instead.
|
||||
|
||||
When 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 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.
|
||||
Note that @code{scm_init_guile} does not inform Guile about the command
|
||||
line arguments that should be returned by the Scheme function
|
||||
@code{command-line}. You can use @code{scm_set_program_arguments} to do
|
||||
this.
|
||||
@end deftypefn
|
||||
|
||||
@deftypefn {C Function} void scm_shell (int @var{argc}, char **@var{argv})
|
||||
|
|
|
@ -113,7 +113,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_frame_block_asyncs} and @code{scm_frame_unblock_asyncs}
|
||||
@code{scm_with_blocked_asyncs} and @code{scm_with_unblocked_asyncs}
|
||||
inside a @dfn{frame} (@pxref{Frames}) to block or unblock system asyncs
|
||||
temporarily.
|
||||
|
||||
|
|
|
@ -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, 2005
|
||||
@c Copyright (C) 1996, 1997, 2000, 2001, 2002, 2003, 2004
|
||||
@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 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.
|
||||
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.
|
||||
|
||||
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,16 +26,10 @@ 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
|
||||
|
@ -383,204 +377,3 @@ 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.
|
||||
|
|
|
@ -508,9 +508,9 @@ do { \
|
|||
(private or global, with unwind where necessary), and remove the
|
||||
remaining DEFER/ALLOWs. */
|
||||
|
||||
#define SCM_DEFER_INTS do { } while (0);
|
||||
#define SCM_DEFER_INTS scm_rec_mutex_lock (&scm_i_defer_mutex);
|
||||
|
||||
#define SCM_ALLOW_INTS do { } while (0);
|
||||
#define SCM_ALLOW_INTS scm_rec_mutex_unlock (&scm_i_defer_mutex);
|
||||
|
||||
#define SCM_REDEFER_INTS SCM_DEFER_INTS
|
||||
|
||||
|
|
|
@ -131,7 +131,10 @@ SCM_DEFINE (scm_strerror, "strerror", 1, 0, 0,
|
|||
{
|
||||
SCM ret;
|
||||
scm_frame_begin (0);
|
||||
scm_frame_pthread_mutex_lock (&scm_i_misc_mutex);
|
||||
scm_frame_unwind_handler ((void(*)(void*)) scm_mutex_unlock,
|
||||
&scm_i_misc_mutex,
|
||||
SCM_F_WIND_EXPLICITLY);
|
||||
scm_mutex_lock (&scm_i_misc_mutex);
|
||||
|
||||
ret = scm_from_locale_string (SCM_I_STRERROR (scm_to_int (err)));
|
||||
|
||||
|
|
|
@ -24,8 +24,6 @@
|
|||
* which are treated differently with respect to DEVAL. The heads of these
|
||||
* sections are marked with the string "SECTION:". */
|
||||
|
||||
#define _GNU_SOURCE
|
||||
|
||||
/* SECTION: This code is compiled once.
|
||||
*/
|
||||
|
||||
|
@ -89,8 +87,6 @@ char *alloca ();
|
|||
|
||||
#include "libguile/eval.h"
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
|
||||
|
||||
static SCM unmemoize_exprs (SCM expr, SCM env);
|
||||
|
@ -2645,7 +2641,7 @@ static SCM deval (SCM x, SCM env);
|
|||
? SCM_CAR (x) \
|
||||
: *scm_lookupcar ((x), (env), 1)))))
|
||||
|
||||
pthread_mutex_t source_mutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
|
||||
SCM_REC_MUTEX (source_mutex);
|
||||
|
||||
|
||||
/* Lookup a given local variable in an environment. The local variable is
|
||||
|
@ -2940,11 +2936,11 @@ scm_eval_body (SCM code, SCM env)
|
|||
{
|
||||
if (SCM_ISYMP (SCM_CAR (code)))
|
||||
{
|
||||
scm_pthread_mutex_lock (&source_mutex);
|
||||
scm_rec_mutex_lock (&source_mutex);
|
||||
/* check for race condition */
|
||||
if (SCM_ISYMP (SCM_CAR (code)))
|
||||
m_expand_body (code, env);
|
||||
pthread_mutex_unlock (&source_mutex);
|
||||
scm_rec_mutex_unlock (&source_mutex);
|
||||
goto again;
|
||||
}
|
||||
}
|
||||
|
@ -3330,11 +3326,11 @@ dispatch:
|
|||
{
|
||||
if (SCM_ISYMP (form))
|
||||
{
|
||||
scm_pthread_mutex_lock (&source_mutex);
|
||||
scm_rec_mutex_lock (&source_mutex);
|
||||
/* check for race condition */
|
||||
if (SCM_ISYMP (SCM_CAR (x)))
|
||||
m_expand_body (x, env);
|
||||
pthread_mutex_unlock (&source_mutex);
|
||||
scm_rec_mutex_unlock (&source_mutex);
|
||||
goto nontoplevel_begin;
|
||||
}
|
||||
else
|
||||
|
@ -4933,11 +4929,11 @@ tail:
|
|||
{
|
||||
if (SCM_ISYMP (SCM_CAR (proc)))
|
||||
{
|
||||
scm_pthread_mutex_lock (&source_mutex);
|
||||
scm_rec_mutex_lock (&source_mutex);
|
||||
/* check for race condition */
|
||||
if (SCM_ISYMP (SCM_CAR (proc)))
|
||||
m_expand_body (proc, args);
|
||||
pthread_mutex_unlock (&source_mutex);
|
||||
scm_rec_mutex_unlock (&source_mutex);
|
||||
goto again;
|
||||
}
|
||||
else
|
||||
|
@ -5564,19 +5560,13 @@ scm_makprom (SCM code)
|
|||
{
|
||||
SCM_RETURN_NEWSMOB2 (scm_tc16_promise,
|
||||
SCM_UNPACK (code),
|
||||
scm_make_recursive_mutex ());
|
||||
}
|
||||
|
||||
static SCM
|
||||
promise_mark (SCM promise)
|
||||
{
|
||||
scm_gc_mark (SCM_PROMISE_MUTEX (promise));
|
||||
return SCM_PROMISE_DATA (promise);
|
||||
scm_make_rec_mutex ());
|
||||
}
|
||||
|
||||
static size_t
|
||||
promise_free (SCM promise)
|
||||
{
|
||||
scm_rec_mutex_free (SCM_PROMISE_MUTEX (promise));
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -5600,7 +5590,7 @@ SCM_DEFINE (scm_force, "force", 1, 0, 0,
|
|||
#define FUNC_NAME s_scm_force
|
||||
{
|
||||
SCM_VALIDATE_SMOB (1, promise, promise);
|
||||
scm_lock_mutex (SCM_PROMISE_MUTEX (promise));
|
||||
scm_rec_mutex_lock (SCM_PROMISE_MUTEX (promise));
|
||||
if (!SCM_PROMISE_COMPUTED_P (promise))
|
||||
{
|
||||
SCM ans = scm_call_0 (SCM_PROMISE_DATA (promise));
|
||||
|
@ -5610,7 +5600,7 @@ SCM_DEFINE (scm_force, "force", 1, 0, 0,
|
|||
SCM_SET_PROMISE_COMPUTED (promise);
|
||||
}
|
||||
}
|
||||
scm_unlock_mutex (SCM_PROMISE_MUTEX (promise));
|
||||
scm_rec_mutex_unlock (SCM_PROMISE_MUTEX (promise));
|
||||
return SCM_PROMISE_DATA (promise);
|
||||
}
|
||||
#undef FUNC_NAME
|
||||
|
@ -6014,7 +6004,7 @@ scm_init_eval ()
|
|||
SCM_N_EVAL_OPTIONS);
|
||||
|
||||
scm_tc16_promise = scm_make_smob_type ("promise", 0);
|
||||
scm_set_smob_mark (scm_tc16_promise, promise_mark);
|
||||
scm_set_smob_mark (scm_tc16_promise, scm_markcdr);
|
||||
scm_set_smob_free (scm_tc16_promise, promise_free);
|
||||
scm_set_smob_print (scm_tc16_promise, promise_print);
|
||||
|
||||
|
|
|
@ -71,7 +71,8 @@ SCM_API SCM scm_eval_options_interface (SCM setting);
|
|||
(SCM_F_PROMISE_COMPUTED & SCM_SMOB_FLAGS (promise))
|
||||
#define SCM_SET_PROMISE_COMPUTED(promise) \
|
||||
SCM_SET_SMOB_FLAGS ((promise), SCM_F_PROMISE_COMPUTED)
|
||||
#define SCM_PROMISE_MUTEX SCM_SMOB_OBJECT_2
|
||||
#define SCM_PROMISE_MUTEX(promise) \
|
||||
((scm_t_rec_mutex *) SCM_SMOB_DATA_2 (promise))
|
||||
#define SCM_PROMISE_DATA SCM_SMOB_OBJECT
|
||||
#define SCM_SET_PROMISE_DATA SCM_SET_SMOB_OBJECT
|
||||
|
||||
|
|
|
@ -201,7 +201,7 @@ scm_evict_ports (int fd)
|
|||
{
|
||||
long i;
|
||||
|
||||
scm_pthread_mutex_lock (&scm_i_port_table_mutex);
|
||||
scm_mutex_lock (&scm_i_port_table_mutex);
|
||||
|
||||
for (i = 0; i < scm_i_port_table_size; i++)
|
||||
{
|
||||
|
@ -221,7 +221,7 @@ scm_evict_ports (int fd)
|
|||
}
|
||||
}
|
||||
|
||||
pthread_mutex_unlock (&scm_i_port_table_mutex);
|
||||
scm_mutex_unlock (&scm_i_port_table_mutex);
|
||||
}
|
||||
|
||||
|
||||
|
@ -425,7 +425,7 @@ scm_i_fdes_to_port (int fdes, long mode_bits, SCM name)
|
|||
SCM_MISC_ERROR ("requested file mode not available on fdes", SCM_EOL);
|
||||
}
|
||||
|
||||
scm_pthread_mutex_lock (&scm_i_port_table_mutex);
|
||||
scm_mutex_lock (&scm_i_port_table_mutex);
|
||||
|
||||
port = scm_new_port_table_entry (scm_tc16_fport);
|
||||
SCM_SET_CELL_TYPE(port, scm_tc16_fport | mode_bits);
|
||||
|
@ -443,7 +443,7 @@ scm_i_fdes_to_port (int fdes, long mode_bits, SCM name)
|
|||
scm_fport_buffer_add (port, -1, -1);
|
||||
}
|
||||
SCM_SET_FILENAME (port, name);
|
||||
pthread_mutex_unlock (&scm_i_port_table_mutex);
|
||||
scm_mutex_unlock (&scm_i_port_table_mutex);
|
||||
return port;
|
||||
}
|
||||
#undef FUNC_NAME
|
||||
|
|
|
@ -39,7 +39,7 @@ do { \
|
|||
list = SCM_FUTURE_NEXT (list); \
|
||||
} while (0)
|
||||
|
||||
pthread_mutex_t future_admin_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
SCM_MUTEX (future_admin_mutex);
|
||||
|
||||
static SCM futures = SCM_EOL;
|
||||
static SCM young = SCM_EOL;
|
||||
|
@ -99,8 +99,8 @@ static char *s_future = "future";
|
|||
static void
|
||||
cleanup (scm_t_future *future)
|
||||
{
|
||||
pthread_mutex_destroy (&future->mutex);
|
||||
pthread_cond_destroy (&future->cond);
|
||||
scm_mutex_destroy (&future->mutex);
|
||||
scm_cond_destroy (&future->cond);
|
||||
scm_gc_free (future, sizeof (*future), s_future);
|
||||
#ifdef SCM_FUTURES_DEBUG
|
||||
++n_dead;
|
||||
|
@ -110,18 +110,18 @@ cleanup (scm_t_future *future)
|
|||
static SCM
|
||||
future_loop (scm_t_future *future)
|
||||
{
|
||||
scm_pthread_mutex_lock (&future->mutex);
|
||||
scm_mutex_lock (&future->mutex);
|
||||
do {
|
||||
if (future->status == SCM_FUTURE_SIGNAL_ME)
|
||||
pthread_cond_broadcast (&future->cond);
|
||||
scm_cond_broadcast (&future->cond);
|
||||
future->status = SCM_FUTURE_COMPUTING;
|
||||
future->data = (SCM_CLOSUREP (future->data)
|
||||
? scm_i_call_closure_0 (future->data)
|
||||
: scm_call_0 (future->data));
|
||||
scm_pthread_cond_wait (&future->cond, &future->mutex);
|
||||
scm_cond_wait (&future->cond, &future->mutex);
|
||||
} while (!future->die_p);
|
||||
future->status = SCM_FUTURE_DEAD;
|
||||
pthread_mutex_unlock (&future->mutex);
|
||||
scm_mutex_unlock (&future->mutex);
|
||||
return SCM_UNSPECIFIED;
|
||||
}
|
||||
|
||||
|
@ -129,7 +129,7 @@ static SCM
|
|||
future_handler (scm_t_future *future, SCM key, SCM args)
|
||||
{
|
||||
future->status = SCM_FUTURE_DEAD;
|
||||
pthread_mutex_unlock (&future->mutex);
|
||||
scm_mutex_unlock (&future->mutex);
|
||||
return scm_apply_1 (*scm_loc_sys_thread_handler, key, args);
|
||||
}
|
||||
|
||||
|
@ -139,15 +139,15 @@ alloc_future (SCM thunk)
|
|||
scm_t_future *f = scm_gc_malloc (sizeof (*f), s_future);
|
||||
SCM future;
|
||||
f->data = SCM_BOOL_F;
|
||||
pthread_mutex_init (&f->mutex, NULL);
|
||||
pthread_cond_init (&f->cond, NULL);
|
||||
scm_mutex_init (&f->mutex, &scm_i_plugin_mutex);
|
||||
scm_cond_init (&f->cond, 0);
|
||||
f->die_p = 0;
|
||||
f->status = SCM_FUTURE_TASK_ASSIGNED;
|
||||
scm_pthread_mutex_lock (&future_admin_mutex);
|
||||
scm_mutex_lock (&future_admin_mutex);
|
||||
SCM_NEWSMOB2 (future, scm_tc16_future, futures, f);
|
||||
SCM_SET_FUTURE_DATA (future, thunk);
|
||||
futures = future;
|
||||
pthread_mutex_unlock (&future_admin_mutex);
|
||||
scm_mutex_unlock (&future_admin_mutex);
|
||||
scm_spawn_thread ((scm_t_catch_body) future_loop,
|
||||
SCM_FUTURE (future),
|
||||
(scm_t_catch_handler) future_handler,
|
||||
|
@ -166,7 +166,7 @@ SCM
|
|||
scm_i_make_future (SCM thunk)
|
||||
{
|
||||
SCM future;
|
||||
scm_pthread_mutex_lock (&future_admin_mutex);
|
||||
scm_mutex_lock (&future_admin_mutex);
|
||||
while (1)
|
||||
{
|
||||
if (!scm_is_null (old))
|
||||
|
@ -175,25 +175,25 @@ scm_i_make_future (SCM thunk)
|
|||
UNLINK (young, future);
|
||||
else
|
||||
{
|
||||
pthread_mutex_unlock (&future_admin_mutex);
|
||||
scm_mutex_unlock (&future_admin_mutex);
|
||||
return alloc_future (thunk);
|
||||
}
|
||||
if (pthread_mutex_trylock (SCM_FUTURE_MUTEX (future)))
|
||||
if (scm_mutex_trylock (SCM_FUTURE_MUTEX (future)))
|
||||
kill_future (future);
|
||||
else if (!SCM_FUTURE_ALIVE_P (future))
|
||||
{
|
||||
pthread_mutex_unlock (SCM_FUTURE_MUTEX (future));
|
||||
scm_mutex_unlock (SCM_FUTURE_MUTEX (future));
|
||||
cleanup (SCM_FUTURE (future));
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
LINK (futures, future);
|
||||
pthread_mutex_unlock (&future_admin_mutex);
|
||||
scm_mutex_unlock (&future_admin_mutex);
|
||||
SCM_SET_FUTURE_DATA (future, thunk);
|
||||
SCM_SET_FUTURE_STATUS (future, SCM_FUTURE_TASK_ASSIGNED);
|
||||
pthread_cond_signal (SCM_FUTURE_COND (future));
|
||||
pthread_mutex_unlock (SCM_FUTURE_MUTEX (future));
|
||||
scm_cond_signal (SCM_FUTURE_COND (future));
|
||||
scm_mutex_unlock (SCM_FUTURE_MUTEX (future));
|
||||
return future;
|
||||
}
|
||||
|
||||
|
@ -223,21 +223,20 @@ SCM_DEFINE (scm_future_ref, "future-ref", 1, 0, 0,
|
|||
{
|
||||
SCM res;
|
||||
SCM_VALIDATE_FUTURE (1, future);
|
||||
scm_pthread_mutex_lock (SCM_FUTURE_MUTEX (future));
|
||||
scm_mutex_lock (SCM_FUTURE_MUTEX (future));
|
||||
if (SCM_FUTURE_STATUS (future) != SCM_FUTURE_COMPUTING)
|
||||
{
|
||||
SCM_SET_FUTURE_STATUS (future, SCM_FUTURE_SIGNAL_ME);
|
||||
scm_pthread_cond_wait (SCM_FUTURE_COND (future),
|
||||
SCM_FUTURE_MUTEX (future));
|
||||
scm_cond_wait (SCM_FUTURE_COND (future), SCM_FUTURE_MUTEX (future));
|
||||
}
|
||||
if (!SCM_FUTURE_ALIVE_P (future))
|
||||
{
|
||||
pthread_mutex_unlock (SCM_FUTURE_MUTEX (future));
|
||||
scm_mutex_unlock (SCM_FUTURE_MUTEX (future));
|
||||
SCM_MISC_ERROR ("requesting result from failed future ~A",
|
||||
scm_list_1 (future));
|
||||
}
|
||||
res = SCM_FUTURE_DATA (future);
|
||||
pthread_mutex_unlock (SCM_FUTURE_MUTEX (future));
|
||||
scm_mutex_unlock (SCM_FUTURE_MUTEX (future));
|
||||
return res;
|
||||
}
|
||||
#undef FUNC_NAME
|
||||
|
@ -250,7 +249,7 @@ kill_futures (SCM victims)
|
|||
SCM future;
|
||||
UNLINK (victims, future);
|
||||
kill_future (future);
|
||||
pthread_cond_signal (SCM_FUTURE_COND (future));
|
||||
scm_cond_signal (SCM_FUTURE_COND (future));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -260,12 +259,12 @@ cleanup_undead ()
|
|||
SCM next = undead, *nextloc = &undead;
|
||||
while (!scm_is_null (next))
|
||||
{
|
||||
if (pthread_mutex_trylock (SCM_FUTURE_MUTEX (next)))
|
||||
if (scm_mutex_trylock (SCM_FUTURE_MUTEX (next)))
|
||||
goto next;
|
||||
else if (SCM_FUTURE_ALIVE_P (next))
|
||||
{
|
||||
pthread_cond_signal (SCM_FUTURE_COND (next));
|
||||
pthread_mutex_unlock (SCM_FUTURE_MUTEX (next));
|
||||
scm_cond_signal (SCM_FUTURE_COND (next));
|
||||
scm_mutex_unlock (SCM_FUTURE_MUTEX (next));
|
||||
next:
|
||||
SCM_SET_GC_MARK (next);
|
||||
nextloc = SCM_FUTURE_NEXTLOC (next);
|
||||
|
@ -275,7 +274,7 @@ cleanup_undead ()
|
|||
{
|
||||
SCM future;
|
||||
UNLINK (next, future);
|
||||
pthread_mutex_unlock (SCM_FUTURE_MUTEX (future));
|
||||
scm_mutex_unlock (SCM_FUTURE_MUTEX (future));
|
||||
cleanup (SCM_FUTURE (future));
|
||||
*nextloc = next;
|
||||
}
|
||||
|
@ -342,8 +341,6 @@ scan_futures (void *dummy1, void *dummy2, void *dummy3)
|
|||
return 0;
|
||||
}
|
||||
|
||||
scm_t_bits scm_tc16_future;
|
||||
|
||||
void
|
||||
scm_init_futures ()
|
||||
{
|
||||
|
|
|
@ -29,8 +29,8 @@
|
|||
|
||||
typedef struct scm_t_future {
|
||||
SCM data;
|
||||
pthread_mutex_t mutex;
|
||||
pthread_cond_t cond;
|
||||
scm_t_mutex mutex;
|
||||
scm_t_cond cond;
|
||||
int status;
|
||||
int die_p;
|
||||
} scm_t_future;
|
||||
|
|
|
@ -145,6 +145,12 @@ scm_gc_init_freelist (void)
|
|||
int init_heap_size_2
|
||||
= scm_getenv_int ("GUILE_INIT_SEGMENT_SIZE_2", SCM_DEFAULT_INIT_HEAP_SIZE_2);
|
||||
|
||||
/* These are the thread-local freelists. */
|
||||
scm_key_create (&scm_i_freelist, free);
|
||||
scm_key_create (&scm_i_freelist2, free);
|
||||
SCM_FREELIST_CREATE (scm_i_freelist);
|
||||
SCM_FREELIST_CREATE (scm_i_freelist2);
|
||||
|
||||
scm_init_freelist (&scm_i_master_freelist2, 2,
|
||||
scm_getenv_int ("GUILE_MIN_YIELD_2", SCM_DEFAULT_MIN_YIELD_2));
|
||||
scm_init_freelist (&scm_i_master_freelist, 1,
|
||||
|
|
|
@ -110,21 +110,21 @@ scm_realloc (void *mem, size_t size)
|
|||
if (ptr)
|
||||
return ptr;
|
||||
|
||||
scm_pthread_mutex_lock (&scm_i_sweep_mutex);
|
||||
scm_rec_mutex_lock (&scm_i_sweep_mutex);
|
||||
|
||||
scm_i_sweep_all_segments ("realloc");
|
||||
|
||||
SCM_SYSCALL (ptr = realloc (mem, size));
|
||||
if (ptr)
|
||||
{
|
||||
pthread_mutex_unlock (&scm_i_sweep_mutex);
|
||||
scm_rec_mutex_unlock (&scm_i_sweep_mutex);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
scm_igc ("realloc");
|
||||
scm_i_sweep_all_segments ("realloc");
|
||||
|
||||
pthread_mutex_unlock (&scm_i_sweep_mutex);
|
||||
scm_rec_mutex_unlock (&scm_i_sweep_mutex);
|
||||
|
||||
SCM_SYSCALL (ptr = realloc (mem, size));
|
||||
if (ptr)
|
||||
|
@ -180,10 +180,10 @@ scm_strdup (const char *str)
|
|||
static void
|
||||
decrease_mtrigger (size_t size, const char * what)
|
||||
{
|
||||
pthread_mutex_lock (&scm_i_gc_admin_mutex);
|
||||
scm_i_plugin_mutex_lock (&scm_i_gc_admin_mutex);
|
||||
scm_mallocated -= size;
|
||||
scm_gc_malloc_collected += size;
|
||||
pthread_mutex_unlock (&scm_i_gc_admin_mutex);
|
||||
scm_i_plugin_mutex_unlock (&scm_i_gc_admin_mutex);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -192,7 +192,7 @@ increase_mtrigger (size_t size, const char *what)
|
|||
size_t mallocated = 0;
|
||||
int overflow = 0, triggered = 0;
|
||||
|
||||
pthread_mutex_lock (&scm_i_gc_admin_mutex);
|
||||
scm_i_plugin_mutex_lock (&scm_i_gc_admin_mutex);
|
||||
if (ULONG_MAX - size < scm_mallocated)
|
||||
overflow = 1;
|
||||
else
|
||||
|
@ -202,10 +202,12 @@ increase_mtrigger (size_t size, const char *what)
|
|||
if (scm_mallocated > scm_mtrigger)
|
||||
triggered = 1;
|
||||
}
|
||||
pthread_mutex_unlock (&scm_i_gc_admin_mutex);
|
||||
scm_i_plugin_mutex_unlock (&scm_i_gc_admin_mutex);
|
||||
|
||||
if (overflow)
|
||||
scm_memory_error ("Overflow of scm_mallocated: too much memory in use.");
|
||||
{
|
||||
scm_memory_error ("Overflow of scm_mallocated: too much memory in use.");
|
||||
}
|
||||
|
||||
/*
|
||||
A program that uses a lot of malloced collectable memory (vectors,
|
||||
|
@ -218,7 +220,7 @@ increase_mtrigger (size_t size, const char *what)
|
|||
unsigned long prev_alloced;
|
||||
float yield;
|
||||
|
||||
scm_pthread_mutex_lock (&scm_i_sweep_mutex);
|
||||
scm_rec_mutex_lock (&scm_i_sweep_mutex);
|
||||
|
||||
prev_alloced = mallocated;
|
||||
scm_igc (what);
|
||||
|
@ -263,7 +265,7 @@ increase_mtrigger (size_t size, const char *what)
|
|||
#endif
|
||||
}
|
||||
|
||||
pthread_mutex_unlock (&scm_i_sweep_mutex);
|
||||
scm_rec_mutex_unlock (&scm_i_sweep_mutex);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -144,7 +144,6 @@ Perhaps this would work better with an explicit markstack?
|
|||
|
||||
|
||||
*/
|
||||
|
||||
void
|
||||
scm_gc_mark_dependencies (SCM p)
|
||||
#define FUNC_NAME "scm_gc_mark_dependencies"
|
||||
|
@ -155,7 +154,7 @@ scm_gc_mark_dependencies (SCM p)
|
|||
|
||||
ptr = p;
|
||||
scm_mark_dependencies_again:
|
||||
|
||||
|
||||
cell_type = SCM_GC_CELL_TYPE (ptr);
|
||||
switch (SCM_ITAG7 (cell_type))
|
||||
{
|
||||
|
@ -415,16 +414,15 @@ gc_mark_loop:
|
|||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
if (SCM_GC_MARK_P (ptr))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (SCM_GC_MARK_P (ptr))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
SCM_SET_GC_MARK (ptr);
|
||||
|
||||
|
||||
goto scm_mark_dependencies_again;
|
||||
goto scm_mark_dependencies_again;
|
||||
|
||||
}
|
||||
#undef FUNC_NAME
|
||||
|
|
|
@ -15,7 +15,6 @@
|
|||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE
|
||||
|
||||
/* #define DEBUGINFO */
|
||||
|
||||
|
@ -72,7 +71,7 @@ unsigned int scm_gc_running_p = 0;
|
|||
|
||||
/* Lock this mutex before doing lazy sweeping.
|
||||
*/
|
||||
pthread_mutex_t scm_i_sweep_mutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
|
||||
scm_t_rec_mutex scm_i_sweep_mutex;
|
||||
|
||||
/* Set this to != 0 if every cell that is accessed shall be checked:
|
||||
*/
|
||||
|
@ -207,6 +206,9 @@ SCM_DEFINE (scm_set_debug_cell_accesses_x, "set-debug-cell-accesses!", 1, 0, 0,
|
|||
|
||||
|
||||
|
||||
scm_t_key scm_i_freelist;
|
||||
scm_t_key scm_i_freelist2;
|
||||
|
||||
|
||||
/* scm_mtrigger
|
||||
* is the number of bytes of malloc allocation needed to trigger gc.
|
||||
|
@ -445,7 +447,7 @@ scm_gc_for_newcell (scm_t_cell_type_statistics *freelist, SCM *free_cells)
|
|||
{
|
||||
SCM cell;
|
||||
|
||||
scm_pthread_mutex_lock (&scm_i_sweep_mutex);
|
||||
scm_rec_mutex_lock (&scm_i_sweep_mutex);
|
||||
|
||||
*free_cells = scm_i_sweep_some_segments (freelist);
|
||||
if (*free_cells == SCM_EOL && scm_i_gc_grow_heap_p (freelist))
|
||||
|
@ -487,7 +489,7 @@ scm_gc_for_newcell (scm_t_cell_type_statistics *freelist, SCM *free_cells)
|
|||
|
||||
*free_cells = SCM_FREE_CELL_CDR (cell);
|
||||
|
||||
pthread_mutex_unlock (&scm_i_sweep_mutex);
|
||||
scm_rec_mutex_unlock (&scm_i_sweep_mutex);
|
||||
|
||||
return cell;
|
||||
}
|
||||
|
@ -502,7 +504,7 @@ scm_t_c_hook scm_after_gc_c_hook;
|
|||
void
|
||||
scm_igc (const char *what)
|
||||
{
|
||||
scm_pthread_mutex_lock (&scm_i_sweep_mutex);
|
||||
scm_rec_mutex_lock (&scm_i_sweep_mutex);
|
||||
++scm_gc_running_p;
|
||||
scm_c_hook_run (&scm_before_gc_c_hook, 0);
|
||||
|
||||
|
@ -606,7 +608,7 @@ scm_igc (const char *what)
|
|||
*/
|
||||
--scm_gc_running_p;
|
||||
scm_c_hook_run (&scm_after_gc_c_hook, 0);
|
||||
pthread_mutex_unlock (&scm_i_sweep_mutex);
|
||||
scm_rec_mutex_unlock (&scm_i_sweep_mutex);
|
||||
|
||||
/*
|
||||
For debugging purposes, you could do
|
||||
|
@ -888,13 +890,18 @@ scm_storage_prehistory ()
|
|||
scm_c_hook_init (&scm_after_gc_c_hook, 0, SCM_C_HOOK_NORMAL);
|
||||
}
|
||||
|
||||
pthread_mutex_t scm_i_gc_admin_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
scm_t_mutex scm_i_gc_admin_mutex;
|
||||
|
||||
int
|
||||
scm_init_storage ()
|
||||
{
|
||||
size_t j;
|
||||
|
||||
/* Fixme: Should use mutexattr from the low-level API. */
|
||||
scm_rec_mutex_init (&scm_i_sweep_mutex, &scm_i_plugin_rec_mutex);
|
||||
|
||||
scm_i_plugin_mutex_init (&scm_i_gc_admin_mutex, &scm_i_plugin_mutex);
|
||||
|
||||
j = SCM_NUM_PROTECTS;
|
||||
while (j)
|
||||
scm_sys_protects[--j] = SCM_BOOL_F;
|
||||
|
@ -912,18 +919,12 @@ scm_init_storage ()
|
|||
if (!scm_i_port_table)
|
||||
return 1;
|
||||
|
||||
#if 0
|
||||
/* We can't have a cleanup handler since we have no thread to run it
|
||||
in. */
|
||||
|
||||
#ifdef HAVE_ATEXIT
|
||||
atexit (cleanup);
|
||||
#else
|
||||
#ifdef HAVE_ON_EXIT
|
||||
on_exit (cleanup, 0);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
scm_stand_in_procs = scm_c_make_hash_table (257);
|
||||
|
|
|
@ -25,7 +25,12 @@
|
|||
#include "libguile/__scm.h"
|
||||
|
||||
#include "libguile/hooks.h"
|
||||
#include "libguile/threads.h"
|
||||
|
||||
#if SCM_USE_PTHREAD_THREADS
|
||||
# include "libguile/pthread-threads.h"
|
||||
#else
|
||||
# include "libguile/null-threads.h"
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
@ -225,12 +230,12 @@ SCM_API int scm_debug_cells_gc_interval ;
|
|||
void scm_i_expensive_validation_check (SCM cell);
|
||||
#endif
|
||||
|
||||
SCM_API pthread_mutex_t scm_i_gc_admin_mutex;
|
||||
SCM_API scm_t_mutex scm_i_gc_admin_mutex;
|
||||
|
||||
SCM_API int scm_block_gc;
|
||||
SCM_API int scm_gc_heap_lock;
|
||||
SCM_API unsigned int scm_gc_running_p;
|
||||
SCM_API pthread_mutex_t scm_i_sweep_mutex;
|
||||
SCM_API scm_t_rec_mutex scm_i_sweep_mutex;
|
||||
|
||||
|
||||
#if (SCM_ENABLE_DEPRECATED == 1)
|
||||
|
@ -250,10 +255,13 @@ SCM_API size_t scm_default_max_segment_size;
|
|||
|
||||
SCM_API size_t scm_max_segment_size;
|
||||
|
||||
#define SCM_SET_FREELIST_LOC(key,ptr) pthread_setspecific ((key), (ptr))
|
||||
#define SCM_FREELIST_LOC(key) ((SCM *) pthread_getspecific (key))
|
||||
SCM_API pthread_key_t scm_i_freelist;
|
||||
SCM_API pthread_key_t scm_i_freelist2;
|
||||
#define SCM_FREELIST_CREATE(key) \
|
||||
do { SCM *ls = (SCM *) malloc (sizeof (SCM)); \
|
||||
*ls = SCM_EOL; \
|
||||
scm_setspecific ((key), ls); } while (0)
|
||||
#define SCM_FREELIST_LOC(key) ((SCM *) scm_getspecific (key))
|
||||
SCM_API scm_t_key scm_i_freelist;
|
||||
SCM_API scm_t_key scm_i_freelist2;
|
||||
SCM_API struct scm_t_cell_type_statistics scm_i_master_freelist;
|
||||
SCM_API struct scm_t_cell_type_statistics scm_i_master_freelist2;
|
||||
|
||||
|
|
|
@ -30,27 +30,6 @@
|
|||
#include "libguile/hashtab.h"
|
||||
|
||||
|
||||
static void
|
||||
loop (void)
|
||||
{
|
||||
int loop = 1;
|
||||
printf ("looping %d\n", getpid ());
|
||||
while (loop)
|
||||
;
|
||||
}
|
||||
|
||||
void
|
||||
scm_i_hashtable_decrement (SCM h)
|
||||
{
|
||||
scm_t_hashtable *t = SCM_HASHTABLE (h);
|
||||
if (t->n_items == 0)
|
||||
{
|
||||
printf ("hashtab underflow\n");
|
||||
loop ();
|
||||
}
|
||||
t->n_items--;
|
||||
}
|
||||
|
||||
/* NOTES
|
||||
*
|
||||
* 1. The current hash table implementation uses weak alist vectors
|
||||
|
@ -166,7 +145,7 @@ scm_i_rehash (SCM table,
|
|||
SCM_HASHTABLE (table)->closure = closure;
|
||||
}
|
||||
SCM_HASHTABLE (table)->size_index = i;
|
||||
|
||||
|
||||
new_size = hashtable_size[i];
|
||||
if (i <= SCM_HASHTABLE (table)->min_size_index)
|
||||
SCM_HASHTABLE (table)->lower = 0;
|
||||
|
|
|
@ -55,12 +55,7 @@ extern scm_t_bits scm_tc16_hashtable;
|
|||
#define SCM_HASHTABLE_N_ITEMS(x) (SCM_HASHTABLE (x)->n_items)
|
||||
#define SCM_SET_HASHTABLE_N_ITEMS(x, n) (SCM_HASHTABLE (x)->n_items = n)
|
||||
#define SCM_HASHTABLE_INCREMENT(x) (SCM_HASHTABLE_N_ITEMS(x)++)
|
||||
#if 0
|
||||
#define SCM_HASHTABLE_DECREMENT(x) (SCM_HASHTABLE_N_ITEMS(x)--)
|
||||
#else
|
||||
SCM_API void scm_i_hashtable_decrement (SCM h);
|
||||
#define SCM_HASHTABLE_DECREMENT(x) scm_i_hashtable_decrement(x)
|
||||
#endif
|
||||
#define SCM_HASHTABLE_UPPER(x) (SCM_HASHTABLE (x)->upper)
|
||||
#define SCM_HASHTABLE_LOWER(x) (SCM_HASHTABLE (x)->lower)
|
||||
|
||||
|
|
135
libguile/init.c
135
libguile/init.c
|
@ -133,6 +133,46 @@
|
|||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
/* Setting up the stack. */
|
||||
|
||||
static void
|
||||
restart_stack (void *base)
|
||||
{
|
||||
scm_dynwinds = SCM_EOL;
|
||||
SCM_DYNENV (scm_rootcont) = SCM_EOL;
|
||||
SCM_THROW_VALUE (scm_rootcont) = SCM_EOL;
|
||||
SCM_DFRAME (scm_rootcont) = scm_last_debug_frame = 0;
|
||||
SCM_BASE (scm_rootcont) = base;
|
||||
}
|
||||
|
||||
static void
|
||||
start_stack (void *base)
|
||||
{
|
||||
SCM root;
|
||||
|
||||
root = scm_permanent_object (scm_make_root (SCM_UNDEFINED));
|
||||
scm_set_root (SCM_ROOT_STATE (root));
|
||||
scm_stack_base = base;
|
||||
|
||||
scm_exitval = SCM_BOOL_F; /* vestigial */
|
||||
|
||||
scm_root->fluids = scm_i_make_initial_fluids ();
|
||||
|
||||
/* Create an object to hold the root continuation.
|
||||
*/
|
||||
{
|
||||
scm_t_contregs *contregs = scm_gc_malloc (sizeof (scm_t_contregs),
|
||||
"continuation");
|
||||
contregs->num_stack_items = 0;
|
||||
contregs->seq = 0;
|
||||
SCM_NEWSMOB (scm_rootcont, scm_tc16_continuation, contregs);
|
||||
}
|
||||
|
||||
/* The remainder of stack initialization is factored out to another
|
||||
* function so that if this stack is ever exitted, it can be
|
||||
* re-entered using restart_stack. */
|
||||
restart_stack (base);
|
||||
}
|
||||
|
||||
|
||||
#if 0
|
||||
|
@ -305,9 +345,11 @@ struct main_func_closure
|
|||
char **argv; /* the argument list it should receive */
|
||||
};
|
||||
|
||||
|
||||
static void scm_init_guile_1 (SCM_STACKITEM *base);
|
||||
static void scm_boot_guile_1 (SCM_STACKITEM *base,
|
||||
struct main_func_closure *closure);
|
||||
static void *invoke_main_func(void *body_data);
|
||||
static SCM invoke_main_func(void *body_data);
|
||||
|
||||
|
||||
/* Fire up the Guile Scheme interpreter.
|
||||
|
@ -341,6 +383,10 @@ static void *invoke_main_func(void *body_data);
|
|||
void
|
||||
scm_boot_guile (int argc, char ** argv, void (*main_func) (), void *closure)
|
||||
{
|
||||
/* The garbage collector uses the address of this variable as one
|
||||
end of the stack, and the address of one of its own local
|
||||
variables as the other end. */
|
||||
SCM_STACKITEM dummy;
|
||||
struct main_func_closure c;
|
||||
|
||||
c.main_func = main_func;
|
||||
|
@ -348,47 +394,19 @@ scm_boot_guile (int argc, char ** argv, void (*main_func) (), void *closure)
|
|||
c.argc = argc;
|
||||
c.argv = argv;
|
||||
|
||||
scm_with_guile (invoke_main_func, &c);
|
||||
scm_boot_guile_1 (&dummy, &c);
|
||||
}
|
||||
|
||||
static void *
|
||||
invoke_main_func (void *body_data)
|
||||
{
|
||||
struct main_func_closure *closure = (struct main_func_closure *) body_data;
|
||||
|
||||
scm_set_program_arguments (closure->argc, closure->argv, 0);
|
||||
(*closure->main_func) (closure->closure, closure->argc, closure->argv);
|
||||
|
||||
scm_restore_signals ();
|
||||
|
||||
/* This tick gives any pending
|
||||
* asyncs a chance to run. This must be done after
|
||||
* the call to scm_restore_signals.
|
||||
*/
|
||||
SCM_ASYNC_TICK;
|
||||
|
||||
/* If the caller doesn't want this, they should exit from main_func
|
||||
themselves.
|
||||
*/
|
||||
pthread_exit (NULL);
|
||||
|
||||
/* never reached */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#if 0
|
||||
void
|
||||
scm_init_guile ()
|
||||
{
|
||||
scm_i_init_guile ((SCM_STACKITEM *)scm_get_stack_base ());
|
||||
scm_init_guile_1 ((SCM_STACKITEM *)scm_get_stack_base ());
|
||||
}
|
||||
#endif
|
||||
|
||||
pthread_mutex_t scm_i_init_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
int scm_initialized_p = 0;
|
||||
|
||||
void
|
||||
scm_i_init_guile (SCM_STACKITEM *base)
|
||||
static void
|
||||
scm_init_guile_1 (SCM_STACKITEM *base)
|
||||
{
|
||||
if (scm_initialized_p)
|
||||
return;
|
||||
|
@ -409,7 +427,7 @@ scm_i_init_guile (SCM_STACKITEM *base)
|
|||
scm_block_gc = 1;
|
||||
|
||||
scm_storage_prehistory ();
|
||||
scm_threads_prehistory (base);
|
||||
scm_threads_prehistory ();
|
||||
scm_ports_prehistory ();
|
||||
scm_smob_prehistory ();
|
||||
scm_hashtab_prehistory (); /* requires storage_prehistory */
|
||||
|
@ -430,7 +448,8 @@ scm_i_init_guile (SCM_STACKITEM *base)
|
|||
scm_init_variable (); /* all bindings need variables */
|
||||
scm_init_continuations ();
|
||||
scm_init_root (); /* requires continuations */
|
||||
scm_init_threads ();
|
||||
scm_init_threads (base);
|
||||
start_stack (base);
|
||||
scm_init_gsubr ();
|
||||
scm_init_thread_procs (); /* requires gsubrs */
|
||||
scm_init_procprop ();
|
||||
|
@ -532,8 +551,6 @@ scm_i_init_guile (SCM_STACKITEM *base)
|
|||
scm_i_init_deprecated ();
|
||||
#endif
|
||||
|
||||
scm_init_threads_root_root ();
|
||||
|
||||
scm_initialized_p = 1;
|
||||
|
||||
scm_block_gc = 0; /* permit the gc to run */
|
||||
|
@ -550,6 +567,50 @@ scm_i_init_guile (SCM_STACKITEM *base)
|
|||
scm_load_startup_files ();
|
||||
}
|
||||
|
||||
/* Record here whether SCM_BOOT_GUILE_1 has already been called. This
|
||||
variable is now here and not inside SCM_BOOT_GUILE_1 so that one
|
||||
can tweak it. This is necessary for unexec to work. (Hey, "1-live"
|
||||
is the name of a local radiostation...) */
|
||||
|
||||
int scm_boot_guile_1_live = 0;
|
||||
|
||||
static void
|
||||
scm_boot_guile_1 (SCM_STACKITEM *base, struct main_func_closure *closure)
|
||||
{
|
||||
scm_init_guile_1 (base);
|
||||
|
||||
/* This function is not re-entrant. */
|
||||
if (scm_boot_guile_1_live)
|
||||
abort ();
|
||||
|
||||
scm_boot_guile_1_live = 1;
|
||||
|
||||
scm_set_program_arguments (closure->argc, closure->argv, 0);
|
||||
invoke_main_func (closure);
|
||||
|
||||
scm_restore_signals ();
|
||||
|
||||
/* This tick gives any pending
|
||||
* asyncs a chance to run. This must be done after
|
||||
* the call to scm_restore_signals.
|
||||
*/
|
||||
SCM_ASYNC_TICK;
|
||||
|
||||
/* If the caller doesn't want this, they should return from
|
||||
main_func themselves. */
|
||||
exit (0);
|
||||
}
|
||||
|
||||
static SCM
|
||||
invoke_main_func (void *body_data)
|
||||
{
|
||||
struct main_func_closure *closure = (struct main_func_closure *) body_data;
|
||||
|
||||
(*closure->main_func) (closure->closure, closure->argc, closure->argv);
|
||||
|
||||
/* never reached */
|
||||
return SCM_UNDEFINED;
|
||||
}
|
||||
|
||||
/*
|
||||
Local Variables:
|
||||
|
|
|
@ -23,10 +23,8 @@
|
|||
|
||||
|
||||
#include "libguile/__scm.h"
|
||||
#include "libguile/threads.h"
|
||||
|
||||
|
||||
SCM_API pthread_mutex_t scm_i_init_mutex;
|
||||
SCM_API int scm_initialized_p;
|
||||
|
||||
SCM_API void scm_init_guile (void);
|
||||
|
@ -37,8 +35,6 @@ SCM_API void scm_boot_guile (int argc, char **argv,
|
|||
char **argv),
|
||||
void *closure);
|
||||
|
||||
SCM_API void scm_i_init_guile (SCM_STACKITEM *base);
|
||||
|
||||
SCM_API void scm_load_startup_files (void);
|
||||
|
||||
#endif /* SCM_INIT_H */
|
||||
|
|
|
@ -67,6 +67,15 @@ SCM
|
|||
scm_cell (scm_t_bits car, scm_t_bits cdr)
|
||||
{
|
||||
SCM z;
|
||||
/* We retrieve the SCM pointer only once since the call to
|
||||
SCM_FREELIST_LOC will be slightly expensive when we support
|
||||
preemptive multithreading. SCM_FREELIST_LOC will then retrieve
|
||||
the thread specific freelist.
|
||||
|
||||
Until then, SCM_FREELIST_DOC expands to (&scm_i_freelist) and the
|
||||
following code will compile to the same as if we had worked
|
||||
directly on the scm_i_freelist variable.
|
||||
*/
|
||||
SCM *freelist = SCM_FREELIST_LOC (scm_i_freelist);
|
||||
|
||||
if (scm_gc_running_p)
|
||||
|
|
|
@ -280,14 +280,14 @@ SCM_DEFINE (scm_fdes_to_ports, "fdes->ports", 1, 0, 0,
|
|||
|
||||
int_fd = scm_to_int (fd);
|
||||
|
||||
scm_pthread_mutex_lock (&scm_i_port_table_mutex);
|
||||
scm_mutex_lock (&scm_i_port_table_mutex);
|
||||
for (i = 0; i < scm_i_port_table_size; i++)
|
||||
{
|
||||
if (SCM_OPFPORTP (scm_i_port_table[i]->port)
|
||||
&& ((scm_t_fport *) scm_i_port_table[i]->stream)->fdes == int_fd)
|
||||
result = scm_cons (scm_i_port_table[i]->port, result);
|
||||
}
|
||||
pthread_mutex_unlock (&scm_i_port_table_mutex);
|
||||
scm_mutex_unlock (&scm_i_port_table_mutex);
|
||||
return result;
|
||||
}
|
||||
#undef FUNC_NAME
|
||||
|
|
|
@ -493,7 +493,7 @@ scm_t_port **scm_i_port_table;
|
|||
long scm_i_port_table_size = 0; /* Number of ports in scm_i_port_table. */
|
||||
long scm_i_port_table_room = 20; /* Size of the array. */
|
||||
|
||||
pthread_mutex_t scm_i_port_table_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
SCM_GLOBAL_MUTEX (scm_i_port_table_mutex);
|
||||
|
||||
/* This function is not and should not be thread safe. */
|
||||
|
||||
|
@ -764,9 +764,9 @@ SCM_DEFINE (scm_close_port, "close-port", 1, 0, 0,
|
|||
rv = (scm_ptobs[i].close) (port);
|
||||
else
|
||||
rv = 0;
|
||||
scm_pthread_mutex_lock (&scm_i_port_table_mutex);
|
||||
scm_mutex_lock (&scm_i_port_table_mutex);
|
||||
scm_remove_from_port_table (port);
|
||||
pthread_mutex_unlock (&scm_i_port_table_mutex);
|
||||
scm_mutex_unlock (&scm_i_port_table_mutex);
|
||||
SCM_CLR_PORT_OPEN_FLAG (port);
|
||||
return scm_from_bool (rv >= 0);
|
||||
}
|
||||
|
@ -815,18 +815,18 @@ scm_c_port_for_each (void (*proc)(void *data, SCM p), void *data)
|
|||
can change arbitrarily (from a GC, for example). So we first
|
||||
collect the ports into a vector. -mvo */
|
||||
|
||||
scm_pthread_mutex_lock (&scm_i_port_table_mutex);
|
||||
scm_mutex_lock (&scm_i_port_table_mutex);
|
||||
n = scm_i_port_table_size;
|
||||
pthread_mutex_unlock (&scm_i_port_table_mutex);
|
||||
scm_mutex_unlock (&scm_i_port_table_mutex);
|
||||
|
||||
ports = scm_c_make_vector (n, SCM_BOOL_F);
|
||||
|
||||
scm_pthread_mutex_lock (&scm_i_port_table_mutex);
|
||||
scm_mutex_lock (&scm_i_port_table_mutex);
|
||||
if (n > scm_i_port_table_size)
|
||||
n = scm_i_port_table_size;
|
||||
for (i = 0; i < n; i++)
|
||||
SCM_SIMPLE_VECTOR_SET (ports, i, scm_i_port_table[i]->port);
|
||||
pthread_mutex_unlock (&scm_i_port_table_mutex);
|
||||
scm_mutex_unlock (&scm_i_port_table_mutex);
|
||||
|
||||
for (i = 0; i < n; i++)
|
||||
proc (data, SCM_SIMPLE_VECTOR_REF (ports, i));
|
||||
|
@ -938,13 +938,13 @@ SCM_DEFINE (scm_flush_all_ports, "flush-all-ports", 0, 0, 0,
|
|||
{
|
||||
size_t i;
|
||||
|
||||
scm_pthread_mutex_lock (&scm_i_port_table_mutex);
|
||||
scm_mutex_lock (&scm_i_port_table_mutex);
|
||||
for (i = 0; i < scm_i_port_table_size; i++)
|
||||
{
|
||||
if (SCM_OPOUTPORTP (scm_i_port_table[i]->port))
|
||||
scm_flush (scm_i_port_table[i]->port);
|
||||
}
|
||||
pthread_mutex_unlock (&scm_i_port_table_mutex);
|
||||
scm_mutex_unlock (&scm_i_port_table_mutex);
|
||||
return SCM_UNSPECIFIED;
|
||||
}
|
||||
#undef FUNC_NAME
|
||||
|
@ -1638,7 +1638,7 @@ write_void_port (SCM port SCM_UNUSED,
|
|||
static SCM
|
||||
scm_i_void_port (long mode_bits)
|
||||
{
|
||||
scm_pthread_mutex_lock (&scm_i_port_table_mutex);
|
||||
scm_mutex_lock (&scm_i_port_table_mutex);
|
||||
{
|
||||
SCM answer = scm_new_port_table_entry (scm_tc16_void_port);
|
||||
scm_t_port * pt = SCM_PTAB_ENTRY(answer);
|
||||
|
@ -1647,7 +1647,7 @@ scm_i_void_port (long mode_bits)
|
|||
|
||||
SCM_SETSTREAM (answer, 0);
|
||||
SCM_SET_CELL_TYPE (answer, scm_tc16_void_port | mode_bits);
|
||||
pthread_mutex_unlock (&scm_i_port_table_mutex);
|
||||
scm_mutex_unlock (&scm_i_port_table_mutex);
|
||||
return answer;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -111,7 +111,7 @@ typedef struct
|
|||
|
||||
SCM_API scm_t_port **scm_i_port_table;
|
||||
SCM_API long scm_i_port_table_size; /* Number of ports in scm_i_port_table. */
|
||||
SCM_API pthread_mutex_t scm_i_port_table_mutex;
|
||||
SCM_API scm_t_mutex scm_i_port_table_mutex;
|
||||
|
||||
#define SCM_READ_BUFFER_EMPTY_P(c_port) (c_port->read_pos >= c_port->read_end)
|
||||
|
||||
|
|
|
@ -40,7 +40,6 @@
|
|||
#include "libguile/validate.h"
|
||||
#include "libguile/posix.h"
|
||||
#include "libguile/i18n.h"
|
||||
#include "libguile/threads.h"
|
||||
|
||||
|
||||
#ifdef HAVE_STRING_H
|
||||
|
@ -821,11 +820,11 @@ SCM_DEFINE (scm_ttyname, "ttyname", 1, 0, 0,
|
|||
return SCM_BOOL_F;
|
||||
fd = SCM_FPORT_FDES (port);
|
||||
|
||||
scm_pthread_mutex_lock (&scm_i_misc_mutex);
|
||||
scm_mutex_lock (&scm_i_misc_mutex);
|
||||
SCM_SYSCALL (result = ttyname (fd));
|
||||
err = errno;
|
||||
ret = scm_from_locale_string (result);
|
||||
pthread_mutex_unlock (&scm_i_misc_mutex);
|
||||
scm_mutex_unlock (&scm_i_misc_mutex);
|
||||
|
||||
if (!result)
|
||||
{
|
||||
|
@ -1506,12 +1505,15 @@ SCM_DEFINE (scm_crypt, "crypt", 2, 0, 0,
|
|||
char *c_key, *c_salt;
|
||||
|
||||
scm_frame_begin (0);
|
||||
scm_frame_pthread_mutex_lock (&scm_i_misc_mutex);
|
||||
scm_frame_unwind_handler ((void(*)(void*)) scm_mutex_unlock,
|
||||
&scm_i_misc_mutex,
|
||||
SCM_F_WIND_EXPLICITLY);
|
||||
scm_mutex_lock (&scm_i_misc_mutex);
|
||||
|
||||
c_key = scm_to_locale_string (key);
|
||||
scm_frame_free (c_key);
|
||||
c_salt = scm_to_locale_string (salt);
|
||||
scm_frame_free (c_salt);
|
||||
scm_frame_free (c_key);
|
||||
|
||||
ret = scm_from_locale_string (crypt (c_key, c_salt));
|
||||
|
||||
|
|
|
@ -133,7 +133,7 @@ do { \
|
|||
|
||||
SCM scm_print_state_vtable = SCM_BOOL_F;
|
||||
static SCM print_state_pool = SCM_EOL;
|
||||
pthread_mutex_t print_state_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
SCM_MUTEX (print_state_mutex);
|
||||
|
||||
#ifdef GUILE_DEBUG /* Used for debugging purposes */
|
||||
|
||||
|
@ -173,13 +173,13 @@ scm_make_print_state ()
|
|||
SCM answer = SCM_BOOL_F;
|
||||
|
||||
/* First try to allocate a print state from the pool */
|
||||
pthread_mutex_lock (&print_state_mutex);
|
||||
scm_i_plugin_mutex_lock (&print_state_mutex);
|
||||
if (!scm_is_null (print_state_pool))
|
||||
{
|
||||
answer = SCM_CAR (print_state_pool);
|
||||
print_state_pool = SCM_CDR (print_state_pool);
|
||||
}
|
||||
pthread_mutex_unlock (&print_state_mutex);
|
||||
scm_i_plugin_mutex_unlock (&print_state_mutex);
|
||||
|
||||
return scm_is_false (answer) ? make_print_state () : answer;
|
||||
}
|
||||
|
@ -197,10 +197,10 @@ scm_free_print_state (SCM print_state)
|
|||
pstate->fancyp = 0;
|
||||
pstate->revealed = 0;
|
||||
pstate->highlight_objects = SCM_EOL;
|
||||
pthread_mutex_lock (&print_state_mutex);
|
||||
scm_i_plugin_mutex_lock (&print_state_mutex);
|
||||
handle = scm_cons (print_state, print_state_pool);
|
||||
print_state_pool = handle;
|
||||
pthread_mutex_unlock (&print_state_mutex);
|
||||
scm_i_plugin_mutex_unlock (&print_state_mutex);
|
||||
}
|
||||
|
||||
SCM
|
||||
|
@ -692,13 +692,13 @@ scm_prin1 (SCM exp, SCM port, int writingp)
|
|||
else
|
||||
{
|
||||
/* First try to allocate a print state from the pool */
|
||||
pthread_mutex_lock (&print_state_mutex);
|
||||
scm_i_plugin_mutex_lock (&print_state_mutex);
|
||||
if (!scm_is_null (print_state_pool))
|
||||
{
|
||||
handle = print_state_pool;
|
||||
print_state_pool = SCM_CDR (print_state_pool);
|
||||
}
|
||||
pthread_mutex_unlock (&print_state_mutex);
|
||||
scm_i_plugin_mutex_unlock (&print_state_mutex);
|
||||
if (scm_is_false (handle))
|
||||
handle = scm_list_1 (make_print_state ());
|
||||
pstate_scm = SCM_CAR (handle);
|
||||
|
@ -715,10 +715,10 @@ scm_prin1 (SCM exp, SCM port, int writingp)
|
|||
|
||||
if (scm_is_true (handle) && !pstate->revealed)
|
||||
{
|
||||
pthread_mutex_lock (&print_state_mutex);
|
||||
scm_i_plugin_mutex_lock (&print_state_mutex);
|
||||
SCM_SETCDR (handle, print_state_pool);
|
||||
print_state_pool = handle;
|
||||
pthread_mutex_unlock (&print_state_mutex);
|
||||
scm_i_plugin_mutex_unlock (&print_state_mutex);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -46,6 +46,7 @@ root_mark (SCM root)
|
|||
scm_gc_mark (s->rootcont);
|
||||
scm_gc_mark (s->dynwinds);
|
||||
scm_gc_mark (s->progargs);
|
||||
scm_gc_mark (s->exitval);
|
||||
scm_gc_mark (s->cur_inp);
|
||||
scm_gc_mark (s->cur_outp);
|
||||
scm_gc_mark (s->cur_errp);
|
||||
|
@ -90,6 +91,7 @@ scm_make_root (SCM parent)
|
|||
root_state->rootcont
|
||||
= root_state->dynwinds
|
||||
= root_state->progargs
|
||||
= root_state->exitval
|
||||
= root_state->cur_inp
|
||||
= root_state->cur_outp
|
||||
= root_state->cur_errp
|
||||
|
@ -344,10 +346,6 @@ scm_apply_with_dynamic_root (SCM proc, SCM a1, SCM args, SCM handler)
|
|||
|
||||
|
||||
|
||||
/* Initialized in scm_threads_prehistory.
|
||||
*/
|
||||
pthread_key_t scm_i_root_key;
|
||||
|
||||
void
|
||||
scm_init_root ()
|
||||
{
|
||||
|
|
|
@ -64,7 +64,8 @@ typedef struct scm_root_state
|
|||
/* It is very inefficient to have this variable in the root state. */
|
||||
scm_t_debug_frame *last_debug_frame;
|
||||
|
||||
SCM progargs;
|
||||
SCM progargs; /* vestigial */
|
||||
SCM exitval; /* vestigial */
|
||||
|
||||
SCM cur_inp;
|
||||
SCM cur_outp;
|
||||
|
@ -86,10 +87,6 @@ typedef struct scm_root_state
|
|||
*/
|
||||
} scm_root_state;
|
||||
|
||||
#define scm_root ((scm_root_state *) pthread_getspecific (scm_i_root_key))
|
||||
#define scm_set_root(new_root) pthread_setspecific (scm_i_root_key, new_root)
|
||||
SCM_API pthread_key_t scm_i_root_key;
|
||||
|
||||
#define scm_stack_base (scm_root->stack_base)
|
||||
#define scm_save_regs_gc_mark (scm_root->save_regs_gc_mark)
|
||||
#define scm_errjmp_bad (scm_root->errjmp_bad)
|
||||
|
@ -104,6 +101,8 @@ SCM_API pthread_key_t scm_i_root_key;
|
|||
#define scm_cur_errp (scm_root->cur_errp)
|
||||
#define scm_cur_loadp (scm_root->cur_loadp)
|
||||
|
||||
#define scm_root ((scm_root_state *) SCM_THREAD_LOCAL_DATA)
|
||||
#define scm_set_root(new_root) SCM_SET_THREAD_LOCAL_DATA (new_root)
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -136,7 +136,7 @@ scm_i_stringbuf_free (SCM buf)
|
|||
STRINGBUF_OUTLINE_LENGTH (buf) + 1, "string");
|
||||
}
|
||||
|
||||
pthread_mutex_t stringbuf_write_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
SCM_MUTEX (stringbuf_write_mutex);
|
||||
|
||||
/* Copy-on-write strings.
|
||||
*/
|
||||
|
@ -209,9 +209,9 @@ scm_i_substring (SCM str, size_t start, size_t end)
|
|||
SCM buf;
|
||||
size_t str_start;
|
||||
get_str_buf_start (&str, &buf, &str_start);
|
||||
pthread_mutex_lock (&stringbuf_write_mutex);
|
||||
scm_i_plugin_mutex_lock (&stringbuf_write_mutex);
|
||||
SET_STRINGBUF_SHARED (buf);
|
||||
pthread_mutex_unlock (&stringbuf_write_mutex);
|
||||
scm_i_plugin_mutex_unlock (&stringbuf_write_mutex);
|
||||
return scm_double_cell (STRING_TAG, SCM_UNPACK(buf),
|
||||
(scm_t_bits)str_start + start,
|
||||
(scm_t_bits) end - start);
|
||||
|
@ -223,9 +223,9 @@ scm_i_substring_read_only (SCM str, size_t start, size_t end)
|
|||
SCM buf;
|
||||
size_t str_start;
|
||||
get_str_buf_start (&str, &buf, &str_start);
|
||||
pthread_mutex_lock (&stringbuf_write_mutex);
|
||||
scm_i_plugin_mutex_lock (&stringbuf_write_mutex);
|
||||
SET_STRINGBUF_SHARED (buf);
|
||||
pthread_mutex_unlock (&stringbuf_write_mutex);
|
||||
scm_i_plugin_mutex_unlock (&stringbuf_write_mutex);
|
||||
return scm_double_cell (RO_STRING_TAG, SCM_UNPACK(buf),
|
||||
(scm_t_bits)str_start + start,
|
||||
(scm_t_bits) end - start);
|
||||
|
@ -334,7 +334,7 @@ scm_i_string_writable_chars (SCM orig_str)
|
|||
if (IS_RO_STRING (str))
|
||||
scm_misc_error (NULL, "string is read-only: ~s", scm_list_1 (orig_str));
|
||||
|
||||
pthread_mutex_lock (&stringbuf_write_mutex);
|
||||
scm_i_plugin_mutex_lock (&stringbuf_write_mutex);
|
||||
if (STRINGBUF_SHARED (buf))
|
||||
{
|
||||
/* Clone stringbuf. For this, we put all threads to sleep.
|
||||
|
@ -343,7 +343,7 @@ scm_i_string_writable_chars (SCM orig_str)
|
|||
size_t len = STRING_LENGTH (str);
|
||||
SCM new_buf;
|
||||
|
||||
pthread_mutex_unlock (&stringbuf_write_mutex);
|
||||
scm_i_plugin_mutex_unlock (&stringbuf_write_mutex);
|
||||
|
||||
new_buf = make_stringbuf (len);
|
||||
memcpy (STRINGBUF_CHARS (new_buf),
|
||||
|
@ -357,7 +357,7 @@ scm_i_string_writable_chars (SCM orig_str)
|
|||
|
||||
buf = new_buf;
|
||||
|
||||
pthread_mutex_lock (&stringbuf_write_mutex);
|
||||
scm_i_plugin_mutex_lock (&stringbuf_write_mutex);
|
||||
}
|
||||
|
||||
return STRINGBUF_CHARS (buf) + start;
|
||||
|
@ -366,7 +366,7 @@ scm_i_string_writable_chars (SCM orig_str)
|
|||
void
|
||||
scm_i_string_stop_writing (void)
|
||||
{
|
||||
pthread_mutex_unlock (&stringbuf_write_mutex);
|
||||
scm_i_plugin_mutex_unlock (&stringbuf_write_mutex);
|
||||
}
|
||||
|
||||
/* Symbols.
|
||||
|
@ -396,9 +396,9 @@ scm_i_make_symbol (SCM name, scm_t_bits flags,
|
|||
if (start == 0 && length == STRINGBUF_LENGTH (buf))
|
||||
{
|
||||
/* reuse buf. */
|
||||
pthread_mutex_lock (&stringbuf_write_mutex);
|
||||
scm_i_plugin_mutex_lock (&stringbuf_write_mutex);
|
||||
SET_STRINGBUF_SHARED (buf);
|
||||
pthread_mutex_unlock (&stringbuf_write_mutex);
|
||||
scm_i_plugin_mutex_unlock (&stringbuf_write_mutex);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -441,9 +441,9 @@ SCM
|
|||
scm_i_symbol_substring (SCM sym, size_t start, size_t end)
|
||||
{
|
||||
SCM buf = SYMBOL_STRINGBUF (sym);
|
||||
pthread_mutex_lock (&stringbuf_write_mutex);
|
||||
scm_i_plugin_mutex_lock (&stringbuf_write_mutex);
|
||||
SET_STRINGBUF_SHARED (buf);
|
||||
pthread_mutex_unlock (&stringbuf_write_mutex);
|
||||
scm_i_plugin_mutex_unlock (&stringbuf_write_mutex);
|
||||
return scm_double_cell (STRING_TAG, SCM_UNPACK(buf),
|
||||
(scm_t_bits)start, (scm_t_bits) end - start);
|
||||
}
|
||||
|
|
|
@ -288,7 +288,7 @@ scm_mkstrport (SCM pos, SCM str, long modes, const char *caller)
|
|||
else
|
||||
str = scm_c_substring (str, 0, str_len);
|
||||
|
||||
scm_pthread_mutex_lock (&scm_i_port_table_mutex);
|
||||
scm_mutex_lock (&scm_i_port_table_mutex);
|
||||
z = scm_new_port_table_entry (scm_tc16_strport);
|
||||
pt = SCM_PTAB_ENTRY(z);
|
||||
SCM_SETSTREAM (z, SCM_UNPACK (str));
|
||||
|
@ -301,7 +301,7 @@ scm_mkstrport (SCM pos, SCM str, long modes, const char *caller)
|
|||
|
||||
pt->rw_random = 1;
|
||||
|
||||
pthread_mutex_unlock (&scm_i_port_table_mutex);
|
||||
scm_mutex_unlock (&scm_i_port_table_mutex);
|
||||
|
||||
/* ensure write_pos is writable. */
|
||||
if ((modes & SCM_WRTNG) && pt->write_pos == pt->write_end)
|
||||
|
|
|
@ -279,9 +279,9 @@ SCM_DEFINE (scm_gensym, "gensym", 0, 1, 0,
|
|||
prefix = scm_from_locale_string (" g");
|
||||
|
||||
/* mutex in case another thread looks and incs at the exact same moment */
|
||||
scm_pthread_mutex_lock (&scm_i_misc_mutex);
|
||||
scm_mutex_lock (&scm_i_misc_mutex);
|
||||
n = gensym_counter++;
|
||||
pthread_mutex_unlock (&scm_i_misc_mutex);
|
||||
scm_mutex_unlock (&scm_i_misc_mutex);
|
||||
|
||||
n_digits = scm_iint2str (n, 10, buf);
|
||||
suffix = scm_from_locale_stringn (buf, n_digits);
|
||||
|
|
1389
libguile/threads.c
1389
libguile/threads.c
File diff suppressed because it is too large
Load diff
|
@ -27,89 +27,165 @@
|
|||
#include "libguile/throw.h"
|
||||
#include "libguile/root.h"
|
||||
#include "libguile/iselect.h"
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
#include "libguile/threads-plugin.h"
|
||||
|
||||
|
||||
/* smob tags for the thread datatypes */
|
||||
SCM_API scm_t_bits scm_tc16_thread;
|
||||
SCM_API scm_t_bits scm_tc16_mutex;
|
||||
SCM_API scm_t_bits scm_tc16_fair_mutex;
|
||||
SCM_API scm_t_bits scm_tc16_condvar;
|
||||
|
||||
typedef struct scm_thread {
|
||||
struct scm_thread *next_thread;
|
||||
|
||||
/* For general blocking.
|
||||
*/
|
||||
pthread_cond_t sleep_cond;
|
||||
|
||||
/* This mutex represents this threads right to access the heap.
|
||||
That right can temporarily be taken away by the GC.
|
||||
*/
|
||||
pthread_mutex_t heap_mutex;
|
||||
SCM freelist, freelist2;
|
||||
int clear_freelists_p; /* set if GC was done while thread was asleep */
|
||||
|
||||
SCM root;
|
||||
|
||||
SCM handle;
|
||||
pthread_t pthread;
|
||||
SCM result;
|
||||
int exited;
|
||||
|
||||
/* For keeping track of the stack and registers. */
|
||||
SCM_STACKITEM *base;
|
||||
SCM_STACKITEM *top;
|
||||
jmp_buf regs;
|
||||
|
||||
} scm_thread;
|
||||
SCM_API scm_t_bits scm_tc16_fair_condvar;
|
||||
|
||||
#define SCM_THREADP(x) SCM_SMOB_PREDICATE (scm_tc16_thread, x)
|
||||
#define SCM_THREAD_DATA(x) ((scm_thread *) SCM_SMOB_DATA (x))
|
||||
|
||||
#define SCM_MUTEXP(x) SCM_SMOB_PREDICATE (scm_tc16_mutex, x)
|
||||
#define SCM_FAIR_MUTEX_P(x) SCM_SMOB_PREDICATE (scm_tc16_fair_mutex, x)
|
||||
#define SCM_MUTEX_DATA(x) ((void *) SCM_SMOB_DATA (x))
|
||||
|
||||
#define SCM_CONDVARP(x) SCM_SMOB_PREDICATE (scm_tc16_condvar, x)
|
||||
#define SCM_FAIR_CONDVAR_P(x) SCM_SMOB_PREDICATE (scm_tc16_fair_condvar, x)
|
||||
#define SCM_CONDVAR_DATA(x) ((void *) SCM_SMOB_DATA (x))
|
||||
|
||||
#define SCM_VALIDATE_THREAD(pos, a) \
|
||||
SCM_MAKE_VALIDATE_MSG (pos, a, THREADP, "thread")
|
||||
|
||||
#define SCM_VALIDATE_MUTEX(pos, a) \
|
||||
SCM_ASSERT_TYPE (SCM_MUTEXP (a), \
|
||||
SCM_ASSERT_TYPE (SCM_MUTEXP (a) || SCM_FAIR_MUTEX_P (a), \
|
||||
a, pos, FUNC_NAME, "mutex");
|
||||
|
||||
#define SCM_VALIDATE_CONDVAR(pos, a) \
|
||||
SCM_ASSERT_TYPE (SCM_CONDVARP (a), \
|
||||
SCM_ASSERT_TYPE (SCM_CONDVARP (a) || SCM_FAIR_CONDVAR_P (a), \
|
||||
a, pos, FUNC_NAME, "condition variable");
|
||||
|
||||
SCM_API void scm_threads_mark_stacks (void);
|
||||
SCM_API void scm_init_threads (SCM_STACKITEM *);
|
||||
SCM_API void scm_init_thread_procs (void);
|
||||
|
||||
#if SCM_USE_PTHREAD_THREADS
|
||||
# include "libguile/pthread-threads.h"
|
||||
#else
|
||||
# include "libguile/null-threads.h"
|
||||
#endif
|
||||
|
||||
/*----------------------------------------------------------------------*/
|
||||
/* Low-level C API */
|
||||
|
||||
/* The purpose of this API is seamless, simple and thread package
|
||||
independent interaction with Guile threads from the application.
|
||||
|
||||
Note that Guile also uses it to implement itself, just like
|
||||
with the rest of the application API.
|
||||
*/
|
||||
|
||||
/* MDJ 021209 <djurfeldt@nada.kth.se>:
|
||||
The separation of the plugin interface (currently in
|
||||
pthread-threads.h and null-threads.h) and the low-level C API needs
|
||||
to be completed in a sensible way.
|
||||
*/
|
||||
|
||||
/* Deprecate this name and rename to scm_thread_create?
|
||||
Introduce the other two arguments in pthread_create to prepare for
|
||||
the future?
|
||||
*/
|
||||
SCM_API SCM scm_spawn_thread (scm_t_catch_body body, void *body_data,
|
||||
scm_t_catch_handler handler, void *handler_data);
|
||||
SCM_API scm_t_thread scm_c_scm2thread (SCM thread);
|
||||
|
||||
#define scm_thread_join scm_i_plugin_thread_join
|
||||
#define scm_thread_detach scm_i_plugin_thread_detach
|
||||
#define scm_thread_self scm_i_plugin_thread_self
|
||||
#define scm_thread_yield scm_i_plugin_thread_yield
|
||||
|
||||
#define scm_mutex_init scm_i_plugin_mutex_init
|
||||
#define scm_mutex_destroy scm_i_plugin_mutex_destroy
|
||||
SCM_API int scm_mutex_lock (scm_t_mutex *m);
|
||||
#define scm_mutex_trylock scm_i_plugin_mutex_trylock
|
||||
#define scm_mutex_unlock scm_i_plugin_mutex_unlock
|
||||
|
||||
/* Guile itself needs recursive mutexes. See for example the
|
||||
implentation of scm_force in eval.c.
|
||||
|
||||
Note that scm_rec_mutex_lock et al can be replaced by direct usage
|
||||
of the corresponding pthread functions if we use the pthread
|
||||
debugging API to access the stack top (in which case there is no
|
||||
longer any need to save the top of the stack before blocking).
|
||||
|
||||
It's therefore highly motivated to use these calls in situations
|
||||
where Guile or the application needs recursive mutexes.
|
||||
*/
|
||||
#define scm_rec_mutex_init scm_i_plugin_rec_mutex_init
|
||||
#define scm_rec_mutex_destroy scm_i_plugin_rec_mutex_destroy
|
||||
/* It's a safer bet to use the following functions.
|
||||
The future of the _init functions is uncertain.
|
||||
*/
|
||||
SCM_API scm_t_rec_mutex *scm_make_rec_mutex (void);
|
||||
SCM_API void scm_rec_mutex_free (scm_t_rec_mutex *);
|
||||
SCM_API int scm_rec_mutex_lock (scm_t_rec_mutex *m);
|
||||
#define scm_rec_mutex_trylock scm_i_plugin_rec_mutex_trylock
|
||||
#define scm_rec_mutex_unlock scm_i_plugin_rec_mutex_unlock
|
||||
|
||||
#define scm_cond_init scm_i_plugin_cond_init
|
||||
#define scm_cond_destroy scm_i_plugin_cond_destroy
|
||||
SCM_API int scm_cond_wait (scm_t_cond *c, scm_t_mutex *m);
|
||||
SCM_API int scm_cond_timedwait (scm_t_cond *c,
|
||||
scm_t_mutex *m,
|
||||
const scm_t_timespec *t);
|
||||
#define scm_cond_signal scm_i_plugin_cond_signal
|
||||
#define scm_cond_broadcast scm_i_plugin_cond_broadcast
|
||||
|
||||
#define scm_key_create scm_i_plugin_key_create
|
||||
#define scm_key_delete scm_i_plugin_key_delete
|
||||
SCM_API int scm_setspecific (scm_t_key k, void *s);
|
||||
SCM_API void *scm_getspecific (scm_t_key k);
|
||||
|
||||
#define scm_thread_select scm_internal_select
|
||||
|
||||
/* The application must scm_leave_guile() before entering any piece of
|
||||
code which can block.
|
||||
code which can
|
||||
1. block, or
|
||||
2. execute for any longer period of time without calling SCM_TICK
|
||||
|
||||
Note, though, that it is *not* necessary to use these calls
|
||||
together with any call in this API.
|
||||
*/
|
||||
|
||||
SCM_API void scm_enter_guile (void);
|
||||
SCM_API void scm_leave_guile (void);
|
||||
|
||||
SCM_API void *scm_with_guile (void *(*func)(void *), void *data);
|
||||
SCM_API void *scm_without_guile (void *(*func)(void *), void *data);
|
||||
SCM_API void *scm_i_with_guile_and_parent (void *(*func)(void *), void *data,
|
||||
SCM parent);
|
||||
/* Better versions (although we need the former ones also in order to
|
||||
avoid forcing code restructuring in existing applications): */
|
||||
/*fixme* Not implemented yet! */
|
||||
SCM_API void *scm_in_guile (void (*func) (void*), void *data);
|
||||
SCM_API void *scm_outside_guile (void (*func) (void*), void *data);
|
||||
|
||||
/* These are versions of the ordinary sleep and usleep functions
|
||||
that play nicely with the thread system. */
|
||||
SCM_API unsigned long scm_thread_sleep (unsigned long);
|
||||
SCM_API unsigned long scm_thread_usleep (unsigned long);
|
||||
|
||||
/* End of low-level C API */
|
||||
/*----------------------------------------------------------------------*/
|
||||
|
||||
typedef struct scm_thread scm_thread;
|
||||
|
||||
SCM_API void scm_i_enter_guile (scm_thread *t);
|
||||
SCM_API scm_thread *scm_i_leave_guile (void);
|
||||
|
||||
/* Critical sections */
|
||||
|
||||
/* This is the generic critical section for places where we are too
|
||||
lazy to allocate a specific mutex. */
|
||||
extern pthread_mutex_t scm_i_critical_section_mutex;
|
||||
extern scm_t_mutex scm_i_critical_section_mutex;
|
||||
|
||||
#define SCM_CRITICAL_SECTION_START \
|
||||
scm_pthread_mutex_lock (&scm_i_critical_section_mutex)
|
||||
scm_mutex_lock (&scm_i_critical_section_mutex)
|
||||
#define SCM_CRITICAL_SECTION_END \
|
||||
pthread_mutex_unlock (&scm_i_critical_section_mutex)
|
||||
scm_mutex_unlock (&scm_i_critical_section_mutex)
|
||||
|
||||
/* This is the temporary support for the old ALLOW/DEFER ints sections */
|
||||
extern scm_t_rec_mutex scm_i_defer_mutex;
|
||||
|
||||
extern int scm_i_thread_go_to_sleep;
|
||||
|
||||
|
@ -117,12 +193,8 @@ void scm_i_thread_put_to_sleep (void);
|
|||
void scm_i_thread_wake_up (void);
|
||||
void scm_i_thread_invalidate_freelists (void);
|
||||
void scm_i_thread_sleep_for_gc (void);
|
||||
void scm_threads_prehistory (SCM_STACKITEM *);
|
||||
void scm_threads_prehistory (void);
|
||||
void scm_threads_init_first_thread (void);
|
||||
SCM_API void scm_threads_mark_stacks (void);
|
||||
SCM_API void scm_init_threads (void);
|
||||
SCM_API void scm_init_thread_procs (void);
|
||||
SCM_API void scm_init_threads_root_root (void);
|
||||
|
||||
#define SCM_THREAD_SWITCHING_CODE \
|
||||
do { \
|
||||
|
@ -139,11 +211,12 @@ SCM_API SCM scm_call_with_new_thread (SCM thunk, SCM handler);
|
|||
SCM_API SCM scm_yield (void);
|
||||
SCM_API SCM scm_join_thread (SCM t);
|
||||
SCM_API SCM scm_make_mutex (void);
|
||||
SCM_API SCM scm_make_recursive_mutex (void);
|
||||
SCM_API SCM scm_make_fair_mutex (void);
|
||||
SCM_API SCM scm_lock_mutex (SCM m);
|
||||
SCM_API SCM scm_try_mutex (SCM m);
|
||||
SCM_API SCM scm_unlock_mutex (SCM m);
|
||||
SCM_API SCM scm_make_condition_variable (void);
|
||||
SCM_API SCM scm_make_fair_condition_variable (void);
|
||||
SCM_API SCM scm_wait_condition_variable (SCM cond, SCM mutex);
|
||||
SCM_API SCM scm_timed_wait_condition_variable (SCM cond, SCM mutex,
|
||||
SCM abstime);
|
||||
|
@ -159,24 +232,17 @@ SCM_API SCM scm_thread_exited_p (SCM thread);
|
|||
SCM_API scm_root_state *scm_i_thread_root (SCM thread);
|
||||
|
||||
#define SCM_CURRENT_THREAD \
|
||||
((scm_thread *) pthread_getspecific (scm_i_thread_key))
|
||||
SCM_API pthread_key_t scm_i_thread_key;
|
||||
((scm_thread *) scm_i_plugin_getspecific (scm_i_thread_key))
|
||||
extern scm_t_key scm_i_thread_key;
|
||||
|
||||
SCM_API pthread_mutex_t scm_i_misc_mutex;
|
||||
/* These macros have confusing names.
|
||||
They really refer to the root state of the running thread. */
|
||||
#define SCM_THREAD_LOCAL_DATA (scm_getspecific (scm_i_root_state_key))
|
||||
#define SCM_SET_THREAD_LOCAL_DATA(x) scm_i_set_thread_data(x)
|
||||
SCM_API scm_t_key scm_i_root_state_key;
|
||||
SCM_API void scm_i_set_thread_data (void *);
|
||||
|
||||
/* Convenience functions for working with the pthread API in guile
|
||||
mode.
|
||||
*/
|
||||
|
||||
SCM_API int scm_pthread_mutex_lock (pthread_mutex_t *mutex);
|
||||
SCM_API void scm_frame_pthread_mutex_lock (pthread_mutex_t *mutex);
|
||||
SCM_API int scm_pthread_cond_wait (pthread_cond_t *cond,
|
||||
pthread_mutex_t *mutex);
|
||||
SCM_API int scm_pthread_cond_timedwait (pthread_cond_t *cond,
|
||||
pthread_mutex_t *mutex,
|
||||
const struct timespec *abstime);
|
||||
SCM_API unsigned long scm_thread_sleep (unsigned long);
|
||||
SCM_API unsigned long scm_thread_usleep (unsigned long);
|
||||
SCM_API scm_t_mutex scm_i_misc_mutex;
|
||||
|
||||
#endif /* SCM_THREADS_H */
|
||||
|
||||
|
|
|
@ -460,7 +460,7 @@ scm_handle_by_message (void *handler_data, SCM tag, SCM args)
|
|||
}
|
||||
|
||||
handler_message (handler_data, tag, args);
|
||||
pthread_exit (NULL);
|
||||
exit (2);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -194,14 +194,14 @@ SCM_DEFINE (scm_make_soft_port, "make-soft-port", 2, 0, 0,
|
|||
SCM_ASSERT ((vlen == 5) || (vlen == 6), pv, 1, FUNC_NAME);
|
||||
SCM_VALIDATE_STRING (2, modes);
|
||||
|
||||
scm_pthread_mutex_lock (&scm_i_port_table_mutex);
|
||||
scm_mutex_lock (&scm_i_port_table_mutex);
|
||||
z = scm_new_port_table_entry (scm_tc16_sfport);
|
||||
pt = SCM_PTAB_ENTRY (z);
|
||||
scm_port_non_buffer (pt);
|
||||
SCM_SET_CELL_TYPE (z, scm_tc16_sfport | scm_i_mode_bits (modes));
|
||||
|
||||
SCM_SETSTREAM (z, SCM_UNPACK (pv));
|
||||
pthread_mutex_unlock (&scm_i_port_table_mutex);
|
||||
scm_mutex_unlock (&scm_i_port_table_mutex);
|
||||
return z;
|
||||
}
|
||||
#undef FUNC_NAME
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue