From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: by sourceware.org (Postfix, from userid 2155) id A460B38582AA; Tue, 9 Aug 2022 20:49:00 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org A460B38582AA Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable From: Corinna Vinschen To: cygwin-cvs@sourceware.org Subject: [newlib-cygwin] Cygwin: pthreads: merge pthread.cc into thread.cc X-Act-Checkin: newlib-cygwin X-Git-Author: Corinna Vinschen X-Git-Refname: refs/heads/master X-Git-Oldrev: 1556b96b1b3b03112f271dfe30e043ed538354fd X-Git-Newrev: 34872ce1a11e3c24154dc2d2ab90c5eb6da47edb Message-Id: <20220809204900.A460B38582AA@sourceware.org> Date: Tue, 9 Aug 2022 20:49:00 +0000 (GMT) X-BeenThere: cygwin-cvs@cygwin.com X-Mailman-Version: 2.1.29 Precedence: list List-Id: Cygwin core component git logs List-Unsubscribe: , List-Archive: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 09 Aug 2022 20:49:00 -0000 https://sourceware.org/git/gitweb.cgi?p=3Dnewlib-cygwin.git;h=3D34872ce1a11= e3c24154dc2d2ab90c5eb6da47edb commit 34872ce1a11e3c24154dc2d2ab90c5eb6da47edb Author: Corinna Vinschen Date: Tue Aug 9 22:48:43 2022 +0200 Cygwin: pthreads: merge pthread.cc into thread.cc =20 provide entire internal and external pthread API from inside the same file. =20 While I dislike to have another even larger file, this is basically cleaning up the source and grouping the external API into useful chunks. Splitting the file cleanly is tricky due to usage of inline methods is_good_object and verifyable_object_isvalid. =20 Signed-off-by: Corinna Vinschen Diff: --- winsup/cygwin/Makefile.am | 5 +- winsup/cygwin/pthread.cc | 196 --- winsup/cygwin/thread.cc | 3018 ++++++++++++++++++++++++-----------------= ---- 3 files changed, 1605 insertions(+), 1614 deletions(-) diff --git a/winsup/cygwin/Makefile.am b/winsup/cygwin/Makefile.am index 6debcc4f2..ff5d4bb4e 100644 --- a/winsup/cygwin/Makefile.am +++ b/winsup/cygwin/Makefile.am @@ -314,7 +314,7 @@ DLL_FILES=3D \ posix_ipc.cc \ posix_timer.cc \ pseudo-reloc.cc \ - pthread.cc \ + thread.cc \ quotactl.cc \ random.cc \ registry.cc \ @@ -339,7 +339,6 @@ DLL_FILES=3D \ sysconf.cc \ syslog.cc \ termios.cc \ - thread.cc \ timerfd.cc \ times.cc \ tls_pbuf.cc \ @@ -653,7 +652,7 @@ libc.a: $(LIB_NAME) libm.a libpthread.a libutil.a libm.a: $(LIB_NAME) $(newlib_build)/libm.a $(addsuffix .o,$(basename $(MAT= H_FILES))) $(AM_V_GEN)$(speclib) $^ $(@F) =20 -libpthread.a: $(LIB_NAME) pthread.o thread.o libc/call_once.o libc/cnd.o \ +libpthread.a: $(LIB_NAME) thread.o libc/call_once.o libc/cnd.o \ libc/mtx.o libc/thrd.o libc/tss.o $(AM_V_GEN)$(speclib) $^ $(@F) =20 diff --git a/winsup/cygwin/pthread.cc b/winsup/cygwin/pthread.cc deleted file mode 100644 index 5d0c0eeaa..000000000 --- a/winsup/cygwin/pthread.cc +++ /dev/null @@ -1,196 +0,0 @@ -/* pthread.cc: posix pthread interface for Cygwin - - Originally written by Marco Fuykschot - - This file is part of Cygwin. - - This software is a copyrighted work licensed under the terms of the - Cygwin license. Please consult the file "CYGWIN_LICENSE" for - details. */ - -#include "winsup.h" -#include "thread.h" - -extern "C" -{ -/* ThreadCreation */ -int -pthread_create (pthread_t *thread, const pthread_attr_t *attr, - void *(*start_routine) (void *), void *arg) -{ - return pthread::create (thread, attr, start_routine, arg); -} - -int -pthread_once (pthread_once_t * once_control, void (*init_routine) (void)) -{ - return pthread::once (once_control, init_routine); -} - -int -pthread_atfork (void (*prepare)(void), void (*parent)(void), void (*child)= (void)) -{ - return pthread::atfork (prepare, parent, child); -} - -/* Thread Exit */ -void -pthread_exit (void *value_ptr) -{ - pthread::self ()->exit (value_ptr); - __builtin_unreachable (); /* FIXME: don't know why this is necessary */ -} - -int -pthread_detach (pthread_t thread) -{ - return pthread::detach (&thread); -} - - -/* This isn't a posix call... should we keep it? */ -int -pthread_suspend (pthread_t thread) -{ - return pthread::suspend (&thread); -} - -/* same */ -int -pthread_continue (pthread_t thread) -{ - return pthread::resume (&thread); -} - -unsigned long -pthread_getsequence_np (pthread_t * thread) -{ - if (!pthread::is_good_object (thread)) - return EINVAL; - return (*thread)->getsequence_np (); -} - -/* ID */ - -pthread_t pthread_self () -{ - return pthread::self (); -} - -/* Mutexes */ -int -pthread_mutex_init (pthread_mutex_t * mutex, const pthread_mutexattr_t * a= ttr) -{ - return pthread_mutex::init (mutex, attr, NULL); -} - -/* Spinlocks */ -int -pthread_spin_init (pthread_spinlock_t *spinlock, int pshared) -{ - return pthread_spinlock::init (spinlock, pshared); -} - - -/* Synchronisation */ -int -pthread_cond_init (pthread_cond_t * cond, const pthread_condattr_t * attr) -{ - return pthread_cond::init (cond, attr); -} - -/* RW Locks */ -int -pthread_rwlock_init (pthread_rwlock_t *rwlock, const pthread_rwlockattr_t = *attr) -{ - return pthread_rwlock::init (rwlock, attr); -} - -/* Cancelability */ - -int -pthread_cancel (pthread_t thread) -{ - return pthread::cancel (thread); -} - -int -pthread_setcancelstate (int state, int *oldstate) -{ - return pthread::self ()->setcancelstate (state, oldstate); -} - -int -pthread_setcanceltype (int type, int *oldtype) -{ - return pthread::self ()->setcanceltype (type, oldtype); -} - -void -pthread_testcancel () -{ - pthread::self ()->testcancel (); -} - -void -_pthread_cleanup_push (__pthread_cleanup_handler *handler) -{ - pthread::self ()->push_cleanup_handler (handler); -} - -void -_pthread_cleanup_pop (int execute) -{ - pthread::self ()->pop_cleanup_handler (execute); -} - -/* Semaphores */ -int -sem_init (sem_t * sem, int pshared, unsigned int value) -{ - return semaphore::init (sem, pshared, value); -} - -int -sem_destroy (sem_t * sem) -{ - return semaphore::destroy (sem); -} - -int -sem_wait (sem_t * sem) -{ - return semaphore::wait (sem); -} - -int -sem_trywait (sem_t * sem) -{ - return semaphore::trywait (sem); -} - -int -sem_clockwait (sem_t * sem, clockid_t clock_id, const struct timespec *abs= time) -{ - return semaphore::clockwait (sem, clock_id, abstime); -} - -int -sem_timedwait (sem_t * sem, const struct timespec *abstime) -{ - return semaphore::clockwait (sem, CLOCK_REALTIME, abstime); -} - -int -sem_post (sem_t *sem) -{ - return semaphore::post (sem); -} - -int -sem_getvalue (sem_t * sem, int *sval) -{ - return semaphore::getvalue (sem, sval); -} - -} diff --git a/winsup/cygwin/thread.cc b/winsup/cygwin/thread.cc index dc59294e7..6f1853bce 100644 --- a/winsup/cygwin/thread.cc +++ b/winsup/cygwin/thread.cc @@ -33,16 +33,14 @@ details. */ #include "cygwait.h" #include "exception.h" =20 +/* For Linux compatibility, the length of a thread name is 16 characters. = */ +#define THRNAMELEN 16 + extern "C" void __fp_lock_all (); extern "C" void __fp_unlock_all (); extern "C" bool valid_sched_parameters(const struct sched_param *); extern "C" int sched_get_thread_priority(HANDLE thread); extern "C" int sched_set_thread_priority(HANDLE thread, int priority); -static inline verifyable_object_state - verifyable_object_isvalid (void const * objectptr, thread_magic_t magic, - void *static_ptr1 =3D NULL, - void *static_ptr2 =3D NULL, - void *static_ptr3 =3D NULL); =20 extern int threadsafe; =20 @@ -50,7 +48,6 @@ const pthread_t pthread_mutex::_new_mutex =3D (pthread_t)= 1; const pthread_t pthread_mutex::_unlocked_mutex =3D (pthread_t) 2; const pthread_t pthread_mutex::_destroyed_mutex =3D (pthread_t) 3; =20 - template static inline void @@ -60,7 +57,6 @@ delete_and_clear (T * * const ptr) *ptr =3D 0; } =20 - inline bool pthread_mutex::no_owner() { @@ -129,8 +125,10 @@ __cygwin_lock_unlock (_LOCK_T *lock) } =20 static inline verifyable_object_state -verifyable_object_isvalid (void const *objectptr, thread_magic_t magic, vo= id *static_ptr1, - void *static_ptr2, void *static_ptr3) +verifyable_object_isvalid (void const *objectptr, thread_magic_t magic, + void *static_ptr1 =3D NULL, + void *static_ptr2 =3D NULL, + void *static_ptr3 =3D NULL) { verifyable_object_state state =3D INVALID_OBJECT; =20 @@ -2184,245 +2182,6 @@ pthread::atfork (void (*prepare)(void), void (*pare= nt)(void), void (*child)(void return 0; } =20 -extern "C" int -pthread_attr_init (pthread_attr_t *attr) -{ - *attr =3D new pthread_attr; - if (!pthread_attr::is_good_object (attr)) - { - delete (*attr); - *attr =3D NULL; - return ENOMEM; - } - return 0; -} - -extern "C" int -pthread_attr_getinheritsched (const pthread_attr_t *attr, - int *inheritsched) -{ - if (!pthread_attr::is_good_object (attr)) - return EINVAL; - *inheritsched =3D (*attr)->inheritsched; - return 0; -} - -extern "C" int -pthread_attr_getschedparam (const pthread_attr_t *attr, - struct sched_param *param) -{ - if (!pthread_attr::is_good_object (attr)) - return EINVAL; - *param =3D (*attr)->schedparam; - return 0; -} - -/* 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 fu= ture. - However that's extremely unlikely, so short and sweet will do us */ -extern "C" int -pthread_attr_getschedpolicy (const pthread_attr_t *attr, int *policy) -{ - if (!pthread_attr::is_good_object (attr)) - return EINVAL; - *policy =3D SCHED_FIFO; - return 0; -} - - -extern "C" int -pthread_attr_getscope (const pthread_attr_t *attr, int *contentionscope) -{ - if (!pthread_attr::is_good_object (attr)) - return EINVAL; - *contentionscope =3D (*attr)->contentionscope; - return 0; -} - -extern "C" int -pthread_attr_setdetachstate (pthread_attr_t *attr, int detachstate) -{ - if (!pthread_attr::is_good_object (attr)) - return EINVAL; - if (detachstate < 0 || detachstate > 1) - return EINVAL; - (*attr)->joinable =3D detachstate; - return 0; -} - -extern "C" int -pthread_attr_getdetachstate (const pthread_attr_t *attr, int *detachstate) -{ - if (!pthread_attr::is_good_object (attr)) - return EINVAL; - *detachstate =3D (*attr)->joinable; - return 0; -} - -extern "C" int -pthread_attr_setinheritsched (pthread_attr_t *attr, int inheritsched) -{ - if (!pthread_attr::is_good_object (attr)) - return EINVAL; - if (inheritsched !=3D PTHREAD_INHERIT_SCHED - && inheritsched !=3D PTHREAD_EXPLICIT_SCHED) - return ENOTSUP; - (*attr)->inheritsched =3D inheritsched; - return 0; -} - -extern "C" int -pthread_attr_setschedparam (pthread_attr_t *attr, - const struct sched_param *param) -{ - if (!pthread_attr::is_good_object (attr)) - return EINVAL; - if (!valid_sched_parameters (param)) - return ENOTSUP; - (*attr)->schedparam =3D *param; - return 0; -} - -/* See __pthread_attr_getschedpolicy for some notes */ -extern "C" int -pthread_attr_setschedpolicy (pthread_attr_t *attr, int policy) -{ - if (!pthread_attr::is_good_object (attr)) - return EINVAL; - if (policy !=3D SCHED_FIFO) - return ENOTSUP; - return 0; -} - -extern "C" int -pthread_attr_setscope (pthread_attr_t *attr, int contentionscope) -{ - if (!pthread_attr::is_good_object (attr)) - return EINVAL; - if (contentionscope !=3D PTHREAD_SCOPE_SYSTEM - && contentionscope !=3D PTHREAD_SCOPE_PROCESS) - return EINVAL; - /* In future, we may be able to support system scope by escalating the t= hread - priority to exceed the priority class. For now we only support PROCES= S scope. */ - if (contentionscope !=3D PTHREAD_SCOPE_PROCESS) - return ENOTSUP; - (*attr)->contentionscope =3D contentionscope; - return 0; -} - -extern "C" int -pthread_attr_setstack (pthread_attr_t *attr, void *addr, size_t size) -{ - if (!pthread_attr::is_good_object (attr)) - return EINVAL; - if (addr =3D=3D NULL) - return EINVAL; - if (size < PTHREAD_STACK_MIN) - return EINVAL; - /* The incoming address addr points to the lowest addressable byte of a - buffer of size bytes. Due to the way pthread_attr_setstackaddr is de= fined - on Linux, the lowest address ot the stack can't be reliably computed = when - using pthread_attr_setstackaddr/pthread_attr_setstacksize. Therefore= we - store the uppermost address of the stack in stackaddr. See also the - comment in pthread_attr_setstackaddr. */ - (*attr)->stackaddr =3D (caddr_t) addr + size; - (*attr)->stacksize =3D size; - return 0; -} - -extern "C" int -pthread_attr_getstack (const pthread_attr_t *attr, void **addr, size_t *si= ze) -{ - if (!pthread_attr::is_good_object (attr)) - return EINVAL; - /* stackaddr holds the uppermost stack address. See the comment in - pthread_attr_setstack. */ - *addr =3D (caddr_t) (*attr)->stackaddr - (*attr)->stacksize; - *size =3D (*attr)->stacksize; - return 0; -} - -extern "C" int -pthread_attr_setstackaddr (pthread_attr_t *attr, void *addr) -{ - if (!pthread_attr::is_good_object (attr)) - return EINVAL; - if (addr =3D=3D NULL) - return EINVAL; - /* This function is deprecated in SUSv4, but SUSv3 didn't define - if the incoming stack address is the lowest address of the memory - area defined as stack, or if it's the start address of the stack - at which it begins its growth. On Linux it's the latter which - means the uppermost stack address on x86 based systems. See comment - in pthread_attr_setstack as well. */ - (*attr)->stackaddr =3D addr; - return 0; -} - -extern "C" int -pthread_attr_getstackaddr (const pthread_attr_t *attr, void **addr) -{ - if (!pthread_attr::is_good_object (attr)) - return EINVAL; - /* See comment in pthread_attr_setstackaddr. */ - *addr =3D (*attr)->stackaddr; - return 0; -} - -extern "C" int -pthread_attr_setstacksize (pthread_attr_t *attr, size_t size) -{ - if (!pthread_attr::is_good_object (attr)) - return EINVAL; - if (size < PTHREAD_STACK_MIN) - return EINVAL; - (*attr)->stacksize =3D size; - return 0; -} - -extern "C" int -pthread_attr_getstacksize (const pthread_attr_t *attr, size_t *size) -{ - if (!pthread_attr::is_good_object (attr)) - return EINVAL; - /* If the stacksize has not been set by the application, return the - default stacksize. Note that this is different from what - pthread_attr_getstack returns. */ - *size =3D (*attr)->stacksize ?: get_rlimit_stack (); - return 0; -} - -extern "C" int -pthread_attr_setguardsize (pthread_attr_t *attr, size_t size) -{ - if (!pthread_attr::is_good_object (attr)) - return EINVAL; - /* We don't support a guardsize of more than 1 Meg. */ - if (size > 1024 * 1024) - return EINVAL; - (*attr)->guardsize =3D size; - return 0; -} - -extern "C" int -pthread_attr_getguardsize (const pthread_attr_t *attr, size_t *size) -{ - if (!pthread_attr::is_good_object (attr)) - return EINVAL; - *size =3D (*attr)->guardsize; - return 0; -} - -extern "C" int -pthread_attr_destroy (pthread_attr_t *attr) -{ - if (!pthread_attr::is_good_object (attr)) - return EINVAL; - delete (*attr); - *attr =3D NULL; - return 0; -} - int pthread::join (pthread_t *thread, void **return_val, PLARGE_INTEGER timeou= t) { @@ -2581,101 +2340,792 @@ pthread_convert_abstime (clockid_t clock_id, cons= t struct timespec *abstime, return 0; } =20 -extern "C" int -pthread_join (pthread_t thread, void **return_val) +int +pthread_cond::init (pthread_cond_t *cond, const pthread_condattr_t *attr) { - return pthread::join (&thread, (void **) return_val, NULL); -} + pthread_cond_t new_cond; =20 -extern "C" int -pthread_tryjoin_np (pthread_t thread, void **return_val) -{ - LARGE_INTEGER timeout =3D { QuadPart:0LL }; + if (attr && !pthread_condattr::is_good_object (attr)) + return EINVAL; + + cond_initialization_lock.lock (); + + new_cond =3D new pthread_cond (attr ? (*attr) : NULL); + if (!is_good_object (&new_cond)) + { + delete new_cond; + cond_initialization_lock.unlock (); + return EAGAIN; + } + + int ret =3D 0; + + __try + { + *cond =3D new_cond; + } + __except (NO_ERROR) + { + delete new_cond; + ret =3D EINVAL; + } + __endtry + cond_initialization_lock.unlock (); + return ret; +} + +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; + + rwlock_initialization_lock.lock (); + + new_rwlock =3D new pthread_rwlock (attr ? (*attr) : NULL); + if (!is_good_object (&new_rwlock)) + { + delete new_rwlock; + rwlock_initialization_lock.unlock (); + return EAGAIN; + } + + int ret =3D 0; + + __try + { + *rwlock =3D new_rwlock; + } + __except (NO_ERROR) + { + delete new_rwlock; + ret =3D EINVAL; + } + __endtry + rwlock_initialization_lock.unlock (); + return ret; +} + +/* Mutexes */ + +int +pthread_mutex::init (pthread_mutex_t *mutex, + const pthread_mutexattr_t *attr, + const pthread_mutex_t initializer) +{ + if (attr && !pthread_mutexattr::is_good_object (attr)) + return EINVAL; + + mutex_initialization_lock.lock (); + if (initializer =3D=3D NULL || pthread_mutex::is_initializer (mutex)) + { + pthread_mutex_t new_mutex =3D new pthread_mutex (attr ? (*attr) : NU= LL); + if (!is_good_object (&new_mutex)) + { + delete new_mutex; + mutex_initialization_lock.unlock (); + return EAGAIN; + } + + if (!attr && initializer) + { + if (initializer =3D=3D PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP) + new_mutex->type =3D PTHREAD_MUTEX_RECURSIVE; + else if (initializer =3D=3D PTHREAD_NORMAL_MUTEX_INITIALIZER_NP) + new_mutex->type =3D PTHREAD_MUTEX_NORMAL; + else if (initializer =3D=3D PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP) + new_mutex->type =3D PTHREAD_MUTEX_ERRORCHECK; + } + + __try + { + *mutex =3D new_mutex; + } + __except (NO_ERROR) + { + delete new_mutex; + mutex_initialization_lock.unlock (); + return EINVAL; + } + __endtry + } + mutex_initialization_lock.unlock (); + pthread_printf ("*mutex %p, attr %p, initializer %p", *mutex, attr, init= ializer); + + return 0; +} + +/* Spinlocks */ + +int +pthread_spinlock::init (pthread_spinlock_t *spinlock, int pshared) +{ + pthread_spinlock_t new_spinlock =3D new pthread_spinlock (pshared); + if (!is_good_object (&new_spinlock)) + { + delete new_spinlock; + return EAGAIN; + } + + __try + { + *spinlock =3D new_spinlock; + } + __except (NO_ERROR) + { + delete new_spinlock; + return EINVAL; + } + __endtry + pthread_printf ("*spinlock %p, pshared %d", *spinlock, pshared); + return 0; +} + +/* Semaphores */ + +List semaphore::semaphores; + +semaphore::semaphore (int pshared, unsigned int value) +: verifyable_object (SEM_MAGIC), + shared (pshared), + currentvalue (-1), + startvalue (value), + fd (-1), + hash (0ULL), + sem (NULL) +{ + SECURITY_ATTRIBUTES sa =3D (pshared !=3D PTHREAD_PROCESS_PRIVATE) + ? sec_all : sec_none_nih; + this->win32_obj_id =3D ::CreateSemaphore (&sa, value, INT32_MAX, NULL); + if (!this->win32_obj_id) + magic =3D 0; + + semaphores.insert (this); +} + +semaphore::semaphore (unsigned long long shash, LUID sluid, int sfd, + sem_t *ssem, int oflag, mode_t mode, unsigned int value) +: verifyable_object (SEM_MAGIC), + shared (PTHREAD_PROCESS_SHARED), + currentvalue (-1), /* Unused for named semaphores. */ + startvalue (value), + fd (sfd), + hash (shash), + luid (sluid), + sem (ssem) +{ + char name[MAX_PATH]; + + __small_sprintf (name, "semaphore/%016X%08x%08x", + hash, luid.HighPart, luid.LowPart); + this->win32_obj_id =3D ::CreateSemaphore (&sec_all, value, INT32_MAX, na= me); + if (!this->win32_obj_id) + magic =3D 0; + if (GetLastError () =3D=3D ERROR_ALREADY_EXISTS && (oflag & O_EXCL)) + { + __seterrno (); + CloseHandle (this->win32_obj_id); + magic =3D 0; + } + + semaphores.insert (this); +} + +semaphore::~semaphore () +{ + if (win32_obj_id) + CloseHandle (win32_obj_id); + + semaphores.remove (this); +} + +void +semaphore::_post () +{ + LONG dummy; + ReleaseSemaphore (win32_obj_id, 1, &dummy); +} + +int +semaphore::_getvalue (int *sval) +{ + NTSTATUS status; + SEMAPHORE_BASIC_INFORMATION sbi; + + status =3D NtQuerySemaphore (win32_obj_id, SemaphoreBasicInformation, &s= bi, + sizeof sbi, NULL); + int res; + if (NT_SUCCESS (status)) + { + *sval =3D sbi.CurrentCount; + res =3D 0; + } + else + { + *sval =3D startvalue; + __seterrno_from_nt_status (status); + res =3D -1; + } + return res; +} + +int +semaphore::_trywait () +{ + /* FIXME: signals should be able to interrupt semaphores... + We probably need WaitForMultipleObjects here. */ + if (WaitForSingleObject (win32_obj_id, 0) =3D=3D WAIT_TIMEOUT) + { + set_errno (EAGAIN); + return -1; + } + return 0; +} + +int +semaphore::_wait (PLARGE_INTEGER timeout) +{ + __try + { + switch (cygwait (win32_obj_id, timeout, + cw_cancel | cw_cancel_self | cw_sig_eintr)) + { + case WAIT_OBJECT_0: + break; + case WAIT_SIGNALED: + set_errno (EINTR); + return -1; + case WAIT_TIMEOUT: + set_errno (ETIMEDOUT); + return -1; + default: + pthread_printf ("cygwait failed. %E"); + __seterrno (); + return -1; + } + } + __except (NO_ERROR) {} + __endtry + return 0; +} + +void +semaphore::_fixup_before_fork () +{ + NTSTATUS status; + SEMAPHORE_BASIC_INFORMATION sbi; + + status =3D NtQuerySemaphore (win32_obj_id, SemaphoreBasicInformation, &s= bi, + sizeof sbi, NULL); + if (NT_SUCCESS (status)) + currentvalue =3D sbi.CurrentCount; + else + currentvalue =3D startvalue; +} + +void +semaphore::_fixup_after_fork () +{ + if (shared =3D=3D PTHREAD_PROCESS_PRIVATE) + { + pthread_printf ("sem %p", this); + win32_obj_id =3D ::CreateSemaphore (&sec_none_nih, currentvalue, + INT32_MAX, NULL); + if (!win32_obj_id) + api_fatal ("failed to create new win32 semaphore, " + "currentvalue %ld, %E", currentvalue); + } +} + +void +semaphore::_terminate () +{ + int _sem_close (sem_t *, bool); + + if (sem) + _sem_close (sem, false); +} + +/* static members */ + +int +semaphore::init (sem_t *sem, int pshared, unsigned int value) +{ + /* + We can't tell the difference between reinitialising an + existing semaphore and initialising a semaphore who's + contents happen to be a valid pointer + */ + if (is_good_object (sem)) + paranoid_printf ("potential attempt to reinitialise a semaphore"); + + if (value > SEM_VALUE_MAX) + { + set_errno(EINVAL); + return -1; + } + + *sem =3D new semaphore (pshared, value); + + if (!is_good_object (sem)) + { + delete (*sem); + *sem =3D NULL; + set_errno(EAGAIN); + return -1; + } + return 0; +} + +int +semaphore::destroy (sem_t *sem) +{ + if (!is_good_object (sem)) + { + set_errno(EINVAL); + return -1; + } + + /* It's invalid to destroy a semaphore not opened with sem_init. */ + if ((*sem)->fd !=3D -1) + { + set_errno(EINVAL); + return -1; + } + + /* FIXME - new feature - test for busy against threads... */ + + delete (*sem); + *sem =3D NULL; + return 0; +} + +int +semaphore::close (sem_t *sem) +{ + if (!is_good_object (sem)) + { + set_errno(EINVAL); + return -1; + } + + /* It's invalid to close a semaphore not opened with sem_open. */ + if ((*sem)->fd =3D=3D -1) + { + set_errno(EINVAL); + return -1; + } + + delete (*sem); + delete sem; + return 0; +} + +sem_t * +semaphore::open (unsigned long long hash, LUID luid, int fd, int oflag, + mode_t mode, unsigned int value, bool &wasopen) +{ + if (value > SEM_VALUE_MAX) + { + set_errno (EINVAL); + return NULL; + } + + /* sem_open is supposed to return the same pointer, if the same named + semaphore is opened multiple times in the same process, as long as + the semaphore hasn't been closed or unlinked in the meantime. */ + semaphores.mx.lock (); + for (semaphore *sema =3D semaphores.head; sema; sema =3D sema->next) + if (sema->fd >=3D 0 && sema->hash =3D=3D hash + && sema->luid.HighPart =3D=3D luid.HighPart + && sema->luid.LowPart =3D=3D luid.LowPart) + { + wasopen =3D true; + semaphores.mx.unlock (); + return sema->sem; + } + semaphores.mx.unlock (); + + wasopen =3D false; + sem_t *sem =3D new sem_t; + if (!sem) + { + set_errno (ENOMEM); + return NULL; + } + + *sem =3D new semaphore (hash, luid, fd, sem, oflag, mode, value); + + if (!is_good_object (sem)) + { + delete *sem; + delete sem; + return NULL; + } + return sem; +} + +int +semaphore::wait (sem_t *sem) +{ + pthread_testcancel (); + + if (!is_good_object (sem)) + { + set_errno (EINVAL); + return -1; + } + + return (*sem)->_wait (); +} + +int +semaphore::trywait (sem_t *sem) +{ + if (!is_good_object (sem)) + { + set_errno (EINVAL); + return -1; + } + + return (*sem)->_trywait (); +} + +int +semaphore::clockwait (sem_t *sem, clockid_t clock_id, + const struct timespec *abstime) +{ + LARGE_INTEGER timeout; + + if (!is_good_object (sem)) + { + set_errno (EINVAL); + return -1; + } + + /* According to SUSv3, abstime need not be checked for validity, + if the semaphore can be locked immediately. */ + if (!(*sem)->_trywait ()) + return 0; + + __try + { + int err =3D pthread_convert_abstime (clock_id, abstime, &timeout); + if (err) + return err; + + return (*sem)->_wait (&timeout); + } + __except (NO_ERROR) {} + __endtry + return EINVAL; +} + +int +semaphore::post (sem_t *sem) +{ + if (!is_good_object (sem)) + { + set_errno (EINVAL); + return -1; + } + + (*sem)->_post (); + return 0; +} + +int +semaphore::getvalue (sem_t *sem, int *sval) +{ + __try + { + if (is_good_object (sem)) + return (*sem)->_getvalue (sval); + } + __except (NO_ERROR) {} + __endtry + set_errno (EINVAL); + return -1; +} + +int +semaphore::getinternal (sem_t *sem, int *sfd, unsigned long long *shash, + LUID *sluid, unsigned int *sval) +{ + __try + { + if (!is_good_object (sem)) + __leave; + if ((*sfd =3D (*sem)->fd) < 0) + __leave; + *shash =3D (*sem)->hash; + *sluid =3D (*sem)->luid; + /* POSIX defines the value in calls to sem_init/sem_open as unsigned, + but the sem_getvalue gets a pointer to int to return the value. + Go figure! */ + return (*sem)->_getvalue ((int *)sval); + } + __except (NO_ERROR) {} + __endtry + set_errno (EINVAL); + return -1; +} + +/* pthread_null */ +pthread * +pthread_null::get_null_pthread () +{ + /* because of weird entry points */ + _instance.magic =3D 0; + return &_instance; +} + +pthread_null::pthread_null () +{ + attr.joinable =3D PTHREAD_CREATE_DETACHED; + /* Mark ourselves as invalid */ + magic =3D 0; +} + +pthread_null::~pthread_null () +{ +} + +bool +pthread_null::create (void *(*)(void *), pthread_attr *, void *) +{ + return true; +} + +void +pthread_null::exit (void *value_ptr) +{ + _my_tls.remove (INFINITE); + ExitThread (0); +} + +int +pthread_null::cancel () +{ + return 0; +} + +void +pthread_null::testcancel () +{ +} + +int +pthread_null::setcancelstate (int state, int *oldstate) +{ + return EINVAL; +} + +int +pthread_null::setcanceltype (int type, int *oldtype) +{ + return EINVAL; +} + +void +pthread_null::push_cleanup_handler (__pthread_cleanup_handler *handler) +{ +} + +void +pthread_null::pop_cleanup_handler (int const execute) +{ +} + +unsigned long +pthread_null::getsequence_np () +{ + return 0; +} + +pthread_null pthread_null::_instance; + +int +pthread_barrier::init (const pthread_barrierattr_t * attr, unsigned count) +{ + pthread_mutex_t * mutex =3D NULL; + + if (unlikely ((attr !=3D NULL + && (! pthread_barrierattr::is_good_object (attr) + || (*attr)->shared =3D=3D PTHREAD_PROCESS_SHARED)) + || count =3D=3D 0)) + return EINVAL; + + int retval =3D pthread_mutex_init (&mtx, NULL); + if (unlikely (retval !=3D 0)) + return retval; + + retval =3D pthread_cond_init (&cond, NULL); + if (unlikely (retval !=3D 0)) + { + int ret =3D pthread_mutex_destroy (mutex); + if (ret !=3D 0) + api_fatal ("pthread_mutex_destroy (%p) =3D %d", mutex, ret); =20 - return pthread::join (&thread, (void **) return_val, &timeout); -} + mtx =3D NULL; + return retval; + } =20 -extern "C" int -pthread_timedjoin_np (pthread_t thread, void **return_val, - const struct timespec *abstime) -{ - LARGE_INTEGER timeout; + cnt =3D count; + cyc =3D 0; + wt =3D 0; =20 - int err =3D pthread_convert_abstime (CLOCK_REALTIME, abstime, &timeout); - if (err) - return err; - return pthread::join (&thread, (void **) return_val, &timeout); + return 0; } =20 -extern "C" int -pthread_getaffinity_np (pthread_t thread, size_t sizeof_set, cpu_set_t *se= t) +int +pthread_barrier::destroy () { - if (!pthread::is_good_object (&thread)) - return ESRCH; + if (unlikely (wt !=3D 0)) + return EBUSY; =20 - return sched_get_thread_affinity (thread->win32_obj_id, sizeof_set, set); -} + int retval =3D pthread_cond_destroy (&cond); + if (unlikely (retval !=3D 0)) + return retval; + else + cond =3D NULL; =20 -extern "C" int -pthread_setaffinity_np (pthread_t thread, size_t sizeof_set, const cpu_set= _t *set) -{ - if (!pthread::is_good_object (&thread)) - return ESRCH; + retval =3D pthread_mutex_destroy (&mtx); + if (unlikely (retval !=3D 0)) + return retval; + else + mtx =3D NULL; =20 - return sched_set_thread_affinity (thread->win32_obj_id, sizeof_set, set); + cnt =3D 0; + cyc =3D 0; + wt =3D 0; + + return 0; } =20 -extern "C" int -pthread_getattr_np (pthread_t thread, pthread_attr_t *attr) +int +pthread_barrier::wait () { - THREAD_BASIC_INFORMATION tbi; - NTSTATUS status; + int retval =3D pthread_mutex_lock (&mtx); + if (unlikely (retval !=3D 0)) + return retval; =20 - if (!pthread::is_good_object (&thread)) - return ESRCH; + if (unlikely (wt >=3D cnt)) + { + api_fatal ("wt >=3D cnt (%u >=3D %u)", wt, cnt); + return EINVAL; + } =20 - /* attr may not be pre-initialized */ - if (!pthread_attr::is_good_object (attr)) - { - int rv =3D pthread_attr_init (attr); - if (rv !=3D 0) - return rv; - } + if (unlikely (++wt =3D=3D cnt)) + { + ++cyc; + /* This is the last thread to reach the barrier. Signal the waiting + threads to wake up and continue. */ + retval =3D pthread_cond_broadcast (&cond); + if (unlikely (retval !=3D 0)) + goto cond_error; =20 - (*attr)->joinable =3D thread->attr.joinable; - (*attr)->contentionscope =3D thread->attr.contentionscope; - (*attr)->inheritsched =3D thread->attr.inheritsched; - (*attr)->schedparam =3D thread->attr.schedparam; - (*attr)->guardsize =3D thread->attr.guardsize; + wt =3D 0; + retval =3D pthread_mutex_unlock (&mtx); + if (unlikely (retval !=3D 0)) + abort (); =20 - status =3D NtQueryInformationThread (thread->win32_obj_id, - ThreadBasicInformation, - &tbi, sizeof (tbi), NULL); - if (NT_SUCCESS (status)) - { - PTEB teb =3D (PTEB) tbi.TebBaseAddress; - /* stackaddr holds the uppermost stack address. See the comments - in pthread_attr_setstack and pthread_attr_setstackaddr for a - description. */ - (*attr)->stackaddr =3D teb->Tib.StackBase; - (*attr)->stacksize =3D (uintptr_t) teb->Tib.StackBase - - (uintptr_t) (teb->DeallocationStack ?: teb->Tib.StackLimit); + return PTHREAD_BARRIER_SERIAL_THREAD; } else { - debug_printf ("NtQueryInformationThread(ThreadBasicInformation), " - "status %y", status); - (*attr)->stackaddr =3D thread->attr.stackaddr; - (*attr)->stacksize =3D thread->attr.stacksize; + uint64_t cycle =3D cyc; + do + { + retval =3D pthread_cond_wait (&cond, &mtx); + if (unlikely (retval !=3D 0)) + goto cond_error; + } + while (unlikely (cycle =3D=3D cyc)); + + retval =3D pthread_mutex_unlock (&mtx); + if (unlikely (retval !=3D 0)) + api_fatal ("pthread_mutex_unlock (%p) =3D %d", &mtx, retval); + + return 0; } =20 - return 0; + cond_error: + { + --wt; + int ret =3D pthread_mutex_unlock (&mtx); + if (unlikely (ret !=3D 0)) + api_fatal ("pthread_mutex_unlock (%p) =3D %d", &mtx, ret); + + return retval; + } } =20 -/* For Linux compatibility, the length of a thread name is 16 characters. = */ -#define THRNAMELEN 16 +/* Returns running thread's name; works for both cygthreads and pthreads */ +char * +mythreadname (void) +{ + char *result =3D (char *) cygthread::name (); =20 -extern "C" int + if (result =3D=3D _my_tls.locals.unknown_thread_name) + { + result[0] =3D '\0'; + pthread_getname_np (pthread_self (), result, (size_t) THRNAMELEN); + } + + return result; +} + +extern "C" +{ + +/* Thread creation */ + +int +pthread_create (pthread_t *thread, const pthread_attr_t *attr, + void *(*start_routine) (void *), void *arg) +{ + return pthread::create (thread, attr, start_routine, arg); +} + +int +pthread_once (pthread_once_t * once_control, void (*init_routine) (void)) +{ + return pthread::once (once_control, init_routine); +} + +int +pthread_atfork (void (*prepare)(void), void (*parent)(void), void (*child)= (void)) +{ + return pthread::atfork (prepare, parent, child); +} + +/* ID */ + +pthread_t pthread_self () +{ + return pthread::self (); +} + +int +pthread_equal (pthread_t t1, pthread_t t2) +{ + return pthread::equal (t1, t2); +} + +unsigned long +pthread_getsequence_np (pthread_t * thread) +{ + if (!pthread::is_good_object (thread)) + return EINVAL; + return (*thread)->getsequence_np (); +} + +/* Thread name */ + +int pthread_getname_np (pthread_t thread, char *buf, size_t buflen) { char *name; @@ -2709,7 +3159,7 @@ pthread_getname_np (pthread_t thread, char *buf, size= _t buflen) return ret; } =20 -extern "C" int +int pthread_setname_np (pthread_t thread, const char *name) { char *oldname, *cp; @@ -2727,744 +3177,606 @@ pthread_setname_np (pthread_t thread, const char = *name) oldname =3D thread->attr.name; thread->attr.name =3D cp; =20 - SetThreadName (GetThreadId (thread->win32_obj_id), thread->attr.name); - - if (oldname) - free (oldname); - - return 0; -} - -/* Returns running thread's name; works for both cygthreads and pthreads */ -char * -mythreadname (void) -{ - char *result =3D (char *) cygthread::name (); - - if (result =3D=3D _my_tls.locals.unknown_thread_name) - { - result[0] =3D '\0'; - pthread_getname_np (pthread_self (), result, (size_t) THRNAMELEN); - } - - return result; -} -#undef THRNAMELEN - -/* provided for source level compatability. - See http://www.opengroup.org/onlinepubs/007908799/xsh/pthread_getconcur= rency.html -*/ -extern "C" int -pthread_getconcurrency () -{ - return MT_INTERFACE->concurrency; -} - -extern "C" int -pthread_getcpuclockid (pthread_t thread, clockid_t *clk_id) -{ - if (!pthread::is_good_object (&thread)) - return (ESRCH); - *clk_id =3D (clockid_t) THREADID_TO_CLOCKID (thread->getsequence_np ()); - return 0; -} - -/* keep this in sync with sched.cc */ -extern "C" int -pthread_getschedparam (pthread_t thread, int *policy, - struct sched_param *param) -{ - if (!pthread::is_good_object (&thread)) - return ESRCH; - *policy =3D SCHED_FIFO; - param->sched_priority =3D sched_get_thread_priority (thread->win32_obj_i= d); - return 0; -} - -/* Thread Specific Data */ -extern "C" int -pthread_key_create (pthread_key_t *key, void (*destructor) (void *)) -{ - *key =3D new pthread_key (destructor); - - if (!pthread_key::is_good_object (key)) - { - delete (*key); - *key =3D NULL; - return EAGAIN; - } - return 0; -} - -extern "C" int -pthread_key_delete (pthread_key_t key) -{ - if (!pthread_key::is_good_object (&key)) - return EINVAL; + SetThreadName (GetThreadId (thread->win32_obj_id), thread->attr.name); =20 - delete (key); - return 0; -} + if (oldname) + free (oldname); =20 -/* provided for source level compatability. See -http://www.opengroup.org/onlinepubs/007908799/xsh/pthread_getconcurrency.h= tml -*/ -extern "C" int -pthread_setconcurrency (int new_level) -{ - if (new_level < 0) - return EINVAL; - MT_INTERFACE->concurrency =3D new_level; return 0; } =20 -/* keep syncronised with sched.cc */ -extern "C" int -pthread_setschedparam (pthread_t thread, int policy, - const struct sched_param *param) +/* Thread exit */ + +void +pthread_exit (void *value_ptr) { - if (!pthread::is_good_object (&thread)) - return ESRCH; - if (policy !=3D SCHED_FIFO) - return ENOTSUP; - if (!param) - return EINVAL; - int rv =3D - sched_set_thread_priority (thread->win32_obj_id, param->sched_priority= ); - if (!rv) - thread->attr.schedparam.sched_priority =3D param->sched_priority; - return rv; + pthread::self ()->exit (value_ptr); + __builtin_unreachable (); /* FIXME: don't know why this is necessary */ } =20 -extern "C" int -pthread_setschedprio (pthread_t thread, int priority) +int +pthread_detach (pthread_t thread) { - if (!pthread::is_good_object (&thread)) - return ESRCH; - int rv =3D - sched_set_thread_priority (thread->win32_obj_id, priority); - if (!rv) - thread->attr.schedparam.sched_priority =3D priority; - return rv; + return pthread::detach (&thread); } =20 -extern "C" int -pthread_setspecific (pthread_key_t key, const void *value) +int +pthread_join (pthread_t thread, void **return_val) { - if (!pthread_key::is_good_object (&key)) - return EINVAL; - (key)->set (value); - return 0; + return pthread::join (&thread, (void **) return_val, NULL); } =20 -extern "C" void * -pthread_getspecific (pthread_key_t key) +int +pthread_tryjoin_np (pthread_t thread, void **return_val) { - if (!pthread_key::is_good_object (&key)) - return NULL; - - return (key)->get (); + LARGE_INTEGER timeout =3D { QuadPart:0LL }; =20 + return pthread::join (&thread, (void **) return_val, &timeout); } =20 -extern "C" int -pthread_cond_destroy (pthread_cond_t *cond) +int +pthread_timedjoin_np (pthread_t thread, void **return_val, + const struct timespec *abstime) { - if (pthread_cond::is_initializer (cond)) - return 0; - if (!pthread_cond::is_good_object (cond)) - return EINVAL; + LARGE_INTEGER timeout; =20 - /* reads are atomic */ - if ((*cond)->waiting) - return EBUSY; + int err =3D pthread_convert_abstime (CLOCK_REALTIME, abstime, &timeout); + if (err) + return err; + return pthread::join (&thread, (void **) return_val, &timeout); +} =20 - delete (*cond); - *cond =3D NULL; +/* Thread suspend/resume */ =20 - return 0; +/* This isn't a posix call... should we keep it? */ +int +pthread_suspend (pthread_t thread) +{ + return pthread::suspend (&thread); } =20 +/* same */ int -pthread_cond::init (pthread_cond_t *cond, const pthread_condattr_t *attr) +pthread_continue (pthread_t thread) { - pthread_cond_t new_cond; + return pthread::resume (&thread); +} =20 - if (attr && !pthread_condattr::is_good_object (attr)) +/* Thread signal */ + +int +pthread_kill (pthread_t thread, int sig) +{ + // lock myself, for the use of thread2signal + // two different kills might clash: FIXME + + if (!pthread::is_good_object (&thread)) return EINVAL; =20 - cond_initialization_lock.lock (); + /* check that sig is in right range */ + if (sig < 0 || sig >=3D _NSIG) + return EINVAL; =20 - new_cond =3D new pthread_cond (attr ? (*attr) : NULL); - if (!is_good_object (&new_cond)) + siginfo_t si =3D {0}; + si.si_signo =3D sig; + si.si_code =3D SI_USER; + si.si_pid =3D myself->pid; + si.si_uid =3D myself->uid; + int rval; + if (!thread->valid) + rval =3D ESRCH; + else if (sig) { - delete new_cond; - cond_initialization_lock.unlock (); - return EAGAIN; + rval =3D (int) sig_send (NULL, si, thread->cygtls); + if (rval =3D=3D -1) + rval =3D get_errno (); } + else + switch (WaitForSingleObject (thread->win32_obj_id, 0)) + { + case WAIT_TIMEOUT: + rval =3D 0; + break; + default: + rval =3D ESRCH; + break; + } =20 - int ret =3D 0; + // unlock myself + return rval; +} =20 - __try - { - *cond =3D new_cond; - } - __except (NO_ERROR) - { - delete new_cond; - ret =3D EINVAL; - } - __endtry - cond_initialization_lock.unlock (); - return ret; +int +pthread_sigmask (int operation, const sigset_t *set, sigset_t *old_set) +{ + int res =3D handle_sigprocmask (operation, set, old_set, _my_tls.sigmask= ); + syscall_printf ("%d =3D pthread_sigmask(%d, %p, %p)", + res, operation, set, old_set); + return res; } =20 -extern "C" int -pthread_cond_broadcast (pthread_cond_t *cond) +int +pthread_sigqueue (pthread_t *thread, int sig, const union sigval value) { - if (pthread_cond::is_initializer (cond)) - return 0; - if (!pthread_cond::is_good_object (cond)) + siginfo_t si =3D {0}; + + if (!pthread::is_good_object (thread)) return EINVAL; + if (!(*thread)->valid) + return ESRCH; =20 - (*cond)->unblock (true); + si.si_signo =3D sig; + si.si_code =3D SI_QUEUE; + si.si_value =3D value; + si.si_pid =3D myself->pid; + si.si_uid =3D myself->uid; + return (int) sig_send (NULL, si, (*thread)->cygtls); +} =20 - return 0; +/* Cancelability */ + +int +pthread_cancel (pthread_t thread) +{ + return pthread::cancel (thread); } =20 -extern "C" int -pthread_cond_signal (pthread_cond_t *cond) +int +pthread_setcancelstate (int state, int *oldstate) { - if (pthread_cond::is_initializer (cond)) - return 0; - if (!pthread_cond::is_good_object (cond)) - return EINVAL; + return pthread::self ()->setcancelstate (state, oldstate); +} =20 - (*cond)->unblock (false); +int +pthread_setcanceltype (int type, int *oldtype) +{ + return pthread::self ()->setcanceltype (type, oldtype); +} =20 - return 0; +void +pthread_testcancel () +{ + pthread::self ()->testcancel (); } =20 -static int -__pthread_cond_wait_init (pthread_cond_t *cond, pthread_mutex_t *mutex) +void +_pthread_cleanup_push (__pthread_cleanup_handler *handler) { - if (!pthread_mutex::is_good_object (mutex)) - return EINVAL; - if (!(*mutex)->can_be_unlocked ()) - return EPERM; + pthread::self ()->push_cleanup_handler (handler); +} =20 - if (pthread_cond::is_initializer (cond)) - pthread_cond::init (cond, NULL); - if (!pthread_cond::is_good_object (cond)) - return EINVAL; +void +_pthread_cleanup_pop (int execute) +{ + pthread::self ()->pop_cleanup_handler (execute); +} =20 - return 0; +/* provided for source level compatability. + See http://www.opengroup.org/onlinepubs/007908799/xsh/pthread_getconcur= rency.html +*/ +int +pthread_getconcurrency () +{ + return MT_INTERFACE->concurrency; } =20 -static int -__pthread_cond_clockwait (pthread_cond_t *cond, pthread_mutex_t *mutex, - clockid_t clock_id, const struct timespec *abstime) +/* provided for source level compatability. See +http://www.opengroup.org/onlinepubs/007908799/xsh/pthread_getconcurrency.h= tml +*/ +int +pthread_setconcurrency (int new_level) { - int err =3D 0; - LARGE_INTEGER timeout; + if (new_level < 0) + return EINVAL; + MT_INTERFACE->concurrency =3D new_level; + return 0; +} =20 - do - { - err =3D pthread_convert_abstime (clock_id, abstime, &timeout); - if (err) - break; +/* Thread scheduling */ =20 - err =3D (*cond)->wait (*mutex, &timeout); - } - while (err =3D=3D ETIMEDOUT); - return err; +/* keep this in sync with sched.cc */ +int +pthread_getschedparam (pthread_t thread, int *policy, + struct sched_param *param) +{ + if (!pthread::is_good_object (&thread)) + return ESRCH; + *policy =3D SCHED_FIFO; + param->sched_priority =3D sched_get_thread_priority (thread->win32_obj_i= d); + return 0; +} + +/* keep this in sync with sched.cc */ +int +pthread_setschedparam (pthread_t thread, int policy, + const struct sched_param *param) +{ + if (!pthread::is_good_object (&thread)) + return ESRCH; + if (policy !=3D SCHED_FIFO) + return ENOTSUP; + if (!param) + return EINVAL; + int rv =3D + sched_set_thread_priority (thread->win32_obj_id, param->sched_priority= ); + if (!rv) + thread->attr.schedparam.sched_priority =3D param->sched_priority; + return rv; } =20 -extern "C" int -pthread_cond_clockwait (pthread_cond_t *cond, pthread_mutex_t *mutex, - clockid_t clock_id, const struct timespec *abstime) +int +pthread_setschedprio (pthread_t thread, int priority) { - int err =3D 0; - - pthread_testcancel (); - - __try - { - err =3D __pthread_cond_wait_init (cond, mutex); - if (err) - __leave; - err =3D __pthread_cond_clockwait (cond, mutex, clock_id, abstime); - } - __except (NO_ERROR) - { - return EINVAL; - } - __endtry - return err; + if (!pthread::is_good_object (&thread)) + return ESRCH; + int rv =3D + sched_set_thread_priority (thread->win32_obj_id, priority); + if (!rv) + thread->attr.schedparam.sched_priority =3D priority; + return rv; } =20 -extern "C" int -pthread_cond_timedwait (pthread_cond_t *cond, pthread_mutex_t *mutex, - const struct timespec *abstime) -{ - int err =3D 0; +/* Thread affinity */ =20 - pthread_testcancel (); +int +pthread_getaffinity_np (pthread_t thread, size_t sizeof_set, cpu_set_t *se= t) +{ + if (!pthread::is_good_object (&thread)) + return ESRCH; =20 - __try - { - err =3D __pthread_cond_wait_init (cond, mutex); - if (err) - __leave; - err =3D __pthread_cond_clockwait (cond, mutex, (*cond)->clock_id, ab= stime); - } - __except (NO_ERROR) - { - return EINVAL; - } - __endtry - return err; + return sched_get_thread_affinity (thread->win32_obj_id, sizeof_set, set); } =20 -extern "C" int -pthread_cond_wait (pthread_cond_t *cond, pthread_mutex_t *mutex) +int +pthread_setaffinity_np (pthread_t thread, size_t sizeof_set, const cpu_set= _t *set) { - pthread_testcancel (); + if (!pthread::is_good_object (&thread)) + return ESRCH; =20 - int err =3D __pthread_cond_wait_init (cond, mutex); - if (err) - return err; - return (*cond)->wait (*mutex, NULL); + return sched_set_thread_affinity (thread->win32_obj_id, sizeof_set, set); } =20 -extern "C" int -pthread_condattr_init (pthread_condattr_t *condattr) +/* pthread_attr */ + +int +pthread_attr_init (pthread_attr_t *attr) { - *condattr =3D new pthread_condattr; - if (!pthread_condattr::is_good_object (condattr)) + *attr =3D new pthread_attr; + if (!pthread_attr::is_good_object (attr)) { - delete (*condattr); - *condattr =3D NULL; + delete (*attr); + *attr =3D NULL; return ENOMEM; } return 0; } =20 -extern "C" int -pthread_condattr_getpshared (const pthread_condattr_t *attr, int *pshared) +int +pthread_attr_getinheritsched (const pthread_attr_t *attr, + int *inheritsched) { - if (!pthread_condattr::is_good_object (attr)) + if (!pthread_attr::is_good_object (attr)) return EINVAL; - *pshared =3D (*attr)->shared; + *inheritsched =3D (*attr)->inheritsched; return 0; } =20 -extern "C" int -pthread_condattr_setpshared (pthread_condattr_t *attr, int pshared) +int +pthread_attr_getschedparam (const pthread_attr_t *attr, + struct sched_param *param) { - if (!pthread_condattr::is_good_object (attr)) - return EINVAL; - if ((pshared < 0) || (pshared > 1)) - return EINVAL; - /* shared cond vars not currently supported */ - if (pshared !=3D PTHREAD_PROCESS_PRIVATE) + if (!pthread_attr::is_good_object (attr)) return EINVAL; - (*attr)->shared =3D pshared; + *param =3D (*attr)->schedparam; return 0; } =20 -extern "C" int -pthread_condattr_getclock (const pthread_condattr_t *attr, clockid_t *cloc= k_id) +/* 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 fu= ture. + However that's extremely unlikely, so short and sweet will do us */ +int +pthread_attr_getschedpolicy (const pthread_attr_t *attr, int *policy) { - if (!pthread_condattr::is_good_object (attr)) + if (!pthread_attr::is_good_object (attr)) return EINVAL; - *clock_id =3D (*attr)->clock_id; + *policy =3D SCHED_FIFO; return 0; } =20 -extern "C" int -pthread_condattr_setclock (pthread_condattr_t *attr, clockid_t clock_id) -{ - if (!pthread_condattr::is_good_object (attr)) - return EINVAL; - if (CLOCKID_IS_PROCESS (clock_id) || CLOCKID_IS_THREAD (clock_id) - || clock_id >=3D MAX_CLOCKS) - return EINVAL; - (*attr)->clock_id =3D clock_id; - return 0; -} =20 -extern "C" int -pthread_condattr_destroy (pthread_condattr_t *condattr) +int +pthread_attr_getscope (const pthread_attr_t *attr, int *contentionscope) { - if (!pthread_condattr::is_good_object (condattr)) + if (!pthread_attr::is_good_object (attr)) return EINVAL; - delete (*condattr); - *condattr =3D NULL; + *contentionscope =3D (*attr)->contentionscope; return 0; } =20 -extern "C" int -pthread_rwlock_destroy (pthread_rwlock_t *rwlock) +int +pthread_attr_setdetachstate (pthread_attr_t *attr, int detachstate) { - if (pthread_rwlock::is_initializer (rwlock)) - return 0; - if (!pthread_rwlock::is_good_object (rwlock)) + if (!pthread_attr::is_good_object (attr)) return EINVAL; - - if ((*rwlock)->writer || (*rwlock)->readers || - (*rwlock)->waiting_readers || (*rwlock)->waiting_writers) - return EBUSY; - - delete (*rwlock); - *rwlock =3D NULL; - + if (detachstate < 0 || detachstate > 1) + return EINVAL; + (*attr)->joinable =3D detachstate; return 0; } =20 int -pthread_rwlock::init (pthread_rwlock_t *rwlock, const pthread_rwlockattr_t= *attr) +pthread_attr_getdetachstate (const pthread_attr_t *attr, int *detachstate) { - pthread_rwlock_t new_rwlock; - - if (attr && !pthread_rwlockattr::is_good_object (attr)) + if (!pthread_attr::is_good_object (attr)) return EINVAL; - - rwlock_initialization_lock.lock (); - - new_rwlock =3D new pthread_rwlock (attr ? (*attr) : NULL); - if (!is_good_object (&new_rwlock)) - { - delete new_rwlock; - rwlock_initialization_lock.unlock (); - return EAGAIN; - } - - int ret =3D 0; - - __try - { - *rwlock =3D new_rwlock; - } - __except (NO_ERROR) - { - delete new_rwlock; - ret =3D EINVAL; - } - __endtry - rwlock_initialization_lock.unlock (); - return ret; + *detachstate =3D (*attr)->joinable; + return 0; } =20 -extern "C" int -pthread_rwlock_rdlock (pthread_rwlock_t *rwlock) +int +pthread_attr_setinheritsched (pthread_attr_t *attr, int inheritsched) { - pthread_testcancel (); - - if (pthread_rwlock::is_initializer (rwlock)) - pthread_rwlock::init (rwlock, NULL); - if (!pthread_rwlock::is_good_object (rwlock)) + if (!pthread_attr::is_good_object (attr)) return EINVAL; - - return (*rwlock)->rdlock (); + if (inheritsched !=3D PTHREAD_INHERIT_SCHED + && inheritsched !=3D PTHREAD_EXPLICIT_SCHED) + return ENOTSUP; + (*attr)->inheritsched =3D inheritsched; + return 0; } =20 -extern "C" int -pthread_rwlock_clockrdlock (pthread_rwlock_t *rwlock, clockid_t clock_id, - const struct timespec *abstime) +int +pthread_attr_setschedparam (pthread_attr_t *attr, + const struct sched_param *param) { - LARGE_INTEGER timeout; - - pthread_testcancel (); - - if (pthread_rwlock::is_initializer (rwlock)) - pthread_rwlock::init (rwlock, NULL); - if (!pthread_rwlock::is_good_object (rwlock)) + if (!pthread_attr::is_good_object (attr)) return EINVAL; - - /* According to SUSv3, abstime need not be checked for validity, - if the rwlock can be locked immediately. */ - if (!(*rwlock)->tryrdlock ()) - return 0; - - __try - { - int err =3D pthread_convert_abstime (clock_id, abstime, &timeout); - if (err) - return err; - - return (*rwlock)->rdlock (&timeout); - } - __except (NO_ERROR) {} - __endtry - return EINVAL; -} - -extern "C" int -pthread_rwlock_timedrdlock (pthread_rwlock_t *rwlock, - const struct timespec *abstime) -{ - return pthread_rwlock_clockrdlock (rwlock, CLOCK_REALTIME, abstime); + if (!valid_sched_parameters (param)) + return ENOTSUP; + (*attr)->schedparam =3D *param; + return 0; } =20 -extern "C" int -pthread_rwlock_tryrdlock (pthread_rwlock_t *rwlock) +/* See __pthread_attr_getschedpolicy for some notes */ +int +pthread_attr_setschedpolicy (pthread_attr_t *attr, int policy) { - if (pthread_rwlock::is_initializer (rwlock)) - pthread_rwlock::init (rwlock, NULL); - if (!pthread_rwlock::is_good_object (rwlock)) + if (!pthread_attr::is_good_object (attr)) return EINVAL; - - return (*rwlock)->tryrdlock (); + if (policy !=3D SCHED_FIFO) + return ENOTSUP; + return 0; } =20 -extern "C" int -pthread_rwlock_wrlock (pthread_rwlock_t *rwlock) +int +pthread_attr_setscope (pthread_attr_t *attr, int contentionscope) { - pthread_testcancel (); - - if (pthread_rwlock::is_initializer (rwlock)) - pthread_rwlock::init (rwlock, NULL); - if (!pthread_rwlock::is_good_object (rwlock)) + if (!pthread_attr::is_good_object (attr)) return EINVAL; - - return (*rwlock)->wrlock (); + if (contentionscope !=3D PTHREAD_SCOPE_SYSTEM + && contentionscope !=3D PTHREAD_SCOPE_PROCESS) + return EINVAL; + /* In future, we may be able to support system scope by escalating the t= hread + priority to exceed the priority class. For now we only support PROCES= S scope. */ + if (contentionscope !=3D PTHREAD_SCOPE_PROCESS) + return ENOTSUP; + (*attr)->contentionscope =3D contentionscope; + return 0; } =20 -extern "C" int -pthread_rwlock_clockwrlock (pthread_rwlock_t *rwlock, clockid_t clock_id, - const struct timespec *abstime) +int +pthread_attr_setstack (pthread_attr_t *attr, void *addr, size_t size) { - LARGE_INTEGER timeout; - - pthread_testcancel (); - - if (pthread_rwlock::is_initializer (rwlock)) - pthread_rwlock::init (rwlock, NULL); - if (!pthread_rwlock::is_good_object (rwlock)) + if (!pthread_attr::is_good_object (attr)) return EINVAL; - - /* According to SUSv3, abstime need not be checked for validity, - if the rwlock can be locked immediately. */ - if (!(*rwlock)->trywrlock ()) - return 0; - - __try - { - int err =3D pthread_convert_abstime (clock_id, abstime, &timeout); - if (err) - return err; - - return (*rwlock)->wrlock (&timeout); - } - __except (NO_ERROR) {} - __endtry - return EINVAL; + if (addr =3D=3D NULL) + return EINVAL; + if (size < PTHREAD_STACK_MIN) + return EINVAL; + /* The incoming address addr points to the lowest addressable byte of a + buffer of size bytes. Due to the way pthread_attr_setstackaddr is de= fined + on Linux, the lowest address ot the stack can't be reliably computed = when + using pthread_attr_setstackaddr/pthread_attr_setstacksize. Therefore= we + store the uppermost address of the stack in stackaddr. See also the + comment in pthread_attr_setstackaddr. */ + (*attr)->stackaddr =3D (caddr_t) addr + size; + (*attr)->stacksize =3D size; + return 0; } =20 -extern "C" int -pthread_rwlock_timedwrlock (pthread_rwlock_t *rwlock, - const struct timespec *abstime) +int +pthread_attr_getstack (const pthread_attr_t *attr, void **addr, size_t *si= ze) { - return pthread_rwlock_clockwrlock (rwlock, CLOCK_REALTIME, abstime); + if (!pthread_attr::is_good_object (attr)) + return EINVAL; + /* stackaddr holds the uppermost stack address. See the comment in + pthread_attr_setstack. */ + *addr =3D (caddr_t) (*attr)->stackaddr - (*attr)->stacksize; + *size =3D (*attr)->stacksize; + return 0; } =20 -extern "C" int -pthread_rwlock_trywrlock (pthread_rwlock_t *rwlock) +int +pthread_attr_setstackaddr (pthread_attr_t *attr, void *addr) { - if (pthread_rwlock::is_initializer (rwlock)) - pthread_rwlock::init (rwlock, NULL); - if (!pthread_rwlock::is_good_object (rwlock)) + if (!pthread_attr::is_good_object (attr)) return EINVAL; - - return (*rwlock)->trywrlock (); + if (addr =3D=3D NULL) + return EINVAL; + /* This function is deprecated in SUSv4, but SUSv3 didn't define + if the incoming stack address is the lowest address of the memory + area defined as stack, or if it's the start address of the stack + at which it begins its growth. On Linux it's the latter which + means the uppermost stack address on x86 based systems. See comment + in pthread_attr_setstack as well. */ + (*attr)->stackaddr =3D addr; + return 0; } =20 -extern "C" int -pthread_rwlock_unlock (pthread_rwlock_t *rwlock) +int +pthread_attr_getstackaddr (const pthread_attr_t *attr, void **addr) { - if (pthread_rwlock::is_initializer (rwlock)) - return 0; - if (!pthread_rwlock::is_good_object (rwlock)) + if (!pthread_attr::is_good_object (attr)) return EINVAL; - - return (*rwlock)->unlock (); + /* See comment in pthread_attr_setstackaddr. */ + *addr =3D (*attr)->stackaddr; + return 0; } =20 -extern "C" int -pthread_rwlockattr_init (pthread_rwlockattr_t *rwlockattr) +int +pthread_attr_setstacksize (pthread_attr_t *attr, size_t size) { - *rwlockattr =3D new pthread_rwlockattr; - if (!pthread_rwlockattr::is_good_object (rwlockattr)) - { - delete (*rwlockattr); - *rwlockattr =3D NULL; - return ENOMEM; - } + if (!pthread_attr::is_good_object (attr)) + return EINVAL; + if (size < PTHREAD_STACK_MIN) + return EINVAL; + (*attr)->stacksize =3D size; return 0; } =20 -extern "C" int -pthread_rwlockattr_getpshared (const pthread_rwlockattr_t *attr, int *psha= red) +int +pthread_attr_getstacksize (const pthread_attr_t *attr, size_t *size) { - if (!pthread_rwlockattr::is_good_object (attr)) + if (!pthread_attr::is_good_object (attr)) return EINVAL; - *pshared =3D (*attr)->shared; + /* If the stacksize has not been set by the application, return the + default stacksize. Note that this is different from what + pthread_attr_getstack returns. */ + *size =3D (*attr)->stacksize ?: get_rlimit_stack (); return 0; } =20 -extern "C" int -pthread_rwlockattr_setpshared (pthread_rwlockattr_t *attr, int pshared) +int +pthread_attr_setguardsize (pthread_attr_t *attr, size_t size) { - if (!pthread_rwlockattr::is_good_object (attr)) + if (!pthread_attr::is_good_object (attr)) return EINVAL; - if ((pshared < 0) || (pshared > 1)) + /* We don't support a guardsize of more than 1 Meg. */ + if (size > 1024 * 1024) return EINVAL; - /* shared rwlock vars not currently supported */ - if (pshared !=3D PTHREAD_PROCESS_PRIVATE) + (*attr)->guardsize =3D size; + return 0; +} + +int +pthread_attr_getguardsize (const pthread_attr_t *attr, size_t *size) +{ + if (!pthread_attr::is_good_object (attr)) return EINVAL; - (*attr)->shared =3D pshared; + *size =3D (*attr)->guardsize; return 0; } =20 -extern "C" int -pthread_rwlockattr_destroy (pthread_rwlockattr_t *rwlockattr) +int +pthread_attr_destroy (pthread_attr_t *attr) { - if (!pthread_rwlockattr::is_good_object (rwlockattr)) + if (!pthread_attr::is_good_object (attr)) return EINVAL; - delete (*rwlockattr); - *rwlockattr =3D NULL; + delete (*attr); + *attr =3D NULL; return 0; } =20 -/* Thread signal */ -extern "C" int -pthread_kill (pthread_t thread, int sig) +int +pthread_getattr_np (pthread_t thread, pthread_attr_t *attr) { - // lock myself, for the use of thread2signal - // two different kills might clash: FIXME + THREAD_BASIC_INFORMATION tbi; + NTSTATUS status; =20 if (!pthread::is_good_object (&thread)) - return EINVAL; + return ESRCH; =20 - /* check that sig is in right range */ - if (sig < 0 || sig >=3D _NSIG) - return EINVAL; + /* attr may not be pre-initialized */ + if (!pthread_attr::is_good_object (attr)) + { + int rv =3D pthread_attr_init (attr); + if (rv !=3D 0) + return rv; + } =20 - siginfo_t si =3D {0}; - si.si_signo =3D sig; - si.si_code =3D SI_USER; - si.si_pid =3D myself->pid; - si.si_uid =3D myself->uid; - int rval; - if (!thread->valid) - rval =3D ESRCH; - else if (sig) + (*attr)->joinable =3D thread->attr.joinable; + (*attr)->contentionscope =3D thread->attr.contentionscope; + (*attr)->inheritsched =3D thread->attr.inheritsched; + (*attr)->schedparam =3D thread->attr.schedparam; + (*attr)->guardsize =3D thread->attr.guardsize; + + status =3D NtQueryInformationThread (thread->win32_obj_id, + ThreadBasicInformation, + &tbi, sizeof (tbi), NULL); + if (NT_SUCCESS (status)) { - rval =3D (int) sig_send (NULL, si, thread->cygtls); - if (rval =3D=3D -1) - rval =3D get_errno (); + PTEB teb =3D (PTEB) tbi.TebBaseAddress; + /* stackaddr holds the uppermost stack address. See the comments + in pthread_attr_setstack and pthread_attr_setstackaddr for a + description. */ + (*attr)->stackaddr =3D teb->Tib.StackBase; + (*attr)->stacksize =3D (uintptr_t) teb->Tib.StackBase + - (uintptr_t) (teb->DeallocationStack ?: teb->Tib.StackLimit); } else - switch (WaitForSingleObject (thread->win32_obj_id, 0)) - { - case WAIT_TIMEOUT: - rval =3D 0; - break; - default: - rval =3D ESRCH; - break; - } + { + debug_printf ("NtQueryInformationThread(ThreadBasicInformation), " + "status %y", status); + (*attr)->stackaddr =3D thread->attr.stackaddr; + (*attr)->stacksize =3D thread->attr.stacksize; + } =20 - // unlock myself - return rval; + return 0; +} + +/* Thread Specific Data */ + +int +pthread_key_create (pthread_key_t *key, void (*destructor) (void *)) +{ + *key =3D new pthread_key (destructor); + + if (!pthread_key::is_good_object (key)) + { + delete (*key); + *key =3D NULL; + return EAGAIN; + } + return 0; } =20 -extern "C" int -pthread_sigmask (int operation, const sigset_t *set, sigset_t *old_set) +int +pthread_key_delete (pthread_key_t key) { - int res =3D handle_sigprocmask (operation, set, old_set, _my_tls.sigmask= ); - syscall_printf ("%d =3D pthread_sigmask(%d, %p, %p)", - res, operation, set, old_set); - return res; + if (!pthread_key::is_good_object (&key)) + return EINVAL; + + delete (key); + return 0; } =20 -extern "C" int -pthread_sigqueue (pthread_t *thread, int sig, const union sigval value) +void * +pthread_getspecific (pthread_key_t key) { - siginfo_t si =3D {0}; - - if (!pthread::is_good_object (thread)) - return EINVAL; - if (!(*thread)->valid) - return ESRCH; + if (!pthread_key::is_good_object (&key)) + return NULL; =20 - si.si_signo =3D sig; - si.si_code =3D SI_QUEUE; - si.si_value =3D value; - si.si_pid =3D myself->pid; - si.si_uid =3D myself->uid; - return (int) sig_send (NULL, si, (*thread)->cygtls); + return (key)->get (); } =20 -/* ID */ - -extern "C" int -pthread_equal (pthread_t t1, pthread_t t2) +int +pthread_setspecific (pthread_key_t key, const void *value) { - return pthread::equal (t1, t2); + if (!pthread_key::is_good_object (&key)) + return EINVAL; + (key)->set (value); + return 0; } =20 /* Mutexes */ =20 int -pthread_mutex::init (pthread_mutex_t *mutex, - const pthread_mutexattr_t *attr, - const pthread_mutex_t initializer) +pthread_mutex_init (pthread_mutex_t * mutex, const pthread_mutexattr_t * a= ttr) { - if (attr && !pthread_mutexattr::is_good_object (attr)) - return EINVAL; - - mutex_initialization_lock.lock (); - if (initializer =3D=3D NULL || pthread_mutex::is_initializer (mutex)) - { - pthread_mutex_t new_mutex =3D new pthread_mutex (attr ? (*attr) : NU= LL); - if (!is_good_object (&new_mutex)) - { - delete new_mutex; - mutex_initialization_lock.unlock (); - return EAGAIN; - } - - if (!attr && initializer) - { - if (initializer =3D=3D PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP) - new_mutex->type =3D PTHREAD_MUTEX_RECURSIVE; - else if (initializer =3D=3D PTHREAD_NORMAL_MUTEX_INITIALIZER_NP) - new_mutex->type =3D PTHREAD_MUTEX_NORMAL; - else if (initializer =3D=3D PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP) - new_mutex->type =3D PTHREAD_MUTEX_ERRORCHECK; - } - - __try - { - *mutex =3D new_mutex; - } - __except (NO_ERROR) - { - delete new_mutex; - mutex_initialization_lock.unlock (); - return EINVAL; - } - __endtry - } - mutex_initialization_lock.unlock (); - pthread_printf ("*mutex %p, attr %p, initializer %p", *mutex, attr, init= ializer); - - return 0; + return pthread_mutex::init (mutex, attr, NULL); } =20 -extern "C" int +int pthread_mutex_getprioceiling (const pthread_mutex_t *mutex, int *prioceiling) { @@ -3478,7 +3790,7 @@ pthread_mutex_getprioceiling (const pthread_mutex_t *= mutex, return ENOSYS; } =20 -extern "C" int +int pthread_mutex_lock (pthread_mutex_t *mutex) { if (pthread_mutex::is_initializer (mutex)) @@ -3488,7 +3800,7 @@ pthread_mutex_lock (pthread_mutex_t *mutex) return (*mutex)->lock (); } =20 -extern "C" int +int pthread_mutex_clocklock (pthread_mutex_t *mutex, clockid_t clock_id, const struct timespec *abstime) { @@ -3517,13 +3829,13 @@ pthread_mutex_clocklock (pthread_mutex_t *mutex, cl= ockid_t clock_id, return EINVAL; } =20 -extern "C" int +int pthread_mutex_timedlock (pthread_mutex_t *mutex, const struct timespec *ab= stime) { return pthread_mutex_clocklock (mutex, CLOCK_REALTIME, abstime); } =20 -extern "C" int +int pthread_mutex_trylock (pthread_mutex_t *mutex) { if (pthread_mutex::is_initializer (mutex)) @@ -3533,7 +3845,7 @@ pthread_mutex_trylock (pthread_mutex_t *mutex) return (*mutex)->trylock (); } =20 -extern "C" int +int pthread_mutex_unlock (pthread_mutex_t *mutex) { if (pthread_mutex::is_initializer (mutex)) @@ -3543,7 +3855,7 @@ pthread_mutex_unlock (pthread_mutex_t *mutex) return (*mutex)->unlock (); } =20 -extern "C" int +int pthread_mutex_destroy (pthread_mutex_t *mutex) { int rv; @@ -3561,74 +3873,18 @@ pthread_mutex_destroy (pthread_mutex_t *mutex) return 0; } =20 -extern "C" int +int pthread_mutex_setprioceiling (pthread_mutex_t *mutex, int prioceiling, int *old_ceiling) { return ENOSYS; } =20 -/* Spinlocks */ - -int -pthread_spinlock::init (pthread_spinlock_t *spinlock, int pshared) -{ - pthread_spinlock_t new_spinlock =3D new pthread_spinlock (pshared); - if (!is_good_object (&new_spinlock)) - { - delete new_spinlock; - return EAGAIN; - } - - __try - { - *spinlock =3D new_spinlock; - } - __except (NO_ERROR) - { - delete new_spinlock; - return EINVAL; - } - __endtry - pthread_printf ("*spinlock %p, pshared %d", *spinlock, pshared); - return 0; -} - -extern "C" int -pthread_spin_lock (pthread_spinlock_t *spinlock) -{ - if (!pthread_spinlock::is_good_object (spinlock)) - return EINVAL; - return (*spinlock)->lock (); -} - -extern "C" int -pthread_spin_trylock (pthread_spinlock_t *spinlock) -{ - if (!pthread_spinlock::is_good_object (spinlock)) - return EINVAL; - return (*spinlock)->trylock (); -} - -extern "C" int -pthread_spin_unlock (pthread_spinlock_t *spinlock) -{ - if (!pthread_spinlock::is_good_object (spinlock)) - return EINVAL; - return (*spinlock)->unlock (); -} - -extern "C" int -pthread_spin_destroy (pthread_spinlock_t *spinlock) -{ - if (!pthread_spinlock::is_good_object (spinlock)) - return EINVAL; - return (*spinlock)->destroy (); -} +/* Mutex attributes */ =20 /* Win32 doesn't support mutex priorities - see __pthread_mutex_getpriocei= ling for more detail */ -extern "C" int +int pthread_mutexattr_getprotocol (const pthread_mutexattr_t *attr, int *protocol) { @@ -3637,7 +3893,7 @@ pthread_mutexattr_getprotocol (const pthread_mutexatt= r_t *attr, return ENOSYS; } =20 -extern "C" int +int pthread_mutexattr_getpshared (const pthread_mutexattr_t *attr, int *pshared) { @@ -3647,7 +3903,7 @@ pthread_mutexattr_getpshared (const pthread_mutexattr= _t *attr, return 0; } =20 -extern "C" int +int pthread_mutexattr_gettype (const pthread_mutexattr_t *attr, int *type) { if (!pthread_mutexattr::is_good_object (attr)) @@ -3657,7 +3913,7 @@ pthread_mutexattr_gettype (const pthread_mutexattr_t = *attr, int *type) } =20 /* FIXME: write and test process shared mutex's. */ -extern "C" int +int pthread_mutexattr_init (pthread_mutexattr_t *attr) { *attr =3D new pthread_mutexattr (); @@ -3670,7 +3926,7 @@ pthread_mutexattr_init (pthread_mutexattr_t *attr) return 0; } =20 -extern "C" int +int pthread_mutexattr_destroy (pthread_mutexattr_t *attr) { if (!pthread_mutexattr::is_good_object (attr)) @@ -3682,7 +3938,7 @@ pthread_mutexattr_destroy (pthread_mutexattr_t *attr) =20 =20 /* Win32 doesn't support mutex priorities */ -extern "C" int +int pthread_mutexattr_setprotocol (pthread_mutexattr_t *attr, int protocol) { if (!pthread_mutexattr::is_good_object (attr)) @@ -3691,7 +3947,7 @@ pthread_mutexattr_setprotocol (pthread_mutexattr_t *a= ttr, int protocol) } =20 /* Win32 doesn't support mutex priorities */ -extern "C" int +int pthread_mutexattr_setprioceiling (pthread_mutexattr_t *attr, int prioceiling) { @@ -3700,7 +3956,7 @@ pthread_mutexattr_setprioceiling (pthread_mutexattr_t= *attr, return ENOSYS; } =20 -extern "C" int +int pthread_mutexattr_getprioceiling (const pthread_mutexattr_t *attr, int *prioceiling) { @@ -3709,7 +3965,7 @@ pthread_mutexattr_getprioceiling (const pthread_mutex= attr_t *attr, return ENOSYS; } =20 -extern "C" int +int pthread_mutexattr_setpshared (pthread_mutexattr_t *attr, int pshared) { if (!pthread_mutexattr::is_good_object (attr)) @@ -3723,352 +3979,335 @@ pthread_mutexattr_setpshared (pthread_mutexattr_t= *attr, int pshared) return 0; } =20 -/* see pthread_mutex_gettype */ -extern "C" int -pthread_mutexattr_settype (pthread_mutexattr_t *attr, int type) +/* see pthread_mutex_gettype */ +int +pthread_mutexattr_settype (pthread_mutexattr_t *attr, int type) +{ + if (!pthread_mutexattr::is_good_object (attr)) + return EINVAL; + + switch (type) + { + case PTHREAD_MUTEX_ERRORCHECK: + case PTHREAD_MUTEX_RECURSIVE: + case PTHREAD_MUTEX_NORMAL: + (*attr)->mutextype =3D type; + break; + default: + return EINVAL; + } + + return 0; +} + +/* Spinlocks */ + +int +pthread_spin_init (pthread_spinlock_t *spinlock, int pshared) +{ + return pthread_spinlock::init (spinlock, pshared); +} + +int +pthread_spin_lock (pthread_spinlock_t *spinlock) +{ + if (!pthread_spinlock::is_good_object (spinlock)) + return EINVAL; + return (*spinlock)->lock (); +} + +int +pthread_spin_trylock (pthread_spinlock_t *spinlock) +{ + if (!pthread_spinlock::is_good_object (spinlock)) + return EINVAL; + return (*spinlock)->trylock (); +} + +int +pthread_spin_unlock (pthread_spinlock_t *spinlock) +{ + if (!pthread_spinlock::is_good_object (spinlock)) + return EINVAL; + return (*spinlock)->unlock (); +} + +int +pthread_spin_destroy (pthread_spinlock_t *spinlock) +{ + if (!pthread_spinlock::is_good_object (spinlock)) + return EINVAL; + return (*spinlock)->destroy (); +} + +/* Synchronisation */ + +int +pthread_cond_init (pthread_cond_t * cond, const pthread_condattr_t * attr) +{ + return pthread_cond::init (cond, attr); +} + +int +pthread_cond_destroy (pthread_cond_t *cond) +{ + if (pthread_cond::is_initializer (cond)) + return 0; + if (!pthread_cond::is_good_object (cond)) + return EINVAL; + + /* reads are atomic */ + if ((*cond)->waiting) + return EBUSY; + + delete (*cond); + *cond =3D NULL; + + return 0; +} + +int +pthread_cond_broadcast (pthread_cond_t *cond) { - if (!pthread_mutexattr::is_good_object (attr)) + if (pthread_cond::is_initializer (cond)) + return 0; + if (!pthread_cond::is_good_object (cond)) return EINVAL; =20 - switch (type) - { - case PTHREAD_MUTEX_ERRORCHECK: - case PTHREAD_MUTEX_RECURSIVE: - case PTHREAD_MUTEX_NORMAL: - (*attr)->mutextype =3D type; - break; - default: - return EINVAL; - } + (*cond)->unblock (true); =20 return 0; } =20 -/* Semaphores */ - -List semaphore::semaphores; - -semaphore::semaphore (int pshared, unsigned int value) -: verifyable_object (SEM_MAGIC), - shared (pshared), - currentvalue (-1), - startvalue (value), - fd (-1), - hash (0ULL), - sem (NULL) +int +pthread_cond_signal (pthread_cond_t *cond) { - SECURITY_ATTRIBUTES sa =3D (pshared !=3D PTHREAD_PROCESS_PRIVATE) - ? sec_all : sec_none_nih; - this->win32_obj_id =3D ::CreateSemaphore (&sa, value, INT32_MAX, NULL); - if (!this->win32_obj_id) - magic =3D 0; + if (pthread_cond::is_initializer (cond)) + return 0; + if (!pthread_cond::is_good_object (cond)) + return EINVAL; =20 - semaphores.insert (this); + (*cond)->unblock (false); + + return 0; } =20 -semaphore::semaphore (unsigned long long shash, LUID sluid, int sfd, - sem_t *ssem, int oflag, mode_t mode, unsigned int value) -: verifyable_object (SEM_MAGIC), - shared (PTHREAD_PROCESS_SHARED), - currentvalue (-1), /* Unused for named semaphores. */ - startvalue (value), - fd (sfd), - hash (shash), - luid (sluid), - sem (ssem) +static int +__pthread_cond_wait_init (pthread_cond_t *cond, pthread_mutex_t *mutex) { - char name[MAX_PATH]; + if (!pthread_mutex::is_good_object (mutex)) + return EINVAL; + if (!(*mutex)->can_be_unlocked ()) + return EPERM; =20 - __small_sprintf (name, "semaphore/%016X%08x%08x", - hash, luid.HighPart, luid.LowPart); - this->win32_obj_id =3D ::CreateSemaphore (&sec_all, value, INT32_MAX, na= me); - if (!this->win32_obj_id) - magic =3D 0; - if (GetLastError () =3D=3D ERROR_ALREADY_EXISTS && (oflag & O_EXCL)) - { - __seterrno (); - CloseHandle (this->win32_obj_id); - magic =3D 0; - } + if (pthread_cond::is_initializer (cond)) + pthread_cond::init (cond, NULL); + if (!pthread_cond::is_good_object (cond)) + return EINVAL; =20 - semaphores.insert (this); + return 0; } =20 -semaphore::~semaphore () +static int +__pthread_cond_clockwait (pthread_cond_t *cond, pthread_mutex_t *mutex, + clockid_t clock_id, const struct timespec *abstime) { - if (win32_obj_id) - CloseHandle (win32_obj_id); + int err =3D 0; + LARGE_INTEGER timeout; =20 - semaphores.remove (this); -} + do + { + err =3D pthread_convert_abstime (clock_id, abstime, &timeout); + if (err) + break; =20 -void -semaphore::_post () -{ - LONG dummy; - ReleaseSemaphore (win32_obj_id, 1, &dummy); + err =3D (*cond)->wait (*mutex, &timeout); + } + while (err =3D=3D ETIMEDOUT); + return err; } =20 int -semaphore::_getvalue (int *sval) +pthread_cond_clockwait (pthread_cond_t *cond, pthread_mutex_t *mutex, + clockid_t clock_id, const struct timespec *abstime) { - NTSTATUS status; - SEMAPHORE_BASIC_INFORMATION sbi; + int err =3D 0; =20 - status =3D NtQuerySemaphore (win32_obj_id, SemaphoreBasicInformation, &s= bi, - sizeof sbi, NULL); - int res; - if (NT_SUCCESS (status)) + pthread_testcancel (); + + __try { - *sval =3D sbi.CurrentCount; - res =3D 0; + err =3D __pthread_cond_wait_init (cond, mutex); + if (err) + __leave; + err =3D __pthread_cond_clockwait (cond, mutex, clock_id, abstime); } - else + __except (NO_ERROR) { - *sval =3D startvalue; - __seterrno_from_nt_status (status); - res =3D -1; + return EINVAL; } - return res; + __endtry + return err; } =20 int -semaphore::_trywait () +pthread_cond_timedwait (pthread_cond_t *cond, pthread_mutex_t *mutex, + const struct timespec *abstime) { - /* FIXME: signals should be able to interrupt semaphores... - We probably need WaitForMultipleObjects here. */ - if (WaitForSingleObject (win32_obj_id, 0) =3D=3D WAIT_TIMEOUT) - { - set_errno (EAGAIN); - return -1; - } - return 0; -} + int err =3D 0; + + pthread_testcancel (); =20 -int -semaphore::_wait (PLARGE_INTEGER timeout) -{ __try { - switch (cygwait (win32_obj_id, timeout, - cw_cancel | cw_cancel_self | cw_sig_eintr)) - { - case WAIT_OBJECT_0: - break; - case WAIT_SIGNALED: - set_errno (EINTR); - return -1; - case WAIT_TIMEOUT: - set_errno (ETIMEDOUT); - return -1; - default: - pthread_printf ("cygwait failed. %E"); - __seterrno (); - return -1; - } + err =3D __pthread_cond_wait_init (cond, mutex); + if (err) + __leave; + err =3D __pthread_cond_clockwait (cond, mutex, (*cond)->clock_id, ab= stime); } - __except (NO_ERROR) {} - __endtry - return 0; -} - -void -semaphore::_fixup_before_fork () -{ - NTSTATUS status; - SEMAPHORE_BASIC_INFORMATION sbi; - - status =3D NtQuerySemaphore (win32_obj_id, SemaphoreBasicInformation, &s= bi, - sizeof sbi, NULL); - if (NT_SUCCESS (status)) - currentvalue =3D sbi.CurrentCount; - else - currentvalue =3D startvalue; -} - -void -semaphore::_fixup_after_fork () -{ - if (shared =3D=3D PTHREAD_PROCESS_PRIVATE) + __except (NO_ERROR) { - pthread_printf ("sem %p", this); - win32_obj_id =3D ::CreateSemaphore (&sec_none_nih, currentvalue, - INT32_MAX, NULL); - if (!win32_obj_id) - api_fatal ("failed to create new win32 semaphore, " - "currentvalue %ld, %E", currentvalue); + return EINVAL; } + __endtry + return err; } =20 -void -semaphore::_terminate () +int +pthread_cond_wait (pthread_cond_t *cond, pthread_mutex_t *mutex) { - int _sem_close (sem_t *, bool); + pthread_testcancel (); =20 - if (sem) - _sem_close (sem, false); + int err =3D __pthread_cond_wait_init (cond, mutex); + if (err) + return err; + return (*cond)->wait (*mutex, NULL); } =20 -/* static members */ +/* Thread cond attributes */ =20 int -semaphore::init (sem_t *sem, int pshared, unsigned int value) +pthread_condattr_init (pthread_condattr_t *condattr) { - /* - We can't tell the difference between reinitialising an - existing semaphore and initialising a semaphore who's - contents happen to be a valid pointer - */ - if (is_good_object (sem)) - paranoid_printf ("potential attempt to reinitialise a semaphore"); - - if (value > SEM_VALUE_MAX) + *condattr =3D new pthread_condattr; + if (!pthread_condattr::is_good_object (condattr)) { - set_errno(EINVAL); - return -1; + delete (*condattr); + *condattr =3D NULL; + return ENOMEM; } + return 0; +} =20 - *sem =3D new semaphore (pshared, value); - - if (!is_good_object (sem)) - { - delete (*sem); - *sem =3D NULL; - set_errno(EAGAIN); - return -1; - } +int +pthread_condattr_getpshared (const pthread_condattr_t *attr, int *pshared) +{ + if (!pthread_condattr::is_good_object (attr)) + return EINVAL; + *pshared =3D (*attr)->shared; return 0; } =20 int -semaphore::destroy (sem_t *sem) +pthread_condattr_setpshared (pthread_condattr_t *attr, int pshared) { - if (!is_good_object (sem)) - { - set_errno(EINVAL); - return -1; - } - - /* It's invalid to destroy a semaphore not opened with sem_init. */ - if ((*sem)->fd !=3D -1) - { - set_errno(EINVAL); - return -1; - } - - /* FIXME - new feature - test for busy against threads... */ - - delete (*sem); - *sem =3D NULL; + if (!pthread_condattr::is_good_object (attr)) + return EINVAL; + if ((pshared < 0) || (pshared > 1)) + return EINVAL; + /* shared cond vars not currently supported */ + if (pshared !=3D PTHREAD_PROCESS_PRIVATE) + return EINVAL; + (*attr)->shared =3D pshared; return 0; } =20 int -semaphore::close (sem_t *sem) +pthread_condattr_getclock (const pthread_condattr_t *attr, clockid_t *cloc= k_id) { - if (!is_good_object (sem)) - { - set_errno(EINVAL); - return -1; - } - - /* It's invalid to close a semaphore not opened with sem_open. */ - if ((*sem)->fd =3D=3D -1) - { - set_errno(EINVAL); - return -1; - } - - delete (*sem); - delete sem; + if (!pthread_condattr::is_good_object (attr)) + return EINVAL; + *clock_id =3D (*attr)->clock_id; return 0; } =20 -sem_t * -semaphore::open (unsigned long long hash, LUID luid, int fd, int oflag, - mode_t mode, unsigned int value, bool &wasopen) +int +pthread_condattr_setclock (pthread_condattr_t *attr, clockid_t clock_id) { - if (value > SEM_VALUE_MAX) - { - set_errno (EINVAL); - return NULL; - } - - /* sem_open is supposed to return the same pointer, if the same named - semaphore is opened multiple times in the same process, as long as - the semaphore hasn't been closed or unlinked in the meantime. */ - semaphores.mx.lock (); - for (semaphore *sema =3D semaphores.head; sema; sema =3D sema->next) - if (sema->fd >=3D 0 && sema->hash =3D=3D hash - && sema->luid.HighPart =3D=3D luid.HighPart - && sema->luid.LowPart =3D=3D luid.LowPart) - { - wasopen =3D true; - semaphores.mx.unlock (); - return sema->sem; - } - semaphores.mx.unlock (); + if (!pthread_condattr::is_good_object (attr)) + return EINVAL; + if (CLOCKID_IS_PROCESS (clock_id) || CLOCKID_IS_THREAD (clock_id) + || clock_id >=3D MAX_CLOCKS) + return EINVAL; + (*attr)->clock_id =3D clock_id; + return 0; +} =20 - wasopen =3D false; - sem_t *sem =3D new sem_t; - if (!sem) - { - set_errno (ENOMEM); - return NULL; - } +int +pthread_condattr_destroy (pthread_condattr_t *condattr) +{ + if (!pthread_condattr::is_good_object (condattr)) + return EINVAL; + delete (*condattr); + *condattr =3D NULL; + return 0; +} =20 - *sem =3D new semaphore (hash, luid, fd, sem, oflag, mode, value); +/* RW Locks */ =20 - if (!is_good_object (sem)) - { - delete *sem; - delete sem; - return NULL; - } - return sem; +int +pthread_rwlock_init (pthread_rwlock_t *rwlock, const pthread_rwlockattr_t = *attr) +{ + return pthread_rwlock::init (rwlock, attr); } =20 int -semaphore::wait (sem_t *sem) +pthread_rwlock_destroy (pthread_rwlock_t *rwlock) { - pthread_testcancel (); + if (pthread_rwlock::is_initializer (rwlock)) + return 0; + if (!pthread_rwlock::is_good_object (rwlock)) + return EINVAL; =20 - if (!is_good_object (sem)) - { - set_errno (EINVAL); - return -1; - } + if ((*rwlock)->writer || (*rwlock)->readers || + (*rwlock)->waiting_readers || (*rwlock)->waiting_writers) + return EBUSY; =20 - return (*sem)->_wait (); + delete (*rwlock); + *rwlock =3D NULL; + + return 0; } =20 int -semaphore::trywait (sem_t *sem) +pthread_rwlock_rdlock (pthread_rwlock_t *rwlock) { - if (!is_good_object (sem)) - { - set_errno (EINVAL); - return -1; - } + pthread_testcancel (); =20 - return (*sem)->_trywait (); + if (pthread_rwlock::is_initializer (rwlock)) + pthread_rwlock::init (rwlock, NULL); + if (!pthread_rwlock::is_good_object (rwlock)) + return EINVAL; + + return (*rwlock)->rdlock (); } =20 int -semaphore::clockwait (sem_t *sem, clockid_t clock_id, - const struct timespec *abstime) +pthread_rwlock_clockrdlock (pthread_rwlock_t *rwlock, clockid_t clock_id, + const struct timespec *abstime) { LARGE_INTEGER timeout; =20 - if (!is_good_object (sem)) - { - set_errno (EINVAL); - return -1; - } + pthread_testcancel (); + + if (pthread_rwlock::is_initializer (rwlock)) + pthread_rwlock::init (rwlock, NULL); + if (!pthread_rwlock::is_good_object (rwlock)) + return EINVAL; =20 /* According to SUSv3, abstime need not be checked for validity, - if the semaphore can be locked immediately. */ - if (!(*sem)->_trywait ()) + if the rwlock can be locked immediately. */ + if (!(*rwlock)->tryrdlock ()) return 0; =20 __try @@ -4077,7 +4316,7 @@ semaphore::clockwait (sem_t *sem, clockid_t clock_id, if (err) return err; =20 - return (*sem)->_wait (&timeout); + return (*rwlock)->rdlock (&timeout); } __except (NO_ERROR) {} __endtry @@ -4085,131 +4324,182 @@ semaphore::clockwait (sem_t *sem, clockid_t clock= _id, } =20 int -semaphore::post (sem_t *sem) +pthread_rwlock_timedrdlock (pthread_rwlock_t *rwlock, + const struct timespec *abstime) { - if (!is_good_object (sem)) - { - set_errno (EINVAL); - return -1; - } - - (*sem)->_post (); - return 0; + return pthread_rwlock_clockrdlock (rwlock, CLOCK_REALTIME, abstime); } =20 int -semaphore::getvalue (sem_t *sem, int *sval) +pthread_rwlock_tryrdlock (pthread_rwlock_t *rwlock) { - __try - { - if (is_good_object (sem)) - return (*sem)->_getvalue (sval); - } - __except (NO_ERROR) {} - __endtry - set_errno (EINVAL); - return -1; + if (pthread_rwlock::is_initializer (rwlock)) + pthread_rwlock::init (rwlock, NULL); + if (!pthread_rwlock::is_good_object (rwlock)) + return EINVAL; + + return (*rwlock)->tryrdlock (); } =20 int -semaphore::getinternal (sem_t *sem, int *sfd, unsigned long long *shash, - LUID *sluid, unsigned int *sval) +pthread_rwlock_wrlock (pthread_rwlock_t *rwlock) { - __try - { - if (!is_good_object (sem)) - __leave; - if ((*sfd =3D (*sem)->fd) < 0) - __leave; - *shash =3D (*sem)->hash; - *sluid =3D (*sem)->luid; - /* POSIX defines the value in calls to sem_init/sem_open as unsigned, - but the sem_getvalue gets a pointer to int to return the value. - Go figure! */ - return (*sem)->_getvalue ((int *)sval); - } - __except (NO_ERROR) {} - __endtry - set_errno (EINVAL); - return -1; -} + pthread_testcancel (); =20 -/* pthread_null */ -pthread * -pthread_null::get_null_pthread () -{ - /* because of weird entry points */ - _instance.magic =3D 0; - return &_instance; + if (pthread_rwlock::is_initializer (rwlock)) + pthread_rwlock::init (rwlock, NULL); + if (!pthread_rwlock::is_good_object (rwlock)) + return EINVAL; + + return (*rwlock)->wrlock (); } =20 -pthread_null::pthread_null () +int +pthread_rwlock_clockwrlock (pthread_rwlock_t *rwlock, clockid_t clock_id, + const struct timespec *abstime) { - attr.joinable =3D PTHREAD_CREATE_DETACHED; - /* Mark ourselves as invalid */ - magic =3D 0; + LARGE_INTEGER timeout; + + pthread_testcancel (); + + if (pthread_rwlock::is_initializer (rwlock)) + pthread_rwlock::init (rwlock, NULL); + if (!pthread_rwlock::is_good_object (rwlock)) + return EINVAL; + + /* According to SUSv3, abstime need not be checked for validity, + if the rwlock can be locked immediately. */ + if (!(*rwlock)->trywrlock ()) + return 0; + + __try + { + int err =3D pthread_convert_abstime (clock_id, abstime, &timeout); + if (err) + return err; + + return (*rwlock)->wrlock (&timeout); + } + __except (NO_ERROR) {} + __endtry + return EINVAL; } =20 -pthread_null::~pthread_null () +int +pthread_rwlock_timedwrlock (pthread_rwlock_t *rwlock, + const struct timespec *abstime) { + return pthread_rwlock_clockwrlock (rwlock, CLOCK_REALTIME, abstime); } =20 -bool -pthread_null::create (void *(*)(void *), pthread_attr *, void *) +int +pthread_rwlock_trywrlock (pthread_rwlock_t *rwlock) { - return true; + if (pthread_rwlock::is_initializer (rwlock)) + pthread_rwlock::init (rwlock, NULL); + if (!pthread_rwlock::is_good_object (rwlock)) + return EINVAL; + + return (*rwlock)->trywrlock (); } =20 -void -pthread_null::exit (void *value_ptr) +int +pthread_rwlock_unlock (pthread_rwlock_t *rwlock) { - _my_tls.remove (INFINITE); - ExitThread (0); + if (pthread_rwlock::is_initializer (rwlock)) + return 0; + if (!pthread_rwlock::is_good_object (rwlock)) + return EINVAL; + + return (*rwlock)->unlock (); } =20 +/* RW Lock attributes */ + int -pthread_null::cancel () +pthread_rwlockattr_init (pthread_rwlockattr_t *rwlockattr) { + *rwlockattr =3D new pthread_rwlockattr; + if (!pthread_rwlockattr::is_good_object (rwlockattr)) + { + delete (*rwlockattr); + *rwlockattr =3D NULL; + return ENOMEM; + } return 0; } =20 -void -pthread_null::testcancel () +int +pthread_rwlockattr_getpshared (const pthread_rwlockattr_t *attr, int *psha= red) { + if (!pthread_rwlockattr::is_good_object (attr)) + return EINVAL; + *pshared =3D (*attr)->shared; + return 0; } =20 int -pthread_null::setcancelstate (int state, int *oldstate) +pthread_rwlockattr_setpshared (pthread_rwlockattr_t *attr, int pshared) { - return EINVAL; + if (!pthread_rwlockattr::is_good_object (attr)) + return EINVAL; + if ((pshared < 0) || (pshared > 1)) + return EINVAL; + /* shared rwlock vars not currently supported */ + if (pshared !=3D PTHREAD_PROCESS_PRIVATE) + return EINVAL; + (*attr)->shared =3D pshared; + return 0; } =20 int -pthread_null::setcanceltype (int type, int *oldtype) +pthread_rwlockattr_destroy (pthread_rwlockattr_t *rwlockattr) { - return EINVAL; + if (!pthread_rwlockattr::is_good_object (rwlockattr)) + return EINVAL; + delete (*rwlockattr); + *rwlockattr =3D NULL; + return 0; } =20 -void -pthread_null::push_cleanup_handler (__pthread_cleanup_handler *handler) +/* Barriers */ + +int +pthread_barrier_init (pthread_barrier_t * bar, + const pthread_barrierattr_t * attr, unsigned count) { + if (unlikely (bar =3D=3D NULL)) + return EINVAL; + + *bar =3D new pthread_barrier; + return (*bar)->init (attr, count); } =20 -void -pthread_null::pop_cleanup_handler (int const execute) +int +pthread_barrier_destroy (pthread_barrier_t * bar) { + if (unlikely (! pthread_barrier::is_good_object (bar))) + return EINVAL; + + int ret; + ret =3D (*bar)->destroy (); + if (ret =3D=3D 0) + delete_and_clear (bar); + + return ret; } =20 -unsigned long -pthread_null::getsequence_np () +int +pthread_barrier_wait (pthread_barrier_t * bar) { - return 0; -} + if (unlikely (! pthread_barrier::is_good_object (bar))) + return EINVAL; =20 -pthread_null pthread_null::_instance; + return (*bar)->wait (); +} =20 +/* Barrier attributes */ =20 -extern "C" int pthread_barrierattr_init (pthread_barrierattr_t * battr) { @@ -4222,8 +4512,6 @@ pthread_barrierattr_init (pthread_barrierattr_t * bat= tr) return 0; } =20 - -extern "C" int pthread_barrierattr_setpshared (pthread_barrierattr_t * battr, int shared) { @@ -4238,8 +4526,6 @@ pthread_barrierattr_setpshared (pthread_barrierattr_t= * battr, int shared) return 0; } =20 - -extern "C" int pthread_barrierattr_getpshared (const pthread_barrierattr_t * battr, int * shared) @@ -4252,8 +4538,6 @@ pthread_barrierattr_getpshared (const pthread_barrier= attr_t * battr, return 0; } =20 - -extern "C" int pthread_barrierattr_destroy (pthread_barrierattr_t * battr) { @@ -4264,161 +4548,65 @@ pthread_barrierattr_destroy (pthread_barrierattr_t= * battr) return 0; } =20 +/* Thread clock ID */ =20 -extern "C" int -pthread_barrier_init (pthread_barrier_t * bar, - const pthread_barrierattr_t * attr, unsigned count) +pthread_getcpuclockid (pthread_t thread, clockid_t *clk_id) { - if (unlikely (bar =3D=3D NULL)) - return EINVAL; - - *bar =3D new pthread_barrier; - return (*bar)->init (attr, count); + if (!pthread::is_good_object (&thread)) + return (ESRCH); + *clk_id =3D (clockid_t) THREADID_TO_CLOCKID (thread->getsequence_np ()); + return 0; } =20 +/* Semaphores */ =20 int -pthread_barrier::init (const pthread_barrierattr_t * attr, unsigned count) +sem_init (sem_t * sem, int pshared, unsigned int value) { - pthread_mutex_t * mutex =3D NULL; - - if (unlikely ((attr !=3D NULL - && (! pthread_barrierattr::is_good_object (attr) - || (*attr)->shared =3D=3D PTHREAD_PROCESS_SHARED)) - || count =3D=3D 0)) - return EINVAL; - - int retval =3D pthread_mutex_init (&mtx, NULL); - if (unlikely (retval !=3D 0)) - return retval; - - retval =3D pthread_cond_init (&cond, NULL); - if (unlikely (retval !=3D 0)) - { - int ret =3D pthread_mutex_destroy (mutex); - if (ret !=3D 0) - api_fatal ("pthread_mutex_destroy (%p) =3D %d", mutex, ret); - - mtx =3D NULL; - return retval; - } - - cnt =3D count; - cyc =3D 0; - wt =3D 0; - - return 0; + return semaphore::init (sem, pshared, value); } =20 - -extern "C" int -pthread_barrier_destroy (pthread_barrier_t * bar) +sem_destroy (sem_t * sem) { - if (unlikely (! pthread_barrier::is_good_object (bar))) - return EINVAL; - - int ret; - ret =3D (*bar)->destroy (); - if (ret =3D=3D 0) - delete_and_clear (bar); - - return ret; + return semaphore::destroy (sem); } =20 - int -pthread_barrier::destroy () +sem_wait (sem_t * sem) { - if (unlikely (wt !=3D 0)) - return EBUSY; - - int retval =3D pthread_cond_destroy (&cond); - if (unlikely (retval !=3D 0)) - return retval; - else - cond =3D NULL; - - retval =3D pthread_mutex_destroy (&mtx); - if (unlikely (retval !=3D 0)) - return retval; - else - mtx =3D NULL; - - cnt =3D 0; - cyc =3D 0; - wt =3D 0; - - return 0; + return semaphore::wait (sem); } =20 - -extern "C" int -pthread_barrier_wait (pthread_barrier_t * bar) +sem_trywait (sem_t * sem) { - if (unlikely (! pthread_barrier::is_good_object (bar))) - return EINVAL; - - return (*bar)->wait (); + return semaphore::trywait (sem); } =20 - int -pthread_barrier::wait () +sem_clockwait (sem_t * sem, clockid_t clock_id, const struct timespec *abs= time) { - int retval =3D pthread_mutex_lock (&mtx); - if (unlikely (retval !=3D 0)) - return retval; - - if (unlikely (wt >=3D cnt)) - { - api_fatal ("wt >=3D cnt (%u >=3D %u)", wt, cnt); - return EINVAL; - } - - if (unlikely (++wt =3D=3D cnt)) - { - ++cyc; - /* This is the last thread to reach the barrier. Signal the waiting - threads to wake up and continue. */ - retval =3D pthread_cond_broadcast (&cond); - if (unlikely (retval !=3D 0)) - goto cond_error; - - wt =3D 0; - retval =3D pthread_mutex_unlock (&mtx); - if (unlikely (retval !=3D 0)) - abort (); - - return PTHREAD_BARRIER_SERIAL_THREAD; - } - else - { - uint64_t cycle =3D cyc; - do - { - retval =3D pthread_cond_wait (&cond, &mtx); - if (unlikely (retval !=3D 0)) - goto cond_error; - } - while (unlikely (cycle =3D=3D cyc)); + return semaphore::clockwait (sem, clock_id, abstime); +} =20 - retval =3D pthread_mutex_unlock (&mtx); - if (unlikely (retval !=3D 0)) - api_fatal ("pthread_mutex_unlock (%p) =3D %d", &mtx, retval); +int +sem_timedwait (sem_t * sem, const struct timespec *abstime) +{ + return semaphore::clockwait (sem, CLOCK_REALTIME, abstime); +} =20 - return 0; - } +int +sem_post (sem_t *sem) +{ + return semaphore::post (sem); +} =20 - cond_error: - { - --wt; - int ret =3D pthread_mutex_unlock (&mtx); - if (unlikely (ret !=3D 0)) - api_fatal ("pthread_mutex_unlock (%p) =3D %d", &mtx, ret); +int +sem_getvalue (sem_t * sem, int *sval) +{ + return semaphore::getvalue (sem, sval); +} =20 - return retval; - } }