fix include-order problem in net_db.c for mingw
[bpt/guile.git] / libguile / threads.c
index c07c853..a3aee0f 100644 (file)
@@ -1,4 +1,6 @@
-/* Copyright (C) 1995,1996,1997,1998,2000,2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
+/* Copyright (C) 1995, 1996, 1997, 1998, 2000, 2001, 2002, 2003, 2004,
+ *   2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012
+ *   Free Software Foundation, Inc.
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public License
@@ -25,6 +27,7 @@
 #include "libguile/bdw-gc.h"
 #include "libguile/_scm.h"
 
+#include <stdlib.h>
 #if HAVE_UNISTD_H
 #include <unistd.h>
 #endif
 #include <sys/time.h>
 #endif
 
+#if HAVE_PTHREAD_NP_H
+# include <pthread_np.h>
+#endif
+
 #include <assert.h>
 #include <fcntl.h>
 #include <nproc.h>
@@ -141,6 +148,29 @@ get_thread_stack_base ()
   return pthread_get_stackaddr_np (pthread_self ());
 }
 
+#elif HAVE_PTHREAD_ATTR_GET_NP
+/* This one is for FreeBSD 9.  */
+static void *
+get_thread_stack_base ()
+{
+  pthread_attr_t attr;
+  void *start, *end;
+  size_t size;
+
+  pthread_attr_init (&attr);
+  pthread_attr_get_np (pthread_self (), &attr);
+  pthread_attr_getstack (&attr, &start, &size);
+  pthread_attr_destroy (&attr);
+
+  end = (char *)start + size;
+
+#if SCM_STACK_GROWS_UP
+  return start;
+#else
+  return end;
+#endif
+}
+
 #else 
 #error Threads enabled with old BDW-GC, but missing get_thread_stack_base impl.  Please upgrade to libgc >= 7.1.
 #endif
@@ -478,7 +508,7 @@ static SCM scm_i_default_dynamic_state;
 
 /* Run when a fluid is collected.  */
 void
-scm_i_reset_fluid (size_t n, SCM val)
+scm_i_reset_fluid (size_t n)
 {
   scm_i_thread *t;
 
@@ -489,7 +519,7 @@ scm_i_reset_fluid (size_t n, SCM val)
         SCM v = SCM_I_DYNAMIC_STATE_FLUIDS (t->dynamic_state);
           
         if (n < SCM_SIMPLE_VECTOR_LENGTH (v))
-          SCM_SIMPLE_VECTOR_SET (v, n, val);
+          SCM_SIMPLE_VECTOR_SET (v, n, SCM_UNDEFINED);
       }
   scm_i_pthread_mutex_unlock (&thread_admin_mutex);
 }
@@ -521,7 +551,7 @@ guilify_self_1 (struct GC_stack_base *base)
   t.critical_section_level = 0;
   t.base = base->mem_base;
 #ifdef __ia64__
-  t.register_backing_store_base = base->reg-base;
+  t.register_backing_store_base = base->reg_base;
 #endif
   t.continuation_root = SCM_EOL;
   t.continuation_base = t.base;
@@ -590,6 +620,9 @@ guilify_self_2 (SCM parent)
 
   t->join_queue = make_queue ();
   t->block_asyncs = 0;
+
+  /* See note in finalizers.c:queue_finalizer_async().  */
+  GC_invoke_finalizers ();
 }
 
 \f
@@ -663,10 +696,11 @@ do_thread_exit (void *v)
 
          scm_i_pthread_mutex_lock (&m->lock);
 
-         /* Since MUTEX is in `t->mutexes', T must be its owner.  */
-         assert (scm_is_eq (m->owner, t->handle));
-
-         unblock_from_queue (m->waiting);
+         /* Check whether T owns MUTEX.  This is usually the case, unless
+            T abandoned MUTEX; in that case, T is no longer its owner (see
+            `fat_mutex_lock') but MUTEX is still in `t->mutexes'.  */
+         if (scm_is_eq (m->owner, t->handle))
+           unblock_from_queue (m->waiting);
 
          scm_i_pthread_mutex_unlock (&m->lock);
        }
@@ -696,6 +730,10 @@ on_thread_exit (void *v)
   /* This handler is executed in non-guile mode.  */
   scm_i_thread *t = (scm_i_thread *) v, **tp;
 
+  /* If we were canceled, we were unable to clear `t->guile_mode', so do
+     it here.  */
+  t->guile_mode = 0;
+
   /* If this thread was cancelled while doing a cond wait, it will
      still have a mutex locked, so we unlock it here. */
   if (t->held_mutex)
@@ -831,16 +869,10 @@ scm_init_guile ()
   else
     {
       fprintf (stderr, "Failed to get stack base for current thread.\n");
-      exit (1);
+      exit (EXIT_FAILURE);
     }
 }
 
-SCM_UNUSED static void
-scm_leave_guile_cleanup (void *x)
-{
-  on_thread_exit (SCM_I_CURRENT_THREAD);
-}
-
 struct with_guile_args
 {
   GC_fn_type func;
@@ -1008,6 +1040,7 @@ SCM_DEFINE (scm_call_with_new_thread, "call-with-new-thread", 1, 1, 0,
   SCM_ASSERT (SCM_UNBNDP (handler) || scm_is_true (scm_procedure_p (handler)),
              handler, SCM_ARG2, FUNC_NAME);
 
+  GC_collect_a_little ();
   data.parent = scm_current_dynamic_state ();
   data.thunk = thunk;
   data.handler = handler;
@@ -1103,6 +1136,8 @@ scm_spawn_thread (scm_t_catch_body body, void *body_data,
   scm_i_scm_pthread_cond_wait (&data.cond, &data.mutex);
   scm_i_pthread_mutex_unlock (&data.mutex);
 
+  assert (SCM_I_IS_THREAD (data.thread));
+
   return data.thread;
 }
 
@@ -1372,7 +1407,9 @@ fat_mutex_lock (SCM mutex, scm_t_timespec *timeout, SCM owner, int *ret)
            {
              scm_i_thread *t = SCM_I_THREAD_DATA (new_owner);
 
-             scm_i_pthread_mutex_unlock (&m->lock);
+             /* FIXME: The order in which `t->admin_mutex' and
+                `m->lock' are taken differs from that in
+                `on_thread_exit', potentially leading to deadlocks.  */
              scm_i_pthread_mutex_lock (&t->admin_mutex);
 
              /* Only keep a weak reference to MUTEX so that it's not
@@ -1383,7 +1420,6 @@ fat_mutex_lock (SCM mutex, scm_t_timespec *timeout, SCM owner, int *ret)
              t->mutexes = scm_weak_car_pair (mutex, t->mutexes);
 
              scm_i_pthread_mutex_unlock (&t->admin_mutex);
-             scm_i_pthread_mutex_lock (&m->lock);
            }
          *ret = 1;
          break;
@@ -1443,11 +1479,12 @@ SCM scm_lock_mutex (SCM mx)
 
 SCM_DEFINE (scm_lock_mutex_timed, "lock-mutex", 1, 2, 0,
            (SCM m, SCM timeout, SCM owner),
-"Lock @var{mutex}. If the mutex is already locked, the calling thread "
-"blocks until the mutex becomes available. The function returns when "
-"the calling thread owns the lock on @var{mutex}.  Locking a mutex that "
-"a thread already owns will succeed right away and will not block the "
-"thread.  That is, Guile's mutexes are @emph{recursive}. ")
+           "Lock mutex @var{m}. If the mutex is already locked, the calling\n"
+           "thread blocks until the mutex becomes available. The function\n"
+           "returns when the calling thread owns the lock on @var{m}.\n"
+           "Locking a mutex that a thread already owns will succeed right\n"
+           "away and will not block the thread.  That is, Guile's mutexes\n"
+           "are @emph{recursive}.")
 #define FUNC_NAME s_scm_lock_mutex_timed
 {
   SCM exception;
@@ -1462,6 +1499,9 @@ SCM_DEFINE (scm_lock_mutex_timed, "lock-mutex", 1, 2, 0,
       waittime = &cwaittime;
     }
 
+  if (!SCM_UNBNDP (owner) && !scm_is_false (owner))
+    SCM_VALIDATE_THREAD (3, owner);
+
   exception = fat_mutex_lock (m, waittime, owner, &ret);
   if (!scm_is_false (exception))
     scm_ithrow (SCM_CAR (exception), scm_list_1 (SCM_CDR (exception)), 1);
@@ -1734,9 +1774,9 @@ SCM_DEFINE (scm_make_condition_variable, "make-condition-variable", 0, 0, 0,
 
 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, "
-"@var{mutex} is atomically unlocked (as with @code{unlock-mutex}) and "
-"is locked again when this function returns.  When @var{time} is given, "
+"Wait until condition variable @var{cv} has been signalled.  While waiting, "
+"mutex @var{mx} is atomically unlocked (as with @code{unlock-mutex}) and "
+"is locked again when this function returns.  When @var{t} is given, "
 "it specifies a point in time where the waiting should be aborted.  It "
 "can be either a integer as returned by @code{current-time} or a pair "
 "as returned by @code{gettimeofday}.  When the waiting is aborted the "
@@ -2198,6 +2238,21 @@ scm_ia64_ar_bsp (const void *opaque)
   return (void *) ctx->uc_mcontext.sc_ar_bsp;
 }
 # endif /* linux */
+# ifdef __FreeBSD__
+#  include <ucontext.h>
+void *
+scm_ia64_register_backing_store_base (void)
+{
+  return (void *)0x8000000000000000;
+}
+void *
+scm_ia64_ar_bsp (const void *opaque)
+{
+  const ucontext_t *ctx = opaque;
+  return (void *)(ctx->uc_mcontext.mc_special.bspstore
+                  + ctx->uc_mcontext.mc_special.ndirty);
+}
+# endif /* __FreeBSD__ */
 #endif /* __ia64__ */