diff -urp src.old/winsup/cygwin/thread.cc src/winsup/cygwin/thread.cc --- src.old/winsup/cygwin/thread.cc Fri Apr 26 10:23:26 2002 +++ src/winsup/cygwin/thread.cc Fri Apr 26 10:08:36 2002 @@ -2101,33 +2101,63 @@ __pthread_equal (pthread_t *t1, pthread_ /*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) { + static pthread_mutex_t init_mutex; + int result = 0; + + { + // Initialize init_mutex for the PTHREAD_MUTEX_INITIALIZER race + // To work around a chicken/egg problem (pthread_once requires mutex_init) + // this is done with an InterlockedIncremented counter + static struct + { + bool done; + LONG counter; + } interlocked_once = { false, -1 }; + + if( !interlocked_once.done ) + { + if( 0 == InterlockedIncrement (&interlocked_once.counter) ) + { + init_mutex = new pthread_mutex ((pthread_mutexattr *)NULL); + interlocked_once.done = true; + } + else + { + InterlockedDecrement (&interlocked_once.counter); + while(!interlocked_once.done) + { + Sleep(0); + } + } + } + } + if (attr && verifyable_object_isvalid (attr, PTHREAD_MUTEXATTR_MAGIC) != VALID_OBJECT || check_valid_pointer (mutex)) return EINVAL; + __pthread_mutex_lock (&init_mutex); + if (verifyable_object_isvalid (mutex, PTHREAD_MUTEX_MAGIC, PTHREAD_MUTEX_INITIALIZER) == VALID_OBJECT) - return EBUSY; + result = EBUSY; - *mutex = new pthread_mutex (attr ? (*attr) : NULL); - if (verifyable_object_isvalid (mutex, PTHREAD_MUTEX_MAGIC) != VALID_OBJECT) + else { - delete (*mutex); - *mutex = NULL; - return EAGAIN; + *mutex = new pthread_mutex (attr ? (*attr) : NULL); + if (verifyable_object_isvalid (mutex, PTHREAD_MUTEX_MAGIC) != VALID_OBJECT) + { + delete (*mutex); + *mutex = NULL; + result = EAGAIN; + } } - return 0; + + __pthread_mutex_unlock (&init_mutex); + + return result; } int