* 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:
parent
881ffcb478
commit
79ed43004f
|
@ -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.
|
||||||
|
|
|
@ -265,7 +265,7 @@ pthread::self ()
|
||||||
void
|
void
|
||||||
pthread::setTlsSelfPointer (pthread *thisThread)
|
pthread::setTlsSelfPointer (pthread *thisThread)
|
||||||
{
|
{
|
||||||
/*the OS doesn't check this for <= 64 Tls entries (pre win2k) */
|
/* the OS doesn't check this for <= 64 Tls entries (pre win2k) */
|
||||||
TlsSetValue (MT_INTERFACE->thread_self_dwTlsIndex, thisThread);
|
TlsSetValue (MT_INTERFACE->thread_self_dwTlsIndex, thisThread);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -297,7 +297,7 @@ pthread::precreate (pthread_attr *newattr)
|
||||||
{
|
{
|
||||||
pthread_mutex *verifyable_mutex_obj = &mutex;
|
pthread_mutex *verifyable_mutex_obj = &mutex;
|
||||||
|
|
||||||
/*already running ? */
|
/* already running ? */
|
||||||
if (win32_obj_id)
|
if (win32_obj_id)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -320,8 +320,8 @@ 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;
|
||||||
}
|
}
|
||||||
|
@ -356,11 +356,11 @@ void
|
||||||
pthread::postcreate ()
|
pthread::postcreate ()
|
||||||
{
|
{
|
||||||
InterlockedIncrement (&MT_INTERFACE->threadcount);
|
InterlockedIncrement (&MT_INTERFACE->threadcount);
|
||||||
/*FIXME: set the priority appropriately for system contention scope */
|
/* FIXME: set the priority appropriately for system contention scope */
|
||||||
if (attr.inheritsched == PTHREAD_EXPLICIT_SCHED)
|
if (attr.inheritsched == PTHREAD_EXPLICIT_SCHED)
|
||||||
{
|
{
|
||||||
/*FIXME: set the scheduling settings for the new thread */
|
/* FIXME: set the scheduling settings for the new thread */
|
||||||
/*sched_thread_setparam (win32_obj_id, attr.schedparam); */
|
/* sched_thread_setparam (win32_obj_id, attr.schedparam); */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -376,7 +376,7 @@ pthread::exit (void *value_ptr)
|
||||||
|
|
||||||
mutex.Lock ();
|
mutex.Lock ();
|
||||||
// cleanup if thread is in detached state and not joined
|
// cleanup if thread is in detached state and not joined
|
||||||
if (__pthread_equal (&joiner, &thread ) )
|
if (__pthread_equal (&joiner, &thread))
|
||||||
delete this;
|
delete this;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -612,7 +612,7 @@ pthread::testcancel (void)
|
||||||
if (cancelstate == PTHREAD_CANCEL_DISABLE)
|
if (cancelstate == PTHREAD_CANCEL_DISABLE)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (WAIT_OBJECT_0 == WaitForSingleObject (cancel_event, 0 ) )
|
if (WAIT_OBJECT_0 == WaitForSingleObject (cancel_event, 0))
|
||||||
cancel_self ();
|
cancel_self ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -672,7 +672,7 @@ pthread::push_cleanup_handler (__pthread_cleanup_handler *handler)
|
||||||
// TODO: do it?
|
// TODO: do it?
|
||||||
api_fatal ("Attempt to push a cleanup handler across threads");
|
api_fatal ("Attempt to push a cleanup handler across threads");
|
||||||
handler->next = cleanup_stack;
|
handler->next = cleanup_stack;
|
||||||
InterlockedExchangePointer (&cleanup_stack, handler );
|
InterlockedExchangePointer (&cleanup_stack, handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -761,15 +761,15 @@ pthread_cond::pthread_cond (pthread_condattr *attr):verifyable_object (PTHREAD_C
|
||||||
this->mutex = NULL;
|
this->mutex = NULL;
|
||||||
this->waiting = 0;
|
this->waiting = 0;
|
||||||
|
|
||||||
this->win32_obj_id = ::CreateEvent (&sec_none_nih, false, /*auto signal reset - which I think is pthreads like ? */
|
this->win32_obj_id = ::CreateEvent (&sec_none_nih, false, /* auto signal reset - which I think is pthreads like ? */
|
||||||
false, /*start non signaled */
|
false, /* start non signaled */
|
||||||
NULL /*no name */);
|
NULL /* no name */);
|
||||||
/*TODO: make a shared mem mutex if out attributes request shared mem cond */
|
/* TODO: make a shared mem mutex if out attributes request shared mem cond */
|
||||||
cond_access = NULL;
|
cond_access = NULL;
|
||||||
if ((temperr = pthread_mutex_init (&this->cond_access, NULL)))
|
if ((temperr = pthread_mutex_init (&this->cond_access, NULL)))
|
||||||
{
|
{
|
||||||
system_printf ("couldn't init mutex, this %p errno %d", this, temperr);
|
system_printf ("couldn't init mutex, this %p errno %d", this, temperr);
|
||||||
/*we need the mutex for correct behaviour */
|
/* we need the mutex for correct behaviour */
|
||||||
magic = 0;
|
magic = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -808,7 +808,7 @@ pthread_cond::BroadCast ()
|
||||||
{
|
{
|
||||||
if (pthread_mutex_unlock (&cond_access))
|
if (pthread_mutex_unlock (&cond_access))
|
||||||
system_printf ("Failed to unlock condition variable access mutex, this %p", this);
|
system_printf ("Failed to unlock condition variable access mutex, this %p", this);
|
||||||
/*This isn't and API error - users are allowed to call this when no threads
|
/* This isn't and API error - users are allowed to call this when no threads
|
||||||
are waiting
|
are waiting
|
||||||
system_printf ("Broadcast called with invalid mutex");
|
system_printf ("Broadcast called with invalid mutex");
|
||||||
*/
|
*/
|
||||||
|
@ -903,12 +903,12 @@ pthread_cond::TimedWait (DWORD dwMilliseconds)
|
||||||
switch (rv)
|
switch (rv)
|
||||||
{
|
{
|
||||||
case WAIT_FAILED:
|
case WAIT_FAILED:
|
||||||
return 0; /*POSIX doesn't allow errors after we modify the mutex state */
|
return 0; /* POSIX doesn't allow errors after we modify the mutex state */
|
||||||
case WAIT_ABANDONED:
|
case WAIT_ABANDONED:
|
||||||
case WAIT_TIMEOUT:
|
case WAIT_TIMEOUT:
|
||||||
return ETIMEDOUT;
|
return ETIMEDOUT;
|
||||||
case WAIT_OBJECT_0:
|
case WAIT_OBJECT_0:
|
||||||
return 0; /*we have been signaled */
|
return 0; /* we have been signaled */
|
||||||
default:
|
default:
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -1006,7 +1006,7 @@ pthread_key::~pthread_key ()
|
||||||
int
|
int
|
||||||
pthread_key::set (const void *value)
|
pthread_key::set (const void *value)
|
||||||
{
|
{
|
||||||
/*the OS function doesn't perform error checking */
|
/* the OS function doesn't perform error checking */
|
||||||
TlsSetValue (dwTlsIndex, (void *) value);
|
TlsSetValue (dwTlsIndex, (void *) value);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -1038,9 +1038,9 @@ pthread_key::recreateKeyFromBuffer ()
|
||||||
void
|
void
|
||||||
pthread_key::run_destructor ()
|
pthread_key::run_destructor ()
|
||||||
{
|
{
|
||||||
if (destructor)
|
if (destructor)
|
||||||
{
|
{
|
||||||
void *oldValue = get();
|
void *oldValue = get ();
|
||||||
if (oldValue)
|
if (oldValue)
|
||||||
{
|
{
|
||||||
set (NULL);
|
set (NULL);
|
||||||
|
@ -1049,29 +1049,28 @@ 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,21 +1100,20 @@ 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");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pthread_mutex::pthread_mutex (pthread_mutexattr *attr):verifyable_object (PTHREAD_MUTEX_MAGIC)
|
pthread_mutex::pthread_mutex (pthread_mutexattr *attr):verifyable_object (PTHREAD_MUTEX_MAGIC)
|
||||||
{
|
{
|
||||||
/*attr checked in the C call */
|
/* attr checked in the C call */
|
||||||
if (attr && attr->pshared == PTHREAD_PROCESS_SHARED)
|
if (attr && attr->pshared == PTHREAD_PROCESS_SHARED)
|
||||||
{
|
{
|
||||||
// fail
|
// fail
|
||||||
|
@ -1273,7 +1271,7 @@ semaphore::Post ()
|
||||||
int
|
int
|
||||||
semaphore::TryWait ()
|
semaphore::TryWait ()
|
||||||
{
|
{
|
||||||
/*FIXME: signals should be able to interrupt semaphores...
|
/* FIXME: signals should be able to interrupt semaphores...
|
||||||
*We probably need WaitForMultipleObjects here.
|
*We probably need WaitForMultipleObjects here.
|
||||||
*/
|
*/
|
||||||
if (WaitForSingleObject (win32_obj_id, 0) == WAIT_TIMEOUT)
|
if (WaitForSingleObject (win32_obj_id, 0) == WAIT_TIMEOUT)
|
||||||
|
@ -1314,7 +1312,7 @@ verifyable_object::~verifyable_object ()
|
||||||
magic = 0;
|
magic = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*Generic memory acccess routine - where should it live ? */
|
/* Generic memory acccess routine - where should it live ? */
|
||||||
int __stdcall
|
int __stdcall
|
||||||
check_valid_pointer (void const *pointer)
|
check_valid_pointer (void const *pointer)
|
||||||
{
|
{
|
||||||
|
@ -1358,7 +1356,7 @@ pthread::thread_init_wrapper (void *_arg)
|
||||||
struct _reent local_clib = _REENT_INIT (local_clib);
|
struct _reent local_clib = _REENT_INIT (local_clib);
|
||||||
|
|
||||||
struct sigaction _sigs[NSIG];
|
struct sigaction _sigs[NSIG];
|
||||||
sigset_t _sig_mask; /*one set for everything to ignore. */
|
sigset_t _sig_mask; /* one set for everything to ignore. */
|
||||||
LONG _sigtodo[NSIG + __SIGOFFSET];
|
LONG _sigtodo[NSIG + __SIGOFFSET];
|
||||||
|
|
||||||
// setup signal structures
|
// setup signal structures
|
||||||
|
@ -1373,7 +1371,7 @@ pthread::thread_init_wrapper (void *_arg)
|
||||||
|
|
||||||
local_winsup._process_logmask = LOG_UPTO (LOG_DEBUG);
|
local_winsup._process_logmask = LOG_UPTO (LOG_DEBUG);
|
||||||
|
|
||||||
/*This is not checked by the OS !! */
|
/* This is not checked by the OS !! */
|
||||||
if (!TlsSetValue (MT_INTERFACE->reent_index, &local_reent))
|
if (!TlsSetValue (MT_INTERFACE->reent_index, &local_reent))
|
||||||
system_printf ("local storage for thread couldn't be set");
|
system_printf ("local storage for thread couldn't be set");
|
||||||
|
|
||||||
|
@ -1402,7 +1400,7 @@ pthread::thread_init_wrapper (void *_arg)
|
||||||
// ??? This code only runs if the thread exits by returning.
|
// ??? This code only runs if the thread exits by returning.
|
||||||
// it's all now in __pthread_exit ();
|
// it's all now in __pthread_exit ();
|
||||||
#endif
|
#endif
|
||||||
/*never reached */
|
/* never reached */
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1448,8 +1446,8 @@ pthread::once (pthread_once_t *once_control, void (*init_routine) (void))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
pthread_mutex_lock (&once_control->mutex);
|
pthread_mutex_lock (&once_control->mutex);
|
||||||
/*Here we must set a cancellation handler to unlock the mutex if needed */
|
/* Here we must set a cancellation handler to unlock the mutex if needed */
|
||||||
/*but a cancellation handler is not the right thing. We need this in the thread
|
/* but a cancellation handler is not the right thing. We need this in the thread
|
||||||
*cleanup routine. Assumption: a thread can only be in one pthread_once routine
|
*cleanup routine. Assumption: a thread can only be in one pthread_once routine
|
||||||
*at a time. Stote a mutex_t *in the pthread_structure. if that's non null unlock
|
*at a time. Stote a mutex_t *in the pthread_structure. if that's non null unlock
|
||||||
*on pthread_exit ();
|
*on pthread_exit ();
|
||||||
|
@ -1459,7 +1457,7 @@ pthread::once (pthread_once_t *once_control, void (*init_routine) (void))
|
||||||
init_routine ();
|
init_routine ();
|
||||||
once_control->state = 1;
|
once_control->state = 1;
|
||||||
}
|
}
|
||||||
/*Here we must remove our cancellation handler */
|
/* Here we must remove our cancellation handler */
|
||||||
pthread_mutex_unlock (&once_control->mutex);
|
pthread_mutex_unlock (&once_control->mutex);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -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)
|
||||||
{
|
{
|
||||||
|
@ -1528,10 +1524,9 @@ 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))
|
||||||
{
|
{
|
||||||
|
@ -1576,7 +1571,7 @@ pthread::atfork (void (*prepare)(void), void (*parent)(void), void (*child)(void
|
||||||
callback **t = &MT_INTERFACE->pthread_parent;
|
callback **t = &MT_INTERFACE->pthread_parent;
|
||||||
while (*t)
|
while (*t)
|
||||||
t = &(*t)->next;
|
t = &(*t)->next;
|
||||||
/*t = pointer to last next in the list */
|
/* t = pointer to last next in the list */
|
||||||
parentcb->next = (callback *) InterlockedExchangePointer ((LONG *) t, (long int) parentcb);
|
parentcb->next = (callback *) InterlockedExchangePointer ((LONG *) t, (long int) parentcb);
|
||||||
}
|
}
|
||||||
if (childcb)
|
if (childcb)
|
||||||
|
@ -1585,7 +1580,7 @@ pthread::atfork (void (*prepare)(void), void (*parent)(void), void (*child)(void
|
||||||
callback **t = &MT_INTERFACE->pthread_child;
|
callback **t = &MT_INTERFACE->pthread_child;
|
||||||
while (*t)
|
while (*t)
|
||||||
t = &(*t)->next;
|
t = &(*t)->next;
|
||||||
/*t = pointer to last next in the list */
|
/* t = pointer to last next in the list */
|
||||||
childcb->next = (callback *) InterlockedExchangePointer ((LONG *) t, (long int) childcb);
|
childcb->next = (callback *) InterlockedExchangePointer ((LONG *) t, (long int) childcb);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -1626,10 +1621,9 @@ __pthread_attr_getschedparam (const pthread_attr_t *attr,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*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)
|
||||||
{
|
{
|
||||||
|
@ -1693,7 +1687,7 @@ __pthread_attr_setschedparam (pthread_attr_t *attr,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*See __pthread_attr_getschedpolicy for some notes */
|
/* See __pthread_attr_getschedpolicy for some notes */
|
||||||
int
|
int
|
||||||
__pthread_attr_setschedpolicy (pthread_attr_t *attr, int policy)
|
__pthread_attr_setschedpolicy (pthread_attr_t *attr, int policy)
|
||||||
{
|
{
|
||||||
|
@ -1712,8 +1706,8 @@ __pthread_attr_setscope (pthread_attr_t *attr, int contentionscope)
|
||||||
if (contentionscope != PTHREAD_SCOPE_SYSTEM
|
if (contentionscope != PTHREAD_SCOPE_SYSTEM
|
||||||
&& 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;
|
||||||
|
@ -1757,7 +1751,7 @@ pthread::join (pthread_t *thread, void **return_val)
|
||||||
if (return_val)
|
if (return_val)
|
||||||
*return_val = NULL;
|
*return_val = NULL;
|
||||||
|
|
||||||
/*FIXME: wait on the thread cancellation event as well - we are a cancellation point*/
|
/* FIXME: wait on the thread cancellation event as well - we are a cancellation point*/
|
||||||
if (!isGoodObject (thread))
|
if (!isGoodObject (thread))
|
||||||
return ESRCH;
|
return ESRCH;
|
||||||
|
|
||||||
|
@ -1781,7 +1775,7 @@ pthread::join (pthread_t *thread, void **return_val)
|
||||||
*return_val = (*thread)->return_ptr;
|
*return_val = (*thread)->return_ptr;
|
||||||
// cleanup
|
// cleanup
|
||||||
delete (*thread);
|
delete (*thread);
|
||||||
} /*End if */
|
} /* End if */
|
||||||
|
|
||||||
pthread_testcancel ();
|
pthread_testcancel ();
|
||||||
|
|
||||||
|
@ -1802,7 +1796,7 @@ pthread::detach (pthread_t *thread)
|
||||||
}
|
}
|
||||||
|
|
||||||
// check if thread is still alive
|
// check if thread is still alive
|
||||||
if (WAIT_TIMEOUT == WaitForSingleObject ((*thread)->win32_obj_id, 0) )
|
if (WAIT_TIMEOUT == WaitForSingleObject ((*thread)->win32_obj_id, 0))
|
||||||
{
|
{
|
||||||
// force cleanup on exit
|
// force cleanup on exit
|
||||||
(*thread)->joiner = *thread;
|
(*thread)->joiner = *thread;
|
||||||
|
@ -1848,16 +1842,16 @@ pthread::resume (pthread_t *thread)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*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)
|
||||||
{
|
{
|
||||||
return MT_INTERFACE->concurrency;
|
return MT_INTERFACE->concurrency;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*keep this in sync with sched.cc */
|
/* keep this in sync with sched.cc */
|
||||||
int
|
int
|
||||||
__pthread_getschedparam (pthread_t thread, int *policy,
|
__pthread_getschedparam (pthread_t thread, int *policy,
|
||||||
struct sched_param *param)
|
struct sched_param *param)
|
||||||
|
@ -1865,19 +1859,18 @@ __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;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*Thread SpecificData */
|
/* Thread SpecificData */
|
||||||
int
|
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,9 +1895,9 @@ __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)
|
||||||
{
|
{
|
||||||
|
@ -1914,7 +1907,7 @@ __pthread_setconcurrency (int new_level)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*keep syncronised with sched.cc */
|
/* keep syncronised with sched.cc */
|
||||||
int
|
int
|
||||||
__pthread_setschedparam (pthread_t thread, int policy,
|
__pthread_setschedparam (pthread_t thread, int policy,
|
||||||
const struct sched_param *param)
|
const struct sched_param *param)
|
||||||
|
@ -1952,7 +1945,7 @@ __pthread_getspecific (pthread_key_t key)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*Thread synchronisation */
|
/* Thread synchronisation */
|
||||||
bool
|
bool
|
||||||
pthread_cond::isGoodObject (pthread_cond_t const *cond)
|
pthread_cond::isGoodObject (pthread_cond_t const *cond)
|
||||||
{
|
{
|
||||||
|
@ -1985,7 +1978,7 @@ __pthread_cond_destroy (pthread_cond_t *cond)
|
||||||
if (!pthread_cond::isGoodObject (cond))
|
if (!pthread_cond::isGoodObject (cond))
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
|
|
||||||
/*reads are atomic */
|
/* reads are atomic */
|
||||||
if ((*cond)->waiting)
|
if ((*cond)->waiting)
|
||||||
return EBUSY;
|
return EBUSY;
|
||||||
|
|
||||||
|
@ -2061,7 +2054,7 @@ __pthread_cond_dowait (pthread_cond_t *cond, pthread_mutex_t *mutex,
|
||||||
if (!pthread_cond::isGoodObject (cond))
|
if (!pthread_cond::isGoodObject (cond))
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
|
|
||||||
/*if the cond variable is blocked, then the above timer test maybe wrong. *shrug**/
|
/* if the cond variable is blocked, then the above timer test maybe wrong. *shrug**/
|
||||||
if (pthread_mutex_lock (&(*cond)->cond_access))
|
if (pthread_mutex_lock (&(*cond)->cond_access))
|
||||||
system_printf ("Failed to lock condition variable access mutex, this %p", *cond);
|
system_printf ("Failed to lock condition variable access mutex, this %p", *cond);
|
||||||
|
|
||||||
|
@ -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));
|
||||||
|
@ -2153,7 +2144,7 @@ __pthread_condattr_setpshared (pthread_condattr_t *attr, int pshared)
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
if ((pshared < 0) || (pshared > 1))
|
if ((pshared < 0) || (pshared > 1))
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
/*shared cond vars not currently supported */
|
/* shared cond vars not currently supported */
|
||||||
if (pshared != PTHREAD_PROCESS_PRIVATE)
|
if (pshared != PTHREAD_PROCESS_PRIVATE)
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
(*attr)->shared = pshared;
|
(*attr)->shared = pshared;
|
||||||
|
@ -2170,11 +2161,11 @@ __pthread_condattr_destroy (pthread_condattr_t *condattr)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*Thread signal */
|
/* Thread signal */
|
||||||
int
|
int
|
||||||
__pthread_kill (pthread_t thread, int sig)
|
__pthread_kill (pthread_t thread, int sig)
|
||||||
{
|
{
|
||||||
// lock myself, for the use of thread2signal
|
// lock myself, for the use of thread2signal
|
||||||
// two different kills might clash: FIXME
|
// two different kills might clash: FIXME
|
||||||
|
|
||||||
if (!pthread::isGoodObject (&thread))
|
if (!pthread::isGoodObject (&thread))
|
||||||
|
@ -2215,7 +2206,7 @@ __pthread_equal (pthread_t *t1, pthread_t *t2)
|
||||||
return (*t1 == *t2);
|
return (*t1 == *t2);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*Mutexes */
|
/* Mutexes */
|
||||||
|
|
||||||
/* FIXME: there's a potential race with PTHREAD_MUTEX_INITALIZER:
|
/* FIXME: there's a potential race with PTHREAD_MUTEX_INITALIZER:
|
||||||
the mutex is not actually inited until the first use.
|
the mutex is not actually inited until the first use.
|
||||||
|
@ -2234,15 +2225,15 @@ 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* FIXME: bugfix: we should check *mutex being a valid address */
|
/* FIXME: bugfix: we should check *mutex being a valid address */
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2251,12 +2242,12 @@ 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2269,14 +2260,13 @@ __pthread_mutex_getprioceiling (const pthread_mutex_t *mutex,
|
||||||
pthread_mutex::init ((pthread_mutex_t *) mutex, NULL);
|
pthread_mutex::init ((pthread_mutex_t *) mutex, NULL);
|
||||||
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;
|
||||||
|
@ -2343,7 +2331,7 @@ __pthread_mutex_destroy (pthread_mutex_t *mutex)
|
||||||
if (!pthread_mutex::isGoodObject (mutex))
|
if (!pthread_mutex::isGoodObject (mutex))
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
|
|
||||||
/*reading a word is atomic */
|
/* reading a word is atomic */
|
||||||
if ((*mutex)->condwaits)
|
if ((*mutex)->condwaits)
|
||||||
return EBUSY;
|
return EBUSY;
|
||||||
|
|
||||||
|
@ -2364,8 +2352,8 @@ __pthread_mutex_setprioceiling (pthread_mutex_t *mutex, int prioceiling,
|
||||||
return ENOSYS;
|
return ENOSYS;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*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)
|
||||||
|
@ -2385,10 +2373,10 @@ __pthread_mutexattr_getpshared (const pthread_mutexattr_t *attr,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*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)
|
||||||
{
|
{
|
||||||
|
@ -2398,11 +2386,10 @@ __pthread_mutexattr_gettype (const pthread_mutexattr_t *attr, int *type)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*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)
|
||||||
{
|
{
|
||||||
|
@ -2430,7 +2417,7 @@ __pthread_mutexattr_destroy (pthread_mutexattr_t *attr)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*Win32 doesn't support mutex priorities */
|
/* Win32 doesn't support mutex priorities */
|
||||||
int
|
int
|
||||||
__pthread_mutexattr_setprotocol (pthread_mutexattr_t *attr, int protocol)
|
__pthread_mutexattr_setprotocol (pthread_mutexattr_t *attr, int protocol)
|
||||||
{
|
{
|
||||||
|
@ -2439,7 +2426,7 @@ __pthread_mutexattr_setprotocol (pthread_mutexattr_t *attr, int protocol)
|
||||||
return ENOSYS;
|
return ENOSYS;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*Win32 doesn't support mutex priorities */
|
/* Win32 doesn't support mutex priorities */
|
||||||
int
|
int
|
||||||
__pthread_mutexattr_setprioceiling (pthread_mutexattr_t *attr,
|
__pthread_mutexattr_setprioceiling (pthread_mutexattr_t *attr,
|
||||||
int prioceiling)
|
int prioceiling)
|
||||||
|
@ -2463,7 +2450,7 @@ __pthread_mutexattr_setpshared (pthread_mutexattr_t *attr, int pshared)
|
||||||
{
|
{
|
||||||
if (!pthread_mutexattr::isGoodObject (attr))
|
if (!pthread_mutexattr::isGoodObject (attr))
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
/*we don't use pshared for anything as yet. We need to test PROCESS_SHARED
|
/* we don't use pshared for anything as yet. We need to test PROCESS_SHARED
|
||||||
*functionality
|
*functionality
|
||||||
*/
|
*/
|
||||||
if (pshared != PTHREAD_PROCESS_PRIVATE)
|
if (pshared != PTHREAD_PROCESS_PRIVATE)
|
||||||
|
@ -2472,7 +2459,7 @@ __pthread_mutexattr_setpshared (pthread_mutexattr_t *attr, int pshared)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*see __pthread_mutex_gettype */
|
/* see __pthread_mutex_gettype */
|
||||||
int
|
int
|
||||||
__pthread_mutexattr_settype (pthread_mutexattr_t *attr, int type)
|
__pthread_mutexattr_settype (pthread_mutexattr_t *attr, int type)
|
||||||
{
|
{
|
||||||
|
@ -2484,7 +2471,7 @@ __pthread_mutexattr_settype (pthread_mutexattr_t *attr, int type)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*Semaphores */
|
/* Semaphores */
|
||||||
|
|
||||||
/* static members */
|
/* static members */
|
||||||
bool
|
bool
|
||||||
|
@ -2498,7 +2485,7 @@ semaphore::isGoodObject (sem_t const * sem)
|
||||||
int
|
int
|
||||||
semaphore::init (sem_t *sem, int pshared, unsigned int value)
|
semaphore::init (sem_t *sem, int pshared, unsigned int value)
|
||||||
{
|
{
|
||||||
/*opengroup calls this undefined */
|
/* opengroup calls this undefined */
|
||||||
if (isGoodObject (sem))
|
if (isGoodObject (sem))
|
||||||
return EBUSY;
|
return EBUSY;
|
||||||
|
|
||||||
|
@ -2522,7 +2509,7 @@ semaphore::destroy (sem_t *sem)
|
||||||
if (!isGoodObject (sem))
|
if (!isGoodObject (sem))
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
|
|
||||||
/*FIXME - new feature - test for busy against threads... */
|
/* FIXME - new feature - test for busy against threads... */
|
||||||
|
|
||||||
delete (*sem);
|
delete (*sem);
|
||||||
*sem = NULL;
|
*sem = NULL;
|
||||||
|
|
Loading…
Reference in New Issue