This patch will add support for PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP,
PTHREAD_NORMAL_MUTEX_INITIALIZER_NP and
PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP (+ some small bugfixes).
Attached are also testcases for these initializers.
The initializer names are borrowed from linux nptl.

These initializers can be used for example to enable thread safe stdio
in newlib without moving __sinit. I really want to get this fixed.

Thomas

P.S.: I will be on winter vacation next week, no reply during that
time.


2004-02-20  Thomas Pfaff  <[EMAIL PROTECTED]>

        * winsup.api/pthread/mutex8e.c: New testcase.
        * winsup.api/pthread/mutex8n.c: Ditto.
        * winsup.api/pthread/mutex8r.c: Ditto.

and

2004-02-20  Thomas Pfaff  <[EMAIL PROTECTED]>

        * include/pthread.h (PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP):
        New define.
        (PTHREAD_NORMAL_MUTEX_INITIALIZER_NP): Ditto.
        (PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP): Ditto.
        * thread.cc (pthread_mutex::is_good_initializer):
        Check for all posssible initializers
        (pthread_mutex::is_good_initializer_or_object): Ditto.
        (pthread_mutex::is_good_initializer_or_bad_object): Ditto.
        (verifyable_object_isvalid): Support up to three static
        initializers.
        (verifyable_object_isvalid (void const *,long)): Remove.
        (pthread_cond::is_good_initializer_or_bad_object): Remove
        unneeded objectState var.
        (pthread_cond::init): Condition remains unchanged when creation
        has failed.
        (pthread_rwlock::is_good_initializer_or_bad_object): Remove
        unneeded objectState var.
        (pthread_rwlock::init): Rwlock remains unchanged when creation
        has failed.
        (pthread_mutex::init): Remove obsolete comment.
        Mutex remains unchanged when creation has failed. Add support
        for new initializers.
        (pthread_mutex_getprioceiling): Do not create mutex,
        just return ENOSYS.
        (pthread_mutex_lock): Simplify.
        (pthread_mutex_trylock): Remove unneeded local themutex.
        (pthread_mutex_unlock): Just return EPERM if mutex is not
        initialized.
        (pthread_mutex_setprioceiling): Do not create mutex,
        just return ENOSYS.
        * thread.h (verifyable_object_isvalid): Support up to three
        static initializers.
        (verifyable_object_isvalid (void const *,long)): Remove
        prototype.
        (pthread_mutex::init): Add optional initializer to parameter
        list.


/* 
 * mutex8r.c
 *
 * Tests PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP.
 *
 * Depends on API functions: 
 *      pthread_mutex_lock()
 *      pthread_mutex_unlock()
 */

#include "test.h"
 
pthread_mutex_t mutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;

int
main()
{
  assert(mutex == PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP);

  assert(pthread_mutex_lock(&mutex) == 0);

  assert(mutex != PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP);

  assert(mutex != NULL);

  assert(pthread_mutex_lock(&mutex) == 0);

  assert(pthread_mutex_unlock(&mutex) == 0);

  assert(pthread_mutex_unlock(&mutex) == 0);

  assert(pthread_mutex_destroy(&mutex) == 0);

  assert(mutex == NULL);

  return 0;
}
/* 
 * mutex8n.c
 *
 * Tests PTHREAD_NORMAL_MUTEX_INITIALIZER_NP.
 * Thread locks mutex twice (recursive lock).
 * The thread should deadlock.
 *
 * Depends on API functions: 
 *      pthread_create()
 *      pthread_mutex_init()
 *      pthread_mutex_lock()
 *      pthread_mutex_unlock()
 */

#include "test.h"

static int lockCount = 0;

pthread_mutex_t mutex = PTHREAD_NORMAL_MUTEX_INITIALIZER_NP;

void * locker(void * arg)
{
  assert(pthread_mutex_lock(&mutex) == 0);
  lockCount++;

  /* Should wait here (deadlocked) */
  assert(pthread_mutex_lock(&mutex) == 0);
  lockCount++;
  assert(pthread_mutex_unlock(&mutex) == 0);

  return (void *) 555;
}
 
int
main()
{
  pthread_t t;

  assert(pthread_create(&t, NULL, locker, NULL) == 0);

  Sleep(1000);

  assert(lockCount == 1);

  /*
   * Should succeed even though we don't own the lock
   * because FAST mutexes don't check ownership.
   */
  assert(pthread_mutex_unlock(&mutex) == 0);

  Sleep (1000);

  assert(lockCount == 2);

  exit(0);

  /* Never reached */
  return 0;
}

/* 
 * mutex8e.c
 *
 * Tests PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP.
 *
 * Depends on API functions: 
 *      pthread_mutex_lock()
 *      pthread_mutex_unlock()
 */

#include "test.h"
 
pthread_mutex_t mutex = PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP;

int
main()
{
  assert(mutex == PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP);

  assert(pthread_mutex_lock(&mutex) == 0);

  assert(mutex != PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP);

  assert(mutex != NULL);

  assert(pthread_mutex_lock(&mutex) == EDEADLK);

  assert(pthread_mutex_unlock(&mutex) == 0);

  assert(pthread_mutex_destroy(&mutex) == 0);

  assert(mutex == NULL);

  return 0;
}
diff -urp cygwin.org/include/pthread.h cygwin/include/pthread.h
--- cygwin.org/include/pthread.h        2004-02-19 08:39:17.438017600 +0100
+++ cygwin/include/pthread.h    2004-02-19 08:44:38.890243200 +0100
@@ -55,7 +55,10 @@ extern "C"
 #define PTHREAD_MUTEX_NORMAL 2
 #define PTHREAD_MUTEX_DEFAULT PTHREAD_MUTEX_ERRORCHECK
 /* this should be too low to ever be a valid address */
-#define PTHREAD_MUTEX_INITIALIZER (pthread_mutex_t)20
+#define PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP (pthread_mutex_t)18
+#define PTHREAD_NORMAL_MUTEX_INITIALIZER_NP (pthread_mutex_t)19
+#define PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP (pthread_mutex_t)20
+#define PTHREAD_MUTEX_INITIALIZER PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP
 #define PTHREAD_ONCE_INIT { PTHREAD_MUTEX_INITIALIZER, 0 }
 #define PTHREAD_PRIO_INHERIT
 #define PTHREAD_PRIO_NONE
diff -urp cygwin.org/thread.cc cygwin/thread.cc
--- cygwin.org/thread.cc        2004-02-19 08:38:58.490772800 +0100
+++ cygwin/thread.cc    2004-02-19 08:44:38.970358400 +0100
@@ -1354,7 +1354,10 @@ pthread_mutex::is_good_object (pthread_m
 bool
 pthread_mutex::is_good_initializer (pthread_mutex_t const *mutex)
 {
-  if (verifyable_object_isvalid (mutex, PTHREAD_MUTEX_MAGIC, 
PTHREAD_MUTEX_INITIALIZER) != VALID_STATIC_OBJECT)
+  if (verifyable_object_isvalid (mutex, PTHREAD_MUTEX_MAGIC,
+                                 PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP,
+                                 PTHREAD_NORMAL_MUTEX_INITIALIZER_NP,
+                                 PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP) != 
VALID_STATIC_OBJECT)
     return false;
   return true;
 }
@@ -1362,7 +1365,10 @@ pthread_mutex::is_good_initializer (pthr
 bool
 pthread_mutex::is_good_initializer_or_object (pthread_mutex_t const *mutex)
 {
-  if (verifyable_object_isvalid (mutex, PTHREAD_MUTEX_MAGIC, 
PTHREAD_MUTEX_INITIALIZER) == INVALID_OBJECT)
+  if (verifyable_object_isvalid (mutex, PTHREAD_MUTEX_MAGIC,
+                                 PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP,
+                                 PTHREAD_NORMAL_MUTEX_INITIALIZER_NP,
+                                 PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP) == 
INVALID_OBJECT)
     return false;
   return true;
 }
@@ -1370,9 +1376,11 @@ pthread_mutex::is_good_initializer_or_ob
 bool
 pthread_mutex::is_good_initializer_or_bad_object (pthread_mutex_t const *mutex)
 {
-  verifyable_object_state objectState = verifyable_object_isvalid (mutex, 
PTHREAD_MUTEX_MAGIC, PTHREAD_MUTEX_INITIALIZER);
-  if (objectState == VALID_OBJECT)
-       return false;
+  if (verifyable_object_isvalid (mutex, PTHREAD_MUTEX_MAGIC,
+                                 PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP,
+                                 PTHREAD_NORMAL_MUTEX_INITIALIZER_NP,
+                                 PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP) == 
VALID_OBJECT)
+    return false;
   return true;
 }
 
@@ -1756,12 +1764,15 @@ check_valid_pointer (void const *pointer
 }
 
 verifyable_object_state
-verifyable_object_isvalid (void const * objectptr, long magic, void *static_ptr)
+verifyable_object_isvalid (void const * objectptr, long magic, void *static_ptr1,
+                           void *static_ptr2, void *static_ptr3)
 {
   verifyable_object **object = (verifyable_object **)objectptr;
   if (check_valid_pointer (object))
     return INVALID_OBJECT;
-  if (static_ptr && *object == static_ptr)
+  if ((static_ptr1 && *object == static_ptr1) ||
+      (static_ptr2 && *object == static_ptr2) ||
+      (static_ptr3 && *object == static_ptr3))
     return VALID_STATIC_OBJECT;
   if (!*object)
     return INVALID_OBJECT;
@@ -1772,12 +1783,6 @@ verifyable_object_isvalid (void const * 
   return VALID_OBJECT;
 }
 
-verifyable_object_state
-verifyable_object_isvalid (void const * objectptr, long magic)
-{
-  return verifyable_object_isvalid (objectptr, magic, NULL);
-}
-
 DWORD WINAPI
 pthread::thread_init_wrapper (void *arg)
 {
@@ -2371,9 +2376,8 @@ pthread_cond::is_good_initializer_or_obj
 bool
 pthread_cond::is_good_initializer_or_bad_object (pthread_cond_t const *cond)
 {
-  verifyable_object_state objectState = verifyable_object_isvalid (cond, 
PTHREAD_COND_MAGIC, PTHREAD_COND_INITIALIZER);
-  if (objectState == VALID_OBJECT)
-       return false;
+  if (verifyable_object_isvalid (cond, PTHREAD_COND_MAGIC, PTHREAD_COND_INITIALIZER) 
== VALID_OBJECT)
+    return false;
   return true;
 }
 
@@ -2398,6 +2402,9 @@ pthread_cond_destroy (pthread_cond_t *co
 int
 pthread_cond::init (pthread_cond_t *cond, const pthread_condattr_t *attr)
 {
+
+  pthread_cond_t new_cond;
+
   if (attr && !pthread_condattr::is_good_object (attr))
     return EINVAL;
 
@@ -2409,15 +2416,17 @@ pthread_cond::init (pthread_cond_t *cond
       return EBUSY;
     }
 
-  *cond = new pthread_cond (attr ? (*attr) : NULL);
-  if (!is_good_object (cond))
+  new_cond = new pthread_cond (attr ? (*attr) : NULL);
+  if (!is_good_object (&new_cond))
     {
-      delete (*cond);
-      *cond = NULL;
+      delete new_cond;
       cond_initialization_lock.unlock ();
       return EAGAIN;
     }
+
+  *cond = new_cond;
   cond_initialization_lock.unlock ();
+
   return 0;
 }
 
@@ -2569,9 +2578,8 @@ pthread_rwlock::is_good_initializer_or_o
 bool
 pthread_rwlock::is_good_initializer_or_bad_object (pthread_rwlock_t const *rwlock)
 {
-  verifyable_object_state objectState = verifyable_object_isvalid (rwlock, 
PTHREAD_RWLOCK_MAGIC, PTHREAD_RWLOCK_INITIALIZER);
-  if (objectState == VALID_OBJECT)
-       return false;
+  if (verifyable_object_isvalid (rwlock, PTHREAD_RWLOCK_MAGIC, 
PTHREAD_RWLOCK_INITIALIZER) == VALID_OBJECT)
+    return false;
   return true;
 }
 
@@ -2596,6 +2604,8 @@ pthread_rwlock_destroy (pthread_rwlock_t
 int
 pthread_rwlock::init (pthread_rwlock_t *rwlock, const pthread_rwlockattr_t *attr)
 {
+  pthread_rwlock_t new_rwlock;
+
   if (attr && !pthread_rwlockattr::is_good_object (attr))
     return EINVAL;
 
@@ -2607,15 +2617,17 @@ pthread_rwlock::init (pthread_rwlock_t *
       return EBUSY;
     }
 
-  *rwlock = new pthread_rwlock (attr ? (*attr) : NULL);
-  if (!is_good_object (rwlock))
+  new_rwlock = new pthread_rwlock (attr ? (*attr) : NULL);
+  if (!is_good_object (&new_rwlock))
     {
-      delete (*rwlock);
-      *rwlock = NULL;
+      delete new_rwlock;
       rwlock_initialization_lock.unlock ();
       return EAGAIN;
     }
+
+  *rwlock = new_rwlock;
   rwlock_initialization_lock.unlock ();
+
   return 0;
 }
 
@@ -2764,18 +2776,13 @@ pthread_equal (pthread_t t1, pthread_t t
 
 /* Mutexes  */
 
-/* FIXME: there's a potential race with PTHREAD_MUTEX_INITALIZER:
-   the mutex is not actually inited until the first use.
-   So two threads trying to lock/trylock may collide.
-   Solution: we need a global mutex on mutex creation, or possibly simply
-   on all constructors that allow INITIALIZER macros.
-   the lock should be very small: only around the init routine, not
-   every test, or all mutex access will be synchronised.  */
-
 int
 pthread_mutex::init (pthread_mutex_t *mutex,
-                     const pthread_mutexattr_t *attr)
+                     const pthread_mutexattr_t *attr,
+                     const pthread_mutex_t initializer)
 {
+  pthread_mutex_t new_mutex;
+
   if (attr && !pthread_mutexattr::is_good_object (attr) || check_valid_pointer 
(mutex))
     return EINVAL;
 
@@ -2787,15 +2794,27 @@ pthread_mutex::init (pthread_mutex_t *mu
       return EBUSY;
     }
 
-  *mutex = new pthread_mutex (attr ? (*attr) : NULL);
-  if (!is_good_object (mutex))
+  new_mutex = new pthread_mutex (attr ? (*attr) : NULL);
+  if (!is_good_object (&new_mutex))
     {
-      delete (*mutex);
-      *mutex = NULL;
+      delete new_mutex;
       mutex_initialization_lock.unlock ();
       return EAGAIN;
     }
+
+  if (!attr && initializer)
+    {
+      if (initializer == PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP)
+        new_mutex->type = PTHREAD_MUTEX_RECURSIVE;
+      else if (initializer == PTHREAD_NORMAL_MUTEX_INITIALIZER_NP)
+        new_mutex->type = PTHREAD_MUTEX_NORMAL;
+      else if (initializer == PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP)
+        new_mutex->type = PTHREAD_MUTEX_ERRORCHECK;
+    }
+
+  *mutex = new_mutex;
   mutex_initialization_lock.unlock ();
+
   return 0;
 }
 
@@ -2803,11 +2822,6 @@ extern "C" int
 pthread_mutex_getprioceiling (const pthread_mutex_t *mutex,
                                int *prioceiling)
 {
-  pthread_mutex_t *themutex = (pthread_mutex_t *) mutex;
-  if (pthread_mutex::is_good_initializer (mutex))
-    pthread_mutex::init ((pthread_mutex_t *) mutex, NULL);
-  if (!pthread_mutex::is_good_object (themutex))
-    return EINVAL;
   /* We don't define _POSIX_THREAD_PRIO_PROTECT because we do't currently support
      mutex priorities.
 
@@ -2821,47 +2835,28 @@ pthread_mutex_getprioceiling (const pthr
 extern "C" int
 pthread_mutex_lock (pthread_mutex_t *mutex)
 {
-  pthread_mutex_t *themutex = mutex;
-  /* This could be simplified via is_good_initializer_or_object
-     and is_good_initializer, but in a performance critical call like this....
-     no.  */
-  switch (verifyable_object_isvalid (themutex, PTHREAD_MUTEX_MAGIC, 
PTHREAD_MUTEX_INITIALIZER))
-    {
-    case INVALID_OBJECT:
-      return EINVAL;
-      break;
-    case VALID_STATIC_OBJECT:
-      if (pthread_mutex::is_good_initializer (mutex))
-       {
-         int rv = pthread_mutex::init (mutex, NULL);
-         if (rv && rv != EBUSY)
-           return rv;
-       }
-      /* No else needed. If it's been initialized while we waited,
-        we can just attempt to lock it */
-      break;
-    case VALID_OBJECT:
-      break;
-    }
-  return (*themutex)->lock ();
+  if (pthread_mutex::is_good_initializer (mutex))
+    pthread_mutex::init (mutex, NULL, *mutex);
+  if (!pthread_mutex::is_good_object (mutex))
+    return EINVAL;
+  return (*mutex)->lock ();
 }
 
 extern "C" int
 pthread_mutex_trylock (pthread_mutex_t *mutex)
 {
-  pthread_mutex_t *themutex = mutex;
   if (pthread_mutex::is_good_initializer (mutex))
-    pthread_mutex::init (mutex, NULL);
-  if (!pthread_mutex::is_good_object (themutex))
+    pthread_mutex::init (mutex, NULL, *mutex);
+  if (!pthread_mutex::is_good_object (mutex))
     return EINVAL;
-  return (*themutex)->trylock ();
+  return (*mutex)->trylock ();
 }
 
 extern "C" int
 pthread_mutex_unlock (pthread_mutex_t *mutex)
 {
   if (pthread_mutex::is_good_initializer (mutex))
-    pthread_mutex::init (mutex, NULL);
+    return EPERM;
   if (!pthread_mutex::is_good_object (mutex))
     return EINVAL;
   return (*mutex)->unlock ();
@@ -2889,11 +2884,6 @@ extern "C" int
 pthread_mutex_setprioceiling (pthread_mutex_t *mutex, int prioceiling,
                                int *old_ceiling)
 {
-  pthread_mutex_t *themutex = mutex;
-  if (pthread_mutex::is_good_initializer (mutex))
-    pthread_mutex::init (mutex, NULL);
-  if (!pthread_mutex::is_good_object (themutex))
-    return EINVAL;
   return ENOSYS;
 }
 
diff -urp cygwin.org/thread.h cygwin/thread.h
--- cygwin.org/thread.h 2004-02-19 08:38:33.875377600 +0100
+++ cygwin/thread.h     2004-02-19 08:44:39.110560000 +0100
@@ -120,8 +120,10 @@ typedef enum
   VALID_STATIC_OBJECT
 } verifyable_object_state;
 
-verifyable_object_state verifyable_object_isvalid (void const *, long);
-verifyable_object_state verifyable_object_isvalid (void const *, long, void *);
+verifyable_object_state verifyable_object_isvalid (void const * objectptr, long magic,
+                                                   void *static_ptr1 = NULL,
+                                                   void *static_ptr2 = NULL,
+                                                   void *static_ptr3 = NULL);
 
 template <class list_node> inline void
 List_insert (list_node *&head, list_node *node)
@@ -276,7 +278,8 @@ public:
   static bool is_good_initializer_or_bad_object (pthread_mutex_t const *mutex);
   static bool can_be_unlocked (pthread_mutex_t const *mutex);
   static void init_mutex ();
-  static int init (pthread_mutex_t *, const pthread_mutexattr_t *);
+  static int init (pthread_mutex_t *mutex, const pthread_mutexattr_t *attr,
+                   const pthread_mutex_t initializer = NULL);
 
   unsigned long lock_counter;
   HANDLE win32_obj_id;

Reply via email to