chore: update to 2a0400ade5535001bfc09e0e7531515e232be6e7

This commit is contained in:
2024-07-03 19:55:17 -05:00
parent e009f01d38
commit c461e29eaa
91 changed files with 39733 additions and 3468 deletions

View File

@@ -0,0 +1,246 @@
/*
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.
*/
#include <windows.h>
#include <stdio.h>
#include <malloc.h>
#include "pthread.h"
#include "barrier.h"
#include "ref.h"
#include "misc.h"
static pthread_spinlock_t barrier_global = PTHREAD_SPINLOCK_INITIALIZER;
static WINPTHREADS_ATTRIBUTE((noinline)) int
barrier_unref(volatile pthread_barrier_t *barrier, int res)
{
pthread_spin_lock(&barrier_global);
#ifdef WINPTHREAD_DBG
assert((((barrier_t *)*barrier)->valid == LIFE_BARRIER) && (((barrier_t *)*barrier)->busy > 0));
#endif
((barrier_t *)*barrier)->busy -= 1;
pthread_spin_unlock(&barrier_global);
return res;
}
static WINPTHREADS_ATTRIBUTE((noinline)) int barrier_ref(volatile pthread_barrier_t *barrier)
{
int r = 0;
pthread_spin_lock(&barrier_global);
if (!barrier || !*barrier || ((barrier_t *)*barrier)->valid != LIFE_BARRIER) r = EINVAL;
else {
((barrier_t *)*barrier)->busy += 1;
}
pthread_spin_unlock(&barrier_global);
return r;
}
static WINPTHREADS_ATTRIBUTE((noinline)) int
barrier_ref_destroy(volatile pthread_barrier_t *barrier, pthread_barrier_t *bDestroy)
{
int r = 0;
*bDestroy = NULL;
pthread_spin_lock(&barrier_global);
if (!barrier || !*barrier || ((barrier_t *)*barrier)->valid != LIFE_BARRIER) r = EINVAL;
else {
barrier_t *b_ = (barrier_t *)*barrier;
if (b_->busy) r = EBUSY;
else {
*bDestroy = *barrier;
*barrier = NULL;
}
}
pthread_spin_unlock(&barrier_global);
return r;
}
static WINPTHREADS_ATTRIBUTE((noinline)) void
barrier_ref_set (volatile pthread_barrier_t *barrier, void *v)
{
pthread_spin_lock(&barrier_global);
*barrier = v;
pthread_spin_unlock(&barrier_global);
}
int pthread_barrier_destroy(pthread_barrier_t *b_)
{
pthread_barrier_t bDestroy;
barrier_t *b;
int r;
while ((r = barrier_ref_destroy(b_,&bDestroy)) == EBUSY)
Sleep(0);
if (r)
return r;
b = (barrier_t *)bDestroy;
pthread_mutex_lock(&b->m);
if (sem_destroy(&b->sems[0]) != 0)
{
/* Could this happen? */
*b_ = bDestroy;
pthread_mutex_unlock (&b->m);
return EBUSY;
}
if (sem_destroy(&b->sems[1]) != 0)
{
sem_init (&b->sems[0], b->share, 0);
*b_ = bDestroy;
pthread_mutex_unlock (&b->m);
return -1;
}
pthread_mutex_unlock(&b->m);
if(pthread_mutex_destroy(&b->m) != 0) {
sem_init (&b->sems[0], b->share, 0);
sem_init (&b->sems[1], b->share, 0);
*b_ = bDestroy;
return -1;
}
b->valid = DEAD_BARRIER;
free(bDestroy);
return 0;
}
int
pthread_barrier_init (pthread_barrier_t *b_, const void *attr,
unsigned int count)
{
barrier_t *b;
if (!count || !b_)
return EINVAL;
if ((b = (pthread_barrier_t)calloc(1,sizeof(*b))) == NULL)
return ENOMEM;
if (!attr || *((int **)attr) == NULL)
b->share = PTHREAD_PROCESS_PRIVATE;
else
memcpy (&b->share, *((void **) attr), sizeof (int));
b->total = count;
b->count = count;
b->valid = LIFE_BARRIER;
b->sel = 0;
if (pthread_mutex_init(&b->m, NULL) != 0)
{
free (b);
return ENOMEM;
}
if (sem_init(&b->sems[0], b->share, 0) != 0)
{
pthread_mutex_destroy(&b->m);
free (b);
return ENOMEM;
}
if (sem_init(&b->sems[1], b->share, 0) != 0)
{
pthread_mutex_destroy(&b->m);
sem_destroy(&b->sems[0]);
free (b);
return ENOMEM;
}
barrier_ref_set (b_,b);
return 0;
}
int pthread_barrier_wait(pthread_barrier_t *b_)
{
long sel;
int r, e, rslt;
barrier_t *b;
r = barrier_ref(b_);
if(r) return r;
b = (barrier_t *)*b_;
if ((r = pthread_mutex_lock(&b->m)) != 0) return barrier_unref(b_,EINVAL);
sel = b->sel;
InterlockedDecrement((long*)&b->total);
if (b->total == 0)
{
b->total = b->count;
b->sel = (sel != 0 ? 0 : 1);
e = 1;
rslt = PTHREAD_BARRIER_SERIAL_THREAD;
r = (b->count > 1 ? sem_post_multiple (&b->sems[sel], b->count - 1) : 0);
}
else { e = 0; rslt= 0; }
pthread_mutex_unlock(&b->m);
if (!e)
r = sem_wait(&b->sems[sel]);
if (!r) r = rslt;
return barrier_unref(b_,r);
}
int pthread_barrierattr_init(void **attr)
{
int *p;
if ((p = (int *) calloc (1, sizeof (int))) == NULL)
return ENOMEM;
*p = PTHREAD_PROCESS_PRIVATE;
*attr = p;
return 0;
}
int pthread_barrierattr_destroy(void **attr)
{
void *p;
if (!attr || (p = *attr) == NULL)
return EINVAL;
*attr = NULL;
free (p);
return 0;
}
int pthread_barrierattr_setpshared(void **attr, int s)
{
if (!attr || *attr == NULL
|| (s != PTHREAD_PROCESS_SHARED && s != PTHREAD_PROCESS_PRIVATE))
return EINVAL;
memcpy (*attr, &s, sizeof (int));
return 0;
}
int pthread_barrierattr_getpshared(void **attr, int *s)
{
if (!attr || !s || *attr == NULL)
return EINVAL;
memcpy (s, *attr, sizeof (int));
return 0;
}

View File

@@ -0,0 +1,52 @@
/*
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.
*/
#ifndef WIN_PTHREADS_BARRIER_H
#define WIN_PTHREADS_BARRIER_H
#define LIFE_BARRIER 0xBAB1FEED
#define DEAD_BARRIER 0xDEADB00F
#define _PTHREAD_BARRIER_FLAG (1<<30)
#define CHECK_BARRIER(b) \
do { \
if (!(b) || ( ((barrier_t *)(*b))->valid != (unsigned int)LIFE_BARRIER ) ) \
return EINVAL; \
} while (0)
#include "semaphore.h"
typedef struct barrier_t barrier_t;
struct barrier_t
{
int valid;
int busy;
int count;
int total;
int share;
long sel;
pthread_mutex_t m;
sem_t sems[2];
};
#endif

View File

@@ -0,0 +1,257 @@
/**
* This file has no copyright assigned and is placed in the Public Domain.
* This file is part of the w64 mingw-runtime package.
* No warranty is given; refer to the file DISCLAIMER.PD within this package.
*/
#include <errno.h>
#include <stdint.h>
#include <time.h>
#include <windows.h>
#ifndef IN_WINPTHREAD
#define IN_WINPTHREAD 1
#endif
#include "pthread.h"
#include "pthread_time.h"
#include "misc.h"
#define POW10_7 10000000
#define POW10_9 1000000000
/* Number of 100ns-seconds between the beginning of the Windows epoch
* (Jan. 1, 1601) and the Unix epoch (Jan. 1, 1970)
*/
#define DELTA_EPOCH_IN_100NS INT64_C(116444736000000000)
static WINPTHREADS_INLINE int lc_set_errno(int result)
{
if (result != 0) {
errno = result;
return -1;
}
return 0;
}
/**
* Get the resolution of the specified clock clock_id and
* stores it in the struct timespec pointed to by res.
* @param clock_id The clock_id argument is the identifier of the particular
* clock on which to act. The following clocks are supported:
* <pre>
* CLOCK_REALTIME System-wide real-time clock. Setting this clock
* requires appropriate privileges.
* CLOCK_MONOTONIC Clock that cannot be set and represents monotonic
* time since some unspecified starting point.
* CLOCK_PROCESS_CPUTIME_ID High-resolution per-process timer from the CPU.
* CLOCK_THREAD_CPUTIME_ID Thread-specific CPU-time clock.
* </pre>
* @param res The pointer to a timespec structure to receive the time
* resolution.
* @return If the function succeeds, the return value is 0.
* If the function fails, the return value is -1,
* with errno set to indicate the error.
*/
int clock_getres(clockid_t clock_id, struct timespec *res)
{
clockid_t id = clock_id;
if (id == CLOCK_REALTIME && _pthread_get_system_time_best_as_file_time == GetSystemTimeAsFileTime)
id = CLOCK_REALTIME_COARSE; /* GetSystemTimePreciseAsFileTime() not available */
switch(id) {
case CLOCK_REALTIME:
case CLOCK_MONOTONIC:
{
LARGE_INTEGER pf;
if (QueryPerformanceFrequency(&pf) == 0)
return lc_set_errno(EINVAL);
res->tv_sec = 0;
res->tv_nsec = (int) ((POW10_9 + (pf.QuadPart >> 1)) / pf.QuadPart);
if (res->tv_nsec < 1)
res->tv_nsec = 1;
return 0;
}
case CLOCK_REALTIME_COARSE:
case CLOCK_PROCESS_CPUTIME_ID:
case CLOCK_THREAD_CPUTIME_ID:
{
DWORD timeAdjustment, timeIncrement;
BOOL isTimeAdjustmentDisabled;
(void) GetSystemTimeAdjustment(&timeAdjustment, &timeIncrement, &isTimeAdjustmentDisabled);
res->tv_sec = 0;
res->tv_nsec = timeIncrement * 100;
return 0;
}
default:
break;
}
return lc_set_errno(EINVAL);
}
/**
* Get the time of the specified clock clock_id and stores it in the struct
* timespec pointed to by tp.
* @param clock_id The clock_id argument is the identifier of the particular
* clock on which to act. The following clocks are supported:
* <pre>
* CLOCK_REALTIME System-wide real-time clock. Setting this clock
* requires appropriate privileges.
* CLOCK_MONOTONIC Clock that cannot be set and represents monotonic
* time since some unspecified starting point.
* CLOCK_PROCESS_CPUTIME_ID High-resolution per-process timer from the CPU.
* CLOCK_THREAD_CPUTIME_ID Thread-specific CPU-time clock.
* </pre>
* @param tp The pointer to a timespec structure to receive the time.
* @return If the function succeeds, the return value is 0.
* If the function fails, the return value is -1,
* with errno set to indicate the error.
*/
int clock_gettime(clockid_t clock_id, struct timespec *tp)
{
unsigned __int64 t;
LARGE_INTEGER pf, pc;
union {
unsigned __int64 u64;
FILETIME ft;
} ct, et, kt, ut;
switch(clock_id) {
case CLOCK_REALTIME:
{
_pthread_get_system_time_best_as_file_time(&ct.ft);
t = ct.u64 - DELTA_EPOCH_IN_100NS;
tp->tv_sec = t / POW10_7;
tp->tv_nsec = ((int) (t % POW10_7)) * 100;
return 0;
}
case CLOCK_REALTIME_COARSE:
{
GetSystemTimeAsFileTime(&ct.ft);
t = ct.u64 - DELTA_EPOCH_IN_100NS;
tp->tv_sec = t / POW10_7;
tp->tv_nsec = ((int) (t % POW10_7)) * 100;
return 0;
}
case CLOCK_MONOTONIC:
{
if (QueryPerformanceFrequency(&pf) == 0)
return lc_set_errno(EINVAL);
if (QueryPerformanceCounter(&pc) == 0)
return lc_set_errno(EINVAL);
tp->tv_sec = pc.QuadPart / pf.QuadPart;
tp->tv_nsec = (int) (((pc.QuadPart % pf.QuadPart) * POW10_9 + (pf.QuadPart >> 1)) / pf.QuadPart);
if (tp->tv_nsec >= POW10_9) {
tp->tv_sec ++;
tp->tv_nsec -= POW10_9;
}
return 0;
}
case CLOCK_PROCESS_CPUTIME_ID:
{
if(0 == GetProcessTimes(GetCurrentProcess(), &ct.ft, &et.ft, &kt.ft, &ut.ft))
return lc_set_errno(EINVAL);
t = kt.u64 + ut.u64;
tp->tv_sec = t / POW10_7;
tp->tv_nsec = ((int) (t % POW10_7)) * 100;
return 0;
}
case CLOCK_THREAD_CPUTIME_ID:
{
if(0 == GetThreadTimes(GetCurrentThread(), &ct.ft, &et.ft, &kt.ft, &ut.ft))
return lc_set_errno(EINVAL);
t = kt.u64 + ut.u64;
tp->tv_sec = t / POW10_7;
tp->tv_nsec = ((int) (t % POW10_7)) * 100;
return 0;
}
default:
break;
}
return lc_set_errno(EINVAL);
}
/**
* Sleep for the specified time.
* @param clock_id This argument should always be CLOCK_REALTIME (0).
* @param flags 0 for relative sleep interval, others for absolute waking up.
* @param request The desired sleep interval or absolute waking up time.
* @param remain The remain amount of time to sleep.
* The current implemention just ignore it.
* @return If the function succeeds, the return value is 0.
* If the function fails, the return value is -1,
* with errno set to indicate the error.
*/
int clock_nanosleep(clockid_t clock_id, int flags,
const struct timespec *request,
struct timespec *remain)
{
struct timespec tp;
if (clock_id != CLOCK_REALTIME)
return lc_set_errno(EINVAL);
if (flags == 0)
return nanosleep(request, remain);
/* TIMER_ABSTIME = 1 */
clock_gettime(CLOCK_REALTIME, &tp);
tp.tv_sec = request->tv_sec - tp.tv_sec;
tp.tv_nsec = request->tv_nsec - tp.tv_nsec;
if (tp.tv_nsec < 0) {
tp.tv_nsec += POW10_9;
tp.tv_sec --;
}
return nanosleep(&tp, remain);
}
/**
* Set the time of the specified clock clock_id.
* @param clock_id This argument should always be CLOCK_REALTIME (0).
* @param tp The requested time.
* @return If the function succeeds, the return value is 0.
* If the function fails, the return value is -1,
* with errno set to indicate the error.
*/
int clock_settime(clockid_t clock_id, const struct timespec *tp)
{
SYSTEMTIME st;
union {
unsigned __int64 u64;
FILETIME ft;
} t;
if (clock_id != CLOCK_REALTIME)
return lc_set_errno(EINVAL);
t.u64 = tp->tv_sec * (__int64) POW10_7 + tp->tv_nsec / 100 + DELTA_EPOCH_IN_100NS;
if (FileTimeToSystemTime(&t.ft, &st) == 0)
return lc_set_errno(EINVAL);
if (SetSystemTime(&st) == 0)
return lc_set_errno(EPERM);
return 0;
}

755
libs/winpthreads/src/cond.c Normal file
View File

@@ -0,0 +1,755 @@
/*
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.
*/
#include <windows.h>
#include <stdio.h>
#include <malloc.h>
#include <time.h>
#include "pthread.h"
#include "pthread_time.h"
#include "ref.h"
#include "cond.h"
#include "thread.h"
#include "misc.h"
#include "winpthread_internal.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);
#ifdef WINPTHREAD_DBG
static int print_state = 0;
static FILE *fo;
void cond_print_set(int state, FILE *f)
{
if (f) fo = f;
if (!fo) fo = stdout;
print_state = state;
}
void cond_print(volatile pthread_cond_t *c, char *txt)
{
if (!print_state) return;
cond_t *c_ = (cond_t *)*c;
if (c_ == NULL) {
fprintf(fo,"C%p %lu %s\n",(void *)*c,GetCurrentThreadId(),txt);
} else {
fprintf(fo,"C%p %lu V=%0X w=%ld %s\n",
(void *)*c,
GetCurrentThreadId(),
(int)c_->valid,
c_->waiters_count_,
txt
);
}
}
#endif
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_clock_nanosleep (clockid_t clock_id, int flags, const struct timespec *rqtp,
struct timespec *rmtp)
{
unsigned long long tick, tick2;
unsigned long long delay;
DWORD dw;
if (clock_id != CLOCK_REALTIME
&& clock_id != CLOCK_MONOTONIC
&& clock_id != CLOCK_PROCESS_CPUTIME_ID)
return EINVAL;
if ((flags & TIMER_ABSTIME) != 0)
delay = _pthread_rel_time_in_ms (rqtp);
else
delay = _pthread_time_in_ms_from_timespec (rqtp);
do
{
dw = (DWORD) (delay >= 99999ULL ? 99999ULL : delay);
tick = _pthread_time_in_ms ();
pthread_delay_np_ms (dw);
tick2 = _pthread_time_in_ms ();
tick2 -= tick;
if (tick2 >= delay)
delay = 0;
else
delay -= tick2;
}
while (delay != 0ULL);
if (rmtp)
memset (rmtp, 0, sizeof (*rmtp));
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 timespec *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_timedwait(pthread_cond_t *c, pthread_mutex_t *m, const struct timespec *t)
{
return pthread_cond_timedwait_impl(c, m, t, 0);
}
int
pthread_cond_timedwait_relative_np(pthread_cond_t *c, pthread_mutex_t *m, const struct timespec *t)
{
return pthread_cond_timedwait_impl(c, m, t, 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;
}

View File

@@ -0,0 +1,63 @@
/*
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.
*/
#ifndef WIN_PTHREADS_COND_H
#define WIN_PTHREADS_COND_H
#include <windows.h>
#define CHECK_COND(c) \
do { \
if (!(c) || !*c || (*c == PTHREAD_COND_INITIALIZER) \
|| ( ((cond_t *)(*c))->valid != (unsigned int)LIFE_COND ) ) \
return EINVAL; \
} while (0)
#define LIFE_COND 0xC0BAB1FD
#define DEAD_COND 0xC0DEADBF
#define STATIC_COND_INITIALIZER(x) ((pthread_cond_t)(x) == ((pthread_cond_t)PTHREAD_COND_INITIALIZER))
typedef struct cond_t cond_t;
struct cond_t
{
unsigned int valid;
int busy;
LONG waiters_count_; /* Number of waiting threads. */
LONG waiters_count_unblock_; /* Number of waiting threads whitch can be unblocked. */
LONG waiters_count_gone_; /* Number of waiters which are gone. */
CRITICAL_SECTION waiters_count_lock_; /* Serialize access to <waiters_count_>. */
CRITICAL_SECTION waiters_q_lock_; /* Serialize access to sema_q. */
LONG value_q;
CRITICAL_SECTION waiters_b_lock_; /* Serialize access to sema_b. */
LONG value_b;
HANDLE sema_q; /* Semaphore used to queue up threads waiting for the condition to
become signaled. */
HANDLE sema_b; /* Semaphore used to queue up threads waiting for the condition which
became signaled. */
};
void cond_print_set(int state, FILE *f);
void cond_print(volatile pthread_cond_t *c, char *txt);
#endif

View File

@@ -0,0 +1,586 @@
/*-
* Copyright (c) 1992, 1993
* The Regents of the University of California. All rights reserved.
*
* This software was developed by the Computer Systems Engineering group
* at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
* contributed to Berkeley.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifndef _LIBKERN_QUAD_H_
#define _LIBKERN_QUAD_H_
/*
* Quad arithmetic.
*
* This library makes the following assumptions:
*
* - The type long long (aka quad_t) exists.
*
* - A quad variable is exactly twice as long as `long'.
*
* - The machine's arithmetic is two's complement.
*
* This library can provide 128-bit arithmetic on a machine with 128-bit
* quads and 64-bit longs, for instance, or 96-bit arithmetic on machines
* with 48-bit longs.
*/
/*
#include <sys/cdefs.h>
#include <sys/types.h>
#include <sys/limits.h>
#include <sys/syslimits.h>
*/
#include <limits.h>
typedef long long quad_t;
typedef unsigned long long u_quad_t;
typedef unsigned long u_long;
#define CHAR_BIT __CHAR_BIT__
/*
* Define the order of 32-bit words in 64-bit words.
* For little endian only.
*/
#define _QUAD_HIGHWORD 1
#define _QUAD_LOWWORD 0
/*
* Depending on the desired operation, we view a `long long' (aka quad_t) in
* one or more of the following formats.
*/
union uu {
quad_t q; /* as a (signed) quad */
quad_t uq; /* as an unsigned quad */
long sl[2]; /* as two signed longs */
u_long ul[2]; /* as two unsigned longs */
};
/*
* Define high and low longwords.
*/
#define H _QUAD_HIGHWORD
#define L _QUAD_LOWWORD
/*
* Total number of bits in a quad_t and in the pieces that make it up.
* These are used for shifting, and also below for halfword extraction
* and assembly.
*/
#define QUAD_BITS (sizeof(quad_t) * CHAR_BIT)
#define LONG_BITS (sizeof(long) * CHAR_BIT)
#define HALF_BITS (sizeof(long) * CHAR_BIT / 2)
/*
* Extract high and low shortwords from longword, and move low shortword of
* longword to upper half of long, i.e., produce the upper longword of
* ((quad_t)(x) << (number_of_bits_in_long/2)). (`x' must actually be u_long.)
*
* These are used in the multiply code, to split a longword into upper
* and lower halves, and to reassemble a product as a quad_t, shifted left
* (sizeof(long)*CHAR_BIT/2).
*/
#define HHALF(x) ((x) >> HALF_BITS)
#define LHALF(x) ((x) & ((1 << HALF_BITS) - 1))
#define LHUP(x) ((x) << HALF_BITS)
typedef unsigned int qshift_t;
quad_t __ashldi3(quad_t, qshift_t);
quad_t __ashrdi3(quad_t, qshift_t);
int __cmpdi2(quad_t a, quad_t b);
quad_t __divdi3(quad_t a, quad_t b);
quad_t __lshrdi3(quad_t, qshift_t);
quad_t __moddi3(quad_t a, quad_t b);
u_quad_t __qdivrem(u_quad_t u, u_quad_t v, u_quad_t *rem);
u_quad_t __udivdi3(u_quad_t a, u_quad_t b);
u_quad_t __umoddi3(u_quad_t a, u_quad_t b);
int __ucmpdi2(u_quad_t a, u_quad_t b);
quad_t __divmoddi4(quad_t a, quad_t b, quad_t *rem);
u_quad_t __udivmoddi4(u_quad_t a, u_quad_t b, u_quad_t *rem);
#endif /* !_LIBKERN_QUAD_H_ */
#if defined (_X86_) && !defined (__x86_64__)
/*
* Shift a (signed) quad value left (arithmetic shift left).
* This is the same as logical shift left!
*/
quad_t
__ashldi3(a, shift)
quad_t a;
qshift_t shift;
{
union uu aa;
aa.q = a;
if (shift >= LONG_BITS) {
aa.ul[H] = shift >= QUAD_BITS ? 0 :
aa.ul[L] << (shift - LONG_BITS);
aa.ul[L] = 0;
} else if (shift > 0) {
aa.ul[H] = (aa.ul[H] << shift) |
(aa.ul[L] >> (LONG_BITS - shift));
aa.ul[L] <<= shift;
}
return (aa.q);
}
/*
* Shift a (signed) quad value right (arithmetic shift right).
*/
quad_t
__ashrdi3(a, shift)
quad_t a;
qshift_t shift;
{
union uu aa;
aa.q = a;
if (shift >= LONG_BITS) {
long s;
/*
* Smear bits rightward using the machine's right-shift
* method, whether that is sign extension or zero fill,
* to get the `sign word' s. Note that shifting by
* LONG_BITS is undefined, so we shift (LONG_BITS-1),
* then 1 more, to get our answer.
*/
s = (aa.sl[H] >> (LONG_BITS - 1)) >> 1;
aa.ul[L] = shift >= QUAD_BITS ? s :
aa.sl[H] >> (shift - LONG_BITS);
aa.ul[H] = s;
} else if (shift > 0) {
aa.ul[L] = (aa.ul[L] >> shift) |
(aa.ul[H] << (LONG_BITS - shift));
aa.sl[H] >>= shift;
}
return (aa.q);
}
/*
* Return 0, 1, or 2 as a <, =, > b respectively.
* Both a and b are considered signed---which means only the high word is
* signed.
*/
int
__cmpdi2(a, b)
quad_t a, b;
{
union uu aa, bb;
aa.q = a;
bb.q = b;
return (aa.sl[H] < bb.sl[H] ? 0 : aa.sl[H] > bb.sl[H] ? 2 :
aa.ul[L] < bb.ul[L] ? 0 : aa.ul[L] > bb.ul[L] ? 2 : 1);
}
/*
* Divide two signed quads.
* ??? if -1/2 should produce -1 on this machine, this code is wrong
*/
quad_t
__divdi3(a, b)
quad_t a, b;
{
u_quad_t ua, ub, uq;
int neg;
if (a < 0)
ua = -(u_quad_t)a, neg = 1;
else
ua = a, neg = 0;
if (b < 0)
ub = -(u_quad_t)b, neg ^= 1;
else
ub = b;
uq = __qdivrem(ua, ub, (u_quad_t *)0);
return (neg ? -uq : uq);
}
/*
* Shift an (unsigned) quad value right (logical shift right).
*/
quad_t
__lshrdi3(a, shift)
quad_t a;
qshift_t shift;
{
union uu aa;
aa.q = a;
if (shift >= LONG_BITS) {
aa.ul[L] = shift >= QUAD_BITS ? 0 :
aa.ul[H] >> (shift - LONG_BITS);
aa.ul[H] = 0;
} else if (shift > 0) {
aa.ul[L] = (aa.ul[L] >> shift) |
(aa.ul[H] << (LONG_BITS - shift));
aa.ul[H] >>= shift;
}
return (aa.q);
}
/*
* Return remainder after dividing two signed quads.
*
* XXX
* If -1/2 should produce -1 on this machine, this code is wrong.
*/
quad_t
__moddi3(a, b)
quad_t a, b;
{
u_quad_t ua, ub, ur;
int neg;
if (a < 0)
ua = -(u_quad_t)a, neg = 1;
else
ua = a, neg = 0;
if (b < 0)
ub = -(u_quad_t)b;
else
ub = b;
(void)__qdivrem(ua, ub, &ur);
return (neg ? -ur : ur);
}
/*
* Multiprecision divide. This algorithm is from Knuth vol. 2 (2nd ed),
* section 4.3.1, pp. 257--259.
*/
#define B (1 << HALF_BITS) /* digit base */
/* Combine two `digits' to make a single two-digit number. */
#define COMBINE(a, b) (((u_long)(a) << HALF_BITS) | (b))
/* select a type for digits in base B: use unsigned short if they fit */
#if ULONG_MAX == 0xffffffff && USHRT_MAX >= 0xffff
typedef unsigned short digit;
#else
typedef u_long digit;
#endif
/*
* Shift p[0]..p[len] left `sh' bits, ignoring any bits that
* `fall out' the left (there never will be any such anyway).
* We may assume len >= 0. NOTE THAT THIS WRITES len+1 DIGITS.
*/
static void
__shl(register digit *p, register int len, register int sh)
{
register int i;
for (i = 0; i < len; i++)
p[i] = LHALF(p[i] << sh) | (p[i + 1] >> (HALF_BITS - sh));
p[i] = LHALF(p[i] << sh);
}
/*
* __qdivrem(u, v, rem) returns u/v and, optionally, sets *rem to u%v.
*
* We do this in base 2-sup-HALF_BITS, so that all intermediate products
* fit within u_long. As a consequence, the maximum length dividend and
* divisor are 4 `digits' in this base (they are shorter if they have
* leading zeros).
*/
u_quad_t
__qdivrem(uq, vq, arq)
u_quad_t uq, vq, *arq;
{
union uu tmp;
digit *u, *v, *q;
register digit v1, v2;
u_long qhat, rhat, t;
int m, n, d, j, i;
digit uspace[5], vspace[5], qspace[5];
/*
* Take care of special cases: divide by zero, and u < v.
*/
if (vq == 0) {
/* divide by zero. */
static volatile const unsigned int zero = 0;
tmp.ul[H] = tmp.ul[L] = 1 / zero;
if (arq)
*arq = uq;
return (tmp.q);
}
if (uq < vq) {
if (arq)
*arq = uq;
return (0);
}
u = &uspace[0];
v = &vspace[0];
q = &qspace[0];
/*
* Break dividend and divisor into digits in base B, then
* count leading zeros to determine m and n. When done, we
* will have:
* u = (u[1]u[2]...u[m+n]) sub B
* v = (v[1]v[2]...v[n]) sub B
* v[1] != 0
* 1 < n <= 4 (if n = 1, we use a different division algorithm)
* m >= 0 (otherwise u < v, which we already checked)
* m + n = 4
* and thus
* m = 4 - n <= 2
*/
tmp.uq = uq;
u[0] = 0;
u[1] = HHALF(tmp.ul[H]);
u[2] = LHALF(tmp.ul[H]);
u[3] = HHALF(tmp.ul[L]);
u[4] = LHALF(tmp.ul[L]);
tmp.uq = vq;
v[1] = HHALF(tmp.ul[H]);
v[2] = LHALF(tmp.ul[H]);
v[3] = HHALF(tmp.ul[L]);
v[4] = LHALF(tmp.ul[L]);
for (n = 4; v[1] == 0; v++) {
if (--n == 1) {
u_long rbj; /* r*B+u[j] (not root boy jim) */
digit q1, q2, q3, q4;
/*
* Change of plan, per exercise 16.
* r = 0;
* for j = 1..4:
* q[j] = floor((r*B + u[j]) / v),
* r = (r*B + u[j]) % v;
* We unroll this completely here.
*/
t = v[2]; /* nonzero, by definition */
q1 = u[1] / t;
rbj = COMBINE(u[1] % t, u[2]);
q2 = rbj / t;
rbj = COMBINE(rbj % t, u[3]);
q3 = rbj / t;
rbj = COMBINE(rbj % t, u[4]);
q4 = rbj / t;
if (arq)
*arq = rbj % t;
tmp.ul[H] = COMBINE(q1, q2);
tmp.ul[L] = COMBINE(q3, q4);
return (tmp.q);
}
}
/*
* By adjusting q once we determine m, we can guarantee that
* there is a complete four-digit quotient at &qspace[1] when
* we finally stop.
*/
for (m = 4 - n; u[1] == 0; u++)
m--;
for (i = 4 - m; --i >= 0;)
q[i] = 0;
q += 4 - m;
/*
* Here we run Program D, translated from MIX to C and acquiring
* a few minor changes.
*
* D1: choose multiplier 1 << d to ensure v[1] >= B/2.
*/
d = 0;
for (t = v[1]; t < B / 2; t <<= 1)
d++;
if (d > 0) {
__shl(&u[0], m + n, d); /* u <<= d */
__shl(&v[1], n - 1, d); /* v <<= d */
}
/*
* D2: j = 0.
*/
j = 0;
v1 = v[1]; /* for D3 -- note that v[1..n] are constant */
v2 = v[2]; /* for D3 */
do {
register digit uj0, uj1, uj2;
/*
* D3: Calculate qhat (\^q, in TeX notation).
* Let qhat = min((u[j]*B + u[j+1])/v[1], B-1), and
* let rhat = (u[j]*B + u[j+1]) mod v[1].
* While rhat < B and v[2]*qhat > rhat*B+u[j+2],
* decrement qhat and increase rhat correspondingly.
* Note that if rhat >= B, v[2]*qhat < rhat*B.
*/
uj0 = u[j + 0]; /* for D3 only -- note that u[j+...] change */
uj1 = u[j + 1]; /* for D3 only */
uj2 = u[j + 2]; /* for D3 only */
if (uj0 == v1) {
qhat = B;
rhat = uj1;
goto qhat_too_big;
} else {
u_long nn = COMBINE(uj0, uj1);
qhat = nn / v1;
rhat = nn % v1;
}
while (v2 * qhat > COMBINE(rhat, uj2)) {
qhat_too_big:
qhat--;
if ((rhat += v1) >= B)
break;
}
/*
* D4: Multiply and subtract.
* The variable `t' holds any borrows across the loop.
* We split this up so that we do not require v[0] = 0,
* and to eliminate a final special case.
*/
for (t = 0, i = n; i > 0; i--) {
t = u[i + j] - v[i] * qhat - t;
u[i + j] = LHALF(t);
t = (B - HHALF(t)) & (B - 1);
}
t = u[j] - t;
u[j] = LHALF(t);
/*
* D5: test remainder.
* There is a borrow if and only if HHALF(t) is nonzero;
* in that (rare) case, qhat was too large (by exactly 1).
* Fix it by adding v[1..n] to u[j..j+n].
*/
if (HHALF(t)) {
qhat--;
for (t = 0, i = n; i > 0; i--) { /* D6: add back. */
t += u[i + j] + v[i];
u[i + j] = LHALF(t);
t = HHALF(t);
}
u[j] = LHALF(u[j] + t);
}
q[j] = qhat;
} while (++j <= m); /* D7: loop on j. */
/*
* If caller wants the remainder, we have to calculate it as
* u[m..m+n] >> d (this is at most n digits and thus fits in
* u[m+1..m+n], but we may need more source digits).
*/
if (arq) {
if (d) {
for (i = m + n; i > m; --i)
u[i] = (u[i] >> d) |
LHALF(u[i - 1] << (HALF_BITS - d));
u[i] = 0;
}
tmp.ul[H] = COMBINE(uspace[1], uspace[2]);
tmp.ul[L] = COMBINE(uspace[3], uspace[4]);
*arq = tmp.q;
}
tmp.ul[H] = COMBINE(qspace[1], qspace[2]);
tmp.ul[L] = COMBINE(qspace[3], qspace[4]);
return (tmp.q);
}
/*
* Return 0, 1, or 2 as a <, =, > b respectively.
* Neither a nor b are considered signed.
*/
int
__ucmpdi2(a, b)
u_quad_t a, b;
{
union uu aa, bb;
aa.uq = a;
bb.uq = b;
return (aa.ul[H] < bb.ul[H] ? 0 : aa.ul[H] > bb.ul[H] ? 2 :
aa.ul[L] < bb.ul[L] ? 0 : aa.ul[L] > bb.ul[L] ? 2 : 1);
}
/*
* Divide two unsigned quads.
*/
u_quad_t
__udivdi3(a, b)
u_quad_t a, b;
{
return (__qdivrem(a, b, (u_quad_t *)0));
}
/*
* Return remainder after dividing two unsigned quads.
*/
u_quad_t
__umoddi3(a, b)
u_quad_t a, b;
{
u_quad_t r;
(void)__qdivrem(a, b, &r);
return (r);
}
/*
* Divide two signed quads.
* This function is new in GCC 7.
*/
quad_t
__divmoddi4(a, b, rem)
quad_t a, b, *rem;
{
u_quad_t ua, ub, uq, ur;
int negq, negr;
if (a < 0)
ua = -(u_quad_t)a, negq = 1, negr = 1;
else
ua = a, negq = 0, negr = 0;
if (b < 0)
ub = -(u_quad_t)b, negq ^= 1;
else
ub = b;
uq = __qdivrem(ua, ub, &ur);
if (rem)
*rem = (negr ? -ur : ur);
return (negq ? -uq : uq);
}
u_quad_t
__udivmoddi4(u_quad_t a, u_quad_t b, u_quad_t *rem)
{
return __qdivrem(a, b, rem);
}
#else
static int __attribute__((unused)) dummy;
#endif /*deined (_X86_) && !defined (__x86_64__)*/

197
libs/winpthreads/src/misc.c Normal file
View File

@@ -0,0 +1,197 @@
/*
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.
*/
#include <windows.h>
#include "pthread.h"
#include "misc.h"
void (WINAPI *_pthread_get_system_time_best_as_file_time) (LPFILETIME) = NULL;
static ULONGLONG (WINAPI *_pthread_get_tick_count_64) (VOID);
#if defined(__GNUC__) || defined(__clang__)
__attribute__((constructor))
#endif
static void winpthreads_init(void)
{
HMODULE mod = GetModuleHandleA("kernel32.dll");
if (mod)
{
_pthread_get_tick_count_64 =
(ULONGLONG (WINAPI *)(VOID))(void*) GetProcAddress(mod, "GetTickCount64");
/* <1us precision on Windows 10 */
_pthread_get_system_time_best_as_file_time =
(void (WINAPI *)(LPFILETIME))(void*) GetProcAddress(mod, "GetSystemTimePreciseAsFileTime");
}
if (!_pthread_get_system_time_best_as_file_time)
/* >15ms precision on Windows 10 */
_pthread_get_system_time_best_as_file_time = GetSystemTimeAsFileTime;
}
#if defined(_MSC_VER) && !defined(__clang__)
/* Force a reference to __xc_t to prevent whole program optimization
* from discarding the variable. */
/* On x86, symbols are prefixed with an underscore. */
# if defined(_M_IX86)
# pragma comment(linker, "/include:___xc_t")
# else
# pragma comment(linker, "/include:__xc_t")
# endif
#pragma section(".CRT$XCT", long, read)
__declspec(allocate(".CRT$XCT"))
extern const _PVFV __xc_t;
const _PVFV __xc_t = winpthreads_init;
#endif
unsigned long long _pthread_time_in_ms(void)
{
FILETIME ft;
GetSystemTimeAsFileTime(&ft);
return (((unsigned long long)ft.dwHighDateTime << 32) + ft.dwLowDateTime
- 0x19DB1DED53E8000ULL) / 10000ULL;
}
unsigned long long _pthread_time_in_ms_from_timespec(const struct timespec *ts)
{
unsigned long long t = (unsigned long long) ts->tv_sec * 1000LL;
/* The +999999 is here to ensure that the division always rounds up */
t += (unsigned long long) (ts->tv_nsec + 999999) / 1000000;
return t;
}
unsigned long long _pthread_rel_time_in_ms(const struct timespec *ts)
{
unsigned long long t1 = _pthread_time_in_ms_from_timespec(ts);
unsigned long long t2 = _pthread_time_in_ms();
/* Prevent underflow */
if (t1 < t2) return 0;
return t1 - t2;
}
static unsigned long long
_pthread_get_tick_count (long long *frequency)
{
if (_pthread_get_tick_count_64 != NULL)
return _pthread_get_tick_count_64 ();
LARGE_INTEGER freq, timestamp;
if (*frequency == 0)
{
if (QueryPerformanceFrequency (&freq))
*frequency = freq.QuadPart;
else
*frequency = -1;
}
if (*frequency > 0 && QueryPerformanceCounter (&timestamp))
return timestamp.QuadPart / (*frequency / 1000);
/* Fallback */
return GetTickCount ();
}
/* A wrapper around WaitForSingleObject() that ensures that
* the wait function does not time out before the time
* actually runs out. This is needed because WaitForSingleObject()
* might have poor accuracy, returning earlier than expected.
* On the other hand, returning a bit *later* than expected
* is acceptable in a preemptive multitasking environment.
*/
unsigned long
_pthread_wait_for_single_object (void *handle, unsigned long timeout)
{
DWORD result;
unsigned long long start_time, end_time;
unsigned long wait_time;
long long frequency = 0;
if (timeout == INFINITE || timeout == 0)
return WaitForSingleObject ((HANDLE) handle, (DWORD) timeout);
start_time = _pthread_get_tick_count (&frequency);
end_time = start_time + timeout;
wait_time = timeout;
do
{
unsigned long long current_time;
result = WaitForSingleObject ((HANDLE) handle, (DWORD) wait_time);
if (result != WAIT_TIMEOUT)
break;
current_time = _pthread_get_tick_count (&frequency);
if (current_time >= end_time)
break;
wait_time = (DWORD) (end_time - current_time);
} while (TRUE);
return result;
}
/* A wrapper around WaitForMultipleObjects() that ensures that
* the wait function does not time out before the time
* actually runs out. This is needed because WaitForMultipleObjects()
* might have poor accuracy, returning earlier than expected.
* On the other hand, returning a bit *later* than expected
* is acceptable in a preemptive multitasking environment.
*/
unsigned long
_pthread_wait_for_multiple_objects (unsigned long count, void **handles, unsigned int all, unsigned long timeout)
{
DWORD result;
unsigned long long start_time, end_time;
unsigned long wait_time;
long long frequency = 0;
if (timeout == INFINITE || timeout == 0)
return WaitForMultipleObjects ((DWORD) count, (HANDLE *) handles, all, (DWORD) timeout);
start_time = _pthread_get_tick_count (&frequency);
end_time = start_time + timeout;
wait_time = timeout;
do
{
unsigned long long current_time;
result = WaitForMultipleObjects ((DWORD) count, (HANDLE *) handles, all, (DWORD) wait_time);
if (result != WAIT_TIMEOUT)
break;
current_time = _pthread_get_tick_count (&frequency);
if (current_time >= end_time)
break;
wait_time = (DWORD) (end_time - current_time);
} while (TRUE);
return result;
}

126
libs/winpthreads/src/misc.h Normal file
View File

@@ -0,0 +1,126 @@
/*
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.
*/
#ifndef WIN_PTHREADS_MISC_H
#define WIN_PTHREADS_MISC_H
#include "pthread_compat.h"
#ifndef assert
#ifndef ASSERT_TRACE
# define ASSERT_TRACE 0
#else
# undef ASSERT_TRACE
# define ASSERT_TRACE 0
#endif
# define assert(e) \
((e) ? ((ASSERT_TRACE) ? fprintf(stderr, \
"Assertion succeeded: (%s), file %s, line %d\n", \
#e, __FILE__, (int) __LINE__), \
fflush(stderr) : \
0) : \
(fprintf(stderr, "Assertion failed: (%s), file %s, line %d\n", \
#e, __FILE__, (int) __LINE__), exit(1), 0))
# define fixme(e) \
((e) ? ((ASSERT_TRACE) ? fprintf(stderr, \
"Assertion succeeded: (%s), file %s, line %d\n", \
#e, __FILE__, (int) __LINE__), \
fflush(stderr) : \
0) : \
(fprintf(stderr, "FIXME: (%s), file %s, line %d\n", \
#e, __FILE__, (int) __LINE__), 0, 0))
#endif
#define PTR2INT(x) ((int)(uintptr_t)(x))
#if SIZE_MAX>UINT_MAX
typedef long long LONGBAG;
#else
typedef long LONGBAG;
#endif
#if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
#undef GetHandleInformation
#define GetHandleInformation(h,f) (1)
#endif
#define CHECK_HANDLE(h) \
do { \
DWORD dwFlags; \
if (!(h) || ((h) == INVALID_HANDLE_VALUE) || !GetHandleInformation((h), &dwFlags)) \
return EINVAL; \
} while (0)
#define CHECK_PTR(p) do { if (!(p)) return EINVAL; } while (0)
#define UPD_RESULT(x,r) do { int _r = (x); (r) = (r) ? (r) : _r; } while (0)
#define CHECK_THREAD(t) \
do { \
CHECK_PTR(t); \
CHECK_HANDLE((t)->h); \
} while (0)
#define CHECK_OBJECT(o, e) \
do { \
DWORD dwFlags; \
if (!(o)) return e; \
if (!((o)->h) || (((o)->h) == INVALID_HANDLE_VALUE) || !GetHandleInformation(((o)->h), &dwFlags)) \
return e; \
} while (0)
#define VALID(x) if (!(p)) return EINVAL;
/* ms can be 64 bit, solve wrap-around issues: */
static WINPTHREADS_INLINE unsigned long dwMilliSecs(unsigned long long ms)
{
if (ms >= 0xffffffffULL) return 0xfffffffful;
return (unsigned long) ms;
}
unsigned long long _pthread_time_in_ms(void);
unsigned long long _pthread_time_in_ms_from_timespec(const struct timespec *ts);
unsigned long long _pthread_rel_time_in_ms(const struct timespec *ts);
unsigned long _pthread_wait_for_single_object (void *handle, unsigned long timeout);
unsigned long _pthread_wait_for_multiple_objects (unsigned long count, void **handles, unsigned int all, unsigned long timeout);
extern void (WINAPI *_pthread_get_system_time_best_as_file_time) (LPFILETIME);
#if defined(__GNUC__) || defined(__clang__)
#define likely(cond) __builtin_expect((cond) != 0, 1)
#define unlikely(cond) __builtin_expect((cond) != 0, 0)
#else
#define likely(cond) (cond)
#define unlikely(cond) (cond)
#endif
#if defined(__GNUC__) || defined(__clang__)
#define UNREACHABLE() __builtin_unreachable()
#elif defined(_MSC_VER)
#define UNREACHABLE() __assume(0)
#endif
#endif

View File

@@ -0,0 +1,381 @@
/*
Copyright (c) 2011, 2014 mingw-w64 project
Copyright (c) 2015 Intel Corporation
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.
*/
#include <windows.h>
#include <stdio.h>
#include <malloc.h>
#include <stdbool.h>
#include "pthread.h"
#include "misc.h"
typedef enum {
Unlocked, /* Not locked. */
Locked, /* Locked but without waiters. */
Waiting, /* Locked, may have waiters. */
} mutex_state_t;
typedef enum {
Normal,
Errorcheck,
Recursive,
} mutex_type_t;
/* The heap-allocated part of a mutex. */
typedef struct {
mutex_state_t state;
mutex_type_t type;
HANDLE event; /* Auto-reset event, or NULL if not yet allocated. */
unsigned rec_lock; /* For recursive mutexes, the number of times the
mutex has been locked in excess by the same thread. */
volatile DWORD owner; /* For recursive and error-checking mutexes, the
ID of the owning thread if the mutex is locked. */
} mutex_impl_t;
/* Whether a mutex is still a static initializer (not a pointer to
a mutex_impl_t). */
static bool
is_static_initializer(pthread_mutex_t m)
{
/* Treat 0 as a static initializer as well (for normal mutexes),
to tolerate sloppy code in libgomp. (We should rather fix that code!) */
intptr_t v = (intptr_t)m;
return v >= -3 && v <= 0;
/* Should be simple:
return (uintptr_t)m >= (uintptr_t)-3; */
}
/* Create and return the implementation part of a mutex from a static
initialiser. Return NULL on out-of-memory error. */
static WINPTHREADS_ATTRIBUTE((noinline)) mutex_impl_t *
mutex_impl_init(pthread_mutex_t *m, mutex_impl_t *mi)
{
mutex_impl_t *new_mi = malloc(sizeof(mutex_impl_t));
if (new_mi == NULL)
return NULL;
new_mi->state = Unlocked;
new_mi->type = (mi == (void *)PTHREAD_RECURSIVE_MUTEX_INITIALIZER ? Recursive
: mi == (void *)PTHREAD_ERRORCHECK_MUTEX_INITIALIZER ? Errorcheck
: Normal);
new_mi->event = NULL;
new_mi->rec_lock = 0;
new_mi->owner = (DWORD)-1;
if (InterlockedCompareExchangePointer((PVOID volatile *)m, new_mi, mi) == mi) {
return new_mi;
} else {
/* Someone created the struct before us. */
free(new_mi);
return (mutex_impl_t *)*m;
}
}
/* Return the implementation part of a mutex, creating it if necessary.
Return NULL on out-of-memory error. */
static inline mutex_impl_t *
mutex_impl(pthread_mutex_t *m)
{
mutex_impl_t *mi = (mutex_impl_t *)*m;
if (is_static_initializer((pthread_mutex_t)mi)) {
return mutex_impl_init(m, mi);
} else {
/* mi cannot be null here; avoid a test in the fast path. */
if (mi == NULL)
UNREACHABLE();
return mi;
}
}
/* Lock a mutex. Give up after 'timeout' ms (with ETIMEDOUT),
or never if timeout=INFINITE. */
static inline int
pthread_mutex_lock_intern (pthread_mutex_t *m, DWORD timeout)
{
mutex_impl_t *mi = mutex_impl(m);
if (mi == NULL)
return ENOMEM;
mutex_state_t old_state = InterlockedExchange((long *)&mi->state, Locked);
if (unlikely(old_state != Unlocked)) {
/* The mutex is already locked. */
if (mi->type != Normal) {
/* Recursive or Errorcheck */
if (mi->owner == GetCurrentThreadId()) {
/* FIXME: A recursive mutex should not need two atomic ops when locking
recursively. We could rewrite by doing compare-and-swap instead of
test-and-set the first time, but it would lead to more code
duplication and add a conditional branch to the critical path. */
InterlockedCompareExchange((long *)&mi->state, old_state, Locked);
if (mi->type == Recursive) {
mi->rec_lock++;
return 0;
} else {
/* type == Errorcheck */
return EDEADLK;
}
}
}
/* Make sure there is an event object on which to wait. */
if (mi->event == NULL) {
/* Make an auto-reset event object. */
HANDLE ev = CreateEvent(NULL, false, false, NULL);
if (ev == NULL) {
switch (GetLastError()) {
case ERROR_ACCESS_DENIED:
return EPERM;
default:
return ENOMEM; /* Probably accurate enough. */
}
}
if (InterlockedCompareExchangePointer(&mi->event, ev, NULL) != NULL) {
/* Someone created the event before us. */
CloseHandle(ev);
}
}
/* At this point, mi->event is non-NULL. */
while (InterlockedExchange((long *)&mi->state, Waiting) != Unlocked) {
/* For timed locking attempts, it is possible (although unlikely)
that we are woken up but someone else grabs the lock before us,
and we have to go back to sleep again. In that case, the total
wait may be longer than expected. */
unsigned r = _pthread_wait_for_single_object(mi->event, timeout);
switch (r) {
case WAIT_TIMEOUT:
return ETIMEDOUT;
case WAIT_OBJECT_0:
break;
default:
return EINVAL;
}
}
}
if (mi->type != Normal)
mi->owner = GetCurrentThreadId();
return 0;
}
int
pthread_mutex_lock (pthread_mutex_t *m)
{
return pthread_mutex_lock_intern (m, INFINITE);
}
int pthread_mutex_timedlock(pthread_mutex_t *m, const struct timespec *ts)
{
unsigned long long patience;
if (ts != NULL) {
unsigned long long end = _pthread_time_in_ms_from_timespec(ts);
unsigned long long now = _pthread_time_in_ms();
patience = end > now ? end - now : 0;
if (patience > 0xffffffff)
patience = INFINITE;
} else {
patience = INFINITE;
}
return pthread_mutex_lock_intern(m, patience);
}
int pthread_mutex_unlock(pthread_mutex_t *m)
{
/* Here m might an initialiser of an error-checking or recursive mutex, in
which case the behaviour is well-defined, so we can't skip this check. */
mutex_impl_t *mi = mutex_impl(m);
if (mi == NULL)
return ENOMEM;
if (unlikely(mi->type != Normal)) {
if (mi->state == Unlocked)
return EINVAL;
if (mi->owner != GetCurrentThreadId())
return EPERM;
if (mi->rec_lock > 0) {
mi->rec_lock--;
return 0;
}
mi->owner = (DWORD)-1;
}
if (unlikely(InterlockedExchange((long *)&mi->state, Unlocked) == Waiting)) {
if (!SetEvent(mi->event))
return EPERM;
}
return 0;
}
int pthread_mutex_trylock(pthread_mutex_t *m)
{
mutex_impl_t *mi = mutex_impl(m);
if (mi == NULL)
return ENOMEM;
if (InterlockedCompareExchange((long *)&mi->state, Locked, Unlocked) == Unlocked) {
if (mi->type != Normal)
mi->owner = GetCurrentThreadId();
return 0;
} else {
if (mi->type == Recursive && mi->owner == GetCurrentThreadId()) {
mi->rec_lock++;
return 0;
}
return EBUSY;
}
}
int
pthread_mutex_init (pthread_mutex_t *m, const pthread_mutexattr_t *a)
{
pthread_mutex_t init = PTHREAD_MUTEX_INITIALIZER;
if (a != NULL) {
int pshared;
if (pthread_mutexattr_getpshared(a, &pshared) == 0
&& pshared == PTHREAD_PROCESS_SHARED)
return ENOSYS;
int type;
if (pthread_mutexattr_gettype(a, &type) == 0) {
switch (type) {
case PTHREAD_MUTEX_ERRORCHECK:
init = PTHREAD_ERRORCHECK_MUTEX_INITIALIZER;
break;
case PTHREAD_MUTEX_RECURSIVE:
init = PTHREAD_RECURSIVE_MUTEX_INITIALIZER;
break;
default:
init = PTHREAD_MUTEX_INITIALIZER;
break;
}
}
}
*m = init;
return 0;
}
int pthread_mutex_destroy (pthread_mutex_t *m)
{
mutex_impl_t *mi = (mutex_impl_t *)*m;
if (!is_static_initializer((pthread_mutex_t)mi)) {
if (mi->event != NULL)
CloseHandle(mi->event);
free(mi);
/* Sabotage attempts to re-use the mutex before initialising it again. */
*m = (pthread_mutex_t)NULL;
}
return 0;
}
int pthread_mutexattr_init(pthread_mutexattr_t *a)
{
*a = PTHREAD_MUTEX_NORMAL | (PTHREAD_PROCESS_PRIVATE << 3);
return 0;
}
int pthread_mutexattr_destroy(pthread_mutexattr_t *a)
{
if (!a)
return EINVAL;
return 0;
}
int pthread_mutexattr_gettype(const pthread_mutexattr_t *a, int *type)
{
if (!a || !type)
return EINVAL;
*type = *a & 3;
return 0;
}
int pthread_mutexattr_settype(pthread_mutexattr_t *a, int type)
{
if (!a || (type != PTHREAD_MUTEX_NORMAL && type != PTHREAD_MUTEX_RECURSIVE && type != PTHREAD_MUTEX_ERRORCHECK))
return EINVAL;
*a &= ~3;
*a |= type;
return 0;
}
int pthread_mutexattr_getpshared(const pthread_mutexattr_t *a, int *type)
{
if (!a || !type)
return EINVAL;
*type = (*a & 4 ? PTHREAD_PROCESS_SHARED : PTHREAD_PROCESS_PRIVATE);
return 0;
}
int pthread_mutexattr_setpshared(pthread_mutexattr_t * a, int type)
{
int r = 0;
if (!a || (type != PTHREAD_PROCESS_SHARED
&& type != PTHREAD_PROCESS_PRIVATE))
return EINVAL;
if (type == PTHREAD_PROCESS_SHARED)
{
type = PTHREAD_PROCESS_PRIVATE;
r = ENOSYS;
}
type = (type == PTHREAD_PROCESS_SHARED ? 4 : 0);
*a &= ~4;
*a |= type;
return r;
}
int pthread_mutexattr_getprotocol(const pthread_mutexattr_t *a, int *type)
{
*type = *a & (8 + 16);
return 0;
}
int pthread_mutexattr_setprotocol(pthread_mutexattr_t *a, int type)
{
if ((type & (8 + 16)) != 8 + 16) return EINVAL;
*a &= ~(8 + 16);
*a |= type;
return 0;
}
int pthread_mutexattr_getprioceiling(const pthread_mutexattr_t *a, int * prio)
{
*prio = *a / PTHREAD_PRIO_MULT;
return 0;
}
int pthread_mutexattr_setprioceiling(pthread_mutexattr_t *a, int prio)
{
*a &= (PTHREAD_PRIO_MULT - 1);
*a += prio * PTHREAD_PRIO_MULT;
return 0;
}

View File

@@ -0,0 +1,71 @@
/**
* This file has no copyright assigned and is placed in the Public Domain.
* This file is part of the w64 mingw-runtime package.
* No warranty is given; refer to the file DISCLAIMER.PD within this package.
*/
#include <errno.h>
#include <time.h>
#include <windows.h>
#include "pthread.h"
#include "pthread_time.h"
#include "winpthread_internal.h"
#define POW10_3 1000
#define POW10_4 10000
#define POW10_6 1000000
#define POW10_9 1000000000
#define MAX_SLEEP_IN_MS 4294967294UL
/**
* Sleep for the specified time.
* @param request The desired amount of time to sleep.
* @param remain The remain amount of time to sleep.
* @return If the function succeeds, the return value is 0.
* If the function fails, the return value is -1,
* with errno set to indicate the error.
*/
int nanosleep(const struct timespec *request, struct timespec *remain)
{
unsigned long ms, rc = 0;
unsigned __int64 u64, want, real;
union {
unsigned __int64 ns100;
FILETIME ft;
} _start, _end;
if (request->tv_sec < 0 || request->tv_nsec < 0 || request->tv_nsec >= POW10_9) {
errno = EINVAL;
return -1;
}
if (remain != NULL) GetSystemTimeAsFileTime(&_start.ft);
want = u64 = request->tv_sec * POW10_3 + request->tv_nsec / POW10_6;
while (u64 > 0 && rc == 0) {
if (u64 >= MAX_SLEEP_IN_MS) ms = MAX_SLEEP_IN_MS;
else ms = (unsigned long) u64;
u64 -= ms;
rc = pthread_delay_np_ms(ms);
}
if (rc != 0) { /* WAIT_IO_COMPLETION (192) */
if (remain != NULL) {
GetSystemTimeAsFileTime(&_end.ft);
real = (_end.ns100 - _start.ns100) / POW10_4;
if (real >= want) u64 = 0;
else u64 = want - real;
remain->tv_sec = u64 / POW10_3;
remain->tv_nsec = (long) (u64 % POW10_3) * POW10_6;
}
errno = EINTR;
return -1;
}
return 0;
}

View File

@@ -0,0 +1,34 @@
/*
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.
*/
#include <windows.h>
#include <winternl.h>
#include <stdio.h>
#include "pthread.h"
#include "semaphore.h"
#include "rwlock.h"
#include "cond.h"
#include "barrier.h"
#include "sem.h"
#include "ref.h"
#include "misc.h"

View File

@@ -0,0 +1,29 @@
/*
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.
*/
#ifndef WIN_PTHREADS_REF_H
#define WIN_PTHREADS_REF_H
#include "pthread.h"
#include "semaphore.h"
#endif

View File

@@ -0,0 +1,537 @@
/*
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.
*/
#include <windows.h>
#include <stdio.h>
#include <malloc.h>
#include "pthread.h"
#include "thread.h"
#include "ref.h"
#include "rwlock.h"
#include "misc.h"
static pthread_spinlock_t rwl_global = PTHREAD_SPINLOCK_INITIALIZER;
static WINPTHREADS_ATTRIBUTE((noinline)) int rwlock_static_init(pthread_rwlock_t *rw);
static WINPTHREADS_ATTRIBUTE((noinline)) int rwl_unref(volatile pthread_rwlock_t *rwl, int res)
{
pthread_spin_lock(&rwl_global);
#ifdef WINPTHREAD_DBG
assert((((rwlock_t *)*rwl)->valid == LIFE_RWLOCK) && (((rwlock_t *)*rwl)->busy > 0));
#endif
((rwlock_t *)*rwl)->busy--;
pthread_spin_unlock(&rwl_global);
return res;
}
static WINPTHREADS_ATTRIBUTE((noinline)) int rwl_ref(pthread_rwlock_t *rwl, int f )
{
int r = 0;
if (STATIC_RWL_INITIALIZER(*rwl)) {
r = rwlock_static_init(rwl);
if (r != 0 && r != EBUSY)
return r;
}
pthread_spin_lock(&rwl_global);
if (!rwl || !*rwl || ((rwlock_t *)*rwl)->valid != LIFE_RWLOCK) r = EINVAL;
else {
((rwlock_t *)*rwl)->busy ++;
}
pthread_spin_unlock(&rwl_global);
return r;
}
static WINPTHREADS_ATTRIBUTE((noinline)) int rwl_ref_unlock(pthread_rwlock_t *rwl )
{
int r = 0;
pthread_spin_lock(&rwl_global);
if (!rwl || !*rwl || ((rwlock_t *)*rwl)->valid != LIFE_RWLOCK) r = EINVAL;
else if (STATIC_RWL_INITIALIZER(*rwl)) r= EPERM;
else {
((rwlock_t *)*rwl)->busy ++;
}
pthread_spin_unlock(&rwl_global);
return r;
}
static WINPTHREADS_ATTRIBUTE((noinline)) int rwl_ref_destroy(pthread_rwlock_t *rwl, pthread_rwlock_t *rDestroy )
{
int r = 0;
*rDestroy = (pthread_rwlock_t)NULL;
pthread_spin_lock(&rwl_global);
if (!rwl || !*rwl) r = EINVAL;
else {
rwlock_t *r_ = (rwlock_t *)*rwl;
if (STATIC_RWL_INITIALIZER(*rwl)) *rwl = (pthread_rwlock_t)NULL;
else if (r_->valid != LIFE_RWLOCK) r = EINVAL;
else if (r_->busy) r = EBUSY;
else {
*rDestroy = *rwl;
*rwl = (pthread_rwlock_t)NULL;
}
}
pthread_spin_unlock(&rwl_global);
return r;
}
static int rwlock_gain_both_locks(rwlock_t *rwlock)
{
int ret;
ret = pthread_mutex_lock(&rwlock->mex);
if (ret != 0)
return ret;
ret = pthread_mutex_lock(&rwlock->mcomplete);
if (ret != 0)
pthread_mutex_unlock(&rwlock->mex);
return ret;
}
static int rwlock_free_both_locks(rwlock_t *rwlock, int last_fail)
{
int ret, ret2;
ret = pthread_mutex_unlock(&rwlock->mcomplete);
ret2 = pthread_mutex_unlock(&rwlock->mex);
if (last_fail && ret2 != 0)
ret = ret2;
else if (!last_fail && !ret)
ret = ret2;
return ret;
}
#ifdef WINPTHREAD_DBG
static int print_state = 0;
void rwl_print_set(int state)
{
print_state = state;
}
void rwl_print(volatile pthread_rwlock_t *rwl, char *txt)
{
if (!print_state) return;
rwlock_t *r = (rwlock_t *)*rwl;
if (r == NULL) {
printf("RWL%p %lu %s\n",(void *)*rwl,GetCurrentThreadId(),txt);
} else {
printf("RWL%p %lu V=%0X B=%d r=%ld w=%ld L=%p %s\n",
(void *)*rwl,
GetCurrentThreadId(),
(int)r->valid,
(int)r->busy,
0L,0L,NULL,txt);
}
}
#endif
static pthread_spinlock_t cond_locked = PTHREAD_SPINLOCK_INITIALIZER;
static WINPTHREADS_ATTRIBUTE((noinline)) int rwlock_static_init(pthread_rwlock_t *rw)
{
int r;
pthread_spin_lock(&cond_locked);
if (*rw != PTHREAD_RWLOCK_INITIALIZER)
{
pthread_spin_unlock(&cond_locked);
return EINVAL;
}
r = pthread_rwlock_init (rw, NULL);
pthread_spin_unlock(&cond_locked);
return r;
}
int pthread_rwlock_init (pthread_rwlock_t *rwlock_, const pthread_rwlockattr_t *attr)
{
rwlock_t *rwlock;
int r;
if(!rwlock_)
return EINVAL;
*rwlock_ = (pthread_rwlock_t)NULL;
if ((rwlock = calloc(1, sizeof(*rwlock))) == NULL)
return ENOMEM;
rwlock->valid = DEAD_RWLOCK;
rwlock->nex_count = rwlock->nsh_count = rwlock->ncomplete = 0;
if ((r = pthread_mutex_init (&rwlock->mex, NULL)) != 0)
{
free(rwlock);
return r;
}
if ((r = pthread_mutex_init (&rwlock->mcomplete, NULL)) != 0)
{
pthread_mutex_destroy(&rwlock->mex);
free(rwlock);
return r;
}
if ((r = pthread_cond_init (&rwlock->ccomplete, NULL)) != 0)
{
pthread_mutex_destroy(&rwlock->mex);
pthread_mutex_destroy (&rwlock->mcomplete);
free(rwlock);
return r;
}
rwlock->valid = LIFE_RWLOCK;
*rwlock_ = (pthread_rwlock_t)rwlock;
return r;
}
int pthread_rwlock_destroy (pthread_rwlock_t *rwlock_)
{
rwlock_t *rwlock;
pthread_rwlock_t rDestroy;
int r, r2;
pthread_spin_lock(&cond_locked);
r = rwl_ref_destroy(rwlock_,&rDestroy);
pthread_spin_unlock(&cond_locked);
if(r) return r;
if(!rDestroy) return 0; /* destroyed a (still) static initialized rwl */
rwlock = (rwlock_t *)rDestroy;
r = rwlock_gain_both_locks (rwlock);
if (r != 0)
{
*rwlock_ = rDestroy;
return r;
}
if (rwlock->nsh_count > rwlock->ncomplete || rwlock->nex_count > 0)
{
*rwlock_ = rDestroy;
r = rwlock_free_both_locks(rwlock, 1);
if (!r)
r = EBUSY;
return r;
}
rwlock->valid = DEAD_RWLOCK;
r = rwlock_free_both_locks(rwlock, 0);
if (r != 0) { *rwlock_ = rDestroy; return r; }
r = pthread_cond_destroy(&rwlock->ccomplete);
r2 = pthread_mutex_destroy(&rwlock->mex);
if (!r) r = r2;
r2 = pthread_mutex_destroy(&rwlock->mcomplete);
if (!r) r = r2;
rwlock->valid = DEAD_RWLOCK;
free((void *)rDestroy);
return 0;
}
int pthread_rwlock_rdlock (pthread_rwlock_t *rwlock_)
{
rwlock_t *rwlock;
int ret;
/* pthread_testcancel(); */
ret = rwl_ref(rwlock_,0);
if(ret != 0) return ret;
rwlock = (rwlock_t *)*rwlock_;
ret = pthread_mutex_lock(&rwlock->mex);
if (ret != 0) return rwl_unref(rwlock_, ret);
InterlockedIncrement((long*)&rwlock->nsh_count);
if (rwlock->nsh_count == INT_MAX)
{
ret = pthread_mutex_lock(&rwlock->mcomplete);
if (ret != 0)
{
pthread_mutex_unlock(&rwlock->mex);
return rwl_unref(rwlock_,ret);
}
rwlock->nsh_count -= rwlock->ncomplete;
rwlock->ncomplete = 0;
ret = rwlock_free_both_locks(rwlock, 0);
return rwl_unref(rwlock_, ret);
}
ret = pthread_mutex_unlock(&rwlock->mex);
return rwl_unref(rwlock_, ret);
}
int pthread_rwlock_timedrdlock (pthread_rwlock_t *rwlock_, const struct timespec *ts)
{
rwlock_t *rwlock;
int ret;
/* pthread_testcancel(); */
ret = rwl_ref(rwlock_,0);
if(ret != 0) return ret;
rwlock = (rwlock_t *)*rwlock_;
if ((ret = pthread_mutex_timedlock (&rwlock->mex, ts)) != 0)
return rwl_unref(rwlock_, ret);
InterlockedIncrement(&rwlock->nsh_count);
if (rwlock->nsh_count == INT_MAX)
{
ret = pthread_mutex_timedlock(&rwlock->mcomplete, ts);
if (ret != 0)
{
if (ret == ETIMEDOUT)
InterlockedIncrement(&rwlock->ncomplete);
pthread_mutex_unlock(&rwlock->mex);
return rwl_unref(rwlock_, ret);
}
rwlock->nsh_count -= rwlock->ncomplete;
rwlock->ncomplete = 0;
ret = rwlock_free_both_locks(rwlock, 0);
return rwl_unref(rwlock_, ret);
}
ret = pthread_mutex_unlock(&rwlock->mex);
return rwl_unref(rwlock_, ret);
}
int pthread_rwlock_tryrdlock (pthread_rwlock_t *rwlock_)
{
rwlock_t *rwlock;
int ret;
ret = rwl_ref(rwlock_,RWL_TRY);
if(ret != 0) return ret;
rwlock = (rwlock_t *)*rwlock_;
ret = pthread_mutex_trylock(&rwlock->mex);
if (ret != 0)
return rwl_unref(rwlock_, ret);
InterlockedIncrement(&rwlock->nsh_count);
if (rwlock->nsh_count == INT_MAX)
{
ret = pthread_mutex_lock(&rwlock->mcomplete);
if (ret != 0)
{
pthread_mutex_unlock(&rwlock->mex);
return rwl_unref(rwlock_, ret);
}
rwlock->nsh_count -= rwlock->ncomplete;
rwlock->ncomplete = 0;
ret = rwlock_free_both_locks(rwlock, 0);
return rwl_unref(rwlock_, ret);
}
ret = pthread_mutex_unlock(&rwlock->mex);
return rwl_unref(rwlock_,ret);
}
int pthread_rwlock_trywrlock (pthread_rwlock_t *rwlock_)
{
rwlock_t *rwlock;
int ret;
ret = rwl_ref(rwlock_,RWL_TRY);
if(ret != 0) return ret;
rwlock = (rwlock_t *)*rwlock_;
ret = pthread_mutex_trylock (&rwlock->mex);
if (ret != 0)
return rwl_unref(rwlock_, ret);
ret = pthread_mutex_trylock(&rwlock->mcomplete);
if (ret != 0)
{
int r1 = pthread_mutex_unlock(&rwlock->mex);
if (r1 != 0)
ret = r1;
return rwl_unref(rwlock_, ret);
}
if (rwlock->nex_count != 0)
return rwl_unref(rwlock_, EBUSY);
if (rwlock->ncomplete > 0)
{
rwlock->nsh_count -= rwlock->ncomplete;
rwlock->ncomplete = 0;
}
if (rwlock->nsh_count > 0)
{
ret = rwlock_free_both_locks(rwlock, 0);
if (!ret)
ret = EBUSY;
return rwl_unref(rwlock_, ret);
}
rwlock->nex_count = 1;
return rwl_unref(rwlock_, 0);
}
int pthread_rwlock_unlock (pthread_rwlock_t *rwlock_)
{
rwlock_t *rwlock;
int ret;
ret = rwl_ref_unlock(rwlock_);
if(ret != 0) return ret;
rwlock = (rwlock_t *)*rwlock_;
if (rwlock->nex_count == 0)
{
ret = pthread_mutex_lock(&rwlock->mcomplete);
if (!ret)
{
int r1;
InterlockedIncrement(&rwlock->ncomplete);
if (rwlock->ncomplete == 0)
ret = pthread_cond_signal(&rwlock->ccomplete);
r1 = pthread_mutex_unlock(&rwlock->mcomplete);
if (!ret)
ret = r1;
}
}
else
{
InterlockedDecrement(&rwlock->nex_count);
ret = rwlock_free_both_locks(rwlock, 0);
}
return rwl_unref(rwlock_, ret);
}
static void st_cancelwrite (void *arg)
{
rwlock_t *rwlock = (rwlock_t *)arg;
rwlock->nsh_count = - rwlock->ncomplete;
rwlock->ncomplete = 0;
rwlock_free_both_locks(rwlock, 0);
}
int pthread_rwlock_wrlock (pthread_rwlock_t *rwlock_)
{
rwlock_t *rwlock;
int ret;
/* pthread_testcancel(); */
ret = rwl_ref(rwlock_,0);
if(ret != 0) return ret;
rwlock = (rwlock_t *)*rwlock_;
ret = rwlock_gain_both_locks(rwlock);
if (ret != 0)
return rwl_unref(rwlock_,ret);
if (rwlock->nex_count == 0)
{
if (rwlock->ncomplete > 0)
{
rwlock->nsh_count -= rwlock->ncomplete;
rwlock->ncomplete = 0;
}
if (rwlock->nsh_count > 0)
{
rwlock->ncomplete = -rwlock->nsh_count;
pthread_cleanup_push(st_cancelwrite, (void *) rwlock);
do {
ret = pthread_cond_wait(&rwlock->ccomplete, &rwlock->mcomplete);
} while (!ret && rwlock->ncomplete < 0);
pthread_cleanup_pop(!ret ? 0 : 1);
if (!ret)
rwlock->nsh_count = 0;
}
}
if(!ret)
InterlockedIncrement((long*)&rwlock->nex_count);
return rwl_unref(rwlock_,ret);
}
int pthread_rwlock_timedwrlock (pthread_rwlock_t *rwlock_, const struct timespec *ts)
{
int ret;
rwlock_t *rwlock;
/* pthread_testcancel(); */
if (!rwlock_ || !ts)
return EINVAL;
if ((ret = rwl_ref(rwlock_,0)) != 0)
return ret;
rwlock = (rwlock_t *)*rwlock_;
ret = pthread_mutex_timedlock(&rwlock->mex, ts);
if (ret != 0)
return rwl_unref(rwlock_,ret);
ret = pthread_mutex_timedlock (&rwlock->mcomplete, ts);
if (ret != 0)
{
pthread_mutex_unlock(&rwlock->mex);
return rwl_unref(rwlock_,ret);
}
if (rwlock->nex_count == 0)
{
if (rwlock->ncomplete > 0)
{
rwlock->nsh_count -= rwlock->ncomplete;
rwlock->ncomplete = 0;
}
if (rwlock->nsh_count > 0)
{
rwlock->ncomplete = -rwlock->nsh_count;
pthread_cleanup_push(st_cancelwrite, (void *) rwlock);
do {
ret = pthread_cond_timedwait(&rwlock->ccomplete, &rwlock->mcomplete, ts);
} while (rwlock->ncomplete < 0 && !ret);
pthread_cleanup_pop(!ret ? 0 : 1);
if (!ret)
rwlock->nsh_count = 0;
}
}
if(!ret)
InterlockedIncrement((long*)&rwlock->nex_count);
return rwl_unref(rwlock_,ret);
}
int pthread_rwlockattr_destroy(pthread_rwlockattr_t *a)
{
if (!a)
return EINVAL;
return 0;
}
int pthread_rwlockattr_init(pthread_rwlockattr_t *a)
{
if (!a)
return EINVAL;
*a = PTHREAD_PROCESS_PRIVATE;
return 0;
}
int pthread_rwlockattr_getpshared(pthread_rwlockattr_t *a, int *s)
{
if (!a || !s)
return EINVAL;
*s = *a;
return 0;
}
int pthread_rwlockattr_setpshared(pthread_rwlockattr_t *a, int s)
{
if (!a || (s != PTHREAD_PROCESS_SHARED && s != PTHREAD_PROCESS_PRIVATE))
return EINVAL;
*a = s;
return 0;
}

View File

@@ -0,0 +1,49 @@
/*
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.
*/
#ifndef WIN_PTHREADS_RWLOCK_H
#define WIN_PTHREADS_RWLOCK_H
#define LIFE_RWLOCK 0xBAB1F0ED
#define DEAD_RWLOCK 0xDEADB0EF
#define STATIC_RWL_INITIALIZER(x) ((pthread_rwlock_t)(x) == ((pthread_rwlock_t)PTHREAD_RWLOCK_INITIALIZER))
typedef struct rwlock_t rwlock_t;
struct rwlock_t {
unsigned int valid;
int busy;
LONG nex_count; /* Exclusive access counter. */
LONG nsh_count; /* Shared access counter. */
LONG ncomplete; /* Shared completed counter. */
pthread_mutex_t mex; /* Exclusive access protection. */
pthread_mutex_t mcomplete; /* Shared completed protection. */
pthread_cond_t ccomplete; /* Shared access completed queue. */
};
#define RWL_SET 0x01
#define RWL_TRY 0x02
void rwl_print(volatile pthread_rwlock_t *rwl, char *txt);
void rwl_print_set(int state);
#endif

View File

@@ -0,0 +1,218 @@
/*
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.
*/
#include <windows.h>
#include <stdio.h>
#include "pthread.h"
#include "thread.h"
#include "misc.h"
int sched_get_priority_min(int pol)
{
if (pol < SCHED_MIN || pol > SCHED_MAX) {
errno = EINVAL;
return -1;
}
return THREAD_PRIORITY_IDLE;
}
int sched_get_priority_max(int pol)
{
if (pol < SCHED_MIN || pol > SCHED_MAX) {
errno = EINVAL;
return -1;
}
return THREAD_PRIORITY_TIME_CRITICAL;
}
int pthread_attr_setschedparam(pthread_attr_t *attr, const struct sched_param *p)
{
int r = 0;
if (attr == NULL || p == NULL) {
return EINVAL;
}
memcpy(&attr->param, p, sizeof (*p));
return r;
}
int pthread_attr_getschedparam(const pthread_attr_t *attr, struct sched_param *p)
{
int r = 0;
if (attr == NULL || p == NULL) {
return EINVAL;
}
memcpy(p, &attr->param, sizeof (*p));
return r;
}
int pthread_attr_setschedpolicy (pthread_attr_t *attr, int pol)
{
if (!attr || pol < SCHED_MIN || pol > SCHED_MAX)
return EINVAL;
if (pol != SCHED_OTHER)
return ENOTSUP;
return 0;
}
int pthread_attr_getschedpolicy (const pthread_attr_t *attr, int *pol)
{
if (!attr || !pol)
return EINVAL;
*pol = SCHED_OTHER;
return 0;
}
static int pthread_check(pthread_t t)
{
struct _pthread_v *pv;
if (!t)
return ESRCH;
pv = __pth_gpointer_locked (t);
if (pv->ended == 0)
return 0;
CHECK_OBJECT(pv, ESRCH);
return 0;
}
int pthread_getschedparam(pthread_t t, int *pol, struct sched_param *p)
{
int r;
//if (!t)
// t = pthread_self();
if ((r = pthread_check(t)) != 0)
{
return r;
}
if (!p || !pol)
{
return EINVAL;
}
*pol = __pth_gpointer_locked (t)->sched_pol;
p->sched_priority = __pth_gpointer_locked (t)->sched.sched_priority;
return 0;
}
int pthread_setschedparam(pthread_t t, int pol, const struct sched_param *p)
{
struct _pthread_v *pv;
int r, pr = 0;
//if (!t.p) t = pthread_self();
if ((r = pthread_check(t)) != 0)
return r;
if (pol < SCHED_MIN || pol > SCHED_MAX || p == NULL)
return EINVAL;
if (pol != SCHED_OTHER)
return ENOTSUP;
pr = p->sched_priority;
if (pr < sched_get_priority_min(pol) || pr > sched_get_priority_max(pol))
return EINVAL;
/* See msdn: there are actually 7 priorities:
THREAD_PRIORITY_IDLE - -15
THREAD_PRIORITY_LOWEST -2
THREAD_PRIORITY_BELOW_NORMAL -1
THREAD_PRIORITY_NORMAL 0
THREAD_PRIORITY_ABOVE_NORMAL 1
THREAD_PRIORITY_HIGHEST 2
THREAD_PRIORITY_TIME_CRITICAL 15
*/
if (pr <= THREAD_PRIORITY_IDLE) {
pr = THREAD_PRIORITY_IDLE;
} else if (pr <= THREAD_PRIORITY_LOWEST) {
pr = THREAD_PRIORITY_LOWEST;
} else if (pr >= THREAD_PRIORITY_TIME_CRITICAL) {
pr = THREAD_PRIORITY_TIME_CRITICAL;
} else if (pr >= THREAD_PRIORITY_HIGHEST) {
pr = THREAD_PRIORITY_HIGHEST;
}
pv = __pth_gpointer_locked (t);
if (SetThreadPriority(pv->h, pr)) {
pv->sched_pol = pol;
pv->sched.sched_priority = p->sched_priority;
} else
r = EINVAL;
return r;
}
int sched_getscheduler(pid_t pid)
{
if (pid != 0)
{
HANDLE h = NULL;
int selfPid = (int) GetCurrentProcessId ();
if (pid != (pid_t) selfPid && (h = OpenProcess (PROCESS_QUERY_INFORMATION, 0, (DWORD) pid)) == NULL)
{
errno = (GetLastError () == (0xFF & ERROR_ACCESS_DENIED)) ? EPERM : ESRCH;
return -1;
}
if (h)
CloseHandle (h);
}
return SCHED_OTHER;
}
int sched_setscheduler(pid_t pid, int pol, const struct sched_param *param)
{
if (!param)
{
errno = EINVAL;
return -1;
}
if (pid != 0)
{
HANDLE h = NULL;
int selfPid = (int) GetCurrentProcessId ();
if (pid != (pid_t) selfPid && (h = OpenProcess (PROCESS_SET_INFORMATION, 0, (DWORD) pid)) == NULL)
{
errno = (GetLastError () == (0xFF & ERROR_ACCESS_DENIED)) ? EPERM : ESRCH;
return -1;
}
if (h)
CloseHandle (h);
}
if (pol != SCHED_OTHER)
{
errno = ENOSYS;
return -1;
}
return SCHED_OTHER;
}
int sched_yield(void)
{
Sleep(0);
return 0;
}

354
libs/winpthreads/src/sem.c Normal file
View File

@@ -0,0 +1,354 @@
/*
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.
*/
#include <windows.h>
#include <stdio.h>
#include <malloc.h>
#include "pthread.h"
#include "thread.h"
#include "misc.h"
#include "semaphore.h"
#include "sem.h"
#include "ref.h"
int do_sema_b_wait_intern (HANDLE sema, int nointerrupt, DWORD timeout);
static int
sem_result (int res)
{
if (res != 0) {
errno = res;
return -1;
}
return 0;
}
int
sem_init (sem_t *sem, int pshared, unsigned int value)
{
_sem_t *sv;
if (!sem || value > (unsigned int)SEM_VALUE_MAX)
return sem_result (EINVAL);
if (pshared != PTHREAD_PROCESS_PRIVATE)
return sem_result (EPERM);
if ((sv = (sem_t) calloc (1,sizeof (*sv))) == NULL)
return sem_result (ENOMEM);
sv->value = value;
if (pthread_mutex_init (&sv->vlock, NULL) != 0)
{
free (sv);
return sem_result (ENOSPC);
}
if ((sv->s = CreateSemaphore (NULL, 0, SEM_VALUE_MAX, NULL)) == NULL)
{
pthread_mutex_destroy (&sv->vlock);
free (sv);
return sem_result (ENOSPC);
}
sv->valid = LIFE_SEM;
*sem = sv;
return 0;
}
int
sem_destroy (sem_t *sem)
{
int r;
_sem_t *sv = NULL;
if (!sem || (sv = *sem) == NULL)
return sem_result (EINVAL);
if ((r = pthread_mutex_lock (&sv->vlock)) != 0)
return sem_result (r);
#if 0
/* We don't wait for destroying a semaphore ...
or? */
if (sv->value < 0)
{
pthread_mutex_unlock (&sv->vlock);
return sem_result (EBUSY);
}
#endif
if (!CloseHandle (sv->s))
{
pthread_mutex_unlock (&sv->vlock);
return sem_result (EINVAL);
}
*sem = NULL;
sv->value = SEM_VALUE_MAX;
pthread_mutex_unlock(&sv->vlock);
Sleep (0);
while (pthread_mutex_destroy (&sv->vlock) == EBUSY)
Sleep (0);
sv->valid = DEAD_SEM;
free (sv);
return 0;
}
static int
sem_std_enter (sem_t *sem,_sem_t **svp, int do_test)
{
int r;
_sem_t *sv;
if (do_test)
pthread_testcancel ();
if (!sem)
return sem_result (EINVAL);
sv = *sem;
if (sv == NULL)
return sem_result (EINVAL);
if ((r = pthread_mutex_lock (&sv->vlock)) != 0)
return sem_result (r);
if (*sem == NULL)
{
pthread_mutex_unlock(&sv->vlock);
return sem_result (EINVAL);
}
*svp = sv;
return 0;
}
int
sem_trywait (sem_t *sem)
{
_sem_t *sv;
if (sem_std_enter (sem, &sv, 0) != 0)
return -1;
if (sv->value <= 0)
{
pthread_mutex_unlock (&sv->vlock);
return sem_result (EAGAIN);
}
sv->value--;
pthread_mutex_unlock (&sv->vlock);
return 0;
}
struct sSemTimedWait
{
sem_t *p;
int *ret;
};
static void
clean_wait_sem (void *s)
{
struct sSemTimedWait *p = (struct sSemTimedWait *) s;
_sem_t *sv = NULL;
if (sem_std_enter (p->p, &sv, 0) != 0)
return;
if (WaitForSingleObject (sv->s, 0) != WAIT_OBJECT_0)
InterlockedIncrement (&sv->value);
else if (p->ret)
p->ret[0] = 0;
pthread_mutex_unlock (&sv->vlock);
}
int
sem_wait (sem_t *sem)
{
long cur_v;
int ret = 0;
_sem_t *sv;
HANDLE semh;
struct sSemTimedWait arg;
if (sem_std_enter (sem, &sv, 1) != 0)
return -1;
arg.ret = &ret;
arg.p = sem;
InterlockedDecrement (&sv->value);
cur_v = sv->value;
semh = sv->s;
pthread_mutex_unlock (&sv->vlock);
if (cur_v >= 0)
return 0;
else
{
pthread_cleanup_push (clean_wait_sem, (void *) &arg);
ret = do_sema_b_wait_intern (semh, 2, INFINITE);
pthread_cleanup_pop (ret);
if (ret == EINVAL)
return 0;
}
if (!ret)
return 0;
return sem_result (ret);
}
int
sem_timedwait (sem_t *sem, const struct timespec *t)
{
int cur_v, ret = 0;
DWORD dwr;
HANDLE semh;
_sem_t *sv;
struct sSemTimedWait arg;
if (!t)
return sem_wait (sem);
dwr = dwMilliSecs(_pthread_rel_time_in_ms (t));
if (sem_std_enter (sem, &sv, 1) != 0)
return -1;
arg.ret = &ret;
arg.p = sem;
InterlockedDecrement (&sv->value);
cur_v = sv->value;
semh = sv->s;
pthread_mutex_unlock(&sv->vlock);
if (cur_v >= 0)
return 0;
else
{
pthread_cleanup_push (clean_wait_sem, (void *) &arg);
ret = do_sema_b_wait_intern (semh, 2, dwr);
pthread_cleanup_pop (ret);
if (ret == EINVAL)
return 0;
}
if (!ret)
return 0;
return sem_result (ret);
}
int
sem_post (sem_t *sem)
{
_sem_t *sv;
if (sem_std_enter (sem, &sv, 0) != 0)
return -1;
if (sv->value >= SEM_VALUE_MAX)
{
pthread_mutex_unlock (&sv->vlock);
return sem_result (ERANGE);
}
InterlockedIncrement (&sv->value);
if (sv->value > 0 || ReleaseSemaphore (sv->s, 1, NULL))
{
pthread_mutex_unlock (&sv->vlock);
return 0;
}
InterlockedDecrement (&sv->value);
pthread_mutex_unlock (&sv->vlock);
return sem_result (EINVAL);
}
int
sem_post_multiple (sem_t *sem, int count)
{
int waiters_count;
_sem_t *sv;
if (count <= 0)
return sem_result (EINVAL);
if (sem_std_enter (sem, &sv, 0) != 0)
return -1;
if (sv->value > (SEM_VALUE_MAX - count))
{
pthread_mutex_unlock (&sv->vlock);
return sem_result (ERANGE);
}
waiters_count = -sv->value;
sv->value += count;
/*InterlockedExchangeAdd((long*)&sv->value, (long) count);*/
if (waiters_count <= 0
|| ReleaseSemaphore (sv->s,
(waiters_count < count ? waiters_count
: count), NULL))
{
pthread_mutex_unlock(&sv->vlock);
return 0;
}
/*InterlockedExchangeAdd((long*)&sv->value, -((long) count));*/
sv->value -= count;
pthread_mutex_unlock(&sv->vlock);
return sem_result (EINVAL);
}
sem_t *
sem_open (const char *name, int oflag, mode_t mode, unsigned int value)
{
sem_result (ENOSYS);
return NULL;
}
int
sem_close (sem_t *sem)
{
return sem_result (ENOSYS);
}
int
sem_unlink (const char *name)
{
return sem_result (ENOSYS);
}
int
sem_getvalue (sem_t *sem, int *sval)
{
_sem_t *sv;
int r;
if (!sval)
return sem_result (EINVAL);
if (!sem || (sv = *sem) == NULL)
return sem_result (EINVAL);
if ((r = pthread_mutex_lock (&sv->vlock)) != 0)
return sem_result (r);
if (*sem == NULL)
{
pthread_mutex_unlock (&sv->vlock);
return sem_result (EINVAL);
}
*sval = (int) sv->value;
pthread_mutex_unlock (&sv->vlock);
return 0;
}

View File

@@ -0,0 +1,40 @@
/*
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.
*/
#ifndef WIN_SEM
#define WIN_SEM
#include <windows.h>
#define LIFE_SEM 0xBAB1F00D
#define DEAD_SEM 0xDEADBEEF
typedef struct _sem_t _sem_t;
struct _sem_t
{
unsigned int valid;
HANDLE s;
volatile long value;
pthread_mutex_t vlock;
};
#endif /* WIN_SEM */

View File

@@ -0,0 +1,74 @@
/*
Copyright (c) 2013 mingw-w64 project
Copyright (c) 2015 Intel Corporation
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.
*/
#include <windows.h>
#include "pthread.h"
#include "misc.h"
/* We use the pthread_spinlock_t itself as a lock:
-1 is free, 0 is locked.
(This is dictated by PTHREAD_SPINLOCK_INITIALIZER, which we can't change
without breaking binary compatibility.) */
typedef intptr_t spinlock_word_t;
int
pthread_spin_init (pthread_spinlock_t *lock, int pshared)
{
spinlock_word_t *lk = (spinlock_word_t *)lock;
*lk = -1;
return 0;
}
int
pthread_spin_destroy (pthread_spinlock_t *lock)
{
return 0;
}
int
pthread_spin_lock (pthread_spinlock_t *lock)
{
volatile spinlock_word_t *lk = (volatile spinlock_word_t *)lock;
while (unlikely(InterlockedExchangePointer((PVOID volatile *)lk, 0) == 0))
do {
YieldProcessor();
} while (*lk == 0);
return 0;
}
int
pthread_spin_trylock (pthread_spinlock_t *lock)
{
spinlock_word_t *lk = (spinlock_word_t *)lock;
return InterlockedExchangePointer((PVOID volatile *)lk, 0) == 0 ? EBUSY : 0;
}
int
pthread_spin_unlock (pthread_spinlock_t *lock)
{
volatile spinlock_word_t *lk = (volatile spinlock_word_t *)lock;
*lk = -1;
return 0;
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,79 @@
/*
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.
*/
#ifndef WIN_PTHREAD_H
#define WIN_PTHREAD_H
#include <windows.h>
#include <setjmp.h>
#include "rwlock.h"
#define LIFE_THREAD 0xBAB1F00D
#define DEAD_THREAD 0xDEADBEEF
#define EXCEPTION_SET_THREAD_NAME ((DWORD) 0x406D1388)
typedef struct _pthread_v _pthread_v;
struct _pthread_v
{
unsigned int valid;
void *ret_arg;
void *(* func)(void *);
_pthread_cleanup *clean;
int nobreak;
HANDLE h;
HANDLE evStart;
pthread_mutex_t p_clock;
int cancelled : 2;
int in_cancel : 2;
int thread_noposix : 2;
unsigned int p_state;
unsigned int keymax;
void **keyval;
unsigned char *keyval_set;
char *thread_name;
pthread_spinlock_t spin_keys;
DWORD tid;
int rwlc;
pthread_rwlock_t rwlq[RWLS_PER_THREAD];
int sched_pol;
int ended;
struct sched_param sched;
jmp_buf jb;
struct _pthread_v *next;
pthread_t x; /* Internal posix handle. */
};
typedef struct __pthread_idlist {
struct _pthread_v *ptr;
pthread_t id;
} __pthread_idlist;
int _pthread_tryjoin(pthread_t t, void **res);
void _pthread_setnobreak(int);
#ifdef WINPTHREAD_DBG
void thread_print_set(int state);
void thread_print(volatile pthread_t t, char *txt);
#endif
int __pthread_shallcancel(void);
struct _pthread_v *WINPTHREAD_API __pth_gpointer_locked (pthread_t id);
#endif

View File

@@ -0,0 +1,27 @@
/*
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.
*/
#ifndef WINPTHREAD_INTERNAL_H
#define WINPTHREAD_INTERNAL_H
WINPTHREAD_API struct _pthread_v * __pth_gpointer_locked (pthread_t id);
int pthread_delay_np_ms (DWORD to);
#endif /*WINPTHREAD_INTERNAL_H*/

View File

@@ -0,0 +1,29 @@
/*
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.
*/
#ifndef __WPTHREADS_VERSION__
#define __WPTHREADS_VERSION__
#define WPTH_VERSION 1,0,0,0
#define WPTH_VERSION_STRING "1, 0, 0, 0\0"
#endif