diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog index b34736dc6..a42758e80 100644 --- a/winsup/cygwin/ChangeLog +++ b/winsup/cygwin/ChangeLog @@ -1,3 +1,14 @@ +aturday Mar 17 01:19 2001 Robert Collins rbtcollins@hotmail.com + + * cygwin.din: Export the new functions. + * pthread.cc (pthread_cond_*): Add wrapper functions that call + __pthread_cond* functions. + * thread.cc (__pthread_cond_*): Implement the pthread_cond* functions. + * thread.h: Add new class entries and prototypes for __pthread_cond* + functions. + * include/pthread.h: user land header prototypes for pthread_cond* + functions and related defines. + Wed Mar 14 16:30:00 2001 Corinna Vinschen * environ.cc (parse_options): Use strtok_r instead of strtok. diff --git a/winsup/cygwin/cygwin.din b/winsup/cygwin/cygwin.din index fb6364c3d..a5ff772cd 100644 --- a/winsup/cygwin/cygwin.din +++ b/winsup/cygwin/cygwin.din @@ -1099,6 +1099,16 @@ cygwin32_internal = cygwin_internal @PTH_ALLOW@pthread_mutex_trylock @PTH_ALLOW@pthread_mutex_unlock @PTH_ALLOW@pthread_mutex_destroy +@PTH_ALLOW@pthread_cond_init +@PTH_ALLOW@pthread_cond_destroy +@PTH_ALLOW@pthread_cond_broadcast +@PTH_ALLOW@pthread_cond_signal +@PTH_ALLOW@pthread_cond_wait +@PTH_ALLOW@pthread_cond_timedwait +@PTH_ALLOW@pthread_condattr_init +@PTH_ALLOW@pthread_condattr_destroy +@PTH_ALLOW@pthread_condattr_getpshared +@PTH_ALLOW@pthread_condattr_setpshared @PTH_ALLOW@sem_init @PTH_ALLOW@sem_destroy @PTH_ALLOW@sem_wait diff --git a/winsup/cygwin/include/pthread.h b/winsup/cygwin/include/pthread.h index 90bf5c28c..1a96e7286 100644 --- a/winsup/cygwin/include/pthread.h +++ b/winsup/cygwin/include/pthread.h @@ -23,6 +23,16 @@ extern "C" #define TFD(n) void*(*n)(void*) +/* Defines. (These are correctly defined here as per + http://www.opengroup.org/onlinepubs/7908799/xsh/pthread.h.html */ + +/* FIXME: this should allocate a new cond variable, and return the value that + would normally be written to the passed parameter of pthread_cond_init(lvalue, NULL); */ +// #define PTHREAD_COND_INITIALIZER 0 + +#define PTHREAD_PROCESS_PRIVATE 0 +#define PTHREAD_PROCESS_SHARED 1 + typedef int pthread_t; typedef int pthread_mutex_t; typedef int sem_t; @@ -43,6 +53,15 @@ typedef struct pthread_mutexattr } pthread_mutexattr_t; +typedef struct pthread_condattr + { + int shared; + int valid; + } +pthread_condattr_t; + +typedef int pthread_cond_t; + /* ThreadCreation */ int pthread_create (pthread_t * thread, const pthread_attr_t * attr, TFD (function), void *arg); int pthread_attr_init (pthread_attr_t * attr); @@ -50,6 +69,20 @@ int pthread_attr_destroy (pthread_attr_t * attr); int pthread_attr_setstacksize (pthread_attr_t * attr, size_t size); int pthread_attr_getstacksize (pthread_attr_t * attr, size_t * size); +/* Condition variables */ +int pthread_cond_broadcast(pthread_cond_t *); +int pthread_cond_destroy(pthread_cond_t *); +int pthread_cond_init(pthread_cond_t *, const pthread_condattr_t *); +int pthread_cond_signal(pthread_cond_t *); +int pthread_cond_timedwait(pthread_cond_t *, + pthread_mutex_t *, const struct timespec *); +int pthread_cond_wait(pthread_cond_t *, pthread_mutex_t *); +int pthread_condattr_destroy(pthread_condattr_t *); +int pthread_condattr_getpshared(const pthread_condattr_t *, int *); +int pthread_condattr_init(pthread_condattr_t *); +int pthread_condattr_setpshared(pthread_condattr_t *, int); + + /* Thread Control */ int pthread_detach (pthread_t thread); int pthread_join (pthread_t thread, void **value_ptr); diff --git a/winsup/cygwin/pthread.cc b/winsup/cygwin/pthread.cc index 82200e4a7..1cbec260b 100644 --- a/winsup/cygwin/pthread.cc +++ b/winsup/cygwin/pthread.cc @@ -171,6 +171,67 @@ pthread_mutex_destroy (pthread_mutex_t * mutex) return __pthread_mutex_destroy (mutex); } +/* Synchronisation */ + +int +pthread_cond_destroy(pthread_cond_t *cond) +{ + return __pthread_cond_destroy (cond); +} + +int +pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr) +{ + return __pthread_cond_init (cond, attr); +} + +int +pthread_cond_signal(pthread_cond_t *cond) +{ + return __pthread_cond_signal (cond); +} + +int pthread_cond_broadcast(pthread_cond_t *cond) +{ + return __pthread_cond_broadcast (cond); +} + +int +pthread_cond_timedwait(pthread_cond_t *cond, + pthread_mutex_t *mutex, const struct timespec *abstime) +{ + return __pthread_cond_timedwait (cond, mutex, abstime); +} + +int +pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex) +{ + return __pthread_cond_wait (cond, mutex); +} + +int +pthread_condattr_init(pthread_condattr_t *condattr) +{ + return __pthread_condattr_init (condattr); +} + +int +pthread_condattr_destroy(pthread_condattr_t *condattr) +{ + return __pthread_condattr_destroy (condattr); +} + +int +pthread_condattr_getpshared (const pthread_condattr_t *attr, int *pshared) +{ + return __pthread_condattr_getpshared (attr, pshared); +} + +int pthread_condattr_setpshared (pthread_condattr_t *attr, int pshared) +{ + return __pthread_condattr_setpshared (attr, pshared); +} + /* Semaphores */ int sem_init (sem_t * sem, int pshared, unsigned int value) diff --git a/winsup/cygwin/thread.cc b/winsup/cygwin/thread.cc index d34906d42..e2d751b0f 100644 --- a/winsup/cygwin/thread.cc +++ b/winsup/cygwin/thread.cc @@ -63,6 +63,13 @@ extern int threadsafe; if (!item) return EINVAL; \ CHECKHANDLE (EINVAL, 0); +#define GETCOND(n) \ + SetResourceLock (LOCK_COND_LIST, READ_LOCK, n); \ + CondItem *item=user_data->threadinterface->GetCond (cond); \ + ReleaseResourceLock (LOCK_COND_LIST, READ_LOCK, n); \ + if (!item) return EINVAL; \ + CHECKHANDLE (EINVAL, 0); + #define CHECKITEM(rn, rm, fn) \ if (!item) { \ ReleaseResourceLock (rn, rm, fn); \ @@ -387,6 +394,13 @@ MTinterface::GetSemaphore (sem_t * sp) return (SemaphoreItem *) Find (sp, &CmpPthreadObj, index, &semalist); } +CondItem * +MTinterface::GetCond (pthread_cond_t * mp) +{ + AssertResourceOwner (LOCK_COND_LIST, READ_LOCK); + int index = 0; + return (CondItem *) Find (mp, &CmpPthreadObj, index, &condlist); +} void MTitem::Destroy () @@ -455,6 +469,78 @@ SemaphoreItem::TryWait () return WaitForSingleObject (win32_obj_id, 0); } +/* Condition Items */ +CondItem * +MTinterface::CreateCond (pthread_cond_t * cond, const pthread_condattr_t * attr) +{ + AssertResourceOwner (LOCK_COND_LIST, WRITE_LOCK | READ_LOCK); + + int i = FindNextUnused (&condlist); + + CondItem *item = (CondItem *) GetItem (i, &condlist); + if (!item) + item = (CondItem *) SetItem (i, new CondItem (), &condlist); + if (!item) + system_printf ("cond creation failed"); + item->used = true; + item->shared = attr->shared; + item->mutexitem=NULL; + item->waiting=0; + + item->win32_obj_id = ::CreateEvent (&sec_none_nih, + false, /* auto signal reset - which I think is pthreads like ? */ + false, /* start non signaled */ + NULL /* no name */ ); + + + CHECKHANDLE (NULL, 1); + + *cond = (pthread_cond_t) item->win32_obj_id; + + return item; +} + + +int +CondItem::Signal () +{ + return !PulseEvent(win32_obj_id); +} + +int +CondItem::Wait () +{ + DWORD rv = SignalObjectAndWait (mutexitem->win32_obj_id, win32_obj_id, INFINITE, false); + switch (rv) { + case WAIT_FAILED: return 0; /* POSIX doesn't allow errors after we modify the mutex state */ + case WAIT_OBJECT_0: return 0; /* we have been signaled */ + default: return 0; + } +} + +int +CondItem::TimedWait (DWORD dwMilliseconds) +{ + DWORD rv = SignalObjectAndWait (mutexitem->win32_obj_id, win32_obj_id, dwMilliseconds, false); + switch (rv) { + case WAIT_FAILED: return 0; /* POSIX doesn't allow errors after we modify the mutex state */ + case WAIT_ABANDONED: return ETIMEDOUT; + case WAIT_OBJECT_0: return 0; /* we have been signaled */ + default: return 0; + } +} + +int +CondItem::BroadCast () +{ + if (!mutexitem) + return 0; + PulseEvent(win32_obj_id); + while (InterlockedDecrement(&waiting)!=0) + PulseEvent(win32_obj_id); + mutexitem=NULL; + return 0; +} ////////////////////////// Pthreads @@ -678,6 +764,147 @@ __pthread_getspecific (pthread_key_t */*key*/) NOT_IMP ("_p_key_getsp\n"); } +/* Thread synchronisation */ + +int +__pthread_cond_destroy(pthread_cond_t *cond) +{ + SetResourceLock (LOCK_COND_LIST, READ_LOCK | WRITE_LOCK, "__pthread_cond_destroy"); + + CondItem *item = MT_INTERFACE->GetCond (cond); + + CHECKITEM (LOCK_COND_LIST, WRITE_LOCK | READ_LOCK, "__pthread_cond_init"); + + item->Destroy (); + + MT_INTERFACE->ReleaseItem (item); + + ReleaseResourceLock (LOCK_COND_LIST, READ_LOCK | WRITE_LOCK, "__pthread_cond_destroy") +; + return 0; +} + +int +__pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr) +{ + if (attr && (attr->valid != 0xf341)) + return EINVAL; + SetResourceLock (LOCK_COND_LIST, WRITE_LOCK | READ_LOCK, "__pthread_cond_init"); + + CondItem *item = MT_INTERFACE->CreateCond (cond, attr); + + CHECKITEM (LOCK_COND_LIST, WRITE_LOCK | READ_LOCK, "__pthread_cond_init"); + + ReleaseResourceLock (LOCK_COND_LIST, WRITE_LOCK | READ_LOCK, "__pthread_cond_init"); + return 0; + +} + +int __pthread_cond_broadcast(pthread_cond_t *cond) +{ + GETCOND("_pthread_cond_lock"); + + item->BroadCast(); + + return 0; +} + +int __pthread_cond_signal(pthread_cond_t *cond) +{ + GETCOND("_pthread_cond_lock"); + + item->Signal(); + + return 0; +} + +int __pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex, const struct timespec *abstime) +{ + int rv; + if (!abstime) + return EINVAL; + SetResourceLock (LOCK_MUTEX_LIST, READ_LOCK, "_ptherad_mutex_lock"); + MutexItem* mutexitem=user_data->threadinterface->GetMutex (mutex); + ReleaseResourceLock (LOCK_MUTEX_LIST, READ_LOCK, "_ptherad_mutex_lock"); + if (!mutexitem) return EINVAL; + if (!mutexitem->HandleOke ()) + { + return EINVAL; + } + GETCOND("_pthread_cond_lock"); + if (item->mutexitem && (item->mutexitem != mutexitem)) + return EINVAL; + + item->mutexitem=mutexitem; + InterlockedIncrement(&item->waiting); + rv = item->TimedWait(abstime->tv_sec*1000); + mutexitem->Lock(); + if (InterlockedDecrement(&item->waiting)==0) + item->mutexitem=NULL; + + return rv; +} + +int __pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex) +{ + int rv; + SetResourceLock (LOCK_MUTEX_LIST, READ_LOCK, "_ptherad_mutex_lock"); + MutexItem* mutexitem=user_data->threadinterface->GetMutex (mutex); + ReleaseResourceLock (LOCK_MUTEX_LIST, READ_LOCK, "_ptherad_mutex_lock"); + if (!mutexitem) return EINVAL; + if (!mutexitem->HandleOke ()) + { + return EINVAL; + } + GETCOND("_pthread_cond_lock"); + if (item->mutexitem && (item->mutexitem != mutexitem)) + return EINVAL; + + item->mutexitem=mutexitem; + InterlockedIncrement(&item->waiting); + rv = item->Wait(); + mutexitem->Lock(); + if (InterlockedDecrement(&item->waiting)==0) + item->mutexitem=NULL; + + return rv; +} + +int +__pthread_condattr_init (pthread_condattr_t * condattr) +{ + condattr->shared = 0; + condattr->valid = 0xf341; /* Roberts magic number */ + return 0; +} + +int +__pthread_condattr_getpshared (const pthread_condattr_t * attr, int *pshared) +{ + if (!attr || (attr->valid != 0xf341)) + return EINVAL; + *pshared = attr->shared; + return 0; +} + +int +__pthread_condattr_setpshared (pthread_condattr_t * attr, int pshared) +{ + if (!attr || (attr->valid != 0xf341) || (pshared <0) || (pshared > 1 )) + return EINVAL; + attr->shared = pshared; + return 0; +} + +int +__pthread_condattr_destroy (pthread_condattr_t * condattr) +{ + if (!condattr || (condattr->valid != 0xf341)) + return EINVAL; + condattr->valid=0; + return 0; +} + /* Thread signal */ int __pthread_kill (pthread_t * thread, int sig) @@ -693,7 +920,6 @@ __pthread_kill (pthread_t * thread, int sig) // unlock myself return rval; - } int @@ -956,6 +1182,46 @@ extern "C" { return -1; } + int __pthread_cond_destroy(pthread_cond_t *) + { + return -1; + } + int __pthread_cond_init(pthread_cond_t *, const pthread_condattr_t *) + { + return -1; + } + int __pthread_cond_signal(pthread_cond_t *) + { + return -1; + } + int __pthread_cond_broadcast(pthread_cond_t *) + { + return -1; + } + int __pthread_cond_timedwait(pthread_cond_t *, pthread_mutex_t *, const struct timespec *) + { + return -1; + } + int __pthread_cond_wait(pthread_cond_t *, pthread_mutex_t *) + { + return -1; + } + int __pthread_condattr_init (pthread_condattr_t *) + { + return -1; + } + int __pthread_condattr_destroy (pthread_condattr_t *) + { + return -1; + } + int __pthread_condattr_getpshared (pthread_condattr_t *, int *) + { + return -1; + } + int __pthread_condattr_setpshared (pthread_condattr_t *, int) + { + return -1; + } int __sem_init (sem_t * sem, int pshared, unsigned int value) { return -1; diff --git a/winsup/cygwin/thread.h b/winsup/cygwin/thread.h index 999bd5ed8..c2758c6e5 100644 --- a/winsup/cygwin/thread.h +++ b/winsup/cygwin/thread.h @@ -20,6 +20,7 @@ details. */ #define LOCK_THREAD_LIST 5 #define LOCK_MUTEX_LIST 6 #define LOCK_SEM_LIST 7 +#define LOCK_COND_LIST 8 #define WRITE_LOCK 1 #define READ_LOCK 2 @@ -190,6 +191,17 @@ public: int TryWait (); }; +class CondItem: public MTitem +{ +public: + int shared; + LONG waiting; + MutexItem *mutexitem; + int Wait (); + int TimedWait (DWORD dwMilliseconds); + int BroadCast (); + int Signal (); +}; typedef struct { @@ -226,6 +238,10 @@ public: SemaphoreItem *CreateSemaphore (sem_t *, int, int); SemaphoreItem *GetSemaphore (sem_t * t); + // Condition functions + CondItem *CreateCond (pthread_cond_t *, const pthread_condattr_t *); + CondItem *GetCond (pthread_cond_t *); + private: // General Administration MTitem * Find (void *, int (*compare) (void *, void *), int &, MTList *); @@ -237,6 +253,7 @@ private: MTList threadlist; MTList mutexlist; MTList semalist; + MTList condlist; }; @@ -274,6 +291,17 @@ int __pthread_key_delete (pthread_key_t * key); int __pthread_setspecific (pthread_key_t * key, const void *value); void *__pthread_getspecific (pthread_key_t * key); +/* Thead synchroniation */ +int __pthread_cond_destroy(pthread_cond_t *cond); +int __pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr); +int __pthread_cond_signal(pthread_cond_t *cond); +int __pthread_cond_broadcast(pthread_cond_t *cond); +int __pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex, const struct timespec *abstime); +int __pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex); +int __pthread_condattr_init (pthread_condattr_t * condattr); +int __pthread_condattr_destroy (pthread_condattr_t * condattr); +int __pthread_condattr_getpshared (const pthread_condattr_t *attr, int *pshared); +int __pthread_condattr_setpshared (pthread_condattr_t *attr, int pshared); /* Thread signal */ int __pthread_kill (pthread_t * thread, int sig);