* thread.cc: Use "%E" in *_printf throughout rather than calling GetLastError.

GNUify comments.
(__pthread_mutex_lock): Don't return error on EBUSY since that just means that
the mutex has already been initialized.
This commit is contained in:
Christopher Faylor 2002-09-30 01:19:45 +00:00
parent 881ffcb478
commit 79ed43004f
2 changed files with 150 additions and 156 deletions

View File

@ -1,3 +1,10 @@
2002-09-29 Christopher Faylor <cgf@redhat.com>
* thread.cc: Use "%E" in *_printf throughout rather than calling
GetLastError. GNUify comments.
(__pthread_mutex_lock): Don't return error on EBUSY since that just
means that the mutex has already been initialized.
2002-09-30 Robert Collins <rbtcollins@hotmail.com> 2002-09-30 Robert Collins <rbtcollins@hotmail.com>
* pthread.cc (pthread_mutex_init): Use new pthread_mutex::init. * pthread.cc (pthread_mutex_init): Use new pthread_mutex::init.

View File

@ -320,7 +320,7 @@ pthread::precreate (pthread_attr *newattr)
cancel_event = ::CreateEvent (NULL,TRUE,FALSE,NULL); cancel_event = ::CreateEvent (NULL,TRUE,FALSE,NULL);
if (!cancel_event) if (!cancel_event)
{ {
system_printf ("couldn't create cancel event, this %p LastError %d", this, GetLastError () ); system_printf ("couldn't create cancel event, this %p LastError %E", this);
/* we need the event for correct behaviour */ /* we need the event for correct behaviour */
magic = 0; magic = 0;
return; return;
@ -1051,27 +1051,26 @@ pthread_key::run_destructor ()
/* pshared mutexs: /* pshared mutexs:
* REMOVED FROM CURRENT. These can be reinstated with the daemon, when all the REMOVED FROM CURRENT. These can be reinstated with the daemon, when all the
gymnastics can be a lot easier. gymnastics can be a lot easier.
*the mutex_t (size 4) is not used as a verifyable object because we cannot the mutex_t (size 4) is not used as a verifyable object because we cannot
*guarantee the same address space for all processes. guarantee the same address space for all processes.
*we use the following: we use the following:
*high bit set (never a valid address). high bit set (never a valid address).
*second byte is reserved for the priority. second byte is reserved for the priority.
*third byte is reserved third byte is reserved
*fourth byte is the mutex id. (max 255 cygwin mutexs system wide). fourth byte is the mutex id. (max 255 cygwin mutexs system wide).
*creating mutex's does get slower and slower, but as creation is a one time creating mutex's does get slower and slower, but as creation is a one time
*job, it should never become an issue job, it should never become an issue
*
*And if you're looking at this and thinking, why not an array in cygwin for all mutexs, And if you're looking at this and thinking, why not an array in cygwin for all mutexs,
*- you incur a penalty on _every_ mutex call and you have toserialise them all. - you incur a penalty on _every_ mutex call and you have toserialise them all.
*... Bad karma. ... Bad karma.
*
*option 2? put everything in userspace and update the ABI? option 2? put everything in userspace and update the ABI?
*- bad karma as well - the HANDLE, while identical across process's, - bad karma as well - the HANDLE, while identical across process's,
*Isn't duplicated, it's reopened. Isn't duplicated, it's reopened. */
*/
/* static members */ /* static members */
bool bool
@ -1101,15 +1100,14 @@ pthread_mutex::isGoodInitializerOrObject (pthread_mutex_t const *mutex)
HANDLE pthread_mutex::mutexInitializationLock; HANDLE pthread_mutex::mutexInitializationLock;
/* We can only be called once. /* We can only be called once.
* TODO: (no rush) use a non copied memory section to TODO: (no rush) use a non copied memory section to
* hold an initialization flag. hold an initialization flag. */
*/
void void
pthread_mutex::initMutex () pthread_mutex::initMutex ()
{ {
mutexInitializationLock = CreateMutex (NULL, FALSE, NULL); mutexInitializationLock = CreateMutex (NULL, FALSE, NULL);
if (!mutexInitializationLock) if (!mutexInitializationLock)
api_fatal ("Could not create win32 Mutex for pthread mutex static initializer support. The error code was %d\n", GetLastError()); api_fatal ("Could not create win32 Mutex for pthread mutex static initializer support. The error code was %E");
} }
@ -1473,24 +1471,22 @@ pthread::cancel (pthread_t thread)
return thread->cancel (); return thread->cancel ();
} }
/* /* Races in pthread_atfork:
*Races in pthread_atfork: We are race safe in that any additions to the lists are made via
*We are race safe in that any additions to the lists are made via InterlockedExchangePointer.
*InterlockedExchangePointer. However, if the user application doesn't perform syncronisation of some sort
*However, if the user application doesn't perform syncronisation of some sort It's not guaranteed that a near simultaneous call to pthread_atfork and fork
*It's not guaranteed that a near simultaneous call to pthread_atfork and fork will result in the new atfork handlers being calls.
*will result in the new atfork handlers being calls. More rigorous internal syncronisation isn't needed as the user program isn't
*More rigorous internal syncronisation isn't needed as the user program isn't guaranteeing their own state.
*guaranteeing their own state.
* as far as multiple calls to pthread_atfork, the worst case is simultaneous calls
*as far as multiple calls to pthread_atfork, the worst case is simultaneous calls will result in an indeterminate order for parent and child calls (what gets inserted
*will result in an indeterminate order for parent and child calls (what gets inserted first isn't guaranteed.)
*first isn't guaranteed.)
* There is one potential race... Does the result of InterlockedExchangePointer
*There is one potential race... Does the result of InterlockedExchangePointer get committed to the return location _before_ any context switches can occur?
*get committed to the return location _before_ any context switches can occur? If yes, we're safe, if no, we're not. */
*If yes, we're safe, if no, we're not.
*/
void void
pthread::atforkprepare (void) pthread::atforkprepare (void)
{ {
@ -1529,9 +1525,8 @@ pthread::atforkchild (void)
} }
/* Register a set of functions to run before and after fork. /* Register a set of functions to run before and after fork.
*prepare calls are called in LI-FC order. prepare calls are called in LI-FC order.
*parent and child calls are called in FI-FC order. parent and child calls are called in FI-FC order. */
*/
int int
pthread::atfork (void (*prepare)(void), void (*parent)(void), void (*child)(void)) pthread::atfork (void (*prepare)(void), void (*parent)(void), void (*child)(void))
{ {
@ -1627,9 +1622,8 @@ __pthread_attr_getschedparam (const pthread_attr_t *attr,
} }
/* From a pure code point of view, this should call a helper in sched.cc, /* From a pure code point of view, this should call a helper in sched.cc,
*to allow for someone adding scheduler policy changes to win32 in the future. to allow for someone adding scheduler policy changes to win32 in the future.
*However that's extremely unlikely, so short and sweet will do us However that's extremely unlikely, so short and sweet will do us */
*/
int int
__pthread_attr_getschedpolicy (const pthread_attr_t *attr, int *policy) __pthread_attr_getschedpolicy (const pthread_attr_t *attr, int *policy)
{ {
@ -1713,7 +1707,7 @@ __pthread_attr_setscope (pthread_attr_t *attr, int contentionscope)
&& contentionscope != PTHREAD_SCOPE_PROCESS) && contentionscope != PTHREAD_SCOPE_PROCESS)
return EINVAL; return EINVAL;
/* In future, we may be able to support system scope by escalating the thread /* In future, we may be able to support system scope by escalating the thread
*priority to exceed the priority class. For now we only support PROCESS scope. */ priority to exceed the priority class. For now we only support PROCESS scope. */
if (contentionscope != PTHREAD_SCOPE_PROCESS) if (contentionscope != PTHREAD_SCOPE_PROCESS)
return ENOTSUP; return ENOTSUP;
(*attr)->contentionscope = contentionscope; (*attr)->contentionscope = contentionscope;
@ -1849,7 +1843,7 @@ pthread::resume (pthread_t *thread)
} }
/* provided for source level compatability. /* provided for source level compatability.
*See http://www.opengroup.org/onlinepubs/007908799/xsh/pthread_getconcurrency.html See http://www.opengroup.org/onlinepubs/007908799/xsh/pthread_getconcurrency.html
*/ */
int int
__pthread_getconcurrency (void) __pthread_getconcurrency (void)
@ -1865,8 +1859,8 @@ __pthread_getschedparam (pthread_t thread, int *policy,
if (!pthread::isGoodObject (&thread)) if (!pthread::isGoodObject (&thread))
return ESRCH; return ESRCH;
*policy = SCHED_FIFO; *policy = SCHED_FIFO;
/*we don't return the current effective priority, we return the current requested /* we don't return the current effective priority, we return the current
*priority */ requested priority */
*param = thread->attr.schedparam; *param = thread->attr.schedparam;
return 0; return 0;
} }
@ -1876,8 +1870,7 @@ int
__pthread_key_create (pthread_key_t *key, void (*destructor) (void *)) __pthread_key_create (pthread_key_t *key, void (*destructor) (void *))
{ {
/* The opengroup docs don't define if we should check this or not, /* The opengroup docs don't define if we should check this or not,
*but creation is relatively rare.. but creation is relatively rare. */
*/
if (pthread_key::isGoodObject (key)) if (pthread_key::isGoodObject (key))
return EBUSY; return EBUSY;
@ -1902,8 +1895,8 @@ __pthread_key_delete (pthread_key_t key)
return 0; return 0;
} }
/*provided for source level compatability. /* provided for source level compatability. See
*See http://www.opengroup.org/onlinepubs/007908799/xsh/pthread_getconcurrency.html http://www.opengroup.org/onlinepubs/007908799/xsh/pthread_getconcurrency.html
*/ */
int int
__pthread_setconcurrency (int new_level) __pthread_setconcurrency (int new_level)
@ -2079,13 +2072,11 @@ __pthread_cond_dowait (pthread_cond_t *cond, pthread_mutex_t *mutex,
if (pthread_mutex_unlock (&(*cond)->cond_access)) if (pthread_mutex_unlock (&(*cond)->cond_access))
system_printf ("Failed to unlock condition variable access mutex, this %p", *cond); system_printf ("Failed to unlock condition variable access mutex, this %p", *cond);
/* At this point calls to Signal will progress evebn if we aren' yet waiting /* At this point calls to Signal will progress evebn if we aren' yet waiting
* However, the loop there should allow us to get scheduled and call wait, However, the loop there should allow us to get scheduled and call wait,
* and have them call PulseEvent again if we dont' respond. and have them call PulseEvent again if we dont' respond. */
*/
rv = (*cond)->TimedWait (waitlength); rv = (*cond)->TimedWait (waitlength);
/* this may allow a race on the mutex acquisition and waits.. /* this may allow a race on the mutex acquisition and waits.
* But doing this within the cond access mutex creates a different race But doing this within the cond access mutex creates a different race */
*/
InterlockedDecrement (&((*cond)->waiting)); InterlockedDecrement (&((*cond)->waiting));
/* Tell Signal that we have been released */ /* Tell Signal that we have been released */
InterlockedDecrement (&((*cond)->ExitingWait)); InterlockedDecrement (&((*cond)->ExitingWait));
@ -2234,7 +2225,7 @@ pthread_mutex::init (pthread_mutex_t *mutex,
DWORD waitResult = WaitForSingleObject (mutexInitializationLock, INFINITE); DWORD waitResult = WaitForSingleObject (mutexInitializationLock, INFINITE);
if (waitResult != WAIT_OBJECT_0) if (waitResult != WAIT_OBJECT_0)
{ {
system_printf ("Recieved a unexpected wait result on mutexInitializationLock %d\n", waitResult); system_printf ("Received a unexpected wait result on mutexInitializationLock %d\n", waitResult);
return EINVAL; return EINVAL;
} }
@ -2242,7 +2233,7 @@ pthread_mutex::init (pthread_mutex_t *mutex,
if (isGoodObject (mutex)) if (isGoodObject (mutex))
{ {
if (!ReleaseMutex (mutexInitializationLock)) if (!ReleaseMutex (mutexInitializationLock))
system_printf ("Recieved a unexpected result releasing mutexInitializationLock %d\n", GetLastError()); system_printf ("Received a unexpected result releasing mutexInitializationLock %E");
return EBUSY; return EBUSY;
} }
@ -2252,11 +2243,11 @@ pthread_mutex::init (pthread_mutex_t *mutex,
delete (*mutex); delete (*mutex);
*mutex = NULL; *mutex = NULL;
if (!ReleaseMutex (mutexInitializationLock)) if (!ReleaseMutex (mutexInitializationLock))
system_printf ("Recieved a unexpected result releasing mutexInitializationLock %d\n", GetLastError()); system_printf ("Received a unexpected result releasing mutexInitializationLock %E");
return EAGAIN; return EAGAIN;
} }
if (!ReleaseMutex (mutexInitializationLock)) if (!ReleaseMutex (mutexInitializationLock))
system_printf ("Recieved a unexpected result releasing mutexInitializationLock %d\n", GetLastError()); system_printf ("Received a unexpected result releasing mutexInitializationLock %E");
return 0; return 0;
} }
@ -2270,13 +2261,12 @@ __pthread_mutex_getprioceiling (const pthread_mutex_t *mutex,
if (!pthread_mutex::isGoodObject (themutex)) if (!pthread_mutex::isGoodObject (themutex))
return EINVAL; return EINVAL;
/* We don't define _POSIX_THREAD_PRIO_PROTECT because we do't currently support /* We don't define _POSIX_THREAD_PRIO_PROTECT because we do't currently support
*mutex priorities. mutex priorities.
*
*We can support mutex priorities in the future though: We can support mutex priorities in the future though:
*Store a priority with each mutex. Store a priority with each mutex.
*When the mutex is optained, set the thread priority as appropriate When the mutex is optained, set the thread priority as appropriate
*When the mutex is released, reset the thread priority. When the mutex is released, reset the thread priority. */
*/
return ENOSYS; return ENOSYS;
} }
@ -2286,8 +2276,7 @@ __pthread_mutex_lock (pthread_mutex_t *mutex)
pthread_mutex_t *themutex = mutex; pthread_mutex_t *themutex = mutex;
/* This could be simplified via isGoodInitializerOrObject /* This could be simplified via isGoodInitializerOrObject
and isGoodInitializer, but in a performance critical call like this.... and isGoodInitializer, but in a performance critical call like this....
no. no. */
*/
switch (verifyable_object_isvalid (themutex, PTHREAD_MUTEX_MAGIC, PTHREAD_MUTEX_INITIALIZER)) switch (verifyable_object_isvalid (themutex, PTHREAD_MUTEX_MAGIC, PTHREAD_MUTEX_INITIALIZER))
{ {
case INVALID_OBJECT: case INVALID_OBJECT:
@ -2297,12 +2286,11 @@ __pthread_mutex_lock (pthread_mutex_t *mutex)
if (pthread_mutex::isGoodInitializer (mutex)) if (pthread_mutex::isGoodInitializer (mutex))
{ {
int rv = pthread_mutex::init (mutex, NULL); int rv = pthread_mutex::init (mutex, NULL);
if (rv) if (rv && rv != EBUSY)
return rv; return rv;
} }
/* No else needed. If it's been initialized while we waited, /* No else needed. If it's been initialized while we waited,
* we can just attempt to lock it we can just attempt to lock it */
*/
break; break;
case VALID_OBJECT: case VALID_OBJECT:
break; break;
@ -2365,7 +2353,7 @@ __pthread_mutex_setprioceiling (pthread_mutex_t *mutex, int prioceiling,
} }
/* Win32 doesn't support mutex priorities - see __pthread_mutex_getprioceiling /* Win32 doesn't support mutex priorities - see __pthread_mutex_getprioceiling
*for more detail */ for more detail */
int int
__pthread_mutexattr_getprotocol (const pthread_mutexattr_t *attr, __pthread_mutexattr_getprotocol (const pthread_mutexattr_t *attr,
int *protocol) int *protocol)
@ -2386,9 +2374,9 @@ __pthread_mutexattr_getpshared (const pthread_mutexattr_t *attr,
} }
/* Win32 mutex's are equivalent to posix RECURSIVE mutexs. /* Win32 mutex's are equivalent to posix RECURSIVE mutexs.
*We need to put glue in place to support other types of mutex's. We map We need to put glue in place to support other types of mutex's. We map
*PTHREAD_MUTEX_DEFAULT to PTHREAD_MUTEX_RECURSIVE and return EINVAL for other types. PTHREAD_MUTEX_DEFAULT to PTHREAD_MUTEX_RECURSIVE and return EINVAL for
*/ other types. */
int int
__pthread_mutexattr_gettype (const pthread_mutexattr_t *attr, int *type) __pthread_mutexattr_gettype (const pthread_mutexattr_t *attr, int *type)
{ {
@ -2399,10 +2387,9 @@ __pthread_mutexattr_gettype (const pthread_mutexattr_t *attr, int *type)
} }
/* Currently pthread_mutex_init ignores the attr variable, this is because /* Currently pthread_mutex_init ignores the attr variable, this is because
*none of the variables have any impact on it's behaviour. none of the variables have any impact on it's behaviour.
*
*FIXME: write and test process shared mutex's. FIXME: write and test process shared mutex's. */
*/
int int
__pthread_mutexattr_init (pthread_mutexattr_t *attr) __pthread_mutexattr_init (pthread_mutexattr_t *attr)
{ {