Threading changes.
authorMarius Vollmer <mvo@zagadka.de>
Mon, 24 Jan 2005 19:14:54 +0000 (19:14 +0000)
committerMarius Vollmer <mvo@zagadka.de>
Mon, 24 Jan 2005 19:14:54 +0000 (19:14 +0000)
34 files changed:
doc/ref/api-init.texi
doc/ref/api-scheduling.texi
doc/ref/libguile-concepts.texi
libguile/__scm.h
libguile/error.c
libguile/eval.c
libguile/eval.h
libguile/fports.c
libguile/futures.c
libguile/futures.h
libguile/gc-freelist.c
libguile/gc-malloc.c
libguile/gc-mark.c
libguile/gc.c
libguile/gc.h
libguile/hashtab.c
libguile/hashtab.h
libguile/init.c
libguile/init.h
libguile/inline.h
libguile/ioext.c
libguile/ports.c
libguile/ports.h
libguile/posix.c
libguile/print.c
libguile/root.c
libguile/root.h
libguile/strings.c
libguile/strports.c
libguile/symbols.c
libguile/threads.c
libguile/threads.h
libguile/throw.c
libguile/vports.c

dissimilarity index 64%
index 9440711..795b6d5 100644 (file)
-@c -*-texinfo-*-
-@c This is part of the GNU Guile Reference Manual.
-@c Copyright (C)  1996, 1997, 2000, 2001, 2002, 2003, 2004
-@c   Free Software Foundation, Inc.
-@c See the file guile.texi for copying conditions.
-
-
-@node Initialization
-@section Initializing Guile
-
-@deftypefn {C Function} void scm_boot_guile (int @var{argc}, char **@var{argv}, void (*@var{main_func}) (void *@var{data}, int @var{argc}, char **@var{argv}), void *@var{data})
-Initialize the Guile Scheme interpreter.  Then call @var{main_func},
-passing it @var{data}, @var{argc}, and @var{argv} as indicated.  The
-function @var{main_func} should do all the work of the program
-(initializing other packages, defining application-specific functions,
-reading user input, and so on) before returning.  When @var{main_func}
-returns, @code{scm_boot_guile} calls @code{exit (0)};
-@code{scm_boot_guile} never returns.  If you want some other exit
-value, have @var{main_func} call @code{exit} itself.
-
-@code{scm_boot_guile} arranges for the Scheme @code{command-line}
-function to return the strings given by @var{argc} and @var{argv}.  If
-@var{main_func} modifies @var{argc} or @var{argv}, it should call
-@code{scm_set_program_arguments} with the final list, so Scheme code
-will know which arguments have been processed.
-
-Why must the caller do all the real work from @var{main_func}?  Guile's
-garbage collector scans the stack to find all local variables that
-reference Scheme objects.  To do this, it needs to know the bounds of
-the stack that might contain such references.  Because there is no
-portable way in C to find the base of the stack, @code{scm_boot_guile}
-assumes that all references are above its own stack frame.  If you try
-to manipulate Scheme objects after this function returns, it's the luck
-of the draw whether Guile's storage manager will be able to find the
-objects you allocate.  So, @code{scm_boot_guile} function exits, rather
-than returning, to discourage you from making that mistake.
-
-See @code{scm_init_guile}, below, for a function that can find the real
-base of the stack, but not in a portable way.
-@end deftypefn
-
-@deftypefn {C Function} void scm_init_guile ()
-Initialize the Guile Scheme interpreter.
-
-In contrast to @code{scm_boot_guile}, this function knows how to find
-the true base of the stack and thus does not need to usurp the control
-flow of your program.  However, since finding the stack base can not be
-done portably, this function might not be available in all installations
-of Guile.  If you can, you should use @code{scm_boot_guile} instead.
-
-Note that @code{scm_init_guile} does not inform Guile about the command
-line arguments that should be returned by the Scheme function
-@code{command-line}.  You can use @code{scm_set_program_arguments} to do
-this.
-@end deftypefn
-
-@deftypefn {C Function} void scm_shell (int @var{argc}, char **@var{argv})
-Process command-line arguments in the manner of the @code{guile}
-executable.  This includes loading the normal Guile initialization
-files, interacting with the user or running any scripts or expressions
-specified by @code{-s} or @code{-e} options, and then exiting.
-@xref{Invoking Guile}, for more details.
-
-Since this function does not return, you must do all
-application-specific initialization before calling this function.
-@end deftypefn
+@c -*-texinfo-*-
+@c This is part of the GNU Guile Reference Manual.
+@c Copyright (C)  1996, 1997, 2000, 2001, 2002, 2003, 2004
+@c   Free Software Foundation, Inc.
+@c See the file guile.texi for copying conditions.
+
+
+@node Initialization
+@section Initializing Guile
+
+Each thread that wants to use 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.
+
+When a thread wants to block outside of a Guile API function, it should
+leave guile mode temporarily with either @code{scm_without_guile} or
+@code{scm_leave_guile}, @xref{Threads}.
+
+Threads that are created by @code{call-with-new-thread} or
+@code{scm_spawn_thread} start out in guile mode so you don't need to
+initialize them.
+
+@deftypefn {C Function} void *scm_with_guile (void *(*func)(void *), void *data)
+Call @var{func}, passing it @var{data} and return what @var{func}
+returns.  While @var{func} is running, the current thread is in guile
+mode and can thus use the Guile API.
+
+When @code{scm_with_guile} is called from guile mode, the thread remains
+in guile mode when @code{scm_with_guile} returns.
+
+Otherwise, it puts the current thread into guile mode and, if needed,
+gives it a Scheme representation that is contained in the list returned
+by @code{all-threads}, for example.  This Scheme representation is not
+removed when @code{scm_with_guile} returns so that a given thread is
+always represented by the same Scheme value during its lifetime, if at
+all.
+
+When this is the first thread that enters guile mode, the global state
+of Guile is initialized before calling @code{func}.
+
+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.
+@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).
+
+When @code{scm_init_guile} is called from a thread that already has been
+in guile mode once, nothing happens.  This behavior matters when you
+call @code{scm_init_guile} while the thread has only temporarily left
+guile mode: in that case the thread will not be in guile mode after
+@code{scm_init_guile} returns.  Thus, you should not use
+@code{scm_init_guile} in such a scenario.
+
+When a uncaught throw happens in a thread that has been put into guile
+mode via @code{scm_init_guile}, a short message is printed to the
+current error port and the thread is exited via @code{scm_pthread_exit
+(NULL)}.  No restrictions are placed on continuations.
+
+The function @code{scm_init_guile} might not be available on all
+platforms since it requires some stack-bounds-finding magic that might
+not have been to all platforms that Guile runs on.  Thus, if you can, it
+is better to use @code{scm_with_guile} or its variation
+@code{scm_boot_guile} instead of this function.
+@end deftypefn
+
+@deftypefn {C Function} void scm_boot_guile (int @var{argc}, char **@var{argv}, void (*@var{main_func}) (void *@var{data}, int @var{argc}, char **@var{argv}), void *@var{data})
+Enter guile mode as with @code{scm_with_guile} and call @var{main_func},
+passing it @var{data}, @var{argc}, and @var{argv} as indicated.  When
+@var{main_func} returns, @code{scm_boot_guile} calls @code{exit (0)};
+@code{scm_boot_guile} never returns.  If you want some other exit value,
+have @var{main_func} call @code{exit} itself.  If you don't want to exit
+at all, use @code{scm_with_guile} instead of @code{scm_boot_guile}.
+
+The function @code{scm_boot_guile} arranges for the Scheme
+@code{command-line} function to return the strings given by @var{argc}
+and @var{argv}.  If @var{main_func} modifies @var{argc} or @var{argv},
+it should call @code{scm_set_program_arguments} with the final list, so
+Scheme code will know which arguments have been processed.
+@end deftypefn
+
+@deftypefn {C Function} void scm_shell (int @var{argc}, char **@var{argv})
+Process command-line arguments in the manner of the @code{guile}
+executable.  This includes loading the normal Guile initialization
+files, interacting with the user or running any scripts or expressions
+specified by @code{-s} or @code{-e} options, and then exiting.
+@xref{Invoking Guile}, for more details.
+
+Since this function does not return, you must do all
+application-specific initialization before calling this function.
+@end deftypefn
index dd830fa..7abaed3 100644 (file)
@@ -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_with_blocked_asyncs} and @code{scm_with_unblocked_asyncs}
+@code{scm_frame_block_asyncs} and @code{scm_frame_unblock_asyncs}
 inside a @dfn{frame} (@pxref{Frames}) to block or unblock system asyncs
 temporarily.
 
index 870c051..7fc0a6c 100644 (file)
@@ -1,6 +1,6 @@
 @c -*-texinfo-*-
 @c This is part of the GNU Guile Reference Manual.
-@c Copyright (C)  1996, 1997, 2000, 2001, 2002, 2003, 2004
+@c Copyright (C)  1996, 1997, 2000, 2001, 2002, 2003, 2004, 2005
 @c   Free Software Foundation, Inc.
 @c See the file guile.texi for copying conditions.
 
@@ -8,12 +8,12 @@
 @node General Libguile Concepts
 @section General concepts for using libguile
 
-When you want to embed the Guile Scheme interpreter into your program,
-you need to link it against the @file{libguile} library (@pxref{Linking
-Programs With Guile}).  Once you have done this, your C code has access
-to a number of data types and functions that can be used to invoke the
-interpreter, or make new functions that you have written in C available
-to be called from Scheme code, among other things.
+When you want to embed the Guile Scheme interpreter into your program or
+library, you need to link it against the @file{libguile} library
+(@pxref{Linking Programs With Guile}).  Once you have done this, your C
+code has access to a number of data types and functions that can be used
+to invoke the interpreter, or make new functions that you have written
+in C available to be called from Scheme code, among other things.
 
 Scheme is different from C in a number of significant ways, and Guile
 tries to make the advantages of Scheme available to C as well.  Thus, in
@@ -26,10 +26,16 @@ You need to understand how libguile offers them to C programs in order
 to use the rest of libguile.  Also, the more general control flow of
 Scheme caused by continuations needs to be dealt with.
 
+Running asynchronous signal handlers and multi-threading is known to C
+code already, but there are of course a few additional rules when using
+them together with libguile.
+
 @menu
 * Dynamic Types::               Dynamic Types.
 * Garbage Collection::          Garbage Collection.
 * Control Flow::                Control Flow.
+* Asynchronous Signals::        Asynchronous Signals
+* Multi-Threading::             Multi-Threading
 @end menu
 
 @node Dynamic Types
@@ -377,3 +383,204 @@ corresponding @code{scm_internal_dynamic_wind} function, but it might
 prefer to use the @dfn{frames} concept that is more natural for C code,
 (@pxref{Frames}).
 
+@node Asynchronous Signals
+@subsection Asynchronous Signals
+
+You can not call libguile functions from handlers for POSIX signals, but
+you can register Scheme handlers for POSIX signals such as
+@code{SIGINT}.  These handlers do not run during the actual signal
+delivery.  Instead, they are run when the program (more precisely, the
+thread that the handler has been registered for) reaches the next
+@emph{safe point}.
+
+The libguile functions themselves have many such safe points.
+Consequently, you must be prepared for arbitrary actions anytime you
+call a libguile function.  For example, even @code{scm_cons} can contain
+a safe point and when a signal handler is pending for your thread,
+calling @code{scm_cons} will run this handler and anything might happen,
+including a non-local exit although @code{scm_cons} would not ordinarily
+do such a thing on its own.
+
+If you do not want to allow the running of asynchronous signal handlers,
+you can block them temporarily with @code{scm_frame_block_asyncs}, for
+example.  See @xref{System asyncs}.
+
+Since signal handling in Guile relies on safe points, you need to make
+sure that your functions do offer enough of them.  Normally, calling
+libguile functions in the normal course of action is all that is needed.
+But when a thread might spent a long time in a code section that calls
+no libguile function, it is good to include explicit safe points.  This
+can allow the user to interrupt your code with @key{C-c}, for example.
+
+You can do this with the macro @code{SCM_TICK}.  This macro is
+syntactically a statement.  That is, you could use it like this:
+
+@example
+while (1)
+  @{
+    SCM_TICK;
+    do_some_work ();
+  @}
+@end example
+
+Frequent execution of a safe point is even more important in multi
+threaded programs, @xref{Multi-Threading}.
+
+@node Multi-Threading
+@subsection Multi-Threading
+
+Guile can be used in multi-threaded programs just as well as in
+single-threaded ones.
+
+Each thread that wants to use functions from libguile must put itself
+into @emph{guile mode} and must then follow a few rules.  If it doesn't
+want to honor these rules in certain situations, a thread can
+temporarily leave guile mode (but can no longer use libguile functions
+during that time, of course).
+
+Threads enter guile mode by calling @code{scm_with_guile},
+@code{scm_boot_guile}, or @code{scm_init_guile}.  As explained in the
+reference documentation for these functions, Guile will then learn about
+the stack bounds of the thread and can protect the @code{SCM} values
+that are stored in local variables.  When a thread puts itself into
+guile mode for the first time, it gets a Scheme representation and is
+listed by @code{all-threads}, for example.
+
+While in guile mode, a thread promises to reach a safe point reasonably
+frequently (@pxref{Asynchronous Signals}).  In addition to running
+signal handlers, these points are also potential rendezvous points of
+all guile mode threads where Guile can orchestrate global things like
+garbage collection.  Consequently, when a thread in guile mode blocks
+and does no longer frequent safe points, it might cause all other guile
+mode threads to block as well.  To prevent this from happening, a guile
+mode thread should either only block in libguile functions (who know how
+to do it right), or should temporarily leave guile mode with
+@code{scm_without_guile} or
+@code{scm_leave_guile}/@code{scm_enter_guile}.
+
+For some common blocking operations, Guile provides convenience
+functions.  For example, if you want to lock a pthread mutex while in
+guile mode, you might want to use @code{scm_pthread_mutex_lock} which is
+just like @code{pthread_mutex_lock} except that it leaves guile mode
+while blocking.
+
+
+All libguile functions are (intended to be) robust in the face of
+multiple threads using them concurrently.  This means that there is no
+risk of the internal data structures of libguile becoming corrupted in
+such a way that the process crashes.
+
+A program might still produce non-sensical results, though.  Taking
+hashtables as an example, Guile guarantees that you can use them from
+multiple threads concurrently and a hashtable will always remain a valid
+hashtable and Guile will not crash when you access it.  It does not
+guarantee, however, that inserting into it concurrently from two threads
+will give useful results: only one insertion might actually happen, none
+might happen, or the table might in general be modified in a totally
+arbitrary manner.  (It will still be a valid hashtable, but not the one
+that you might have expected.)  Guile might also signal an error when it
+detects a harmful race condition.
+
+Thus, you need to put in additional synchronizations when multiple
+threads want to use a single hashtable, or any other mutable Scheme
+object.
+
+When writing C code for use with libguile, you should try to make it
+robust as well.  An example that converts a list into a vector will help
+to illustrate.  Here is a correct version:
+
+@example
+SCM
+my_list_to_vector (SCM list)
+@{
+  SCM vector = scm_make_vector (scm_length (list), SCM_UNDEFINED);
+  size_t len, i;
+
+  len = SCM_SIMPLE_VECTOR_LENGTH (vector);
+  i = 0;
+  while (i < len && scm_is_pair (list))
+    @{
+      SCM_SIMPLE_VECTOR_SET (vector, i, SCM_CAR (list));
+      list = SCM_CDR (list);
+      i++;
+    @}
+
+  return vector;
+@}
+@end example
+
+The first thing to note is that storing into a @code{SCM} location
+concurrently from multiple threads is guaranteed to be robust: you don't
+know which value wins but it will in any case be a valid @code{SCM}
+value.
+
+But there is no guarantee that the list referenced by @var{list} is not
+modified in another thread while the loop iterates over it.  Thus, while
+copying its elements into the vector, the list might get longer or
+shorter.  For this reason, the loop must check both that it doesn't
+overrun the vector (@code{SCM_SIMPLE_VECTOR_SET} does no range-checking)
+and that it doesn't overrung the list (@code{SCM_CAR} and @code{SCM_CDR}
+likewise do no type checking).
+
+It is safe to use @code{SCM_CAR} and @code{SCM_CDR} on the local
+variable @var{list} once it is known that the variable contains a pair.
+The contents of the pair might change spontaneously, but it will always
+stay a valid pair (and a local variable will of course not spontaneously
+point to a different Scheme object).
+
+Likewise, a simple vector such as the one returned by
+@code{scm_make_vector} is guaranteed to always stay the same length so
+that it is safe to only use SCM_SIMPLE_VECTOR_LENGTH once and store the
+result.  (In the example, @var{vector} is safe anyway since it is a
+fresh object that no other thread can possibly know about until it is
+returned from @code{my_list_to_vector}.)
+
+Of course the behavior of @code{my_list_to_vector} is suboptimal when
+@var{list} does indeed gets asynchronously lengthened or shortened in
+another thread.  But it is robust: it will always return a valid vector.
+That vector might be shorter than expected, or its last elements might
+be unspecified, but it is a valid vector and if a program wants to rule
+out these cases, it must avoid modifying the list asynchronously.
+
+Here is another version that is also correct:
+
+@example
+SCM
+my_pedantic_list_to_vector (SCM list)
+@{
+  SCM vector = scm_make_vector (scm_length (list), SCM_UNDEFINED);
+  size_t len, i;
+
+  len = SCM_SIMPLE_VECTOR_LENGTH (vector);
+  i = 0;
+  while (i < len)
+    @{
+      SCM_SIMPLE_VECTOR_SET (vector, i, scm_car (list));
+      list = scm_cdr (list);
+      i++;
+    @}
+
+  return vector;
+@}
+@end example
+
+This version uses the type-checking and thread-robust functions
+@code{scm_car} and @code{scm_cdr} instead of the faster, but less robust
+macros @code{SCM_CAR} and @code{SCM_CDR}.  When the list is shortened
+(that is, when @var{list} holds a non-pair), @code{scm_car} will throw
+an error.  This might be preferable to just returning a half-initialized
+vector.
+
+The API for accessing vectors and arrays of various kinds from C takes a
+slightly different approach to thread-robustness.  In order to get at
+the raw memory that stores the elements of an array, you need to
+@emph{reserve} that array as long as you need the raw memory.  During
+the time an array is reserved, its elements can still spontaneously
+change their values, but the memory itself and other things like the
+size of the array are guaranteed to stay fixed.  Any operation that
+would change these parameters of an array that is currently reserved
+will signal an error.  In order to avoid these errors, a program should
+of course put suitable synchronization mechanisms in place.  As you can
+see, Guile itself is again only concerned about robustness, not about
+correctness: without proper synchronization, your program will likely
+not be correct, but the worst consequence is an error message.
index 6ab774c..8fbd43c 100644 (file)
@@ -508,9 +508,9 @@ do { \
    (private or global, with unwind where necessary), and remove the
    remaining DEFER/ALLOWs.  */
 
-#define SCM_DEFER_INTS scm_rec_mutex_lock (&scm_i_defer_mutex);
+#define SCM_DEFER_INTS do { } while (0);
 
-#define SCM_ALLOW_INTS scm_rec_mutex_unlock (&scm_i_defer_mutex);
+#define SCM_ALLOW_INTS do { } while (0);
 
 #define SCM_REDEFER_INTS SCM_DEFER_INTS
 
index 28b5bc1..300d333 100644 (file)
@@ -131,10 +131,7 @@ SCM_DEFINE (scm_strerror, "strerror", 1, 0, 0,
 {
   SCM ret;
   scm_frame_begin (0);
-  scm_frame_unwind_handler ((void(*)(void*)) scm_mutex_unlock,
-                            &scm_i_misc_mutex,
-                            SCM_F_WIND_EXPLICITLY);
-  scm_mutex_lock (&scm_i_misc_mutex);
+  scm_frame_pthread_mutex_lock (&scm_i_misc_mutex);
 
   ret = scm_from_locale_string (SCM_I_STRERROR (scm_to_int (err)));
 
index 8c3ed56..53de218 100644 (file)
@@ -24,6 +24,8 @@
  * 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.
  */
 
@@ -87,6 +89,8 @@ char *alloca ();
 
 #include "libguile/eval.h"
 
+#include <pthread.h>
+
 \f
 
 static SCM unmemoize_exprs (SCM expr, SCM env);
@@ -2641,7 +2645,7 @@ static SCM deval (SCM x, SCM env);
             ? SCM_CAR (x) \
             :  *scm_lookupcar ((x), (env), 1)))))
 
-SCM_REC_MUTEX (source_mutex);
+pthread_mutex_t source_mutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
 
 
 /* Lookup a given local variable in an environment.  The local variable is
@@ -2936,11 +2940,11 @@ scm_eval_body (SCM code, SCM env)
        {
          if (SCM_ISYMP (SCM_CAR (code)))
            {
-             scm_rec_mutex_lock (&source_mutex);
+             scm_pthread_mutex_lock (&source_mutex);
              /* check for race condition */
              if (SCM_ISYMP (SCM_CAR (code)))
                m_expand_body (code, env);
-             scm_rec_mutex_unlock (&source_mutex);
+             pthread_mutex_unlock (&source_mutex);
              goto again;
            }
        }
@@ -3326,11 +3330,11 @@ dispatch:
                 {
                   if (SCM_ISYMP (form))
                     {
-                      scm_rec_mutex_lock (&source_mutex);
+                      scm_pthread_mutex_lock (&source_mutex);
                       /* check for race condition */
                       if (SCM_ISYMP (SCM_CAR (x)))
                         m_expand_body (x, env);
-                      scm_rec_mutex_unlock (&source_mutex);
+                      pthread_mutex_unlock (&source_mutex);
                       goto nontoplevel_begin;
                     }
                   else
@@ -4929,11 +4933,11 @@ tail:
            {
              if (SCM_ISYMP (SCM_CAR (proc)))
                {
-                 scm_rec_mutex_lock (&source_mutex);
+                 scm_pthread_mutex_lock (&source_mutex);
                  /* check for race condition */
                  if (SCM_ISYMP (SCM_CAR (proc)))
                    m_expand_body (proc, args);
-                 scm_rec_mutex_unlock (&source_mutex);
+                 pthread_mutex_unlock (&source_mutex);
                  goto again;
                }
              else
@@ -5560,13 +5564,19 @@ scm_makprom (SCM code)
 {
   SCM_RETURN_NEWSMOB2 (scm_tc16_promise,
                       SCM_UNPACK (code),
-                      scm_make_rec_mutex ());
+                      scm_make_recursive_mutex ());
+}
+
+static SCM
+promise_mark (SCM promise)
+{
+  scm_gc_mark (SCM_PROMISE_MUTEX (promise));
+  return SCM_PROMISE_DATA (promise);
 }
 
 static size_t
 promise_free (SCM promise)
 {
-  scm_rec_mutex_free (SCM_PROMISE_MUTEX (promise));
   return 0;
 }
 
@@ -5590,7 +5600,7 @@ SCM_DEFINE (scm_force, "force", 1, 0, 0,
 #define FUNC_NAME s_scm_force
 {
   SCM_VALIDATE_SMOB (1, promise, promise);
-  scm_rec_mutex_lock (SCM_PROMISE_MUTEX (promise));
+  scm_lock_mutex (SCM_PROMISE_MUTEX (promise));
   if (!SCM_PROMISE_COMPUTED_P (promise))
     {
       SCM ans = scm_call_0 (SCM_PROMISE_DATA (promise));
@@ -5600,7 +5610,7 @@ SCM_DEFINE (scm_force, "force", 1, 0, 0,
          SCM_SET_PROMISE_COMPUTED (promise);
        }
     }
-  scm_rec_mutex_unlock (SCM_PROMISE_MUTEX (promise));
+  scm_unlock_mutex (SCM_PROMISE_MUTEX (promise));
   return SCM_PROMISE_DATA (promise);
 }
 #undef FUNC_NAME
@@ -6004,7 +6014,7 @@ scm_init_eval ()
                 SCM_N_EVAL_OPTIONS);
   
   scm_tc16_promise = scm_make_smob_type ("promise", 0);
-  scm_set_smob_mark (scm_tc16_promise, scm_markcdr);
+  scm_set_smob_mark (scm_tc16_promise, promise_mark);
   scm_set_smob_free (scm_tc16_promise, promise_free);
   scm_set_smob_print (scm_tc16_promise, promise_print);
 
index 1d10e08..f1b94a0 100644 (file)
@@ -71,8 +71,7 @@ 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(promise) \
-  ((scm_t_rec_mutex *) SCM_SMOB_DATA_2 (promise))
+#define SCM_PROMISE_MUTEX     SCM_SMOB_OBJECT_2
 #define SCM_PROMISE_DATA      SCM_SMOB_OBJECT
 #define SCM_SET_PROMISE_DATA  SCM_SET_SMOB_OBJECT
 
index 9d8d1f4..c79fdc8 100644 (file)
@@ -201,7 +201,7 @@ scm_evict_ports (int fd)
 {
   long i;
 
-  scm_mutex_lock (&scm_i_port_table_mutex);
+  scm_pthread_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)
        }
     }
 
-  scm_mutex_unlock (&scm_i_port_table_mutex);
+  pthread_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_mutex_lock (&scm_i_port_table_mutex);
+  scm_pthread_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);
-  scm_mutex_unlock (&scm_i_port_table_mutex);
+  pthread_mutex_unlock (&scm_i_port_table_mutex);
   return port;
 }
 #undef FUNC_NAME
index 0f6000a..0757186 100644 (file)
@@ -39,7 +39,7 @@ do {                                          \
   list = SCM_FUTURE_NEXT (list);               \
 } while (0)
      
-SCM_MUTEX (future_admin_mutex);
+pthread_mutex_t future_admin_mutex = PTHREAD_MUTEX_INITIALIZER;
 
 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)
 {
-  scm_mutex_destroy (&future->mutex);
-  scm_cond_destroy (&future->cond);
+  pthread_mutex_destroy (&future->mutex);
+  pthread_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_mutex_lock (&future->mutex);
+  scm_pthread_mutex_lock (&future->mutex);
   do {
     if (future->status == SCM_FUTURE_SIGNAL_ME)
-      scm_cond_broadcast (&future->cond);
+      pthread_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_cond_wait (&future->cond, &future->mutex);
+    scm_pthread_cond_wait (&future->cond, &future->mutex);
   } while (!future->die_p);
   future->status = SCM_FUTURE_DEAD;
-  scm_mutex_unlock (&future->mutex);
+  pthread_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;
-  scm_mutex_unlock (&future->mutex);
+  pthread_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;
-  scm_mutex_init (&f->mutex, &scm_i_plugin_mutex);
-  scm_cond_init (&f->cond, 0);
+  pthread_mutex_init (&f->mutex, NULL);
+  pthread_cond_init (&f->cond, NULL);
   f->die_p = 0;
   f->status = SCM_FUTURE_TASK_ASSIGNED;
-  scm_mutex_lock (&future_admin_mutex);
+  scm_pthread_mutex_lock (&future_admin_mutex);
   SCM_NEWSMOB2 (future, scm_tc16_future, futures, f);
   SCM_SET_FUTURE_DATA (future, thunk);
   futures = future;
-  scm_mutex_unlock (&future_admin_mutex);
+  pthread_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_mutex_lock (&future_admin_mutex);
+  scm_pthread_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
        {
-         scm_mutex_unlock (&future_admin_mutex);
+         pthread_mutex_unlock (&future_admin_mutex);
          return alloc_future (thunk);
        }
-      if (scm_mutex_trylock (SCM_FUTURE_MUTEX (future)))
+      if (pthread_mutex_trylock (SCM_FUTURE_MUTEX (future)))
        kill_future (future);
       else if (!SCM_FUTURE_ALIVE_P (future))
        {
-         scm_mutex_unlock (SCM_FUTURE_MUTEX (future));
+         pthread_mutex_unlock (SCM_FUTURE_MUTEX (future));
          cleanup (SCM_FUTURE (future));
        }
       else
        break;
     }
   LINK (futures, future);
-  scm_mutex_unlock (&future_admin_mutex);
+  pthread_mutex_unlock (&future_admin_mutex);
   SCM_SET_FUTURE_DATA (future, thunk);
   SCM_SET_FUTURE_STATUS (future, SCM_FUTURE_TASK_ASSIGNED);
-  scm_cond_signal (SCM_FUTURE_COND (future));
-  scm_mutex_unlock (SCM_FUTURE_MUTEX (future));
+  pthread_cond_signal (SCM_FUTURE_COND (future));
+  pthread_mutex_unlock (SCM_FUTURE_MUTEX (future));
   return future;
 }
 
@@ -223,20 +223,21 @@ SCM_DEFINE (scm_future_ref, "future-ref", 1, 0, 0,
 {
   SCM res;
   SCM_VALIDATE_FUTURE (1, future);
-  scm_mutex_lock (SCM_FUTURE_MUTEX (future));
+  scm_pthread_mutex_lock (SCM_FUTURE_MUTEX (future));
   if (SCM_FUTURE_STATUS (future) != SCM_FUTURE_COMPUTING)
     {
       SCM_SET_FUTURE_STATUS (future, SCM_FUTURE_SIGNAL_ME);
-      scm_cond_wait (SCM_FUTURE_COND (future), SCM_FUTURE_MUTEX (future));
+      scm_pthread_cond_wait (SCM_FUTURE_COND (future),
+                            SCM_FUTURE_MUTEX (future));
     }
   if (!SCM_FUTURE_ALIVE_P (future))
     {
-      scm_mutex_unlock (SCM_FUTURE_MUTEX (future));
+      pthread_mutex_unlock (SCM_FUTURE_MUTEX (future));
       SCM_MISC_ERROR ("requesting result from failed future ~A",
                      scm_list_1 (future));
     }
   res = SCM_FUTURE_DATA (future);
-  scm_mutex_unlock (SCM_FUTURE_MUTEX (future));
+  pthread_mutex_unlock (SCM_FUTURE_MUTEX (future));
   return res;
 }
 #undef FUNC_NAME
@@ -249,7 +250,7 @@ kill_futures (SCM victims)
       SCM future;
       UNLINK (victims, future);
       kill_future (future);
-      scm_cond_signal (SCM_FUTURE_COND (future));
+      pthread_cond_signal (SCM_FUTURE_COND (future));
     }
 }
 
@@ -259,12 +260,12 @@ cleanup_undead ()
   SCM next = undead, *nextloc = &undead;
   while (!scm_is_null (next))
     {
-      if (scm_mutex_trylock (SCM_FUTURE_MUTEX (next)))
+      if (pthread_mutex_trylock (SCM_FUTURE_MUTEX (next)))
        goto next;
       else if (SCM_FUTURE_ALIVE_P (next))
        {
-         scm_cond_signal (SCM_FUTURE_COND (next));
-         scm_mutex_unlock (SCM_FUTURE_MUTEX (next));
+         pthread_cond_signal (SCM_FUTURE_COND (next));
+         pthread_mutex_unlock (SCM_FUTURE_MUTEX (next));
        next:
          SCM_SET_GC_MARK (next);
          nextloc = SCM_FUTURE_NEXTLOC (next);
@@ -274,7 +275,7 @@ cleanup_undead ()
        {
          SCM future;
          UNLINK (next, future);
-         scm_mutex_unlock (SCM_FUTURE_MUTEX (future));
+         pthread_mutex_unlock (SCM_FUTURE_MUTEX (future));
          cleanup (SCM_FUTURE (future));
          *nextloc = next;
        }
@@ -341,6 +342,8 @@ scan_futures (void *dummy1, void *dummy2, void *dummy3)
   return 0;
 }
 
+scm_t_bits scm_tc16_future;
+
 void
 scm_init_futures ()
 {
index 2654be1..70669ac 100644 (file)
@@ -29,8 +29,8 @@
 
 typedef struct scm_t_future {
   SCM data;
-  scm_t_mutex mutex;
-  scm_t_cond cond;
+  pthread_mutex_t mutex;
+  pthread_cond_t cond;
   int status;
   int die_p;
 } scm_t_future;
index e986369..15145fa 100644 (file)
@@ -145,12 +145,6 @@ 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,
index b909e94..faa37fb 100644 (file)
@@ -110,21 +110,21 @@ scm_realloc (void *mem, size_t size)
   if (ptr)
     return ptr;
 
-  scm_rec_mutex_lock (&scm_i_sweep_mutex);
+  scm_pthread_mutex_lock (&scm_i_sweep_mutex);
   
   scm_i_sweep_all_segments ("realloc");
   
   SCM_SYSCALL (ptr = realloc (mem, size));
   if (ptr)
     { 
-      scm_rec_mutex_unlock (&scm_i_sweep_mutex);
+      pthread_mutex_unlock (&scm_i_sweep_mutex);
       return ptr;
     }
 
   scm_igc ("realloc");
   scm_i_sweep_all_segments ("realloc");
   
-  scm_rec_mutex_unlock (&scm_i_sweep_mutex);
+  pthread_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)
 {
-  scm_i_plugin_mutex_lock (&scm_i_gc_admin_mutex);
+  pthread_mutex_lock (&scm_i_gc_admin_mutex);
   scm_mallocated -= size;
   scm_gc_malloc_collected += size;
-  scm_i_plugin_mutex_unlock (&scm_i_gc_admin_mutex);
+  pthread_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;
 
-  scm_i_plugin_mutex_lock (&scm_i_gc_admin_mutex);
+  pthread_mutex_lock (&scm_i_gc_admin_mutex);
   if (ULONG_MAX - size < scm_mallocated)
     overflow = 1;
   else
@@ -202,12 +202,10 @@ increase_mtrigger (size_t size, const char *what)
       if (scm_mallocated > scm_mtrigger)
        triggered = 1;
     }
-  scm_i_plugin_mutex_unlock (&scm_i_gc_admin_mutex);
+  pthread_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,
@@ -220,7 +218,7 @@ increase_mtrigger (size_t size, const char *what)
       unsigned long prev_alloced;
       float yield;
       
-      scm_rec_mutex_lock (&scm_i_sweep_mutex);
+      scm_pthread_mutex_lock (&scm_i_sweep_mutex);
       
       prev_alloced  = mallocated;
       scm_igc (what);
@@ -265,7 +263,7 @@ increase_mtrigger (size_t size, const char *what)
 #endif
        }
       
-      scm_rec_mutex_unlock (&scm_i_sweep_mutex);
+      pthread_mutex_unlock (&scm_i_sweep_mutex);
     }
 }
 
index 95ac820..3373cc8 100644 (file)
@@ -144,6 +144,7 @@ Perhaps this would work better with an explicit markstack?
 
 
 */
+
 void
 scm_gc_mark_dependencies (SCM p)
 #define FUNC_NAME "scm_gc_mark_dependencies"
@@ -154,7 +155,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))
     {
@@ -414,15 +415,16 @@ 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
index c1d489c..eba3371 100644 (file)
@@ -15,6 +15,7 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  */
 
+#define _GNU_SOURCE
 
 /* #define DEBUGINFO */
 
@@ -71,7 +72,7 @@ unsigned int scm_gc_running_p = 0;
 
 /* Lock this mutex before doing lazy sweeping.
  */
-scm_t_rec_mutex scm_i_sweep_mutex;
+pthread_mutex_t scm_i_sweep_mutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
 
 /* Set this to != 0 if every cell that is accessed shall be checked:
  */
@@ -206,9 +207,6 @@ SCM_DEFINE (scm_set_debug_cell_accesses_x, "set-debug-cell-accesses!", 1, 0, 0,
 
 \f
 
-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.
@@ -447,7 +445,7 @@ scm_gc_for_newcell (scm_t_cell_type_statistics *freelist, SCM *free_cells)
 {
   SCM cell;
  
-  scm_rec_mutex_lock (&scm_i_sweep_mutex);
+  scm_pthread_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))
@@ -489,7 +487,7 @@ scm_gc_for_newcell (scm_t_cell_type_statistics *freelist, SCM *free_cells)
 
   *free_cells = SCM_FREE_CELL_CDR (cell);
 
-  scm_rec_mutex_unlock (&scm_i_sweep_mutex);
+  pthread_mutex_unlock (&scm_i_sweep_mutex);
 
   return cell;
 }
@@ -504,7 +502,7 @@ scm_t_c_hook scm_after_gc_c_hook;
 void
 scm_igc (const char *what)
 {
-  scm_rec_mutex_lock (&scm_i_sweep_mutex);
+  scm_pthread_mutex_lock (&scm_i_sweep_mutex);
   ++scm_gc_running_p;
   scm_c_hook_run (&scm_before_gc_c_hook, 0);
 
@@ -608,7 +606,7 @@ scm_igc (const char *what)
    */
   --scm_gc_running_p;
   scm_c_hook_run (&scm_after_gc_c_hook, 0);
-  scm_rec_mutex_unlock (&scm_i_sweep_mutex);
+  pthread_mutex_unlock (&scm_i_sweep_mutex);
 
   /*
     For debugging purposes, you could do
@@ -890,18 +888,13 @@ scm_storage_prehistory ()
   scm_c_hook_init (&scm_after_gc_c_hook, 0, SCM_C_HOOK_NORMAL);
 }
 
-scm_t_mutex scm_i_gc_admin_mutex;
+pthread_mutex_t scm_i_gc_admin_mutex = PTHREAD_MUTEX_INITIALIZER;
 
 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;
@@ -919,12 +912,18 @@ 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);
index 4e54644..3427631 100644 (file)
 #include "libguile/__scm.h"
 
 #include "libguile/hooks.h"
-
-#if SCM_USE_PTHREAD_THREADS
-# include "libguile/pthread-threads.h"
-#else
-# include "libguile/null-threads.h"
-#endif
+#include "libguile/threads.h"
 
 \f
 
@@ -230,12 +225,12 @@ SCM_API int scm_debug_cells_gc_interval ;
 void scm_i_expensive_validation_check (SCM cell);
 #endif
 
-SCM_API scm_t_mutex scm_i_gc_admin_mutex;
+SCM_API pthread_mutex_t 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 scm_t_rec_mutex scm_i_sweep_mutex;
+SCM_API pthread_mutex_t scm_i_sweep_mutex;
 \f
 
 #if (SCM_ENABLE_DEPRECATED == 1)
@@ -255,13 +250,10 @@ SCM_API size_t scm_default_max_segment_size;
 
 SCM_API size_t scm_max_segment_size;
 
-#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;
+#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;
 SCM_API struct scm_t_cell_type_statistics scm_i_master_freelist;
 SCM_API struct scm_t_cell_type_statistics scm_i_master_freelist2;
 
index 453a674..a1d6bb4 100644 (file)
 #include "libguile/hashtab.h"
 \f
 
+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
@@ -145,7 +166,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;
index 441716f..301d9f1 100644 (file)
@@ -55,7 +55,12 @@ 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)
 
index ca964af..4d25299 100644 (file)
 #include <unistd.h>
 #endif
 \f
-/* 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
@@ -345,11 +305,9 @@ 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 SCM invoke_main_func(void *body_data);
+static void *invoke_main_func(void *body_data);
 
 
 /* Fire up the Guile Scheme interpreter.
@@ -383,10 +341,6 @@ static SCM 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;
@@ -394,19 +348,47 @@ scm_boot_guile (int argc, char ** argv, void (*main_func) (), void *closure)
   c.argc = argc;
   c.argv = argv;
 
-  scm_boot_guile_1 (&dummy, &c);
+  scm_with_guile (invoke_main_func, &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_init_guile_1 ((SCM_STACKITEM *)scm_get_stack_base ());
+  scm_i_init_guile ((SCM_STACKITEM *)scm_get_stack_base ());
 }
+#endif
 
+pthread_mutex_t scm_i_init_mutex = PTHREAD_MUTEX_INITIALIZER;
 int scm_initialized_p = 0;
 
-static void
-scm_init_guile_1 (SCM_STACKITEM *base)
+void
+scm_i_init_guile (SCM_STACKITEM *base)
 {
   if (scm_initialized_p)
     return;
@@ -427,7 +409,7 @@ scm_init_guile_1 (SCM_STACKITEM *base)
   scm_block_gc = 1;
 
   scm_storage_prehistory ();
-  scm_threads_prehistory ();
+  scm_threads_prehistory (base);
   scm_ports_prehistory ();
   scm_smob_prehistory ();
   scm_hashtab_prehistory ();   /* requires storage_prehistory */
@@ -448,8 +430,7 @@ scm_init_guile_1 (SCM_STACKITEM *base)
   scm_init_variable ();           /* all bindings need variables */
   scm_init_continuations ();
   scm_init_root ();              /* requires continuations */
-  scm_init_threads (base);
-  start_stack (base);
+  scm_init_threads ();
   scm_init_gsubr ();
   scm_init_thread_procs ();       /* requires gsubrs */
   scm_init_procprop ();
@@ -551,6 +532,8 @@ scm_init_guile_1 (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 */
@@ -567,50 +550,6 @@ scm_init_guile_1 (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:
index ac8e626..9c42d3e 100644 (file)
 \f
 
 #include "libguile/__scm.h"
+#include "libguile/threads.h"
 
 \f
+SCM_API pthread_mutex_t scm_i_init_mutex;
 SCM_API int scm_initialized_p;
 
 SCM_API void scm_init_guile (void);
@@ -35,6 +37,8 @@ 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 */
index 823ddc4..49f99a1 100644 (file)
@@ -67,15 +67,6 @@ 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)
index 22a2de5..f49d697 100644 (file)
@@ -280,14 +280,14 @@ SCM_DEFINE (scm_fdes_to_ports, "fdes->ports", 1, 0, 0,
 
   int_fd = scm_to_int (fd);
 
-  scm_mutex_lock (&scm_i_port_table_mutex);
+  scm_pthread_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);
     }
-  scm_mutex_unlock (&scm_i_port_table_mutex);
+  pthread_mutex_unlock (&scm_i_port_table_mutex);
   return result;
 }
 #undef FUNC_NAME    
index ffa01f7..b0ede66 100644 (file)
@@ -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.  */
 
-SCM_GLOBAL_MUTEX (scm_i_port_table_mutex);
+pthread_mutex_t scm_i_port_table_mutex = PTHREAD_MUTEX_INITIALIZER;
 
 /* 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_mutex_lock (&scm_i_port_table_mutex);
+  scm_pthread_mutex_lock (&scm_i_port_table_mutex);
   scm_remove_from_port_table (port);
-  scm_mutex_unlock (&scm_i_port_table_mutex);
+  pthread_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_mutex_lock (&scm_i_port_table_mutex);
+  scm_pthread_mutex_lock (&scm_i_port_table_mutex);
   n = scm_i_port_table_size;
-  scm_mutex_unlock (&scm_i_port_table_mutex);
+  pthread_mutex_unlock (&scm_i_port_table_mutex);
 
   ports = scm_c_make_vector (n, SCM_BOOL_F);
 
-  scm_mutex_lock (&scm_i_port_table_mutex);
+  scm_pthread_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);
-  scm_mutex_unlock (&scm_i_port_table_mutex);
+  pthread_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_mutex_lock (&scm_i_port_table_mutex);
+  scm_pthread_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);
     }
-  scm_mutex_unlock (&scm_i_port_table_mutex);
+  pthread_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_mutex_lock (&scm_i_port_table_mutex);
+  scm_pthread_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);
-    scm_mutex_unlock (&scm_i_port_table_mutex);
+    pthread_mutex_unlock (&scm_i_port_table_mutex);
     return answer;
   }
 }
index 606aaa8..4cd1b9c 100644 (file)
@@ -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 scm_t_mutex scm_i_port_table_mutex;
+SCM_API pthread_mutex_t scm_i_port_table_mutex;
 
 #define SCM_READ_BUFFER_EMPTY_P(c_port) (c_port->read_pos >= c_port->read_end)
 
index 2c37ae8..a98147a 100644 (file)
@@ -40,6 +40,7 @@
 #include "libguile/validate.h"
 #include "libguile/posix.h"
 #include "libguile/i18n.h"
+#include "libguile/threads.h"
 \f
 
 #ifdef HAVE_STRING_H
@@ -820,11 +821,11 @@ SCM_DEFINE (scm_ttyname, "ttyname", 1, 0, 0,
     return SCM_BOOL_F;
   fd = SCM_FPORT_FDES (port);
 
-  scm_mutex_lock (&scm_i_misc_mutex);
+  scm_pthread_mutex_lock (&scm_i_misc_mutex);
   SCM_SYSCALL (result = ttyname (fd));
   err = errno;
   ret = scm_from_locale_string (result);
-  scm_mutex_unlock (&scm_i_misc_mutex);
+  pthread_mutex_unlock (&scm_i_misc_mutex);
 
   if (!result)
     {
@@ -1505,15 +1506,12 @@ SCM_DEFINE (scm_crypt, "crypt", 2, 0, 0,
   char *c_key, *c_salt;
 
   scm_frame_begin (0);
-  scm_frame_unwind_handler ((void(*)(void*)) scm_mutex_unlock,
-                            &scm_i_misc_mutex,
-                            SCM_F_WIND_EXPLICITLY);
-  scm_mutex_lock (&scm_i_misc_mutex);
+  scm_frame_pthread_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_key);
+  scm_frame_free (c_salt);
 
   ret = scm_from_locale_string (crypt (c_key, c_salt));
 
index be6b7c2..3c5e902 100644 (file)
@@ -133,7 +133,7 @@ do { \
 
 SCM scm_print_state_vtable = SCM_BOOL_F;
 static SCM print_state_pool = SCM_EOL;
-SCM_MUTEX (print_state_mutex);
+pthread_mutex_t print_state_mutex = PTHREAD_MUTEX_INITIALIZER;
 
 #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 */
-  scm_i_plugin_mutex_lock (&print_state_mutex);
+  pthread_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);
     }
-  scm_i_plugin_mutex_unlock (&print_state_mutex);
+  pthread_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;
-  scm_i_plugin_mutex_lock (&print_state_mutex);
+  pthread_mutex_lock (&print_state_mutex);
   handle = scm_cons (print_state, print_state_pool);
   print_state_pool = handle;
-  scm_i_plugin_mutex_unlock (&print_state_mutex);
+  pthread_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 */
-      scm_i_plugin_mutex_lock (&print_state_mutex);
+      pthread_mutex_lock (&print_state_mutex);
       if (!scm_is_null (print_state_pool))
        {
          handle = print_state_pool;
          print_state_pool = SCM_CDR (print_state_pool);
        }
-      scm_i_plugin_mutex_unlock (&print_state_mutex);
+      pthread_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)
     {
-      scm_i_plugin_mutex_lock (&print_state_mutex);
+      pthread_mutex_lock (&print_state_mutex);
       SCM_SETCDR (handle, print_state_pool);
       print_state_pool = handle;
-      scm_i_plugin_mutex_unlock (&print_state_mutex);
+      pthread_mutex_unlock (&print_state_mutex);
     }
 }
 
index dfe0ae3..09ec7c0 100644 (file)
@@ -46,7 +46,6 @@ 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);
@@ -91,7 +90,6 @@ 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
@@ -346,6 +344,10 @@ scm_apply_with_dynamic_root (SCM proc, SCM a1, SCM args, SCM handler)
 
 \f
 
+/* Initialized in scm_threads_prehistory.
+ */
+pthread_key_t scm_i_root_key;
+
 void
 scm_init_root ()
 {
index a97cf75..f33278a 100644 (file)
@@ -64,8 +64,7 @@ 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;                        /* vestigial */
-  SCM exitval;                 /* vestigial */
+  SCM progargs;
 
   SCM cur_inp;
   SCM cur_outp;
@@ -87,6 +86,10 @@ 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)
@@ -101,8 +104,6 @@ typedef struct scm_root_state
 #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)
 
 \f
 
index 8560a58..ad87409 100644 (file)
@@ -136,7 +136,7 @@ scm_i_stringbuf_free (SCM buf)
                 STRINGBUF_OUTLINE_LENGTH (buf) + 1, "string");
 }
 
-SCM_MUTEX (stringbuf_write_mutex);
+pthread_mutex_t stringbuf_write_mutex = PTHREAD_MUTEX_INITIALIZER;
 
 /* 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);
-  scm_i_plugin_mutex_lock (&stringbuf_write_mutex);
+  pthread_mutex_lock (&stringbuf_write_mutex);
   SET_STRINGBUF_SHARED (buf);
-  scm_i_plugin_mutex_unlock (&stringbuf_write_mutex);
+  pthread_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);
-  scm_i_plugin_mutex_lock (&stringbuf_write_mutex);
+  pthread_mutex_lock (&stringbuf_write_mutex);
   SET_STRINGBUF_SHARED (buf);
-  scm_i_plugin_mutex_unlock (&stringbuf_write_mutex);
+  pthread_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));
 
-  scm_i_plugin_mutex_lock (&stringbuf_write_mutex);
+  pthread_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;
 
-      scm_i_plugin_mutex_unlock (&stringbuf_write_mutex);
+      pthread_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;
 
-      scm_i_plugin_mutex_lock (&stringbuf_write_mutex);
+      pthread_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)
 {
-  scm_i_plugin_mutex_unlock (&stringbuf_write_mutex);
+  pthread_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. */
-      scm_i_plugin_mutex_lock (&stringbuf_write_mutex);
+      pthread_mutex_lock (&stringbuf_write_mutex);
       SET_STRINGBUF_SHARED (buf);
-      scm_i_plugin_mutex_unlock (&stringbuf_write_mutex);
+      pthread_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);
-  scm_i_plugin_mutex_lock (&stringbuf_write_mutex);
+  pthread_mutex_lock (&stringbuf_write_mutex);
   SET_STRINGBUF_SHARED (buf);
-  scm_i_plugin_mutex_unlock (&stringbuf_write_mutex);
+  pthread_mutex_unlock (&stringbuf_write_mutex);
   return scm_double_cell (STRING_TAG, SCM_UNPACK(buf),
                          (scm_t_bits)start, (scm_t_bits) end - start);
 }
index f7b4013..fbc39c2 100644 (file)
@@ -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_mutex_lock (&scm_i_port_table_mutex);
+  scm_pthread_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;
 
-  scm_mutex_unlock (&scm_i_port_table_mutex);
+  pthread_mutex_unlock (&scm_i_port_table_mutex);
 
   /* ensure write_pos is writable. */
   if ((modes & SCM_WRTNG) && pt->write_pos == pt->write_end)
index 204bc74..e63b79b 100644 (file)
@@ -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_mutex_lock (&scm_i_misc_mutex);
+  scm_pthread_mutex_lock (&scm_i_misc_mutex);
   n = gensym_counter++;
-  scm_mutex_unlock (&scm_i_misc_mutex);
+  pthread_mutex_unlock (&scm_i_misc_mutex);
 
   n_digits = scm_iint2str (n, 10, buf);
   suffix = scm_from_locale_stringn (buf, n_digits);
index b772b84..68f6f4b 100644 (file)
 
 \f
 
-/* This file implements nice Scheme level threads on top of the gastly
-   C level threads.
-*/
-
 #include "libguile/_scm.h"
 
 #if HAVE_UNISTD_H
@@ -41,6 +37,9 @@
 #include "libguile/threads.h"
 #include "libguile/dynwind.h"
 #include "libguile/iselect.h"
+#include "libguile/fluids.h"
+#include "libguile/continuations.h"
+#include "libguile/init.h"
 
 /*** Queues */
 
@@ -97,66 +96,12 @@ dequeue (SCM q)
 
 /*** Threads */
 
-#define THREAD_INITIALIZED_P(t) (t->base != NULL)
-
-struct scm_thread {
-  
-  /* Blocking.
-   */
-  scm_t_cond sleep_cond;
-  struct scm_thread *next_waiting;
-
-  /* This mutex represents this threads right to access the heap.
-     That right can temporarily be taken away by the GC.  */
-  scm_t_mutex heap_mutex;
-  int clear_freelists_p; /* set if GC was done while thread was asleep */
-  
-  scm_root_state *root;
-  SCM handle;
-  scm_t_thread thread;
-  SCM result;
-  int exited;
-
-  /* For keeping track of the stack and registers. */
-  SCM_STACKITEM *base;
-  SCM_STACKITEM *top;
-  jmp_buf regs;
-
-};
-
-static SCM
-make_thread (SCM creation_protects)
-{
-  SCM z;
-  scm_thread *t;
-  z = scm_make_smob (scm_tc16_thread);
-  t = SCM_THREAD_DATA (z);
-  t->handle = z;
-  t->result = creation_protects;
-  t->base = NULL;
-  scm_i_plugin_cond_init (&t->sleep_cond, 0);
-  scm_i_plugin_mutex_init (&t->heap_mutex, &scm_i_plugin_mutex);
-  t->clear_freelists_p = 0;
-  t->exited = 0;
-  return z;
-}
-
-static void
-init_thread_creatant (SCM thread,
-                     SCM_STACKITEM *base)
-{
-  scm_thread *t = SCM_THREAD_DATA (thread);
-  t->thread = scm_thread_self ();
-  t->base = base;
-  t->top = NULL;
-}
-
 static SCM
 thread_mark (SCM obj)
 {
   scm_thread *t = SCM_THREAD_DATA (obj);
   scm_gc_mark (t->result);
-  return t->root->handle; /* mark root-state of this thread */
+  return t->root;
 }
 
 static int
@@ -164,7 +109,7 @@ thread_print (SCM exp, SCM port, scm_print_state *pstate SCM_UNUSED)
 {
   scm_thread *t = SCM_THREAD_DATA (exp);
   scm_puts ("#<thread ", port);
-  scm_uintprint ((size_t)t->thread, 10, port);
+  scm_uintprint ((size_t)t->pthread, 10, port);
   scm_puts (" (", port);
   scm_uintprint ((scm_t_bits)t, 16, port);
   scm_puts (")>", port);
@@ -175,8 +120,7 @@ static size_t
 thread_free (SCM obj)
 {
   scm_thread *t = SCM_THREAD_DATA (obj);
-  if (!t->exited)
-    abort ();
+  assert (t->exited);
   scm_gc_free (t, sizeof (*t), "thread");
   return 0;
 }
@@ -184,17 +128,8 @@ thread_free (SCM obj)
 /*** Scheduling */
 
 #define cur_thread (SCM_CURRENT_THREAD->handle)
-scm_t_key scm_i_thread_key;
-scm_t_key scm_i_root_state_key;
+pthread_key_t scm_i_thread_key;
 
-void
-scm_i_set_thread_data (void *data)
-{
-  scm_thread *t = SCM_CURRENT_THREAD;
-  scm_setspecific (scm_i_root_state_key, data);
-  t->root = (scm_root_state *)data;
-}
-  
 static void
 resume (scm_thread *t)
 {
@@ -207,10 +142,10 @@ resume (scm_thread *t)
     }
 }
 
-void
+static void
 scm_i_enter_guile (scm_thread *t)
 {
-  scm_i_plugin_mutex_lock (&t->heap_mutex);
+  pthread_mutex_lock (&t->heap_mutex);
   resume (t);
 }
 
@@ -228,11 +163,11 @@ suspend ()
   return c;
 }
 
-scm_thread *
+static scm_thread *
 scm_i_leave_guile ()
 {
   scm_thread *t = suspend ();
-  scm_i_plugin_mutex_unlock (&t->heap_mutex);
+  pthread_mutex_unlock (&t->heap_mutex);
   return t;
 }
 
@@ -243,7 +178,7 @@ block ()
 {
   int err;
   scm_thread *t = suspend ();
-  err = scm_i_plugin_cond_wait (&t->sleep_cond, &t->heap_mutex);
+  err = pthread_cond_wait (&t->sleep_cond, &t->heap_mutex);
   resume (t);
   return err;
 }
@@ -257,7 +192,7 @@ timed_block (const scm_t_timespec *at)
 {
   int err;
   scm_thread *t = suspend ();
-  err = scm_i_plugin_cond_timedwait (&t->sleep_cond, &t->heap_mutex, at);
+  err = pthread_cond_timedwait (&t->sleep_cond, &t->heap_mutex, at);
   resume (t);
   return err;
 }
@@ -267,153 +202,268 @@ timed_block (const scm_t_timespec *at)
 static void
 unblock (scm_thread *t)
 {
-  scm_i_plugin_cond_signal (&t->sleep_cond);
+  pthread_cond_signal (&t->sleep_cond);
 }
 
-/*** Thread creation */
+/* Getting into and out of guile mode.
+ */
 
-static scm_t_mutex thread_admin_mutex;
-static SCM all_threads;
+static pthread_mutex_t thread_admin_mutex = PTHREAD_MUTEX_INITIALIZER;
+static scm_thread *all_threads = NULL;
 static int thread_count;
 
-typedef struct launch_data {
-  SCM thread;
-  SCM rootcont;
-  scm_t_catch_body body;
-  void *body_data;
-  scm_t_catch_handler handler;
-  void *handler_data;
-} launch_data;
+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 SCM
-body_bootstrip (launch_data* data)
+static void
+start_stack (void *base)
 {
-  /* First save the new root continuation */
-  data->rootcont = scm_root->rootcont;
-  return (data->body) (data->body_data);
+  scm_stack_base = base;
+  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);
 }
 
-static SCM
-handler_bootstrip (launch_data* data, SCM tag, SCM throw_args)
+static SCM scm_i_root_root;
+
+static void
+guilify_self_1 (SCM_STACKITEM *base)
 {
-  scm_root->rootcont = data->rootcont;
-  return (data->handler) (data->handler_data, tag, throw_args);
+  scm_thread *t = malloc (sizeof (scm_thread));
+
+  t->pthread = pthread_self ();
+  t->handle = SCM_BOOL_F;
+  t->root = SCM_BOOL_F;
+  t->result = SCM_BOOL_F;
+  t->base = base;
+  pthread_cond_init (&t->sleep_cond, NULL);
+  pthread_mutex_init (&t->heap_mutex, NULL);
+  t->clear_freelists_p = 0;
+  t->exited = 0;
+
+  t->freelist = SCM_EOL;
+  t->freelist2 = SCM_EOL;
+  SCM_SET_FREELIST_LOC (scm_i_freelist, &t->freelist);
+  SCM_SET_FREELIST_LOC (scm_i_freelist2, &t->freelist2);
+
+  pthread_setspecific (scm_i_thread_key, t);
+
+  pthread_mutex_lock (&t->heap_mutex);
+
+  pthread_mutex_lock (&thread_admin_mutex);
+  t->next_thread = all_threads;
+  all_threads = t;
+  thread_count++;
+  pthread_mutex_unlock (&thread_admin_mutex);
 }
 
 static void
-really_launch (SCM_STACKITEM *base, launch_data *data)
+guilify_self_2 (SCM parent)
 {
-  SCM thread;
-  scm_thread *t;
-  thread = data->thread;
-  t = SCM_THREAD_DATA (thread);
-  SCM_FREELIST_CREATE (scm_i_freelist);
-  SCM_FREELIST_CREATE (scm_i_freelist2);
-  scm_setspecific (scm_i_thread_key, t);
-  scm_setspecific (scm_i_root_state_key, t->root);
-  scm_i_plugin_mutex_lock (&t->heap_mutex); /* ensure that we "own" the heap */
-  init_thread_creatant (thread, base); /* must own the heap */
-  
-  data->rootcont = SCM_BOOL_F;
-  t->result =
-    scm_internal_cwdr ((scm_t_catch_body) body_bootstrip,
-                      data,
-                      (scm_t_catch_handler) handler_bootstrip,
-                      data, base);
-  scm_i_leave_guile (); /* release the heap */
-  free (data);
-
-  scm_i_plugin_mutex_lock (&thread_admin_mutex);
-  all_threads = scm_delq_x (thread, all_threads);
+  scm_thread *t = SCM_CURRENT_THREAD;
+
+  SCM_NEWSMOB (t->handle, scm_tc16_thread, t);
+  scm_gc_register_collectable_memory (t, sizeof (scm_thread), "thread");
+  t->root = scm_make_root (SCM_BOOL_F);
+  scm_set_root (SCM_ROOT_STATE (t->root));
+  start_stack (t->base);
+
+  if (SCM_ROOTP (parent))
+    {
+      scm_root_state *thread_root = SCM_ROOT_STATE (t->root);
+      scm_root_state *parent_root = SCM_ROOT_STATE (parent);
+
+      thread_root->cur_inp = parent_root->cur_inp;
+      thread_root->cur_outp = parent_root->cur_outp;
+      thread_root->cur_errp = parent_root->cur_errp;
+      thread_root->fluids = parent_root->fluids;
+      scm_i_copy_fluids (thread_root);
+    }
+}
+
+static void
+on_thread_exit (void *v)
+{
+  scm_thread *t = (scm_thread *)v, **tp;
+
+  pthread_mutex_lock (&thread_admin_mutex);
   t->exited = 1;
+  for (tp = &all_threads; *tp; tp = &(*tp)->next_thread)
+    if (*tp == t)
+      {
+       *tp = t->next_thread;
+       break;
+      }
   thread_count--;
-  /* detach before unlocking in order to not become joined when detached */
-  scm_thread_detach (t->thread);
-  scm_i_plugin_mutex_unlock (&thread_admin_mutex);
+  pthread_mutex_unlock (&thread_admin_mutex);
 }
 
-static void *
-launch_thread (void *p)
+static void
+scm_i_init_thread_for_guile (SCM_STACKITEM *base, SCM parent)
 {
-  really_launch (SCM_STACK_PTR (&p), (launch_data *) p);
-  return 0;
+  scm_thread *t;
+
+  pthread_mutex_lock (&scm_i_init_mutex);
+  if (scm_initialized_p == 0)
+    {
+      /* First thread ever to enter Guile.  Run the full
+        initialization.
+      */
+      scm_i_init_guile (base);
+    }
+  else if ((t = SCM_CURRENT_THREAD) == NULL)
+    {
+      /* Guile is already initialized, but this thread enters it for
+        the first time.  Only initialize this thread.
+      */
+      guilify_self_1 (base);
+      guilify_self_2 (parent);
+    }
+  else
+    {
+      /* This thread is already guilified, just resume it.
+       */
+      scm_i_enter_guile (t);
+    }
+  pthread_mutex_unlock (&scm_i_init_mutex);
 }
 
-static SCM
-create_thread (scm_t_catch_body body, void *body_data,
-              scm_t_catch_handler handler, void *handler_data,
-              SCM protects)
+extern void *__libc_stack_end;
+
+static SCM_STACKITEM *
+get_thread_stack_base ()
 {
-  SCM thread;
+  pthread_attr_t attr;
+  void *start, *end;
+  size_t size;
+  int res;
 
-  /* Make new thread.  The first thing the new thread will do is to
-     lock guile_mutex.  Thus, we can safely complete its
-     initialization after creating it.  While the new thread starts,
-     all its data is protected via all_threads.
-   */
+  /* XXX - pthread_getattr_np does not seem to work for the main
+     thread, but we can use __libc_stack_end in that case.
+  */
 
-  {
-    scm_t_thread th;
-    SCM root;
-    launch_data *data;
-    scm_thread *t;
-    int err;
-
-    /* Allocate thread locals. */
-    root = scm_make_root (scm_root->handle);
-    data = scm_malloc (sizeof (launch_data));
-
-    /* Make thread. */
-    thread = make_thread (protects);
-    data->thread = thread;
-    data->body = body;
-    data->body_data = body_data;
-    data->handler = handler;
-    data->handler_data = handler_data;
-    t = SCM_THREAD_DATA (thread);
-    /* must initialize root state pointer before the thread is linked
-       into all_threads */
-    t->root = SCM_ROOT_STATE (root);
-    /* disconnect from parent, to prevent remembering dead threads */
-    t->root->parent = SCM_BOOL_F;
-    /* start with an empty dynwind chain */
-    t->root->dynwinds = SCM_EOL;
-    
-    /* In order to avoid the need of synchronization between parent
-       and child thread, we need to insert the child into all_threads
-       before creation. */
+  pthread_getattr_np (pthread_self (), &attr);
+  pthread_attr_getstack (&attr, &start, &size);
+  end = (char *)start + size;
+
+  if ((void *)&attr < start || (void *)&attr >= end)
+    return __libc_stack_end;
+  else
     {
-      SCM new_threads = scm_cons (thread, SCM_BOOL_F); /* could cause GC */
-      scm_thread *parent = scm_i_leave_guile (); /* to prevent deadlock */
-      scm_i_plugin_mutex_lock (&thread_admin_mutex);
-      SCM_SETCDR (new_threads, all_threads);
-      all_threads = new_threads;
-      thread_count++;
-      scm_i_plugin_mutex_unlock (&thread_admin_mutex);
-
-      scm_remember_upto_here_1 (root);
-      
-      scm_i_enter_guile (parent);
+#if SCM_STACK_GROWS_UP
+      return start;
+#else
+      return end;
+#endif
     }
-    
-    err = scm_i_plugin_thread_create (&th, 0, launch_thread, (void *) data);
-    if (err != 0)
-      {
-       scm_i_plugin_mutex_lock (&thread_admin_mutex);
-       all_threads = scm_delq_x (thread, all_threads);
-       ((scm_thread *) SCM_THREAD_DATA(thread))->exited = 1;
-       thread_count--;
-       scm_i_plugin_mutex_unlock (&thread_admin_mutex);
-      }
+}
 
-    if (err)
-      {
-       errno = err;
-       scm_syserror ("create-thread");
-      }
-  }
+void
+scm_init_guile ()
+{
+  scm_i_init_thread_for_guile (get_thread_stack_base (), scm_i_root_root);
+}
+
+void
+scm_enter_guile ()
+{
+  SCM_STACKITEM base_item;
+  scm_i_init_thread_for_guile (&base_item, scm_i_root_root);
+}
+
+void
+scm_leave_guile ()
+{
+  scm_i_leave_guile ();
+}
+
+void *
+scm_with_guile (void *(*func)(void *), void *data)
+{
+  return scm_i_with_guile_and_parent (func, data, scm_i_root_root);
+}
+
+void *
+scm_i_with_guile_and_parent (void *(*func)(void *), void *data,
+                            SCM parent)
+{
+  void *res;
+  SCM_STACKITEM base_item;
+  scm_i_init_thread_for_guile (&base_item, parent);
+  res = func (data);
+  scm_i_leave_guile ();
+  return res;
+}
+
+void *
+scm_without_guile (void *(*func)(void *), void *data)
+{
+  void *res;
+  scm_thread *t;
+  t = scm_i_leave_guile ();
+  res = func (data);
+  scm_i_enter_guile (t);
+  return res;
+}
+
+/*** Thread creation */
+
+typedef struct {
+  SCM parent;
+  SCM thunk;
+  SCM handler;
+  SCM thread;
+  pthread_mutex_t mutex;
+  pthread_cond_t cond;
+} launch_data;
+
+static void *
+really_launch (void *d)
+{
+  launch_data *data = (launch_data *)d;
+  SCM thunk = data->thunk, handler = data->handler;
+  scm_thread *t;
+
+  t = SCM_CURRENT_THREAD;
+
+  pthread_mutex_lock (&data->mutex);
+  data->thread = scm_current_thread ();
+  pthread_cond_signal (&data->cond);
+  pthread_mutex_unlock (&data->mutex);
+
+  t->result = scm_catch (SCM_BOOL_T, thunk, handler);
 
-  return thread;
+  t->exited = 1;
+  pthread_detach (t->pthread);
+
+  return 0;
+}
+
+static void *
+launch_thread (void *d)
+{
+  launch_data *data = (launch_data *)d;
+  return scm_i_with_guile_and_parent (really_launch, d, data->parent);
 }
 
 SCM_DEFINE (scm_call_with_new_thread, "call-with-new-thread", 2, 0, 0,
@@ -428,22 +478,110 @@ SCM_DEFINE (scm_call_with_new_thread, "call-with-new-thread", 2, 0, 0,
 "All the evaluation rules for dynamic roots apply to threads.")
 #define FUNC_NAME s_scm_call_with_new_thread
 {
+  launch_data data;
+  pthread_t id;
+
   SCM_ASSERT (scm_is_true (scm_thunk_p (thunk)), thunk, SCM_ARG1, FUNC_NAME);
   SCM_ASSERT (scm_is_true (scm_procedure_p (handler)), handler, SCM_ARG2,
              FUNC_NAME);
 
-  return create_thread ((scm_t_catch_body) scm_call_0, thunk,
-                       (scm_t_catch_handler) scm_apply_1, handler,
-                       scm_cons (thunk, handler));
+  data.parent = scm_root->handle;
+  data.thunk = thunk;
+  data.handler = handler;
+  data.thread = SCM_BOOL_F;
+  pthread_mutex_init (&data.mutex, NULL);
+  pthread_cond_init (&data.cond, NULL);
+
+  pthread_mutex_lock (&data.mutex);
+  if (pthread_create (&id, NULL, launch_thread, &data))
+    {
+      pthread_mutex_unlock (&data.mutex);
+      SCM_SYSERROR;
+    }
+  pthread_cond_wait (&data.cond, &data.mutex);
+  pthread_mutex_unlock (&data.mutex);
+  
+  return data.thread;
 }
 #undef FUNC_NAME
 
+typedef struct {
+  SCM parent;
+  scm_t_catch_body body;
+  void *body_data;
+  scm_t_catch_handler handler;
+  void *handler_data;
+  SCM thread;
+  pthread_mutex_t mutex;
+  pthread_cond_t cond;
+} spawn_data;
+
+static void *
+really_spawn (void *d)
+{
+  spawn_data *data = (spawn_data *)d;
+  scm_t_catch_body body = data->body;
+  void *body_data = data->body_data;
+  scm_t_catch_handler handler = data->handler;
+  void *handler_data = data->handler_data;
+  scm_thread *t = SCM_CURRENT_THREAD;
+
+  pthread_mutex_lock (&data->mutex);
+  data->thread = scm_current_thread ();
+  pthread_cond_signal (&data->cond);
+  pthread_mutex_unlock (&data->mutex);
+
+  t->result = scm_internal_catch (SCM_BOOL_T,
+                                 body, body_data,
+                                 handler, handler_data);
+
+  t->exited = 1;
+  pthread_detach (t->pthread);
+
+  return 0;
+}
+
+static void *
+spawn_thread (void *d)
+{
+  spawn_data *data = (spawn_data *)d;
+  return scm_i_with_guile_and_parent (really_spawn, d, data->parent);
+}
+
+SCM
+scm_spawn_thread (scm_t_catch_body body, void *body_data,
+                 scm_t_catch_handler handler, void *handler_data)
+{
+  spawn_data data;
+  pthread_t id;
+
+  data.parent = scm_root->handle;
+  data.body = body;
+  data.body_data = body_data;
+  data.handler = handler;
+  data.handler_data = handler_data;
+  data.thread = SCM_BOOL_F;
+  pthread_mutex_init (&data.mutex, NULL);
+  pthread_cond_init (&data.cond, NULL);
+
+  pthread_mutex_lock (&data.mutex);
+  if (pthread_create (&id, NULL, spawn_thread, &data))
+    {
+      pthread_mutex_unlock (&data.mutex);
+      scm_syserror (NULL);
+    }
+  pthread_cond_wait (&data.cond, &data.mutex);
+  pthread_mutex_unlock (&data.mutex);
+  
+  return data.thread;
+}
+
 SCM_DEFINE (scm_yield, "yield", 0, 0, 0,
            (),
 "Move the calling thread to the end of the scheduling queue.")
 #define FUNC_NAME s_scm_yield
 {
-  return scm_from_bool (scm_thread_yield ());
+  return scm_from_bool (sched_yield ());
 }
 #undef FUNC_NAME
 
@@ -465,9 +603,7 @@ SCM_DEFINE (scm_join_thread, "join-thread", 1, 0, 0,
     {
       scm_thread *c;
       c = scm_i_leave_guile ();
-      while (!THREAD_INITIALIZED_P (t))
-       scm_i_plugin_thread_yield ();
-      scm_thread_join (t->thread, 0);
+      pthread_join (t->pthread, 0);
       scm_i_enter_guile (c);
     }
   res = t->result;
@@ -476,7 +612,7 @@ SCM_DEFINE (scm_join_thread, "join-thread", 1, 0, 0,
 }
 #undef FUNC_NAME
 
-/*** Fair mutexes */
+/*** Fat mutexes */
 
 /* We implement our own mutex type since we want them to be 'fair', we
    want to do fancy things while waiting for them (like running
@@ -484,220 +620,120 @@ SCM_DEFINE (scm_join_thread, "join-thread", 1, 0, 0,
    Also, we might add things that are nice for debugging.
 */
 
-typedef struct fair_mutex {
-  /* the thread currently owning the mutex, or SCM_BOOL_F. */
-  scm_t_mutex lock;
-  int lockedp;
+typedef struct {
+  pthread_mutex_t lock;
   SCM owner;
-  /* how much the owner owns us. */
-  int level;
-  /* the threads waiting for this mutex. */
-  SCM waiting;
-} fair_mutex;
+  int level;      /* how much the owner owns us.  
+                    < 0 for non-recursive mutexes */
+  SCM waiting;    /* the threads waiting for this mutex. */
+} fat_mutex;
 
 static SCM
-fair_mutex_mark (SCM mx)
+fat_mutex_mark (SCM mx)
 {
-  fair_mutex *m = SCM_MUTEX_DATA (mx);
+  fat_mutex *m = SCM_MUTEX_DATA (mx);
   scm_gc_mark (m->owner);
   return m->waiting;
 }
 
-SCM_DEFINE (scm_make_fair_mutex, "make-fair-mutex", 0, 0, 0,
-           (void),
-           "Create a new fair mutex object. ")
-#define FUNC_NAME s_scm_make_fair_mutex
-{
-  SCM mx = scm_make_smob (scm_tc16_fair_mutex);
-  fair_mutex *m = SCM_MUTEX_DATA (mx);
-  scm_i_plugin_mutex_init (&m->lock, &scm_i_plugin_mutex);
-  m->lockedp = 0;
-  m->owner = SCM_BOOL_F;
-  m->level = 0;
-  m->waiting = make_queue ();
-  return mx;
-}
-#undef FUNC_NAME
-
-static int
-fair_mutex_lock (fair_mutex *m)
-{
-  scm_i_plugin_mutex_lock (&m->lock);
-#if 0
-  /* Need to wait if another thread is just temporarily unlocking.
-     This is happens very seldom and only when the other thread is
-     between scm_mutex_unlock and scm_i_plugin_mutex_lock below. */
-  while (m->lockedp)
-    SCM_TICK;
-    m->lockedp = 1;
-#endif
-  
-  if (m->owner == SCM_BOOL_F)
-    m->owner = cur_thread;
-  else if (m->owner == cur_thread)
-    m->level++;
-  else
-    {
-      while (1)
-       {
-         SCM c = enqueue (m->waiting, cur_thread);
-         int err;
-         /* Note: It's important that m->lock is never locked for
-            any longer amount of time since that could prevent GC */
-         scm_i_plugin_mutex_unlock (&m->lock);
-         err = block ();
-         if (m->owner == cur_thread)
-           return 0;
-         scm_i_plugin_mutex_lock (&m->lock);
-         remqueue (m->waiting, c);
-         scm_i_plugin_mutex_unlock (&m->lock);
-         if (err)
-           return err;
-         SCM_ASYNC_TICK;
-         scm_i_plugin_mutex_lock (&m->lock);
-       }
-    }
-  scm_i_plugin_mutex_unlock (&m->lock);
-  return 0;
-}
-
-static int
-fair_mutex_trylock (fair_mutex *m)
-{
-  scm_i_plugin_mutex_lock (&m->lock);
-  if (m->owner == SCM_BOOL_F)
-    m->owner = cur_thread;
-  else if (m->owner == cur_thread)
-    m->level++;
-  else
-    {
-      scm_i_plugin_mutex_unlock (&m->lock);
-      return EBUSY;
-    }
-  scm_i_plugin_mutex_unlock (&m->lock);
-  return 0;
-}
-
-static int
-fair_mutex_unlock (fair_mutex *m)
-{
-  scm_i_plugin_mutex_lock (&m->lock);
-  if (m->owner != cur_thread)
-    {
-      scm_i_plugin_mutex_unlock (&m->lock);
-      return EPERM;
-    }
-  else if (m->level > 0)
-    m->level--;
-  else
-    {
-      SCM next = dequeue (m->waiting);
-      if (scm_is_true (next))
-       {
-         m->owner = next;
-         unblock (SCM_THREAD_DATA (next));
-       }
-      else
-       m->owner = SCM_BOOL_F;
-    }
-  scm_i_plugin_mutex_unlock (&m->lock);
-  return 0;
-}
-
-/*** Fair condition variables */
-
-/* Like mutexes, we implement our own condition variables using the
-   primitives above.
-*/
-
-typedef struct fair_cond {
-  scm_t_mutex lock;
-  /* the threads waiting for this condition. */
-  SCM waiting;
-} fair_cond;
-
-static SCM
-fair_cond_mark (SCM cv)
-{
-  fair_cond *c = SCM_CONDVAR_DATA (cv);
-  return c->waiting;
-}
-
-SCM_DEFINE (scm_make_fair_condition_variable, "make-fair-condition-variable", 0, 0, 0,
-           (void),
-           "Make a new fair condition variable.")
-#define FUNC_NAME s_scm_make_fair_condition_variable
-{
-  SCM cv = scm_make_smob (scm_tc16_fair_condvar);
-  fair_cond *c = SCM_CONDVAR_DATA (cv);
-  scm_i_plugin_mutex_init (&c->lock, 0);
-  c->waiting = make_queue ();
-  return cv;
-}
-#undef FUNC_NAME
-
-static int
-fair_cond_timedwait (fair_cond *c,
-                    fair_mutex *m,
-                    const scm_t_timespec *waittime)
-{
-  int err;
-  scm_i_plugin_mutex_lock (&c->lock);
-
-  while (1)
-    {
-      enqueue (c->waiting, cur_thread);
-      scm_i_plugin_mutex_unlock (&c->lock);
-      fair_mutex_unlock (m); /*fixme* - not thread safe */
-      if (waittime == NULL)
-       err = block ();
-      else
-       err = timed_block (waittime);
-      fair_mutex_lock (m);
-      if (err)
-       return err;
-      /* XXX - check whether we have been signalled. */
-      break;
-    }
-  return err;
-}
-
-static int
-fair_cond_signal (fair_cond *c)
+static size_t
+fat_mutex_free (SCM mx)
 {
-  SCM th;
-  scm_i_plugin_mutex_lock (&c->lock);
-  if (scm_is_true (th = dequeue (c->waiting)))
-    unblock (SCM_THREAD_DATA (th));
-  scm_i_plugin_mutex_unlock (&c->lock);
+  fat_mutex *m = SCM_MUTEX_DATA (mx);
+  pthread_mutex_destroy (&m->lock);
+  scm_gc_free (m, sizeof (fat_mutex), "mutex");
   return 0;
 }
 
 static int
-fair_cond_broadcast (fair_cond *c)
+fat_mutex_print (SCM mx, SCM port, scm_print_state *pstate SCM_UNUSED)
 {
-  SCM th;
-  scm_i_plugin_mutex_lock (&c->lock);
-  while (scm_is_true (th = dequeue (c->waiting)))
-    unblock (SCM_THREAD_DATA (th));
-  scm_i_plugin_mutex_unlock (&c->lock);
-  return 0;
+  fat_mutex *m = SCM_MUTEX_DATA (mx);
+  scm_puts ("#<mutex ", port);
+  scm_uintprint ((scm_t_bits)m, 16, port);
+  scm_puts (">", port);
+  return 1;
 }
+static SCM
+make_fat_mutex (int recursive)
+{
+  fat_mutex *m;
+  SCM mx;
 
-/*** Mutexes */
+  m = scm_gc_malloc (sizeof (fat_mutex), "mutex");
+  pthread_mutex_init (&m->lock, NULL);
+  m->owner = SCM_BOOL_F;
+  m->level = recursive? 0 : -1;
+  m->waiting = SCM_EOL;
+  SCM_NEWSMOB (mx, scm_tc16_mutex, (scm_t_bits) m);
+  m->waiting = make_queue ();
+  return mx;
+}
 
 SCM_DEFINE (scm_make_mutex, "make-mutex", 0, 0, 0,
            (void),
-           "Create a new mutex object. ")
+           "Create a new mutex. ")
 #define FUNC_NAME s_scm_make_mutex
 {
-  SCM mx = scm_make_smob (scm_tc16_mutex);
-  scm_i_plugin_mutex_init (SCM_MUTEX_DATA (mx), &scm_i_plugin_mutex);
-  return mx;
+  return make_fat_mutex (0);
+}
+#undef FUNC_NAME
+
+SCM_DEFINE (scm_make_recursive_mutex, "make-recursive-mutex", 0, 0, 0,
+           (void),
+           "Create a new recursive mutex. ")
+#define FUNC_NAME s_scm_make_recursive_mutex
+{
+  return make_fat_mutex (1);
 }
 #undef FUNC_NAME
 
-/*fixme* change documentation */
+static void
+fat_mutex_lock (fat_mutex *m)
+{
+  pthread_mutex_lock (&m->lock);
+  
+  if (scm_is_false (m->owner))
+    m->owner = cur_thread;
+  else if (scm_is_eq (m->owner, cur_thread))
+    {
+      if (m->level >= 0)
+       m->level++;
+      else
+       {
+         pthread_mutex_unlock (&m->lock);
+         scm_misc_error (NULL, "mutex already locked by current thread",
+                         SCM_EOL);
+       }
+    }
+  else
+    {
+      while (1)
+       {
+         SCM c = enqueue (m->waiting, cur_thread);
+         int err;
+         /* Note: It's important that m->lock is never locked for
+            any longer amount of time since that could prevent GC */
+         pthread_mutex_unlock (&m->lock);
+         err = block ();
+         if (scm_is_eq (m->owner, cur_thread))
+           return;
+         pthread_mutex_lock (&m->lock);
+         remqueue (m->waiting, c);
+         pthread_mutex_unlock (&m->lock);
+         if (err)
+           {
+             errno = err;
+             scm_syserror (NULL);
+           }
+         SCM_ASYNC_TICK;
+         pthread_mutex_lock (&m->lock);
+       }
+    }
+  pthread_mutex_unlock (&m->lock);
+}
+
 SCM_DEFINE (scm_lock_mutex, "lock-mutex", 1, 0, 0,
            (SCM mx),
 "Lock @var{mutex}. If the mutex is already locked, the calling thread "
@@ -707,25 +743,38 @@ SCM_DEFINE (scm_lock_mutex, "lock-mutex", 1, 0, 0,
 "thread.  That is, Guile's mutexes are @emph{recursive}. ")
 #define FUNC_NAME s_scm_lock_mutex
 {
-  int err;
   SCM_VALIDATE_MUTEX (1, mx);
   
-  if (SCM_TYP16 (mx) == scm_tc16_fair_mutex)
-    err = fair_mutex_lock (SCM_MUTEX_DATA (mx));
-  else
+  fat_mutex_lock (SCM_MUTEX_DATA (mx));
+  return SCM_BOOL_T;
+}
+#undef FUNC_NAME
+
+static int
+fat_mutex_trylock (fat_mutex *m)
+{
+  pthread_mutex_lock (&m->lock);
+  if (scm_is_false (m->owner))
+    m->owner = cur_thread;
+  else if (scm_is_eq (m->owner, cur_thread))
     {
-      scm_t_mutex *m = SCM_MUTEX_DATA (mx);
-      err = scm_mutex_lock (m);
+      if (m->level >= 0)
+       m->level++;
+      else
+       {
+         pthread_mutex_unlock (&m->lock);
+         scm_misc_error (NULL, "mutex already locked by current thread",
+                         SCM_EOL);
+       }
     }
-
-  if (err)
+  else
     {
-      errno = err;
-      SCM_SYSERROR;
+      pthread_mutex_unlock (&m->lock);
+      return 0;
     }
-  return SCM_BOOL_T;
+  pthread_mutex_unlock (&m->lock);
+  return 1;
 }
-#undef FUNC_NAME
 
 SCM_DEFINE (scm_try_mutex, "try-mutex", 1, 0, 0,
            (SCM mx),
@@ -733,29 +782,42 @@ SCM_DEFINE (scm_try_mutex, "try-mutex", 1, 0, 0,
 "else, return @code{#f}.  Else lock the mutex and return @code{#t}. ")
 #define FUNC_NAME s_scm_try_mutex
 {
-  int err;
   SCM_VALIDATE_MUTEX (1, mx);
   
-  if (SCM_TYP16 (mx) == scm_tc16_fair_mutex)
-    err = fair_mutex_trylock (SCM_MUTEX_DATA (mx));
-  else
+  return scm_from_bool (fat_mutex_trylock (SCM_MUTEX_DATA (mx)));
+}
+#undef FUNC_NAME
+
+static void
+fat_mutex_unlock (fat_mutex *m)
+{
+  pthread_mutex_lock (&m->lock);
+  if (!scm_is_eq (m->owner, cur_thread))
     {
-      scm_t_mutex *m = SCM_MUTEX_DATA (mx);
-      err = scm_mutex_trylock (m);
-    }
+      const char *msg;
+      if (scm_is_false (m->owner))
+       msg = "mutex not locked";
+      else
+       msg = "mutex not locked by current thread";
 
-  if (err == EBUSY)
-    return SCM_BOOL_F;
-  
-  if (err)
+      pthread_mutex_unlock (&m->lock);
+      scm_misc_error (NULL, msg, SCM_EOL);
+    }
+  else if (m->level > 0)
+    m->level--;
+  else
     {
-      errno = err;
-      SCM_SYSERROR;
+      SCM next = dequeue (m->waiting);
+      if (scm_is_true (next))
+       {
+         m->owner = next;
+         unblock (SCM_THREAD_DATA (next));
+       }
+      else
+       m->owner = SCM_BOOL_F;
     }
-  
-  return SCM_BOOL_T;
+  pthread_mutex_unlock (&m->lock);
 }
-#undef FUNC_NAME
 
 SCM_DEFINE (scm_unlock_mutex, "unlock-mutex", 1, 0, 0,
            (SCM mx),
@@ -768,52 +830,95 @@ SCM_DEFINE (scm_unlock_mutex, "unlock-mutex", 1, 0, 0,
 "@code{unlock-mutex} will actually unlock the mutex. ")
 #define FUNC_NAME s_scm_unlock_mutex
 {
-  int err;
   SCM_VALIDATE_MUTEX (1, mx);
   
-  if (SCM_TYP16 (mx) == scm_tc16_fair_mutex)
-    {
-      err = fair_mutex_unlock (SCM_MUTEX_DATA (mx));
-      if (err == EPERM)
-       {
-         fair_mutex *m = SCM_MUTEX_DATA (mx);
-         if (m->owner != cur_thread)
-           {
-             if (m->owner == SCM_BOOL_F)
-               SCM_MISC_ERROR ("mutex not locked", SCM_EOL);
-             else
-               SCM_MISC_ERROR ("mutex not locked by this thread", SCM_EOL);
-           }
-       }
-    }
-  else
-    {
-      scm_t_mutex *m = SCM_MUTEX_DATA (mx);
-      err = scm_mutex_unlock (m);
-    }
-
-  if (err)
-    {
-      errno = err;
-      SCM_SYSERROR;
-    }
+  fat_mutex_unlock (SCM_MUTEX_DATA (mx));
   return SCM_BOOL_T;
 }
 #undef FUNC_NAME
 
-/*** Condition variables */
+/*** Fat condition variables */
+
+/* Like mutexes, we implement our own condition variables using the
+   primitives above.
+*/
+
+typedef struct {
+  pthread_mutex_t lock;
+  SCM waiting;               /* the threads waiting for this condition. */
+} fat_cond;
+
+static SCM
+fat_cond_mark (SCM cv)
+{
+  fat_cond *c = SCM_CONDVAR_DATA (cv);
+  return c->waiting;
+}
+
+static size_t
+fat_cond_free (SCM mx)
+{
+  fat_cond *c = SCM_CONDVAR_DATA (mx);
+  pthread_mutex_destroy (&c->lock);
+  scm_gc_free (c, sizeof (fat_cond), "condition-variable");
+  return 0;
+}
+
+static int
+fat_cond_print (SCM cv, SCM port, scm_print_state *pstate SCM_UNUSED)
+{
+  fat_cond *c = SCM_CONDVAR_DATA (cv);
+  scm_puts ("#<condition-variable ", port);
+  scm_uintprint ((scm_t_bits)c, 16, port);
+  scm_puts (">", port);
+  return 1;
+}
 
 SCM_DEFINE (scm_make_condition_variable, "make-condition-variable", 0, 0, 0,
            (void),
            "Make a new condition variable.")
 #define FUNC_NAME s_scm_make_condition_variable
 {
-  SCM cv = scm_make_smob (scm_tc16_condvar);
-  scm_i_plugin_cond_init (SCM_CONDVAR_DATA (cv), 0);
+  fat_cond *c;
+  SCM cv;
+
+  c = scm_gc_malloc (sizeof (fat_cond), "condition variable");
+  pthread_mutex_init (&c->lock, 0);
+  c->waiting = SCM_EOL;
+  SCM_NEWSMOB (cv, scm_tc16_condvar, (scm_t_bits) c);
+  c->waiting = make_queue ();
   return cv;
 }
 #undef FUNC_NAME
 
+static void
+fat_cond_timedwait (fat_cond *c,
+                   fat_mutex *m,
+                   const scm_t_timespec *waittime)
+{
+  int err;
+  pthread_mutex_lock (&c->lock);
+
+  while (1)
+    {
+      enqueue (c->waiting, cur_thread);
+      pthread_mutex_unlock (&c->lock);
+      fat_mutex_unlock (m); /*fixme* - not thread safe */
+      if (waittime == NULL)
+       err = block ();
+      else
+       err = timed_block (waittime);
+      fat_mutex_lock (m);
+      if (err)
+       {
+         errno = err;
+         scm_syserror (NULL);
+       }
+      /* XXX - check whether we have been signalled. */
+      break;
+    }
+}
+
 SCM_DEFINE (scm_timed_wait_condition_variable, "wait-condition-variable", 2, 1, 0,
            (SCM cv, SCM mx, SCM t),
 "Wait until @var{cond-var} has been signalled.  While waiting, "
@@ -828,87 +933,71 @@ SCM_DEFINE (scm_timed_wait_condition_variable, "wait-condition-variable", 2, 1,
 #define FUNC_NAME s_scm_timed_wait_condition_variable
 {
   scm_t_timespec waittime;
-  int err;
 
   SCM_VALIDATE_CONDVAR (1, cv);
   SCM_VALIDATE_MUTEX (2, mx);
-  if (!((SCM_TYP16 (cv) == scm_tc16_condvar
-        && SCM_TYP16 (mx) == scm_tc16_mutex)
-       || (SCM_TYP16 (cv) == scm_tc16_fair_condvar
-           && SCM_TYP16 (mx) == scm_tc16_fair_mutex)))
-    SCM_MISC_ERROR ("Condition variable and mutex are of different kinds.",
-                   SCM_EOL);
   
   if (!SCM_UNBNDP (t))
     {
       if (scm_is_pair (t))
        {
-         SCM_VALIDATE_UINT_COPY (3, SCM_CAR (t), waittime.tv_sec);
-         SCM_VALIDATE_UINT_COPY (3, SCM_CDR (t), waittime.tv_nsec);
-         waittime.tv_nsec *= 1000;
+         waittime.tv_sec = scm_to_ulong (SCM_CAR (t));
+         waittime.tv_nsec = scm_to_ulong (SCM_CAR (t)) * 1000;
        }
       else
        {
-         SCM_VALIDATE_UINT_COPY (3, t, waittime.tv_sec);
+         waittime.tv_sec = scm_to_ulong (t);
          waittime.tv_nsec = 0;
        }
     }
 
-  if (SCM_TYP16 (cv) == scm_tc16_fair_condvar)
-    err = fair_cond_timedwait (SCM_CONDVAR_DATA (cv),
-                              SCM_MUTEX_DATA (mx),
-                              SCM_UNBNDP (t) ? NULL : &waittime);
-  else
-    {
-      scm_t_cond *c = SCM_CONDVAR_DATA (cv);
-      scm_t_mutex *m = SCM_MUTEX_DATA (mx);
-      if (SCM_UNBNDP (t))
-       err = scm_cond_wait (c, m);
-      else
-       err = scm_cond_timedwait (c, m, &waittime);
-    }
-
-  if (err)
-    {
-      if (err == ETIMEDOUT)
-       return SCM_BOOL_F;
-      errno = err;
-      SCM_SYSERROR;
-    }
+  fat_cond_timedwait (SCM_CONDVAR_DATA (cv),
+                     SCM_MUTEX_DATA (mx),
+                     SCM_UNBNDP (t) ? NULL : &waittime);
   return SCM_BOOL_T;
 }
 #undef FUNC_NAME
 
+static int
+fat_cond_signal (fat_cond *c)
+{
+  SCM th;
+  pthread_mutex_lock (&c->lock);
+  if (scm_is_true (th = dequeue (c->waiting)))
+    unblock (SCM_THREAD_DATA (th));
+  pthread_mutex_unlock (&c->lock);
+  return 0;
+}
+
 SCM_DEFINE (scm_signal_condition_variable, "signal-condition-variable", 1, 0, 0,
            (SCM cv),
            "Wake up one thread that is waiting for @var{cv}")
 #define FUNC_NAME s_scm_signal_condition_variable
 {
   SCM_VALIDATE_CONDVAR (1, cv);
-  if (SCM_TYP16 (cv) == scm_tc16_fair_condvar)
-    fair_cond_signal (SCM_CONDVAR_DATA (cv));
-  else
-    {
-      scm_t_cond *c = SCM_CONDVAR_DATA (cv);
-      scm_cond_signal (c);
-    }
+  fat_cond_signal (SCM_CONDVAR_DATA (cv));
   return SCM_BOOL_T;
 }
 #undef FUNC_NAME
 
+static int
+fat_cond_broadcast (fat_cond *c)
+{
+  SCM th;
+  pthread_mutex_lock (&c->lock);
+  while (scm_is_true (th = dequeue (c->waiting)))
+    unblock (SCM_THREAD_DATA (th));
+  pthread_mutex_unlock (&c->lock);
+  return 0;
+}
+
 SCM_DEFINE (scm_broadcast_condition_variable, "broadcast-condition-variable", 1, 0, 0,
            (SCM cv),
            "Wake up all threads that are waiting for @var{cv}. ")
 #define FUNC_NAME s_scm_broadcast_condition_variable
 {
   SCM_VALIDATE_CONDVAR (1, cv);
-  if (SCM_TYP16 (cv) == scm_tc16_fair_condvar)
-    fair_cond_broadcast (SCM_CONDVAR_DATA (cv));
-  else
-    {
-      scm_t_cond *c = SCM_CONDVAR_DATA (cv);
-      scm_cond_broadcast (c);
-    }
+  fat_cond_broadcast (SCM_CONDVAR_DATA (cv));
   return SCM_BOOL_T;
 }
 #undef FUNC_NAME
@@ -936,31 +1025,20 @@ SCM_DEFINE (scm_broadcast_condition_variable, "broadcast-condition-variable", 1,
 void
 scm_threads_mark_stacks (void)
 {
-  volatile SCM c;
-
-  for (c = all_threads; !scm_is_null (c); c = SCM_CDR (c))
+  scm_thread *t;
+  for (t = all_threads; t; t = t->next_thread)
     {
-      scm_thread *t = SCM_THREAD_DATA (SCM_CAR (c));
-      if (!THREAD_INITIALIZED_P (t))
-       {
-         /* Not fully initialized yet. */
-         continue;
-       }
+      /* Check that thread has indeed been suspended.
+       */
+      assert (t->top);
 
-      if (t->top == NULL)
-       {
-         /* Thread has not been suspended, which should never happen.
-          */
-         abort ();
-       }
+      scm_gc_mark (t->handle);
 
-      {
 #if SCM_STACK_GROWS_UP
-       scm_mark_locations (t->base, t->top - t->base);
+      scm_mark_locations (t->base, t->top - t->base);
 #else
-       scm_mark_locations (t->top, t->base - t->top);
+      scm_mark_locations (t->top, t->base - t->top);
 #endif
-      }
       scm_mark_locations ((SCM_STACKITEM *) t->regs,
                          ((size_t) sizeof(t->regs)
                           / sizeof (SCM_STACKITEM)));
@@ -980,7 +1058,7 @@ scm_internal_select (int nfds,
 {
   int res, eno;
   scm_thread *c = scm_i_leave_guile ();
-  res = scm_i_plugin_select (nfds, readfds, writefds, exceptfds, timeout);
+  res = select (nfds, readfds, writefds, exceptfds, timeout);
   eno = errno;
   scm_i_enter_guile (c);
   SCM_ASYNC_TICK;
@@ -988,96 +1066,50 @@ scm_internal_select (int nfds,
   return res;
 }
 
-/* Low-level C API */
-
-SCM
-scm_spawn_thread (scm_t_catch_body body, void *body_data,
-                 scm_t_catch_handler handler, void *handler_data)
-{
-  return create_thread (body, body_data, handler, handler_data, SCM_BOOL_F);
-}
-
-scm_t_thread
-scm_c_scm2thread (SCM thread)
-{
-  return SCM_THREAD_DATA (thread)->thread;
-}
+/* Convenience API */
 
 int
-scm_mutex_lock (scm_t_mutex *m)
+scm_pthread_mutex_lock (pthread_mutex_t *mutex)
 {
   scm_thread *t = scm_i_leave_guile ();
-  int res = scm_i_plugin_mutex_lock (m);
+  int res = pthread_mutex_lock (mutex);
   scm_i_enter_guile (t);
   return res;
 }
 
-scm_t_rec_mutex *
-scm_make_rec_mutex ()
+static void
+unlock (void *data)
 {
-  scm_t_rec_mutex *m = scm_malloc (sizeof (scm_t_rec_mutex));
-  scm_i_plugin_rec_mutex_init (m, &scm_i_plugin_rec_mutex);
-  return m;
+  pthread_mutex_unlock ((pthread_mutex_t *)data);
 }
 
 void
-scm_rec_mutex_free (scm_t_rec_mutex *m)
-{
-  scm_i_plugin_rec_mutex_destroy (m);
-  free (m);
-}
-
-int
-scm_rec_mutex_lock (scm_t_rec_mutex *m)
+scm_frame_pthread_mutex_lock (pthread_mutex_t *mutex)
 {
-  scm_thread *t = scm_i_leave_guile ();
-  int res = scm_i_plugin_rec_mutex_lock (m);
-  scm_i_enter_guile (t);
-  return res;  
+  scm_pthread_mutex_lock (mutex);
+  scm_frame_unwind_handler (unlock, mutex, SCM_F_WIND_EXPLICITLY);
 }
 
 int
-scm_cond_wait (scm_t_cond *c, scm_t_mutex *m)
+scm_pthread_cond_wait (pthread_cond_t *cond, pthread_mutex_t *mutex)
 {
   scm_thread *t = scm_i_leave_guile ();
-  scm_i_plugin_cond_wait (c, m);
+  int res = pthread_cond_wait (cond, mutex);
   scm_i_enter_guile (t);
-  return 0;
+  return res;
 }
 
 int
-scm_cond_timedwait (scm_t_cond *c, scm_t_mutex *m, const scm_t_timespec *wt)
+scm_pthread_cond_timedwait (pthread_cond_t *cond,
+                           pthread_mutex_t *mutex,
+                           const scm_t_timespec *wt)
 {
   scm_thread *t = scm_i_leave_guile ();
-  int res = scm_i_plugin_cond_timedwait (c, m, wt);
+  int res = pthread_cond_timedwait (cond, mutex, wt);
   scm_i_enter_guile (t);
   return res;
 }
 
-void *
-scm_getspecific (scm_t_key k)
-{
-  return scm_i_plugin_getspecific (k);
-}
-
-int
-scm_setspecific (scm_t_key k, void *s)
-{
-  return scm_i_plugin_setspecific (k, s);
-}
-
-void
-scm_enter_guile ()
-{
-  scm_i_enter_guile (SCM_CURRENT_THREAD);
-}
-
-void
-scm_leave_guile ()
-{
-  scm_i_leave_guile ();
-}
-
 unsigned long
 scm_thread_usleep (unsigned long usecs)
 {
@@ -1109,19 +1141,45 @@ SCM_DEFINE (scm_current_thread, "current-thread", 0, 0, 0,
 }
 #undef FUNC_NAME
 
+static SCM
+scm_c_make_list (size_t n, SCM fill)
+{
+  SCM res = SCM_EOL;
+  while (n-- > 0)
+    res = scm_cons (fill, res);
+  return res;
+}
+
 SCM_DEFINE (scm_all_threads, "all-threads", 0, 0, 0,
            (void),
            "Return a list of all threads.")
 #define FUNC_NAME s_scm_all_threads
 {
-  return scm_list_copy (all_threads);
+  /* We can not allocate while holding the thread_admin_mutex because
+     of the way GC is done.
+  */
+  int n = thread_count;
+  scm_thread *t;
+  SCM list = scm_c_make_list (n, SCM_UNSPECIFIED), *l;
+
+  pthread_mutex_lock (&thread_admin_mutex);
+  l = &list;
+  for (t = all_threads; t && n > 0; t = t->next_thread)
+    {
+      SCM_SETCAR (*l, t->handle);
+      l = SCM_CDRLOC (*l);
+      n--;
+    }
+  *l = SCM_EOL;
+  pthread_mutex_unlock (&thread_admin_mutex);
+  return list;
 }
 #undef FUNC_NAME
 
 scm_root_state *
 scm_i_thread_root (SCM thread)
 {
-  return ((scm_thread *) SCM_THREAD_DATA (thread))->root;
+  return SCM_ROOT_STATE ((SCM_CURRENT_THREAD)->root);
 }
 
 SCM_DEFINE (scm_thread_exited_p, "thread-exited?", 1, 0, 0,
@@ -1144,7 +1202,7 @@ scm_c_thread_exited_p (SCM thread)
 }
 #undef FUNC_NAME
 
-static scm_t_cond wake_up_cond;
+static pthread_cond_t wake_up_cond;
 int scm_i_thread_go_to_sleep;
 static int threads_initialized_p = 0;
 
@@ -1153,22 +1211,18 @@ scm_i_thread_put_to_sleep ()
 {
   if (threads_initialized_p)
     {
-      SCM threads;
+      scm_thread *t;
 
       /* We leave Guile completely before locking the
         thread_admin_mutex.  This ensures that other threads can put
         us to sleep while we block on that mutex.
       */
       scm_i_leave_guile ();
-      scm_i_plugin_mutex_lock (&thread_admin_mutex);
-      threads = all_threads;
+      pthread_mutex_lock (&thread_admin_mutex);
       /* Signal all threads to go to sleep */
       scm_i_thread_go_to_sleep = 1;
-      for (; !scm_is_null (threads); threads = SCM_CDR (threads))
-       {
-         scm_thread *t = SCM_THREAD_DATA (SCM_CAR (threads));
-         scm_i_plugin_mutex_lock (&t->heap_mutex);
-       }
+      for (t = all_threads; t; t = t->next_thread)
+       pthread_mutex_lock (&t->heap_mutex);
       scm_i_thread_go_to_sleep = 0;
     }
 }
@@ -1176,14 +1230,12 @@ scm_i_thread_put_to_sleep ()
 void
 scm_i_thread_invalidate_freelists ()
 {
-  /* Don't need to lock thread_admin_mutex here since we are single threaded */
-  SCM threads = all_threads;
-  for (; !scm_is_null (threads); threads = SCM_CDR (threads))
-    if (SCM_CAR (threads) != cur_thread)
-      {
-       scm_thread *t = SCM_THREAD_DATA (SCM_CAR (threads));
-       t->clear_freelists_p = 1;
-      }
+  /* thread_admin_mutex is already locked. */
+
+  scm_thread *t;
+  for (t = all_threads; t; t = t->next_thread)
+    if (t != SCM_CURRENT_THREAD)
+      t->clear_freelists_p = 1;
 }
 
 void
@@ -1191,15 +1243,11 @@ scm_i_thread_wake_up ()
 {
   if (threads_initialized_p)
     {
-      SCM threads;
-      threads = all_threads;
-      scm_i_plugin_cond_broadcast (&wake_up_cond);
-      for (; !scm_is_null (threads); threads = SCM_CDR (threads))
-       {
-         scm_thread *t = SCM_THREAD_DATA (SCM_CAR (threads));
-         scm_i_plugin_mutex_unlock (&t->heap_mutex);
-       }
-      scm_i_plugin_mutex_unlock (&thread_admin_mutex);
+      scm_thread *t;
+      pthread_cond_broadcast (&wake_up_cond);
+      for (t = all_threads; t; t = t->next_thread)
+       pthread_mutex_unlock (&t->heap_mutex);
+      pthread_mutex_unlock (&thread_admin_mutex);
       scm_i_enter_guile (SCM_CURRENT_THREAD);
     }
 }
@@ -1209,92 +1257,73 @@ scm_i_thread_sleep_for_gc ()
 {
   scm_thread *t;
   t = suspend ();
-  scm_i_plugin_cond_wait (&wake_up_cond, &t->heap_mutex);
+  pthread_cond_wait (&wake_up_cond, &t->heap_mutex);
   resume (t);
 }
 
-scm_t_mutex scm_i_critical_section_mutex;
-scm_t_rec_mutex scm_i_defer_mutex;
-
-#if SCM_USE_PTHREAD_THREADS
-# include "libguile/pthread-threads.c"
-#endif
-#include "libguile/threads-plugin.c"
+pthread_mutex_t scm_i_critical_section_mutex = PTHREAD_MUTEX_INITIALIZER;
 
 /*** Initialization */
 
+pthread_key_t scm_i_freelist, scm_i_freelist2;
+pthread_mutex_t scm_i_misc_mutex;
+
 void
-scm_threads_prehistory ()
-{
-  scm_thread *t;
-#if SCM_USE_PTHREAD_THREADS
-  /* Must be called before any initialization of a mutex. */
-  scm_init_pthread_threads ();
-#endif  
-  scm_i_plugin_mutex_init (&thread_admin_mutex, &scm_i_plugin_mutex);
-  scm_i_plugin_cond_init (&wake_up_cond, 0);
-  scm_i_plugin_mutex_init (&scm_i_critical_section_mutex, &scm_i_plugin_mutex);
-  thread_count = 1;
-  scm_i_plugin_key_create (&scm_i_thread_key, 0);
-  scm_i_plugin_key_create (&scm_i_root_state_key, 0);
-  scm_i_plugin_rec_mutex_init (&scm_i_defer_mutex, &scm_i_plugin_rec_mutex);
-  /* Allocate a fake thread object to be used during bootup. */
-  t = malloc (sizeof (scm_thread));
-  t->base = NULL;
-  t->clear_freelists_p = 0;
-  scm_i_plugin_mutex_init (&t->heap_mutex, &scm_i_plugin_mutex);
-  scm_setspecific (scm_i_thread_key, t);
-  scm_i_enter_guile (t);
+scm_threads_prehistory (SCM_STACKITEM *base)
+{
+  pthread_mutex_init (&thread_admin_mutex, NULL);
+  pthread_mutex_init (&scm_i_misc_mutex, NULL);
+  pthread_cond_init (&wake_up_cond, NULL);
+  pthread_mutex_init (&scm_i_critical_section_mutex, NULL);
+  pthread_key_create (&scm_i_thread_key, on_thread_exit);
+  pthread_key_create (&scm_i_root_key, NULL);
+  pthread_key_create (&scm_i_freelist, NULL);
+  pthread_key_create (&scm_i_freelist2, NULL);
+  
+  guilify_self_1 (base);
 }
 
 scm_t_bits scm_tc16_thread;
-scm_t_bits scm_tc16_future;
 scm_t_bits scm_tc16_mutex;
-scm_t_bits scm_tc16_fair_mutex;
 scm_t_bits scm_tc16_condvar;
-scm_t_bits scm_tc16_fair_condvar;
 
 void
-scm_init_threads (SCM_STACKITEM *base)
+scm_init_threads ()
 {
-  SCM thread;
   scm_tc16_thread = scm_make_smob_type ("thread", sizeof (scm_thread));
-  scm_tc16_mutex = scm_make_smob_type ("mutex", sizeof (scm_t_mutex));
-  scm_tc16_fair_mutex = scm_make_smob_type ("fair-mutex",
-                                           sizeof (fair_mutex));
-  scm_tc16_condvar = scm_make_smob_type ("condition-variable",
-                                        sizeof (scm_t_cond));
-  scm_tc16_fair_condvar = scm_make_smob_type ("fair-condition-variable",
-                                             sizeof (fair_cond));
-
-  thread = make_thread (SCM_BOOL_F);
-  /* Replace initial fake thread with a real thread object */
-  free (SCM_CURRENT_THREAD);
-  scm_setspecific (scm_i_thread_key, SCM_THREAD_DATA (thread));
-  scm_i_enter_guile (SCM_CURRENT_THREAD);
-
-  /* root is set later from init.c */
-  init_thread_creatant (thread, base);
-  thread_count = 1;
-  scm_gc_register_root (&all_threads);
-  all_threads = scm_cons (thread, SCM_EOL);
-
   scm_set_smob_mark (scm_tc16_thread, thread_mark);
   scm_set_smob_print (scm_tc16_thread, thread_print);
   scm_set_smob_free (scm_tc16_thread, thread_free);
 
-  scm_set_smob_mark (scm_tc16_fair_mutex, fair_mutex_mark);
+  scm_tc16_mutex = scm_make_smob_type ("mutex", sizeof (fat_mutex));
+  scm_set_smob_mark (scm_tc16_mutex, fat_mutex_mark);
+  scm_set_smob_print (scm_tc16_mutex, fat_mutex_print);
+  scm_set_smob_free (scm_tc16_mutex, fat_mutex_free);
 
-  scm_set_smob_mark (scm_tc16_fair_condvar, fair_cond_mark);
+  scm_tc16_condvar = scm_make_smob_type ("condition-variable",
+                                        sizeof (fat_cond));
+  scm_set_smob_mark (scm_tc16_condvar, fat_cond_mark);
+  scm_set_smob_print (scm_tc16_condvar, fat_cond_print);
+  scm_set_smob_free (scm_tc16_condvar, fat_cond_free);
 
+  scm_i_root_root = SCM_BOOL_F;
+  guilify_self_2 (SCM_BOOL_F);
   threads_initialized_p = 1;
 }
 
-/* scm_i_misc_mutex is intended for miscellaneous uses, to protect
-   operations which are non-reentrant or non-thread-safe but which are
-   either not important enough or not used often enough to deserve their own
-   private mutex.  */
-SCM_GLOBAL_MUTEX (scm_i_misc_mutex);
+void
+scm_init_threads_root_root ()
+{
+  scm_root_state *rr;
+
+  scm_i_root_root = scm_permanent_object (scm_make_root (SCM_BOOL_F));
+  rr = SCM_ROOT_STATE (scm_i_root_root);
+  rr->cur_inp = scm_cur_inp;
+  rr->cur_outp = scm_cur_outp;
+  rr->cur_errp = scm_cur_errp;
+  rr->fluids = scm_root->fluids;
+  scm_i_copy_fluids (rr);
+}
 
 void
 scm_init_thread_procs ()
index 4faf54c..8b707f5 100644 (file)
 #include "libguile/throw.h"
 #include "libguile/root.h"
 #include "libguile/iselect.h"
-#include "libguile/threads-plugin.h"
+
+#include <pthread.h>
+
 \f
 
 /* 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;
-SCM_API scm_t_bits scm_tc16_fair_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;
 
 #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_FAIR_MUTEX_P (a), \
+ SCM_ASSERT_TYPE (SCM_MUTEXP (a), \
                   a, pos, FUNC_NAME, "mutex");
 
 #define SCM_VALIDATE_CONDVAR(pos, a) \
- SCM_ASSERT_TYPE (SCM_CONDVARP (a) || SCM_FAIR_CONDVAR_P (a), \
+ SCM_ASSERT_TYPE (SCM_CONDVARP (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
-   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.
+   code which can block.
  */
 
 SCM_API void scm_enter_guile (void);
 SCM_API void scm_leave_guile (void);
 
-/* 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);
+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);
 
 /* Critical sections */
 
 /* This is the generic critical section for places where we are too
    lazy to allocate a specific mutex. */
-extern scm_t_mutex scm_i_critical_section_mutex;
+extern pthread_mutex_t scm_i_critical_section_mutex;
 
 #define SCM_CRITICAL_SECTION_START \
-  scm_mutex_lock (&scm_i_critical_section_mutex)
+  scm_pthread_mutex_lock (&scm_i_critical_section_mutex)
 #define SCM_CRITICAL_SECTION_END \
-  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;
+  pthread_mutex_unlock (&scm_i_critical_section_mutex)
 
 extern int scm_i_thread_go_to_sleep;
 
@@ -193,8 +117,12 @@ 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 (void);
+void scm_threads_prehistory (SCM_STACKITEM *);
 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 { \
@@ -211,12 +139,11 @@ 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_fair_mutex (void);
+SCM_API SCM scm_make_recursive_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);
@@ -232,17 +159,24 @@ 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 *) scm_i_plugin_getspecific (scm_i_thread_key))
-extern scm_t_key scm_i_thread_key;
+  ((scm_thread *) pthread_getspecific (scm_i_thread_key))
+SCM_API pthread_key_t 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 scm_t_mutex scm_i_misc_mutex;
+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);
 
 #endif  /* SCM_THREADS_H */
 
index b5bbbae..60fe663 100644 (file)
@@ -460,7 +460,7 @@ scm_handle_by_message (void *handler_data, SCM tag, SCM args)
     }
 
   handler_message (handler_data, tag, args);
-  exit (2);
+  pthread_exit (NULL);
 }
 
 
index 9e248e6..ee6c5dd 100644 (file)
@@ -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_mutex_lock (&scm_i_port_table_mutex);
+  scm_pthread_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));
-  scm_mutex_unlock (&scm_i_port_table_mutex);
+  pthread_mutex_unlock (&scm_i_port_table_mutex);
   return z;
 }
 #undef FUNC_NAME