mirror of
https://github.com/ziglang/zig.git
synced 2025-12-06 14:23:09 +00:00
718 lines
17 KiB
C
Vendored
718 lines
17 KiB
C
Vendored
/*
|
|
Copyright (c) 2011-2016 mingw-w64 project
|
|
|
|
Permission is hereby granted, free of charge, to any person obtaining a
|
|
copy of this software and associated documentation files (the "Software"),
|
|
to deal in the Software without restriction, including without limitation
|
|
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
and/or sell copies of the Software, and to permit persons to whom the
|
|
Software is furnished to do so, subject to the following conditions:
|
|
|
|
The above copyright notice and this permission notice shall be included in
|
|
all copies or substantial portions of the Software.
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
|
DEALINGS IN THE SOFTWARE.
|
|
*/
|
|
|
|
/*
|
|
* Posix Condition Variables for Microsoft Windows.
|
|
* 22-9-2010 Partly based on the ACE framework implementation.
|
|
*/
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include "config.h"
|
|
#endif
|
|
|
|
#include <malloc.h>
|
|
#include <stdio.h>
|
|
#include <time.h>
|
|
|
|
#define WIN32_LEAN_AND_MEAN
|
|
#include <windows.h>
|
|
|
|
#define WINPTHREAD_COND_DECL WINPTHREAD_API
|
|
|
|
/* public header files */
|
|
#include "pthread.h"
|
|
#include "pthread_time.h"
|
|
/* internal header files */
|
|
#include "cond.h"
|
|
#include "misc.h"
|
|
#include "thread.h"
|
|
|
|
#include "pthread_compat.h"
|
|
|
|
int __pthread_shallcancel (void);
|
|
|
|
static int do_sema_b_wait (HANDLE sema, int nointerrupt, DWORD timeout,CRITICAL_SECTION *cs, LONG *val);
|
|
static int do_sema_b_release(HANDLE sema, LONG count,CRITICAL_SECTION *cs, LONG *val);
|
|
static void cleanup_wait(void *arg);
|
|
|
|
typedef struct sCondWaitHelper {
|
|
cond_t *c;
|
|
pthread_mutex_t *external_mutex;
|
|
int *r;
|
|
} sCondWaitHelper;
|
|
|
|
int do_sema_b_wait_intern (HANDLE sema, int nointerrupt, DWORD timeout);
|
|
|
|
static pthread_spinlock_t cond_locked = PTHREAD_SPINLOCK_INITIALIZER;
|
|
|
|
static int
|
|
cond_static_init (pthread_cond_t *c)
|
|
{
|
|
int r = 0;
|
|
|
|
pthread_spin_lock (&cond_locked);
|
|
if (c == NULL)
|
|
r = EINVAL;
|
|
else if (*c == PTHREAD_COND_INITIALIZER)
|
|
r = pthread_cond_init (c, NULL);
|
|
else
|
|
/* We assume someone was faster ... */
|
|
r = 0;
|
|
pthread_spin_unlock (&cond_locked);
|
|
return r;
|
|
}
|
|
|
|
int
|
|
pthread_condattr_destroy (pthread_condattr_t *a)
|
|
{
|
|
if (!a)
|
|
return EINVAL;
|
|
*a = 0;
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
pthread_condattr_init (pthread_condattr_t *a)
|
|
{
|
|
if (!a)
|
|
return EINVAL;
|
|
*a = 0;
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
pthread_condattr_getpshared (const pthread_condattr_t *a, int *s)
|
|
{
|
|
if (!a || !s)
|
|
return EINVAL;
|
|
*s = *a;
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
pthread_condattr_getclock (const pthread_condattr_t *a, clockid_t *clock_id)
|
|
{
|
|
if (!a || !clock_id)
|
|
return EINVAL;
|
|
*clock_id = 0;
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
pthread_condattr_setclock(pthread_condattr_t *a, clockid_t clock_id)
|
|
{
|
|
if (!a || clock_id != 0)
|
|
return EINVAL;
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
pthread_condattr_setpshared (pthread_condattr_t *a, int s)
|
|
{
|
|
if (!a || (s != PTHREAD_PROCESS_SHARED && s != PTHREAD_PROCESS_PRIVATE))
|
|
return EINVAL;
|
|
if (s == PTHREAD_PROCESS_SHARED)
|
|
{
|
|
*a = PTHREAD_PROCESS_PRIVATE;
|
|
return ENOSYS;
|
|
}
|
|
*a = s;
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
pthread_cond_init (pthread_cond_t *c, const pthread_condattr_t *a)
|
|
{
|
|
cond_t *_c;
|
|
int r = 0;
|
|
|
|
if (!c)
|
|
return EINVAL;
|
|
if (a && *a == PTHREAD_PROCESS_SHARED)
|
|
return ENOSYS;
|
|
|
|
if ((_c = calloc(1, sizeof(*_c))) == NULL)
|
|
return ENOMEM;
|
|
|
|
_c->valid = DEAD_COND;
|
|
_c->busy = 0;
|
|
_c->waiters_count_ = 0;
|
|
_c->waiters_count_gone_ = 0;
|
|
_c->waiters_count_unblock_ = 0;
|
|
|
|
_c->sema_q = CreateSemaphore (NULL, /* no security */
|
|
0, /* initially 0 */
|
|
0x7fffffff, /* max count */
|
|
NULL); /* unnamed */
|
|
_c->sema_b = CreateSemaphore (NULL, /* no security */
|
|
0, /* initially 0 */
|
|
0x7fffffff, /* max count */
|
|
NULL);
|
|
if (_c->sema_q == NULL || _c->sema_b == NULL) {
|
|
if (_c->sema_q != NULL)
|
|
CloseHandle (_c->sema_q);
|
|
if (_c->sema_b != NULL)
|
|
CloseHandle (_c->sema_b);
|
|
free (_c);
|
|
r = EAGAIN;
|
|
} else {
|
|
InitializeCriticalSection(&_c->waiters_count_lock_);
|
|
InitializeCriticalSection(&_c->waiters_b_lock_);
|
|
InitializeCriticalSection(&_c->waiters_q_lock_);
|
|
_c->value_q = 0;
|
|
_c->value_b = 1;
|
|
}
|
|
if (!r)
|
|
{
|
|
_c->valid = LIFE_COND;
|
|
*c = (pthread_cond_t)_c;
|
|
}
|
|
else
|
|
*c = (pthread_cond_t)NULL;
|
|
return r;
|
|
}
|
|
|
|
int
|
|
pthread_cond_destroy (pthread_cond_t *c)
|
|
{
|
|
cond_t *_c;
|
|
int r;
|
|
if (!c || !*c)
|
|
return EINVAL;
|
|
if (*c == PTHREAD_COND_INITIALIZER)
|
|
{
|
|
pthread_spin_lock (&cond_locked);
|
|
if (*c == PTHREAD_COND_INITIALIZER)
|
|
{
|
|
*c = (pthread_cond_t)NULL;
|
|
r = 0;
|
|
}
|
|
else
|
|
r = EBUSY;
|
|
pthread_spin_unlock (&cond_locked);
|
|
return r;
|
|
}
|
|
_c = (cond_t *) *c;
|
|
r = do_sema_b_wait(_c->sema_b, 0, INFINITE,&_c->waiters_b_lock_,&_c->value_b);
|
|
if (r != 0)
|
|
return r;
|
|
if (!TryEnterCriticalSection (&_c->waiters_count_lock_))
|
|
{
|
|
do_sema_b_release (_c->sema_b, 1,&_c->waiters_b_lock_,&_c->value_b);
|
|
return EBUSY;
|
|
}
|
|
if (_c->waiters_count_ > _c->waiters_count_gone_)
|
|
{
|
|
r = do_sema_b_release (_c->sema_b, 1,&_c->waiters_b_lock_,&_c->value_b);
|
|
if (!r) r = EBUSY;
|
|
LeaveCriticalSection(&_c->waiters_count_lock_);
|
|
return r;
|
|
}
|
|
*c = (pthread_cond_t)NULL;
|
|
do_sema_b_release (_c->sema_b, 1,&_c->waiters_b_lock_,&_c->value_b);
|
|
|
|
if (!CloseHandle (_c->sema_q) && !r)
|
|
r = EINVAL;
|
|
if (!CloseHandle (_c->sema_b) && !r)
|
|
r = EINVAL;
|
|
LeaveCriticalSection (&_c->waiters_count_lock_);
|
|
DeleteCriticalSection(&_c->waiters_count_lock_);
|
|
DeleteCriticalSection(&_c->waiters_b_lock_);
|
|
DeleteCriticalSection(&_c->waiters_q_lock_);
|
|
_c->valid = DEAD_COND;
|
|
free(_c);
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
pthread_cond_signal (pthread_cond_t *c)
|
|
{
|
|
cond_t *_c;
|
|
int r;
|
|
|
|
if (!c || !*c)
|
|
return EINVAL;
|
|
_c = (cond_t *)*c;
|
|
if (_c == (cond_t *)PTHREAD_COND_INITIALIZER)
|
|
return 0;
|
|
else if (_c->valid != (unsigned int)LIFE_COND)
|
|
return EINVAL;
|
|
|
|
EnterCriticalSection (&_c->waiters_count_lock_);
|
|
/* If there aren't any waiters, then this is a no-op. */
|
|
if (_c->waiters_count_unblock_ != 0)
|
|
{
|
|
if (_c->waiters_count_ == 0)
|
|
{
|
|
LeaveCriticalSection (&_c->waiters_count_lock_);
|
|
/* pthread_testcancel(); */
|
|
return 0;
|
|
}
|
|
_c->waiters_count_ -= 1;
|
|
_c->waiters_count_unblock_ += 1;
|
|
}
|
|
else if (_c->waiters_count_ > _c->waiters_count_gone_)
|
|
{
|
|
r = do_sema_b_wait (_c->sema_b, 1, INFINITE,&_c->waiters_b_lock_,&_c->value_b);
|
|
if (r != 0)
|
|
{
|
|
LeaveCriticalSection (&_c->waiters_count_lock_);
|
|
/* pthread_testcancel(); */
|
|
return r;
|
|
}
|
|
if (_c->waiters_count_gone_ != 0)
|
|
{
|
|
_c->waiters_count_ -= _c->waiters_count_gone_;
|
|
_c->waiters_count_gone_ = 0;
|
|
}
|
|
_c->waiters_count_ -= 1;
|
|
_c->waiters_count_unblock_ = 1;
|
|
}
|
|
else
|
|
{
|
|
LeaveCriticalSection (&_c->waiters_count_lock_);
|
|
/* pthread_testcancel(); */
|
|
return 0;
|
|
}
|
|
LeaveCriticalSection (&_c->waiters_count_lock_);
|
|
r = do_sema_b_release(_c->sema_q, 1,&_c->waiters_q_lock_,&_c->value_q);
|
|
/* pthread_testcancel(); */
|
|
return r;
|
|
}
|
|
|
|
int
|
|
pthread_cond_broadcast (pthread_cond_t *c)
|
|
{
|
|
cond_t *_c;
|
|
int r;
|
|
int relCnt = 0;
|
|
|
|
if (!c || !*c)
|
|
return EINVAL;
|
|
_c = (cond_t *)*c;
|
|
if (_c == (cond_t*)PTHREAD_COND_INITIALIZER)
|
|
return 0;
|
|
else if (_c->valid != (unsigned int)LIFE_COND)
|
|
return EINVAL;
|
|
|
|
EnterCriticalSection (&_c->waiters_count_lock_);
|
|
/* If there aren't any waiters, then this is a no-op. */
|
|
if (_c->waiters_count_unblock_ != 0)
|
|
{
|
|
if (_c->waiters_count_ == 0)
|
|
{
|
|
LeaveCriticalSection (&_c->waiters_count_lock_);
|
|
/* pthread_testcancel(); */
|
|
return 0;
|
|
}
|
|
relCnt = _c->waiters_count_;
|
|
_c->waiters_count_ = 0;
|
|
_c->waiters_count_unblock_ += relCnt;
|
|
}
|
|
else if (_c->waiters_count_ > _c->waiters_count_gone_)
|
|
{
|
|
r = do_sema_b_wait (_c->sema_b, 1, INFINITE,&_c->waiters_b_lock_,&_c->value_b);
|
|
if (r != 0)
|
|
{
|
|
LeaveCriticalSection (&_c->waiters_count_lock_);
|
|
/* pthread_testcancel(); */
|
|
return r;
|
|
}
|
|
if (_c->waiters_count_gone_ != 0)
|
|
{
|
|
_c->waiters_count_ -= _c->waiters_count_gone_;
|
|
_c->waiters_count_gone_ = 0;
|
|
}
|
|
relCnt = _c->waiters_count_;
|
|
_c->waiters_count_ = 0;
|
|
_c->waiters_count_unblock_ = relCnt;
|
|
}
|
|
else
|
|
{
|
|
LeaveCriticalSection (&_c->waiters_count_lock_);
|
|
/* pthread_testcancel(); */
|
|
return 0;
|
|
}
|
|
LeaveCriticalSection (&_c->waiters_count_lock_);
|
|
r = do_sema_b_release(_c->sema_q, relCnt,&_c->waiters_q_lock_,&_c->value_q);
|
|
/* pthread_testcancel(); */
|
|
return r;
|
|
}
|
|
|
|
int
|
|
pthread_cond_wait (pthread_cond_t *c, pthread_mutex_t *external_mutex)
|
|
{
|
|
sCondWaitHelper ch;
|
|
cond_t *_c;
|
|
int r;
|
|
|
|
/* pthread_testcancel(); */
|
|
|
|
if (!c || *c == (pthread_cond_t)NULL)
|
|
return EINVAL;
|
|
_c = (cond_t *)*c;
|
|
if (*c == PTHREAD_COND_INITIALIZER)
|
|
{
|
|
r = cond_static_init(c);
|
|
if (r != 0 && r != EBUSY)
|
|
return r;
|
|
_c = (cond_t *) *c;
|
|
} else if (_c->valid != (unsigned int)LIFE_COND)
|
|
return EINVAL;
|
|
|
|
tryagain:
|
|
r = do_sema_b_wait (_c->sema_b, 0, INFINITE,&_c->waiters_b_lock_,&_c->value_b);
|
|
if (r != 0)
|
|
return r;
|
|
|
|
if (!TryEnterCriticalSection (&_c->waiters_count_lock_))
|
|
{
|
|
r = do_sema_b_release (_c->sema_b, 1,&_c->waiters_b_lock_,&_c->value_b);
|
|
if (r != 0)
|
|
return r;
|
|
sched_yield();
|
|
goto tryagain;
|
|
}
|
|
|
|
_c->waiters_count_++;
|
|
LeaveCriticalSection(&_c->waiters_count_lock_);
|
|
r = do_sema_b_release (_c->sema_b, 1,&_c->waiters_b_lock_,&_c->value_b);
|
|
if (r != 0)
|
|
return r;
|
|
|
|
ch.c = _c;
|
|
ch.r = &r;
|
|
ch.external_mutex = external_mutex;
|
|
|
|
pthread_cleanup_push(cleanup_wait, (void *) &ch);
|
|
r = pthread_mutex_unlock(external_mutex);
|
|
if (!r)
|
|
r = do_sema_b_wait (_c->sema_q, 0, INFINITE,&_c->waiters_q_lock_,&_c->value_q);
|
|
|
|
pthread_cleanup_pop(1);
|
|
return r;
|
|
}
|
|
|
|
static int
|
|
pthread_cond_timedwait_impl (pthread_cond_t *c, pthread_mutex_t *external_mutex, const struct _timespec64 *t, int rel)
|
|
{
|
|
sCondWaitHelper ch;
|
|
DWORD dwr;
|
|
int r;
|
|
cond_t *_c;
|
|
|
|
/* pthread_testcancel(); */
|
|
|
|
if (!c || !*c)
|
|
return EINVAL;
|
|
_c = (cond_t *)*c;
|
|
if (_c == (cond_t *)PTHREAD_COND_INITIALIZER)
|
|
{
|
|
r = cond_static_init(c);
|
|
if (r && r != EBUSY)
|
|
return r;
|
|
_c = (cond_t *) *c;
|
|
} else if ((_c)->valid != (unsigned int)LIFE_COND)
|
|
return EINVAL;
|
|
|
|
if (rel == 0)
|
|
{
|
|
dwr = dwMilliSecs(_pthread_rel_time_in_ms(t));
|
|
}
|
|
else
|
|
{
|
|
dwr = dwMilliSecs(_pthread_time_in_ms_from_timespec(t));
|
|
}
|
|
|
|
tryagain:
|
|
r = do_sema_b_wait (_c->sema_b, 0, INFINITE,&_c->waiters_b_lock_,&_c->value_b);
|
|
if (r != 0)
|
|
return r;
|
|
|
|
if (!TryEnterCriticalSection (&_c->waiters_count_lock_))
|
|
{
|
|
r = do_sema_b_release (_c->sema_b, 1,&_c->waiters_b_lock_,&_c->value_b);
|
|
if (r != 0)
|
|
return r;
|
|
sched_yield();
|
|
goto tryagain;
|
|
}
|
|
|
|
_c->waiters_count_++;
|
|
LeaveCriticalSection(&_c->waiters_count_lock_);
|
|
r = do_sema_b_release (_c->sema_b, 1,&_c->waiters_b_lock_,&_c->value_b);
|
|
if (r != 0)
|
|
return r;
|
|
|
|
ch.c = _c;
|
|
ch.r = &r;
|
|
ch.external_mutex = external_mutex;
|
|
{
|
|
pthread_cleanup_push(cleanup_wait, (void *) &ch);
|
|
|
|
r = pthread_mutex_unlock(external_mutex);
|
|
if (!r)
|
|
r = do_sema_b_wait (_c->sema_q, 0, dwr,&_c->waiters_q_lock_,&_c->value_q);
|
|
|
|
pthread_cleanup_pop(1);
|
|
}
|
|
return r;
|
|
}
|
|
|
|
int
|
|
pthread_cond_timedwait64(pthread_cond_t *c, pthread_mutex_t *m, const struct _timespec64 *t)
|
|
{
|
|
return pthread_cond_timedwait_impl(c, m, t, 0);
|
|
}
|
|
|
|
int
|
|
pthread_cond_timedwait32(pthread_cond_t *c, pthread_mutex_t *m, const struct _timespec32 *t)
|
|
{
|
|
struct _timespec64 t64 = {.tv_sec = t->tv_sec, .tv_nsec = t->tv_nsec};
|
|
return pthread_cond_timedwait_impl(c, m, &t64, 0);
|
|
}
|
|
|
|
int
|
|
pthread_cond_timedwait64_relative_np(pthread_cond_t *c, pthread_mutex_t *m, const struct _timespec64 *t)
|
|
{
|
|
return pthread_cond_timedwait_impl(c, m, t, 1);
|
|
}
|
|
|
|
int
|
|
pthread_cond_timedwait32_relative_np(pthread_cond_t *c, pthread_mutex_t *m, const struct _timespec32 *t)
|
|
{
|
|
struct _timespec64 t64 = {.tv_sec = t->tv_sec, .tv_nsec = t->tv_nsec};
|
|
return pthread_cond_timedwait_impl(c, m, &t64, 1);
|
|
}
|
|
|
|
static void
|
|
cleanup_wait (void *arg)
|
|
{
|
|
int n, r;
|
|
sCondWaitHelper *ch = (sCondWaitHelper *) arg;
|
|
cond_t *_c;
|
|
|
|
_c = ch->c;
|
|
EnterCriticalSection (&_c->waiters_count_lock_);
|
|
n = _c->waiters_count_unblock_;
|
|
if (n != 0)
|
|
_c->waiters_count_unblock_ -= 1;
|
|
else if ((INT_MAX/2) - 1 == _c->waiters_count_gone_)
|
|
{
|
|
_c->waiters_count_gone_ += 1;
|
|
r = do_sema_b_wait (_c->sema_b, 1, INFINITE,&_c->waiters_b_lock_,&_c->value_b);
|
|
if (r != 0)
|
|
{
|
|
LeaveCriticalSection(&_c->waiters_count_lock_);
|
|
ch->r[0] = r;
|
|
return;
|
|
}
|
|
_c->waiters_count_ -= _c->waiters_count_gone_;
|
|
r = do_sema_b_release (_c->sema_b, 1,&_c->waiters_b_lock_,&_c->value_b);
|
|
if (r != 0)
|
|
{
|
|
LeaveCriticalSection(&_c->waiters_count_lock_);
|
|
ch->r[0] = r;
|
|
return;
|
|
}
|
|
_c->waiters_count_gone_ = 0;
|
|
}
|
|
else
|
|
_c->waiters_count_gone_ += 1;
|
|
LeaveCriticalSection (&_c->waiters_count_lock_);
|
|
|
|
if (n == 1)
|
|
{
|
|
r = do_sema_b_release (_c->sema_b, 1,&_c->waiters_b_lock_,&_c->value_b);
|
|
if (r != 0)
|
|
{
|
|
ch->r[0] = r;
|
|
return;
|
|
}
|
|
}
|
|
r = pthread_mutex_lock(ch->external_mutex);
|
|
if (r != 0)
|
|
ch->r[0] = r;
|
|
}
|
|
|
|
static int
|
|
do_sema_b_wait (HANDLE sema, int nointerrupt, DWORD timeout,CRITICAL_SECTION *cs, LONG *val)
|
|
{
|
|
int r;
|
|
LONG v;
|
|
EnterCriticalSection(cs);
|
|
InterlockedDecrement(val);
|
|
v = val[0];
|
|
LeaveCriticalSection(cs);
|
|
if (v >= 0)
|
|
return 0;
|
|
r = do_sema_b_wait_intern (sema, nointerrupt, timeout);
|
|
EnterCriticalSection(cs);
|
|
if (r != 0)
|
|
InterlockedIncrement(val);
|
|
LeaveCriticalSection(cs);
|
|
return r;
|
|
}
|
|
|
|
int
|
|
do_sema_b_wait_intern (HANDLE sema, int nointerrupt, DWORD timeout)
|
|
{
|
|
HANDLE arr[2];
|
|
DWORD maxH = 1;
|
|
int r = 0;
|
|
DWORD res, dt;
|
|
if (nointerrupt == 1)
|
|
{
|
|
res = _pthread_wait_for_single_object(sema, timeout);
|
|
switch (res) {
|
|
case WAIT_TIMEOUT:
|
|
r = ETIMEDOUT;
|
|
break;
|
|
case WAIT_ABANDONED:
|
|
r = EPERM;
|
|
break;
|
|
case WAIT_OBJECT_0:
|
|
break;
|
|
default:
|
|
/*We can only return EINVAL though it might not be posix compliant */
|
|
r = EINVAL;
|
|
}
|
|
if (r != 0 && r != EINVAL && WaitForSingleObject(sema, 0) == WAIT_OBJECT_0)
|
|
r = 0;
|
|
return r;
|
|
}
|
|
arr[0] = sema;
|
|
arr[1] = (HANDLE) pthread_getevent ();
|
|
if (arr[1] != NULL) maxH += 1;
|
|
if (maxH == 2)
|
|
{
|
|
redo:
|
|
res = _pthread_wait_for_multiple_objects(maxH, arr, 0, timeout);
|
|
switch (res) {
|
|
case WAIT_TIMEOUT:
|
|
r = ETIMEDOUT;
|
|
break;
|
|
case (WAIT_OBJECT_0 + 1):
|
|
ResetEvent(arr[1]);
|
|
if (nointerrupt != 2)
|
|
{
|
|
pthread_testcancel();
|
|
return EINVAL;
|
|
}
|
|
pthread_testcancel ();
|
|
goto redo;
|
|
case WAIT_ABANDONED:
|
|
r = EPERM;
|
|
break;
|
|
case WAIT_OBJECT_0:
|
|
r = 0;
|
|
break;
|
|
default:
|
|
/*We can only return EINVAL though it might not be posix compliant */
|
|
r = EINVAL;
|
|
}
|
|
if (r != 0 && r != EINVAL && WaitForSingleObject(arr[0], 0) == WAIT_OBJECT_0)
|
|
r = 0;
|
|
if (r != 0 && nointerrupt != 2 && __pthread_shallcancel ())
|
|
return EINVAL;
|
|
return r;
|
|
}
|
|
if (timeout == INFINITE)
|
|
{
|
|
do {
|
|
res = _pthread_wait_for_single_object(sema, 40);
|
|
switch (res) {
|
|
case WAIT_TIMEOUT:
|
|
r = ETIMEDOUT;
|
|
break;
|
|
case WAIT_ABANDONED:
|
|
r = EPERM;
|
|
break;
|
|
case WAIT_OBJECT_0:
|
|
r = 0;
|
|
break;
|
|
default:
|
|
/*We can only return EINVAL though it might not be posix compliant */
|
|
r = EINVAL;
|
|
}
|
|
if (r != 0 && __pthread_shallcancel ())
|
|
{
|
|
if (nointerrupt != 2)
|
|
pthread_testcancel();
|
|
return EINVAL;
|
|
}
|
|
} while (r == ETIMEDOUT);
|
|
if (r != 0 && r != EINVAL && WaitForSingleObject(sema, 0) == WAIT_OBJECT_0)
|
|
r = 0;
|
|
return r;
|
|
}
|
|
dt = 20;
|
|
do {
|
|
if (dt > timeout) dt = timeout;
|
|
res = _pthread_wait_for_single_object(sema, dt);
|
|
switch (res) {
|
|
case WAIT_TIMEOUT:
|
|
r = ETIMEDOUT;
|
|
break;
|
|
case WAIT_ABANDONED:
|
|
r = EPERM;
|
|
break;
|
|
case WAIT_OBJECT_0:
|
|
r = 0;
|
|
break;
|
|
default:
|
|
/*We can only return EINVAL though it might not be posix compliant */
|
|
r = EINVAL;
|
|
}
|
|
timeout -= dt;
|
|
if (timeout != 0 && r != 0 && __pthread_shallcancel ())
|
|
return EINVAL;
|
|
} while (r == ETIMEDOUT && timeout != 0);
|
|
if (r != 0 && r == ETIMEDOUT && WaitForSingleObject(sema, 0) == WAIT_OBJECT_0)
|
|
r = 0;
|
|
if (r != 0 && nointerrupt != 2)
|
|
pthread_testcancel();
|
|
return r;
|
|
}
|
|
|
|
static int
|
|
do_sema_b_release(HANDLE sema, LONG count,CRITICAL_SECTION *cs, LONG *val)
|
|
{
|
|
int wc;
|
|
EnterCriticalSection(cs);
|
|
if (((long long) val[0] + (long long) count) > (long long) 0x7fffffffLL)
|
|
{
|
|
LeaveCriticalSection(cs);
|
|
return ERANGE;
|
|
}
|
|
wc = -val[0];
|
|
InterlockedExchangeAdd(val, count);
|
|
if (wc <= 0 || ReleaseSemaphore(sema, (wc < count ? wc : count), NULL))
|
|
{
|
|
LeaveCriticalSection(cs);
|
|
return 0;
|
|
}
|
|
InterlockedExchangeAdd(val, -count);
|
|
LeaveCriticalSection(cs);
|
|
return EINVAL;
|
|
}
|