initial commit based on 53c4889

This commit is contained in:
georgemoralis 2024-05-09 23:12:57 +03:00
parent dda7cca444
commit d937b60055
32 changed files with 7560 additions and 0 deletions

8
CMakeLists.txt Normal file
View File

@ -0,0 +1,8 @@
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include)
file(GLOB_RECURSE WIN_PTHREAD_SOURCE "${CMAKE_CURRENT_SOURCE_DIR}/*.c")
file(GLOB_RECURSE WIN_PTHREAD_HEADER "${CMAKE_CURRENT_SOURCE_DIR}/*.h")
add_library(winpthreads STATIC ${WIN_PTHREAD_SOURCE} ${WIN_PTHREAD_HEADER})
add_definitions(-D_DEBUG)
add_definitions(-D_CONSOLE)
add_definitions(-D_MBCS)

701
include/pthread.h Normal file
View File

@ -0,0 +1,701 @@
/*
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.
*/
/*
* Parts of this library are derived by:
*
* Posix Threads library for Microsoft Windows
*
* Use at own risk, there is no implied warranty to this code.
* It uses undocumented features of Microsoft Windows that can change
* at any time in the future.
*
* (C) 2010 Lockless Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* * 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.
* * Neither the name of Lockless Inc. 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AN
* 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 COPYRIGHT HOLDER 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 WIN_PTHREADS_H
#define WIN_PTHREADS_H
#include <stddef.h>
#include <errno.h>
#include <sys/types.h>
#include <process.h>
#include <limits.h>
#include <signal.h>
#include <time.h>
#include <sys/timeb.h>
#include "pthread_compat.h"
#ifdef __cplusplus
extern "C" {
#endif
#define __WINPTHREADS_VERSION_MAJOR 0
#define __WINPTHREADS_VERSION_MINOR 5
#define __WINPTHREADS_VERSION_PATCHLEVEL 0
/* MSB 8-bit major version, 8-bit minor version, 16-bit patch level. */
#define __WINPTHREADS_VERSION 0x00050000
#if defined(IN_WINPTHREAD)
# if defined(DLL_EXPORT)
# define WINPTHREAD_API __declspec(dllexport) /* building the DLL */
# else
# define WINPTHREAD_API /* building the static library */
# endif
#else
# if defined(WINPTHREADS_USE_DLLIMPORT)
# define WINPTHREAD_API __declspec(dllimport) /* user wants explicit `dllimport` */
# else
# define WINPTHREAD_API /* the default; auto imported in case of DLL */
# endif
#endif
/* #define WINPTHREAD_DBG 1 */
/* Compatibility stuff: */
#define RWLS_PER_THREAD 8
/* Error-codes. */
#ifndef ETIMEDOUT
#define ETIMEDOUT 138
#endif
#ifndef ENOTSUP
#define ENOTSUP 129
#endif
#ifndef EWOULDBLOCK
#define EWOULDBLOCK 140
#endif
/* pthread specific defines. */
#define PTHREAD_CANCEL_DISABLE 0
#define PTHREAD_CANCEL_ENABLE 0x01
#define PTHREAD_CANCEL_DEFERRED 0
#define PTHREAD_CANCEL_ASYNCHRONOUS 0x02
#define PTHREAD_CREATE_JOINABLE 0
#define PTHREAD_CREATE_DETACHED 0x04
#define PTHREAD_EXPLICIT_SCHED 0
#define PTHREAD_INHERIT_SCHED 0x08
#define PTHREAD_SCOPE_PROCESS 0
#define PTHREAD_SCOPE_SYSTEM 0x10
#define PTHREAD_DEFAULT_ATTR (PTHREAD_CANCEL_ENABLE)
#define PTHREAD_CANCELED ((void *) (intptr_t) 0xDEADBEEF)
#define _PTHREAD_NULL_THREAD ((pthread_t) 0)
#define PTHREAD_ONCE_INIT 0
#define PTHREAD_DESTRUCTOR_ITERATIONS 256
#define PTHREAD_KEYS_MAX (1<<20)
#define PTHREAD_MUTEX_NORMAL 0
#define PTHREAD_MUTEX_ERRORCHECK 1
#define PTHREAD_MUTEX_RECURSIVE 2
#define PTHREAD_MUTEX_DEFAULT PTHREAD_MUTEX_NORMAL
#define PTHREAD_MUTEX_SHARED 1
#define PTHREAD_MUTEX_PRIVATE 0
#define PTHREAD_PRIO_NONE 0
#define PTHREAD_PRIO_INHERIT 8
#define PTHREAD_PRIO_PROTECT 16
#define PTHREAD_PRIO_MULT 32
#define PTHREAD_PROCESS_SHARED 1
#define PTHREAD_PROCESS_PRIVATE 0
#define PTHREAD_MUTEX_FAST_NP PTHREAD_MUTEX_NORMAL
#define PTHREAD_MUTEX_TIMED_NP PTHREAD_MUTEX_FAST_NP
#define PTHREAD_MUTEX_ADAPTIVE_NP PTHREAD_MUTEX_FAST_NP
#define PTHREAD_MUTEX_ERRORCHECK_NP PTHREAD_MUTEX_ERRORCHECK
#define PTHREAD_MUTEX_RECURSIVE_NP PTHREAD_MUTEX_RECURSIVE
WINPTHREAD_API void * pthread_timechange_handler_np(void * dummy);
WINPTHREAD_API int pthread_delay_np (const struct timespec *interval);
WINPTHREAD_API int pthread_num_processors_np(void);
WINPTHREAD_API int pthread_set_num_processors_np(int n);
#define PTHREAD_BARRIER_SERIAL_THREAD 1
/* maximum number of times a read lock may be obtained */
#define MAX_READ_LOCKS (INT_MAX - 1)
/* No fork() in windows - so ignore this */
#define pthread_atfork(F1,F2,F3) 0
/* unsupported stuff: */
#define pthread_mutex_getprioceiling(M, P) ENOTSUP
#define pthread_mutex_setprioceiling(M, P) ENOTSUP
#define pthread_getcpuclockid(T, C) ENOTSUP
#define pthread_attr_getguardsize(A, S) ENOTSUP
#define pthread_attr_setgaurdsize(A, S) ENOTSUP
typedef long pthread_once_t;
typedef unsigned pthread_mutexattr_t;
typedef unsigned pthread_key_t;
typedef void *pthread_barrierattr_t;
typedef int pthread_condattr_t;
typedef int pthread_rwlockattr_t;
/*
struct _pthread_v;
typedef struct pthread_t {
struct _pthread_v *p;
int x;
} pthread_t;
*/
typedef uintptr_t pthread_t;
typedef struct _pthread_cleanup _pthread_cleanup;
struct _pthread_cleanup
{
void (*func)(void *);
void *arg;
_pthread_cleanup *next;
};
/* Using MemoryBarrier() requires including Windows headers. User code
* may want to use pthread_cleanup_push without including Windows headers
* first, thus prefer GCC specific intrinsics where possible. */
#ifdef __GNUC__
#define __pthread_MemoryBarrier() __sync_synchronize()
#else
#define __pthread_MemoryBarrier() MemoryBarrier()
#endif
#define pthread_cleanup_push(F, A) \
do { \
const _pthread_cleanup _pthread_cup = \
{ (F), (A), *pthread_getclean() }; \
__pthread_MemoryBarrier(); \
*pthread_getclean() = (_pthread_cleanup *) &_pthread_cup; \
__pthread_MemoryBarrier(); \
do { \
do {} while (0)
/* Note that if async cancelling is used, then there is a race here */
#define pthread_cleanup_pop(E) \
} while (0); \
*pthread_getclean() = _pthread_cup.next; \
if ((E)) _pthread_cup.func((pthread_once_t *)_pthread_cup.arg); \
} while (0)
#ifndef SCHED_OTHER
/* Some POSIX realtime extensions, mostly stubbed */
#define SCHED_OTHER 0
#define SCHED_FIFO 1
#define SCHED_RR 2
#define SCHED_MIN SCHED_OTHER
#define SCHED_MAX SCHED_RR
struct sched_param {
int sched_priority;
};
WINPTHREAD_API int sched_yield(void);
WINPTHREAD_API int sched_get_priority_min(int pol);
WINPTHREAD_API int sched_get_priority_max(int pol);
WINPTHREAD_API int sched_getscheduler(pid_t pid);
WINPTHREAD_API int sched_setscheduler(pid_t pid, int pol, const struct sched_param *param);
#endif
typedef struct pthread_attr_t pthread_attr_t;
struct pthread_attr_t
{
unsigned p_state;
void *stack;
size_t s_size;
struct sched_param param;
};
WINPTHREAD_API int pthread_attr_setschedparam(pthread_attr_t *attr, const struct sched_param *param);
WINPTHREAD_API int pthread_attr_getschedparam(const pthread_attr_t *attr, struct sched_param *param);
WINPTHREAD_API int pthread_getschedparam(pthread_t thread, int *pol, struct sched_param *param);
WINPTHREAD_API int pthread_setschedparam(pthread_t thread, int pol, const struct sched_param *param);
WINPTHREAD_API int pthread_attr_setschedpolicy (pthread_attr_t *attr, int pol);
WINPTHREAD_API int pthread_attr_getschedpolicy (const pthread_attr_t *attr, int *pol);
/* synchronization objects */
typedef intptr_t pthread_spinlock_t;
typedef intptr_t pthread_mutex_t;
typedef intptr_t pthread_cond_t;
typedef intptr_t pthread_rwlock_t;
typedef void *pthread_barrier_t;
#define PTHREAD_MUTEX_NORMAL 0
#define PTHREAD_MUTEX_ERRORCHECK 1
#define PTHREAD_MUTEX_RECURSIVE 2
#define GENERIC_INITIALIZER -1
#define GENERIC_ERRORCHECK_INITIALIZER -2
#define GENERIC_RECURSIVE_INITIALIZER -3
#define GENERIC_NORMAL_INITIALIZER -1
#define PTHREAD_MUTEX_INITIALIZER (pthread_mutex_t)GENERIC_INITIALIZER
#define PTHREAD_RECURSIVE_MUTEX_INITIALIZER (pthread_mutex_t)GENERIC_RECURSIVE_INITIALIZER
#define PTHREAD_ERRORCHECK_MUTEX_INITIALIZER (pthread_mutex_t)GENERIC_ERRORCHECK_INITIALIZER
#define PTHREAD_NORMAL_MUTEX_INITIALIZER (pthread_mutex_t)GENERIC_NORMAL_INITIALIZER
#define PTHREAD_DEFAULT_MUTEX_INITIALIZER PTHREAD_NORMAL_MUTEX_INITIALIZER
#define PTHREAD_COND_INITIALIZER (pthread_cond_t)GENERIC_INITIALIZER
#define PTHREAD_RWLOCK_INITIALIZER (pthread_rwlock_t)GENERIC_INITIALIZER
#define PTHREAD_SPINLOCK_INITIALIZER (pthread_spinlock_t)GENERIC_INITIALIZER
WINPTHREAD_API extern void (**_pthread_key_dest)(void *);
WINPTHREAD_API int pthread_key_create(pthread_key_t *key, void (* dest)(void *));
WINPTHREAD_API int pthread_key_delete(pthread_key_t key);
WINPTHREAD_API void * pthread_getspecific(pthread_key_t key);
WINPTHREAD_API int pthread_setspecific(pthread_key_t key, const void *value);
WINPTHREAD_API pthread_t pthread_self(void);
WINPTHREAD_API int pthread_once(pthread_once_t *o, void (*func)(void));
WINPTHREAD_API void pthread_testcancel(void);
WINPTHREAD_API int pthread_equal(pthread_t t1, pthread_t t2);
WINPTHREAD_API void pthread_tls_init(void);
WINPTHREAD_API void _pthread_cleanup_dest(pthread_t t);
WINPTHREAD_API int pthread_get_concurrency(int *val);
WINPTHREAD_API int pthread_set_concurrency(int val);
WINPTHREAD_API void pthread_exit(void *res);
WINPTHREAD_API void _pthread_invoke_cancel(void);
WINPTHREAD_API int pthread_cancel(pthread_t t);
WINPTHREAD_API int pthread_kill(pthread_t t, int sig);
WINPTHREAD_API unsigned _pthread_get_state(const pthread_attr_t *attr, unsigned flag);
WINPTHREAD_API int _pthread_set_state(pthread_attr_t *attr, unsigned flag, unsigned val);
WINPTHREAD_API int pthread_setcancelstate(int state, int *oldstate);
WINPTHREAD_API int pthread_setcanceltype(int type, int *oldtype);
WINPTHREAD_API unsigned __stdcall pthread_create_wrapper(void *args);
WINPTHREAD_API int pthread_create(pthread_t *th, const pthread_attr_t *attr, void *(* func)(void *), void *arg);
WINPTHREAD_API int pthread_join(pthread_t t, void **res);
WINPTHREAD_API int pthread_detach(pthread_t t);
WINPTHREAD_API int pthread_setname_np(pthread_t thread, const char *name);
WINPTHREAD_API int pthread_getname_np(pthread_t thread, char *name, size_t len);
WINPTHREAD_API int pthread_rwlock_init(pthread_rwlock_t *rwlock_, const pthread_rwlockattr_t *attr);
WINPTHREAD_API int pthread_rwlock_wrlock(pthread_rwlock_t *l);
WINPTHREAD_API int pthread_rwlock_timedwrlock(pthread_rwlock_t *rwlock, const struct timespec *ts);
WINPTHREAD_API int pthread_rwlock_rdlock(pthread_rwlock_t *l);
WINPTHREAD_API int pthread_rwlock_timedrdlock(pthread_rwlock_t *l, const struct timespec *ts);
WINPTHREAD_API int pthread_rwlock_unlock(pthread_rwlock_t *l);
WINPTHREAD_API int pthread_rwlock_tryrdlock(pthread_rwlock_t *l);
WINPTHREAD_API int pthread_rwlock_trywrlock(pthread_rwlock_t *l);
WINPTHREAD_API int pthread_rwlock_destroy (pthread_rwlock_t *l);
WINPTHREAD_API int pthread_cond_init(pthread_cond_t *cv, const pthread_condattr_t *a);
WINPTHREAD_API int pthread_cond_destroy(pthread_cond_t *cv);
WINPTHREAD_API int pthread_cond_signal (pthread_cond_t *cv);
WINPTHREAD_API int pthread_cond_broadcast (pthread_cond_t *cv);
WINPTHREAD_API int pthread_cond_wait (pthread_cond_t *cv, pthread_mutex_t *external_mutex);
WINPTHREAD_API int pthread_cond_timedwait(pthread_cond_t *cv, pthread_mutex_t *external_mutex, const struct timespec *t);
WINPTHREAD_API int pthread_cond_timedwait_relative_np(pthread_cond_t *cv, pthread_mutex_t *external_mutex, const struct timespec *t);
WINPTHREAD_API int pthread_mutex_lock(pthread_mutex_t *m);
WINPTHREAD_API int pthread_mutex_timedlock(pthread_mutex_t *m, const struct timespec *ts);
WINPTHREAD_API int pthread_mutex_unlock(pthread_mutex_t *m);
WINPTHREAD_API int pthread_mutex_trylock(pthread_mutex_t *m);
WINPTHREAD_API int pthread_mutex_init(pthread_mutex_t *m, const pthread_mutexattr_t *a);
WINPTHREAD_API int pthread_mutex_destroy(pthread_mutex_t *m);
WINPTHREAD_API int pthread_barrier_destroy(pthread_barrier_t *b);
WINPTHREAD_API int pthread_barrier_init(pthread_barrier_t *b, const void *attr, unsigned int count);
WINPTHREAD_API int pthread_barrier_wait(pthread_barrier_t *b);
WINPTHREAD_API int pthread_spin_init(pthread_spinlock_t *l, int pshared);
WINPTHREAD_API int pthread_spin_destroy(pthread_spinlock_t *l);
/* No-fair spinlock due to lack of knowledge of thread number. */
WINPTHREAD_API int pthread_spin_lock(pthread_spinlock_t *l);
WINPTHREAD_API int pthread_spin_trylock(pthread_spinlock_t *l);
WINPTHREAD_API int pthread_spin_unlock(pthread_spinlock_t *l);
WINPTHREAD_API int pthread_attr_init(pthread_attr_t *attr);
WINPTHREAD_API int pthread_attr_destroy(pthread_attr_t *attr);
WINPTHREAD_API int pthread_attr_setdetachstate(pthread_attr_t *a, int flag);
WINPTHREAD_API int pthread_attr_getdetachstate(const pthread_attr_t *a, int *flag);
WINPTHREAD_API int pthread_attr_setinheritsched(pthread_attr_t *a, int flag);
WINPTHREAD_API int pthread_attr_getinheritsched(const pthread_attr_t *a, int *flag);
WINPTHREAD_API int pthread_attr_setscope(pthread_attr_t *a, int flag);
WINPTHREAD_API int pthread_attr_getscope(const pthread_attr_t *a, int *flag);
WINPTHREAD_API int pthread_attr_getstack(const pthread_attr_t *attr, void **stack, size_t *size);
WINPTHREAD_API int pthread_attr_setstack(pthread_attr_t *attr, void *stack, size_t size);
WINPTHREAD_API int pthread_attr_getstackaddr(const pthread_attr_t *attr, void **stack);
WINPTHREAD_API int pthread_attr_setstackaddr(pthread_attr_t *attr, void *stack);
WINPTHREAD_API int pthread_attr_getstacksize(const pthread_attr_t *attr, size_t *size);
WINPTHREAD_API int pthread_attr_setstacksize(pthread_attr_t *attr, size_t size);
WINPTHREAD_API int pthread_mutexattr_init(pthread_mutexattr_t *a);
WINPTHREAD_API int pthread_mutexattr_destroy(pthread_mutexattr_t *a);
WINPTHREAD_API int pthread_mutexattr_gettype(const pthread_mutexattr_t *a, int *type);
WINPTHREAD_API int pthread_mutexattr_settype(pthread_mutexattr_t *a, int type);
WINPTHREAD_API int pthread_mutexattr_getpshared(const pthread_mutexattr_t *a, int *type);
WINPTHREAD_API int pthread_mutexattr_setpshared(pthread_mutexattr_t * a, int type);
WINPTHREAD_API int pthread_mutexattr_getprotocol(const pthread_mutexattr_t *a, int *type);
WINPTHREAD_API int pthread_mutexattr_setprotocol(pthread_mutexattr_t *a, int type);
WINPTHREAD_API int pthread_mutexattr_getprioceiling(const pthread_mutexattr_t *a, int * prio);
WINPTHREAD_API int pthread_mutexattr_setprioceiling(pthread_mutexattr_t *a, int prio);
WINPTHREAD_API int pthread_getconcurrency(void);
WINPTHREAD_API int pthread_setconcurrency(int new_level);
WINPTHREAD_API int pthread_condattr_destroy(pthread_condattr_t *a);
WINPTHREAD_API int pthread_condattr_init(pthread_condattr_t *a);
WINPTHREAD_API int pthread_condattr_getpshared(const pthread_condattr_t *a, int *s);
WINPTHREAD_API int pthread_condattr_setpshared(pthread_condattr_t *a, int s);
#ifndef __clockid_t_defined
typedef int clockid_t;
#define __clockid_t_defined 1
#endif /* __clockid_t_defined */
WINPTHREAD_API int pthread_condattr_getclock (const pthread_condattr_t *attr,
clockid_t *clock_id);
WINPTHREAD_API int pthread_condattr_setclock(pthread_condattr_t *attr,
clockid_t clock_id);
WINPTHREAD_API int __pthread_clock_nanosleep(clockid_t clock_id, int flags, const struct timespec *rqtp, struct timespec *rmtp);
WINPTHREAD_API int pthread_barrierattr_init(void **attr);
WINPTHREAD_API int pthread_barrierattr_destroy(void **attr);
WINPTHREAD_API int pthread_barrierattr_setpshared(void **attr, int s);
WINPTHREAD_API int pthread_barrierattr_getpshared(void **attr, int *s);
/* Private extensions for analysis and internal use. */
WINPTHREAD_API struct _pthread_cleanup ** pthread_getclean (void);
WINPTHREAD_API void * pthread_gethandle (pthread_t t);
WINPTHREAD_API void * pthread_getevent (void);
WINPTHREAD_API unsigned long long _pthread_rel_time_in_ms(const struct timespec *ts);
WINPTHREAD_API unsigned long long _pthread_time_in_ms(void);
WINPTHREAD_API unsigned long long _pthread_time_in_ms_from_timespec(const struct timespec *ts);
WINPTHREAD_API int _pthread_tryjoin (pthread_t t, void **res);
WINPTHREAD_API int pthread_rwlockattr_destroy(pthread_rwlockattr_t *a);
WINPTHREAD_API int pthread_rwlockattr_getpshared(pthread_rwlockattr_t *a, int *s);
WINPTHREAD_API int pthread_rwlockattr_init(pthread_rwlockattr_t *a);
WINPTHREAD_API int pthread_rwlockattr_setpshared(pthread_rwlockattr_t *a, int s);
#ifndef SIG_BLOCK
#define SIG_BLOCK 0
#endif
#ifndef SIG_UNBLOCK
#define SIG_UNBLOCK 1
#endif
#ifndef SIG_SETMASK
#define SIG_SETMASK 2
#endif
#include <pthread_unistd.h>
#undef _POSIX_THREAD_DESTRUCTOR_ITERATIONS
#define _POSIX_THREAD_DESTRUCTOR_ITERATIONS PTHREAD_DESTRUCTOR_ITERATIONS
#undef _POSIX_THREAD_KEYS_MAX
#define _POSIX_THREAD_KEYS_MAX PTHREAD_KEYS_MAX
#undef PTHREAD_THREADS_MAX
#define PTHREAD_THREADS_MAX 2019
#undef _POSIX_SEM_NSEMS_MAX
#define _POSIX_SEM_NSEMS_MAX 256
#undef SEM_NSEMS_MAX
#define SEM_NSEMS_MAX 1024
/* Wrap cancellation points. */
#if defined(__WINPTHREAD_ENABLE_WRAP_API) \
|| defined(__WINPTRHEAD_ENABLE_WRAP_API) /* historical typo */
#define accept(...) (pthread_testcancel(), accept(__VA_ARGS__))
#define aio_suspend(...) (pthread_testcancel(), aio_suspend(__VA_ARGS__))
#define clock_nanosleep(...) (pthread_testcancel(), clock_nanosleep(__VA_ARGS__))
#define close(...) (pthread_testcancel(), close(__VA_ARGS__))
#define connect(...) (pthread_testcancel(), connect(__VA_ARGS__))
#define creat(...) (pthread_testcancel(), creat(__VA_ARGS__))
#define fcntl(...) (pthread_testcancel(), fcntl(__VA_ARGS__))
#define fdatasync(...) (pthread_testcancel(), fdatasync(__VA_ARGS__))
#define fsync(...) (pthread_testcancel(), fsync(__VA_ARGS__))
#define getmsg(...) (pthread_testcancel(), getmsg(__VA_ARGS__))
#define getpmsg(...) (pthread_testcancel(), getpmsg(__VA_ARGS__))
#define lockf(...) (pthread_testcancel(), lockf(__VA_ARGS__))
#define mg_receive(...) (pthread_testcancel(), mg_receive(__VA_ARGS__))
#define mg_send(...) (pthread_testcancel(), mg_send(__VA_ARGS__))
#define mg_timedreceive(...) (pthread_testcancel(), mg_timedreceive(__VA_ARGS__))
#define mg_timessend(...) (pthread_testcancel(), mg_timedsend(__VA_ARGS__))
#define msgrcv(...) (pthread_testcancel(), msgrecv(__VA_ARGS__))
#define msgsnd(...) (pthread_testcancel(), msgsnd(__VA_ARGS__))
#define msync(...) (pthread_testcancel(), msync(__VA_ARGS__))
#define nanosleep(...) (pthread_testcancel(), nanosleep(__VA_ARGS__))
#define open(...) (pthread_testcancel(), open(__VA_ARGS__))
#define pause(...) (pthread_testcancel(), pause(__VA_ARGS__))
#define poll(...) (pthread_testcancel(), poll(__VA_ARGS__))
#define pread(...) (pthread_testcancel(), pread(__VA_ARGS__))
#define pselect(...) (pthread_testcancel(), pselect(__VA_ARGS__))
#define putmsg(...) (pthread_testcancel(), putmsg(__VA_ARGS__))
#define putpmsg(...) (pthread_testcancel(), putpmsg(__VA_ARGS__))
#define pwrite(...) (pthread_testcancel(), pwrite(__VA_ARGS__))
#define read(...) (pthread_testcancel(), read(__VA_ARGS__))
#define readv(...) (pthread_testcancel(), readv(__VA_ARGS__))
#define recv(...) (pthread_testcancel(), recv(__VA_ARGS__))
#define recvfrom(...) (pthread_testcancel(), recvfrom(__VA_ARGS__))
#define recvmsg(...) (pthread_testcancel(), recvmsg(__VA_ARGS__))
#define select(...) (pthread_testcancel(), select(__VA_ARGS__))
#define sem_timedwait(...) (pthread_testcancel(), sem_timedwait(__VA_ARGS__))
#define sem_wait(...) (pthread_testcancel(), sem_wait(__VA_ARGS__))
#define send(...) (pthread_testcancel(), send(__VA_ARGS__))
#define sendmsg(...) (pthread_testcancel(), sendmsg(__VA_ARGS__))
#define sendto(...) (pthread_testcancel(), sendto(__VA_ARGS__))
#define sigpause(...) (pthread_testcancel(), sigpause(__VA_ARGS__))
#define sigsuspend(...) (pthread_testcancel(), sigsuspend(__VA_ARGS__))
#define sigwait(...) (pthread_testcancel(), sigwait(__VA_ARGS__))
#define sigwaitinfo(...) (pthread_testcancel(), sigwaitinfo(__VA_ARGS__))
#define sleep(...) (pthread_testcancel(), sleep(__VA_ARGS__))
//#define Sleep(...) (pthread_testcancel(), Sleep(__VA_ARGS__))
#define system(...) (pthread_testcancel(), system(__VA_ARGS__))
#define access(...) (pthread_testcancel(), access(__VA_ARGS__))
#define asctime(...) (pthread_testcancel(), asctime(__VA_ARGS__))
#define catclose(...) (pthread_testcancel(), catclose(__VA_ARGS__))
#define catgets(...) (pthread_testcancel(), catgets(__VA_ARGS__))
#define catopen(...) (pthread_testcancel(), catopen(__VA_ARGS__))
#define closedir(...) (pthread_testcancel(), closedir(__VA_ARGS__))
#define closelog(...) (pthread_testcancel(), closelog(__VA_ARGS__))
#define ctermid(...) (pthread_testcancel(), ctermid(__VA_ARGS__))
#define ctime(...) (pthread_testcancel(), ctime(__VA_ARGS__))
#define dbm_close(...) (pthread_testcancel(), dbm_close(__VA_ARGS__))
#define dbm_delete(...) (pthread_testcancel(), dbm_delete(__VA_ARGS__))
#define dbm_fetch(...) (pthread_testcancel(), dbm_fetch(__VA_ARGS__))
#define dbm_nextkey(...) (pthread_testcancel(), dbm_nextkey(__VA_ARGS__))
#define dbm_open(...) (pthread_testcancel(), dbm_open(__VA_ARGS__))
#define dbm_store(...) (pthread_testcancel(), dbm_store(__VA_ARGS__))
#define dlclose(...) (pthread_testcancel(), dlclose(__VA_ARGS__))
#define dlopen(...) (pthread_testcancel(), dlopen(__VA_ARGS__))
#define endgrent(...) (pthread_testcancel(), endgrent(__VA_ARGS__))
#define endhostent(...) (pthread_testcancel(), endhostent(__VA_ARGS__))
#define endnetent(...) (pthread_testcancel(), endnetent(__VA_ARGS__))
#define endprotoent(...) (pthread_testcancel(), endprotoend(__VA_ARGS__))
#define endpwent(...) (pthread_testcancel(), endpwent(__VA_ARGS__))
#define endservent(...) (pthread_testcancel(), endservent(__VA_ARGS__))
#define endutxent(...) (pthread_testcancel(), endutxent(__VA_ARGS__))
#define fclose(...) (pthread_testcancel(), fclose(__VA_ARGS__))
#define fflush(...) (pthread_testcancel(), fflush(__VA_ARGS__))
#define fgetc(...) (pthread_testcancel(), fgetc(__VA_ARGS__))
#define fgetpos(...) (pthread_testcancel(), fgetpos(__VA_ARGS__))
#define fgets(...) (pthread_testcancel(), fgets(__VA_ARGS__))
#define fgetwc(...) (pthread_testcancel(), fgetwc(__VA_ARGS__))
#define fgetws(...) (pthread_testcancel(), fgetws(__VA_ARGS__))
#define fmtmsg(...) (pthread_testcancel(), fmtmsg(__VA_ARGS__))
#define fopen(...) (pthread_testcancel(), fopen(__VA_ARGS__))
#define fpathconf(...) (pthread_testcancel(), fpathconf(__VA_ARGS__))
#define fprintf(...) (pthread_testcancel(), fprintf(__VA_ARGS__))
#define fputc(...) (pthread_testcancel(), fputc(__VA_ARGS__))
#define fputs(...) (pthread_testcancel(), fputs(__VA_ARGS__))
#define fputwc(...) (pthread_testcancel(), fputwc(__VA_ARGS__))
#define fputws(...) (pthread_testcancel(), fputws(__VA_ARGS__))
#define fread(...) (pthread_testcancel(), fread(__VA_ARGS__))
#define freopen(...) (pthread_testcancel(), freopen(__VA_ARGS__))
#define fscanf(...) (pthread_testcancel(), fscanf(__VA_ARGS__))
#define fseek(...) (pthread_testcancel(), fseek(__VA_ARGS__))
#define fseeko(...) (pthread_testcancel(), fseeko(__VA_ARGS__))
#define fsetpos(...) (pthread_testcancel(), fsetpos(__VA_ARGS__))
#define fstat(...) (pthread_testcancel(), fstat(__VA_ARGS__))
#define ftell(...) (pthread_testcancel(), ftell(__VA_ARGS__))
#define ftello(...) (pthread_testcancel(), ftello(__VA_ARGS__))
#define ftw(...) (pthread_testcancel(), ftw(__VA_ARGS__))
#define fwprintf(...) (pthread_testcancel(), fwprintf(__VA_ARGS__))
#define fwrite(...) (pthread_testcancel(), fwrite(__VA_ARGS__))
#define fwscanf(...) (pthread_testcancel(), fwscanf(__VA_ARGS__))
#define getaddrinfo(...) (pthread_testcancel(), getaddrinfo(__VA_ARGS__))
#define getc(...) (pthread_testcancel(), getc(__VA_ARGS__))
#define getc_unlocked(...) (pthread_testcancel(), getc_unlocked(__VA_ARGS__))
#define getchar(...) (pthread_testcancel(), getchar(__VA_ARGS__))
#define getchar_unlocked(...) (pthread_testcancel(), getchar_unlocked(__VA_ARGS__))
#define getcwd(...) (pthread_testcancel(), getcwd(__VA_ARGS__))
#define getdate(...) (pthread_testcancel(), getdate(__VA_ARGS__))
#define getgrent(...) (pthread_testcancel(), getgrent(__VA_ARGS__))
#define getgrgid(...) (pthread_testcancel(), getgrgid(__VA_ARGS__))
#define getgrgid_r(...) (pthread_testcancel(), getgrgid_r(__VA_ARGS__))
#define gergrnam(...) (pthread_testcancel(), getgrnam(__VA_ARGS__))
#define getgrnam_r(...) (pthread_testcancel(), getgrnam_r(__VA_ARGS__))
#define gethostbyaddr(...) (pthread_testcancel(), gethostbyaddr(__VA_ARGS__))
#define gethostbyname(...) (pthread_testcancel(), gethostbyname(__VA_ARGS__))
#define gethostent(...) (pthread_testcancel(), gethostent(__VA_ARGS__))
#define gethostid(...) (pthread_testcancel(), gethostid(__VA_ARGS__))
#define gethostname(...) (pthread_testcancel(), gethostname(__VA_ARGS__))
#define getlogin(...) (pthread_testcancel(), getlogin(__VA_ARGS__))
#define getlogin_r(...) (pthread_testcancel(), getlogin_r(__VA_ARGS__))
#define getnameinfo(...) (pthread_testcancel(), getnameinfo(__VA_ARGS__))
#define getnetbyaddr(...) (pthread_testcancel(), getnetbyaddr(__VA_ARGS__))
#define getnetbyname(...) (pthread_testcancel(), getnetbyname(__VA_ARGS__))
#define getnetent(...) (pthread_testcancel(), getnetent(__VA_ARGS__))
#define getopt(...) (pthread_testcancel(), getopt(__VA_ARGS__))
#define getprotobyname(...) (pthread_testcancel(), getprotobyname(__VA_ARGS__))
#define getprotobynumber(...) (pthread_testcancel(), getprotobynumber(__VA_ARGS__))
#define getprotoent(...) (pthread_testcancel(), getprotoent(__VA_ARGS__))
#define getpwent(...) (pthread_testcancel(), getpwent(__VA_ARGS__))
#define getpwnam(...) (pthread_testcancel(), getpwnam(__VA_ARGS__))
#define getpwnam_r(...) (pthread_testcancel(), getpwnam_r(__VA_ARGS__))
#define getpwuid(...) (pthread_testcancel(), getpwuid(__VA_ARGS__))
#define getpwuid_r(...) (pthread_testcancel(), getpwuid_r(__VA_ARGS__))
#define gets(...) (pthread_testcancel(), gets(__VA_ARGS__))
#define getservbyname(...) (pthread_testcancel(), getservbyname(__VA_ARGS__))
#define getservbyport(...) (pthread_testcancel(), getservbyport(__VA_ARGS__))
#define getservent(...) (pthread_testcancel(), getservent(__VA_ARGS__))
#define getutxent(...) (pthread_testcancel(), getutxent(__VA_ARGS__))
#define getutxid(...) (pthread_testcancel(), getutxid(__VA_ARGS__))
#define getutxline(...) (pthread_testcancel(), getutxline(__VA_ARGS__))
#undef getwc
#define getwc(...) (pthread_testcancel(), getwc(__VA_ARGS__))
#undef getwchar
#define getwchar(...) (pthread_testcancel(), getwchar(__VA_ARGS__))
#define getwd(...) (pthread_testcancel(), getwd(__VA_ARGS__))
#define glob(...) (pthread_testcancel(), glob(__VA_ARGS__))
#define iconv_close(...) (pthread_testcancel(), iconv_close(__VA_ARGS__))
#define iconv_open(...) (pthread_testcancel(), iconv_open(__VA_ARGS__))
#define ioctl(...) (pthread_testcancel(), ioctl(__VA_ARGS__))
#define link(...) (pthread_testcancel(), link(__VA_ARGS__))
#define localtime(...) (pthread_testcancel(), localtime(__VA_ARGS__))
#define lseek(...) (pthread_testcancel(), lseek(__VA_ARGS__))
#define lstat(...) (pthread_testcancel(), lstat(__VA_ARGS__))
#define mkstemp(...) (pthread_testcancel(), mkstemp(__VA_ARGS__))
#define nftw(...) (pthread_testcancel(), nftw(__VA_ARGS__))
#define opendir(...) (pthread_testcancel(), opendir(__VA_ARGS__))
#define openlog(...) (pthread_testcancel(), openlog(__VA_ARGS__))
#define pathconf(...) (pthread_testcancel(), pathconf(__VA_ARGS__))
#define pclose(...) (pthread_testcancel(), pclose(__VA_ARGS__))
#define perror(...) (pthread_testcancel(), perror(__VA_ARGS__))
#define popen(...) (pthread_testcancel(), popen(__VA_ARGS__))
#define posix_fadvise(...) (pthread_testcancel(), posix_fadvise(__VA_ARGS__))
#define posix_fallocate(...) (pthread_testcancel(), posix_fallocate(__VA_ARGS__))
#define posix_madvise(...) (pthread_testcancel(), posix_madvise(__VA_ARGS__))
#define posix_openpt(...) (pthread_testcancel(), posix_openpt(__VA_ARGS__))
#define posix_spawn(...) (pthread_testcancel(), posix_spawn(__VA_ARGS__))
#define posix_spawnp(...) (pthread_testcancel(), posix_spawnp(__VA_ARGS__))
#define posix_trace_clear(...) (pthread_testcancel(), posix_trace_clear(__VA_ARGS__))
#define posix_trace_close(...) (pthread_testcancel(), posix_trace_close(__VA_ARGS__))
#define posix_trace_create(...) (pthread_testcancel(), posix_trace_create(__VA_ARGS__))
#define posix_trace_create_withlog(...) (pthread_testcancel(), posix_trace_create_withlog(__VA_ARGS__))
#define posix_trace_eventtypelist_getne(...) (pthread_testcancel(), posix_trace_eventtypelist_getne(__VA_ARGS__))
#define posix_trace_eventtypelist_rewin(...) (pthread_testcancel(), posix_trace_eventtypelist_rewin(__VA_ARGS__))
#define posix_trace_flush(...) (pthread_testcancel(), posix_trace_flush(__VA_ARGS__))
#define posix_trace_get_attr(...) (pthread_testcancel(), posix_trace_get_attr(__VA_ARGS__))
#define posix_trace_get_filter(...) (pthread_testcancel(), posix_trace_get_filter(__VA_ARGS__))
#define posix_trace_get_status(...) (pthread_testcancel(), posix_trace_get_status(__VA_ARGS__))
#define posix_trace_getnext_event(...) (pthread_testcancel(), posix_trace_getnext_event(__VA_ARGS__))
#define posix_trace_open(...) (pthread_testcancel(), posix_trace_open(__VA_ARGS__))
#define posix_trace_rewind(...) (pthread_testcancel(), posix_trace_rewind(__VA_ARGS__))
#define posix_trace_setfilter(...) (pthread_testcancel(), posix_trace_setfilter(__VA_ARGS__))
#define posix_trace_shutdown(...) (pthread_testcancel(), posix_trace_shutdown(__VA_ARGS__))
#define posix_trace_timedgetnext_event(...) (pthread_testcancel(), posix_trace_timedgetnext_event(__VA_ARGS__))
#define posix_typed_mem_open(...) (pthread_testcancel(), posix_typed_mem_open(__VA_ARGS__))
#define printf(...) (pthread_testcancel(), printf(__VA_ARGS__))
#define putc(...) (pthread_testcancel(), putc(__VA_ARGS__))
#define putc_unlocked(...) (pthread_testcancel(), putc_unlocked(__VA_ARGS__))
#define putchar(...) (pthread_testcancel(), putchar(__VA_ARGS__))
#define putchar_unlocked(...) (pthread_testcancel(), putchar_unlocked(__VA_ARGS__))
#define puts(...) (pthread_testcancel(), puts(__VA_ARGS__))
#define pututxline(...) (pthread_testcancel(), pututxline(__VA_ARGS__))
#undef putwc
#define putwc(...) (pthread_testcancel(), putwc(__VA_ARGS__))
#undef putwchar
#define putwchar(...) (pthread_testcancel(), putwchar(__VA_ARGS__))
#define readdir(...) (pthread_testcancel(), readdir(__VA_ARSG__))
#define readdir_r(...) (pthread_testcancel(), readdir_r(__VA_ARGS__))
#define remove(...) (pthread_testcancel(), remove(__VA_ARGS__))
#define rename(...) (pthread_testcancel(), rename(__VA_ARGS__))
#define rewind(...) (pthread_testcancel(), rewind(__VA_ARGS__))
#define rewinddir(...) (pthread_testcancel(), rewinddir(__VA_ARGS__))
#define scanf(...) (pthread_testcancel(), scanf(__VA_ARGS__))
#define seekdir(...) (pthread_testcancel(), seekdir(__VA_ARGS__))
#define semop(...) (pthread_testcancel(), semop(__VA_ARGS__))
#define setgrent(...) (pthread_testcancel(), setgrent(__VA_ARGS__))
#define sethostent(...) (pthread_testcancel(), sethostemt(__VA_ARGS__))
#define setnetent(...) (pthread_testcancel(), setnetent(__VA_ARGS__))
#define setprotoent(...) (pthread_testcancel(), setprotoent(__VA_ARGS__))
#define setpwent(...) (pthread_testcancel(), setpwent(__VA_ARGS__))
#define setservent(...) (pthread_testcancel(), setservent(__VA_ARGS__))
#define setutxent(...) (pthread_testcancel(), setutxent(__VA_ARGS__))
#define stat(...) (pthread_testcancel(), stat(__VA_ARGS__))
#define strerror(...) (pthread_testcancel(), strerror(__VA_ARGS__))
#define strerror_r(...) (pthread_testcancel(), strerror_r(__VA_ARGS__))
#define strftime(...) (pthread_testcancel(), strftime(__VA_ARGS__))
#define symlink(...) (pthread_testcancel(), symlink(__VA_ARGS__))
#define sync(...) (pthread_testcancel(), sync(__VA_ARGS__))
#define syslog(...) (pthread_testcancel(), syslog(__VA_ARGS__))
#define tmpfile(...) (pthread_testcancel(), tmpfile(__VA_ARGS__))
#define tmpnam(...) (pthread_testcancel(), tmpnam(__VA_ARGS__))
#define ttyname(...) (pthread_testcancel(), ttyname(__VA_ARGS__))
#define ttyname_r(...) (pthread_testcancel(), ttyname_r(__VA_ARGS__))
#define tzset(...) (pthread_testcancel(), tzset(__VA_ARGS__))
#define ungetc(...) (pthread_testcancel(), ungetc(__VA_ARGS__))
#define ungetwc(...) (pthread_testcancel(), ungetwc(__VA_ARGS__))
#define unlink(...) (pthread_testcancel(), unlink(__VA_ARGS__))
#define vfprintf(...) (pthread_testcancel(), vfprintf(__VA_ARGS__))
#define vfwprintf(...) (pthread_testcancel(), vfwprintf(__VA_ARGS__))
#define vprintf(...) (pthread_testcancel(), vprintf(__VA_ARGS__))
#define vwprintf(...) (pthread_testcancel(), vwprintf(__VA_ARGS__))
#define wcsftime(...) (pthread_testcancel(), wcsftime(__VA_ARGS__))
#define wordexp(...) (pthread_testcancel(), wordexp(__VA_ARGS__))
#define wprintf(...) (pthread_testcancel(), wprintf(__VA_ARGS__))
#define wscanf(...) (pthread_testcancel(), wscanf(__VA_ARGS__))
#endif
/* We deal here with a gcc issue for posix threading on Windows.
We would need to change here gcc's gthr-posix.h header, but this
got rejected. So we deal it within this header. */
#ifdef _GTHREAD_USE_MUTEX_INIT_FUNC
#undef _GTHREAD_USE_MUTEX_INIT_FUNC
#endif
#define _GTHREAD_USE_MUTEX_INIT_FUNC 1
#ifdef __cplusplus
}
#endif
#endif /* WIN_PTHREADS_H */

86
include/pthread_compat.h Normal file
View File

@ -0,0 +1,86 @@
/*
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.
*/
/*
* Parts of this library are derived by:
*
* Posix Threads library for Microsoft Windows
*
* Use at own risk, there is no implied warranty to this code.
* It uses undocumented features of Microsoft Windows that can change
* at any time in the future.
*
* (C) 2010 Lockless Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* * 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.
* * Neither the name of Lockless Inc. 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AN
* 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 COPYRIGHT HOLDER 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 WIN_PTHREADS_PTHREAD_COMPAT_H
#define WIN_PTHREADS_PTHREAD_COMPAT_H
#ifdef __GNUC__
#define WINPTHREADS_INLINE inline
#define WINPTHREADS_ATTRIBUTE(X) __attribute__(X)
#define WINPTHREADS_SECTION(X) __section__(X)
#elif _MSC_VER
#include "pthread_time.h"
#ifdef _WIN64
typedef __int64 pid_t;
#else
typedef int pid_t;
#endif
typedef int clockid_t;
#define WINPTHREADS_INLINE __inline
#define WINPTHREADS_ATTRIBUTE(X) __declspec X
#define WINPTHREADS_SECTION(X) allocate(X)
#endif
#endif

29
include/pthread_signal.h Normal file
View File

@ -0,0 +1,29 @@
/*
Copyright (c) 2013-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_SIGNAL_H
#define WIN_PTHREADS_SIGNAL_H
/* Windows has rudimentary signals support. */
#define pthread_sigmask(H, S1, S2) 0
#endif /* WIN_PTHREADS_SIGNAL_H */

102
include/pthread_time.h Normal file
View File

@ -0,0 +1,102 @@
/*
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 <sys/timeb.h>
#ifndef WIN_PTHREADS_TIME_H
#define WIN_PTHREADS_TIME_H
/* Posix timers are supported */
#ifndef _POSIX_TIMERS
#define _POSIX_TIMERS 200809L
#endif
/* Monotonic clocks are available. */
#ifndef _POSIX_MONOTONIC_CLOCK
#define _POSIX_MONOTONIC_CLOCK 200809L
#endif
/* CPU-time clocks are available. */
#ifndef _POSIX_CPUTIME
#define _POSIX_CPUTIME 200809L
#endif
/* Clock support in threads are available. */
#ifndef _POSIX_THREAD_CPUTIME
#define _POSIX_THREAD_CPUTIME 200809L
#endif
#ifndef __clockid_t_defined
typedef int clockid_t;
#define __clockid_t_defined 1
#endif /* __clockid_t_defined */
#ifndef TIMER_ABSTIME
#define TIMER_ABSTIME 1
#endif
#ifndef CLOCK_REALTIME
#define CLOCK_REALTIME 0
#endif
#ifndef CLOCK_MONOTONIC
#define CLOCK_MONOTONIC 1
#endif
#ifndef CLOCK_PROCESS_CPUTIME_ID
#define CLOCK_PROCESS_CPUTIME_ID 2
#endif
#ifndef CLOCK_THREAD_CPUTIME_ID
#define CLOCK_THREAD_CPUTIME_ID 3
#endif
#ifndef CLOCK_REALTIME_COARSE
#define CLOCK_REALTIME_COARSE 4
#endif
#ifdef __cplusplus
extern "C" {
#endif
/* Make sure we provide default for WINPTHREAD_API, if not defined. */
#pragma push_macro("WINPTHREAD_API")
#ifndef WINPTHREAD_API
#define WINPTHREAD_API
#endif
/* These should really be dllimport'ed if using winpthread dll */
WINPTHREAD_API int __cdecl nanosleep(const struct timespec *request, struct timespec *remain);
WINPTHREAD_API int __cdecl clock_nanosleep(clockid_t clock_id, int flags, const struct timespec *request, struct timespec *remain);
WINPTHREAD_API int __cdecl clock_getres(clockid_t clock_id, struct timespec *res);
WINPTHREAD_API int __cdecl clock_gettime(clockid_t clock_id, struct timespec *tp);
WINPTHREAD_API int __cdecl clock_settime(clockid_t clock_id, const struct timespec *tp);
#pragma pop_macro("WINPTHREAD_API")
#ifdef __cplusplus
}
#endif
#endif /* WIN_PTHREADS_TIME_H */

192
include/pthread_unistd.h Normal file
View File

@ -0,0 +1,192 @@
/*
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_UNISTD_H
#define WIN_PTHREADS_UNISTD_H
/* Set defines described by the POSIX Threads Extension (1003.1c-1995) */
/* _SC_THREADS
Basic support for POSIX threads is available. The functions
pthread_atfork(),
pthread_attr_destroy(),
pthread_attr_getdetachstate(),
pthread_attr_getschedparam(),
pthread_attr_init(),
pthread_attr_setdetachstate(),
pthread_attr_setschedparam(),
pthread_cancel(),
pthread_cleanup_push(),
pthread_cleanup_pop(),
pthread_cond_broadcast(),
pthread_cond_destroy(),
pthread_cond_init(),
pthread_cond_signal(),
pthread_cond_timedwait(),
pthread_cond_wait(),
pthread_condattr_destroy(),
pthread_condattr_init(),
pthread_create(),
pthread_detach(),
pthread_equal(),
pthread_exit(),
pthread_getspecific(),
pthread_join(,
pthread_key_create(),
pthread_key_delete(),
pthread_mutex_destroy(),
pthread_mutex_init(),
pthread_mutex_lock(),
pthread_mutex_trylock(),
pthread_mutex_unlock(),
pthread_mutexattr_destroy(),
pthread_mutexattr_init(),
pthread_once(),
pthread_rwlock_destroy(),
pthread_rwlock_init(),
pthread_rwlock_rdlock(),
pthread_rwlock_tryrdlock(),
pthread_rwlock_trywrlock(),
pthread_rwlock_unlock(),
pthread_rwlock_wrlock(),
pthread_rwlockattr_destroy(),
pthread_rwlockattr_init(),
pthread_self(),
pthread_setcancelstate(),
pthread_setcanceltype(),
pthread_setspecific(),
pthread_testcancel()
are present. */
#undef _POSIX_THREADS
#define _POSIX_THREADS 200112L
/* _SC_READER_WRITER_LOCKS
This option implies the _POSIX_THREADS option. Conversely, under
POSIX 1003.1-2001 the _POSIX_THREADS option implies this option.
The functions
pthread_rwlock_destroy(),
pthread_rwlock_init(),
pthread_rwlock_rdlock(),
pthread_rwlock_tryrdlock(),
pthread_rwlock_trywrlock(),
pthread_rwlock_unlock(),
pthread_rwlock_wrlock(),
pthread_rwlockattr_destroy(),
pthread_rwlockattr_init()
are present.
*/
#undef _POSIX_READER_WRITER_LOCKS
#define _POSIX_READER_WRITER_LOCKS 200112L
/* _SC_SPIN_LOCKS
This option implies the _POSIX_THREADS and _POSIX_THREAD_SAFE_FUNCTIONS
options. The functions
pthread_spin_destroy(),
pthread_spin_init(),
pthread_spin_lock(),
pthread_spin_trylock(),
pthread_spin_unlock()
are present. */
#undef _POSIX_SPIN_LOCKS
#define _POSIX_SPIN_LOCKS 200112L
/* _SC_BARRIERS
This option implies the _POSIX_THREADS and _POSIX_THREAD_SAFE_FUNCTIONS
options. The functions
pthread_barrier_destroy(),
pthread_barrier_init(),
pthread_barrier_wait(),
pthread_barrierattr_destroy(),
pthread_barrierattr_init()
are present.
*/
#undef _POSIX_BARRIERS
#define _POSIX_BARRIERS 200112L
/* _SC_TIMEOUTS
The functions
mq_timedreceive(), - not supported
mq_timedsend(), - not supported
posix_trace_timedgetnext_event(), - not supported
pthread_mutex_timedlock(),
pthread_rwlock_timedrdlock(),
pthread_rwlock_timedwrlock(),
sem_timedwait(),
are present. */
#undef _POSIX_TIMEOUTS
#define _POSIX_TIMEOUTS 200112L
/* _SC_TIMERS - not supported
The functions
clock_getres(),
clock_gettime(),
clock_settime(),
nanosleep(),
timer_create(),
timer_delete(),
timer_gettime(),
timer_getoverrun(),
timer_settime()
are present. */
/* #undef _POSIX_TIMERS */
/* _SC_CLOCK_SELECTION
This option implies the _POSIX_TIMERS option. The functions
pthread_condattr_getclock(),
pthread_condattr_setclock(),
clock_nanosleep()
are present.
*/
#undef _POSIX_CLOCK_SELECTION
#define _POSIX_CLOCK_SELECTION 200112
/* _SC_SEMAPHORES
The include file <semaphore.h> is present. The functions
sem_close(),
sem_destroy(),
sem_getvalue(),
sem_init(),
sem_open(),
sem_post(),
sem_trywait(),
sem_unlink(),
sem_wait()
are present. */
#undef _POSIX_SEMAPHORES
#define _POSIX_SEMAPHORES 200112
#endif /* WIN_PTHREADS_UNISTD_H */

83
include/sched.h Normal file
View File

@ -0,0 +1,83 @@
/*
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 <stddef.h>
#include <errno.h>
#include <sys/types.h>
#include <process.h>
#include <limits.h>
#include <signal.h>
#include <sys/timeb.h>
#ifndef WIN_PTHREADS_SCHED_H
#define WIN_PTHREADS_SCHED_H
#ifndef SCHED_OTHER
/* Some POSIX realtime extensions, mostly stubbed */
#define SCHED_OTHER 0
#define SCHED_FIFO 1
#define SCHED_RR 2
#define SCHED_MIN SCHED_OTHER
#define SCHED_MAX SCHED_RR
struct sched_param {
int sched_priority;
};
#ifdef __cplusplus
extern "C" {
#endif
#if defined(IN_WINPTHREAD)
# if defined(DLL_EXPORT) && !defined(WINPTHREAD_EXPORT_ALL_DEBUG)
# define WINPTHREAD_SCHED_API __declspec(dllexport) /* building the DLL */
# else
# define WINPTHREAD_SCHED_API /* building the static library */
# endif
#else
# if defined(WINPTHREADS_USE_DLLIMPORT)
# define WINPTHREAD_SCHED_API __declspec(dllimport) /* user wants explicit `dllimport` */
# else
# define WINPTHREAD_SCHED_API /* the default; auto imported in case of DLL */
# endif
#endif
WINPTHREAD_SCHED_API int sched_yield(void);
WINPTHREAD_SCHED_API int sched_get_priority_min(int pol);
WINPTHREAD_SCHED_API int sched_get_priority_max(int pol);
WINPTHREAD_SCHED_API int sched_getscheduler(pid_t pid);
WINPTHREAD_SCHED_API int sched_setscheduler(pid_t pid, int pol, const struct sched_param *param);
#ifdef __cplusplus
}
#endif
#endif
#ifndef sched_rr_get_interval
#define sched_rr_get_interval(_p, _i) \
( errno = ENOTSUP, (int) -1 )
#endif
#endif /* WIN_PTHREADS_SCHED_H */

85
include/semaphore.h Normal file
View File

@ -0,0 +1,85 @@
/*
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_SEMAPHORE_H
#define WIN_PTHREADS_SEMAPHORE_H
#ifdef __cplusplus
extern "C" {
#endif
#if defined(IN_WINPTHREAD)
# if defined(DLL_EXPORT) && !defined(WINPTHREAD_EXPORT_ALL_DEBUG)
# define WINPTHREAD_SEMA_API __declspec(dllexport) /* building the DLL */
# else
# define WINPTHREAD_SEMA_API /* building the static library */
# endif
#else
# if defined(WINPTHREADS_USE_DLLIMPORT)
# define WINPTHREAD_SEMA_API __declspec(dllimport) /* user wants explicit `dllimport` */
# else
# define WINPTHREAD_SEMA_API /* the default; auto imported in case of DLL */
# endif
#endif
/* Set this to 0 to disable it */
#define USE_SEM_CriticalSection_SpinCount 100
#define SEM_VALUE_MAX INT_MAX
#ifndef _MODE_T_
#define _MODE_T_
typedef unsigned short mode_t;
#endif
typedef void *sem_t;
#define SEM_FAILED NULL
WINPTHREAD_SEMA_API int sem_init(sem_t * sem, int pshared, unsigned int value);
WINPTHREAD_SEMA_API int sem_destroy(sem_t *sem);
WINPTHREAD_SEMA_API int sem_trywait(sem_t *sem);
WINPTHREAD_SEMA_API int sem_wait(sem_t *sem);
WINPTHREAD_SEMA_API int sem_timedwait(sem_t * sem, const struct timespec *t);
WINPTHREAD_SEMA_API int sem_post(sem_t *sem);
WINPTHREAD_SEMA_API int sem_post_multiple(sem_t *sem, int count);
/* yes, it returns a semaphore (or SEM_FAILED) */
WINPTHREAD_SEMA_API sem_t * sem_open(const char * name, int oflag, mode_t mode, unsigned int value);
WINPTHREAD_SEMA_API int sem_close(sem_t * sem);
WINPTHREAD_SEMA_API int sem_unlink(const char * name);
WINPTHREAD_SEMA_API int sem_getvalue(sem_t * sem, int * sval);
#ifdef __cplusplus
}
#endif
#endif /* WIN_PTHREADS_SEMAPHORE_H */

246
src/barrier.c Normal file
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;
}

52
src/barrier.h Normal file
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

257
src/clock.c Normal file
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
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;
}

63
src/cond.h Normal file
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,90 @@
/* Implementation for gcc's internal stack-allocation routines. */
#if defined(__i386__) || defined(__x86_64__)
.global ___chkstk
.global __alloca
.global ___chkstk_ms
___chkstk_ms:
#ifdef _WIN64
pushq %rax
pushq %rcx
cmpq $0x1000, %rax
leaq 24(%rsp), %rcx
jb .Lchkstk_ms_end
.Lchkstk_ms_loop:
subq $0x1000, %rcx
subq $0x1000, %rax
orq $0x0, (%rcx)
cmpq $0x1000, %rax
ja .Lchkstk_ms_loop
.Lchkstk_ms_end:
subq %rax, %rcx
orq $0x0, (%rcx)
popq %rcx
popq %rax
ret
#else
pushl %eax
pushl %ecx
cmpl $0x1000, %eax
leal 12(%esp), %ecx
jb chkstk_ms_end
chkstk_ms_loop:
subl $0x1000, %ecx
subl $0x1000, %eax
orl $0x0, (%ecx)
cmpl $0x1000, %eax
ja chkstk_ms_loop
chkstk_ms_end:
subl %eax, %ecx
orl $0x0, (%ecx)
popl %ecx
popl %eax
ret
#endif
#ifdef _WIN64
__alloca:
movq %rcx, %rax
.align 4
___chkstk:
popq %r11
movq %rsp, %r10
cmpq $0x1000, %rax
jb .Lchkstk_end
.Lchkstk_loop:
subq $0x1000, %r10
subq $0x1000, %rax
orl $0x0, (%r10)
cmpq $0x1000, %rax
ja .Lchkstk_loop
.Lchkstk_end:
subq %rax, %r10
movq %rsp, %rax
orl $0x0, (%r10)
movq %r10, %rsp
pushq %r11
ret
#else
___chkstk:
__alloca:
pushl %ecx
leal 8(%esp), %ecx
cmpl $0x1000, %eax /* > 4k ?*/
jb chkstk_end
chkstk_loop:
subl $0x1000, %ecx
subl $0x1000, %eax
orl $0x0, (%ecx)
cmpl $0x1000, %eax
ja chkstk_loop
chkstk_end:
subl %eax, %ecx
orl $0x0, (%ecx)
movl %esp, %eax
movl %ecx, %esp
movl (%eax), %ecx
pushl 4(%eax)
ret
#endif
#endif

586
src/libgcc/dll_math.c Normal file
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
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
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

381
src/mutex.c Normal file
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;
}

71
src/nanosleep.c Normal file
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;
}

34
src/ref.c Normal file
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"

29
src/ref.h Normal file
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

537
src/rwlock.c Normal file
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;
}

49
src/rwlock.h Normal file
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

218
src/sched.c Normal file
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
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;
}

40
src/sem.h Normal file
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 */

74
src/spinlock.c Normal file
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;
}

1914
src/thread.c Normal file

File diff suppressed because it is too large Load Diff

79
src/thread.h Normal file
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

66
src/version.rc Normal file
View File

@ -0,0 +1,66 @@
/*
Copyright (c) 2011 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 <winver.h>
#include "wpth_ver.h"
#if defined(__MINGW64__)
# define WPTH_VERSIONINFO_COMMENT "GNU C build -- MinGW-w64 64-bit\0"
# define WPTH_VERSIONINFO_NAME "WinPthreadGC\0"
#elif defined(__MINGW32__)
# define WPTH_VERSIONINFO_COMMENT "GNU C build -- MinGW-w64 32-bit\0"
# define WPTH_VERSIONINFO_NAME "WinPthreadGC\0"
#else
# define WPTH_VERSIONINFO_COMMENT "MSVC build\0"
# define WPTH_VERSIONINFO_NAME "WinPthreadMS\0"
#endif
VS_VERSION_INFO VERSIONINFO
FILEVERSION WPTH_VERSION
PRODUCTVERSION WPTH_VERSION
FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
FILEFLAGS 0
FILEOS VOS__WINDOWS32
FILETYPE VFT_DLL
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "040904b0"
BEGIN
VALUE "FileDescription", "POSIX WinThreads for Windows\0"
VALUE "ProductVersion", WPTH_VERSION_STRING
VALUE "FileVersion", WPTH_VERSION_STRING
VALUE "InternalName", WPTH_VERSIONINFO_NAME
VALUE "OriginalFilename", WPTH_VERSIONINFO_NAME
VALUE "CompanyName", "MinGW-W64 Project. All rights reserved.\0"
VALUE "LegalCopyright", "Copyright (C) MinGW-W64 Project Members 2010-2023\0"
VALUE "Licence", "MIT AND BSD-3-Clause\0"
VALUE "Info", "https://www.mingw-w64.org/\0"
VALUE "Comment", WPTH_VERSIONINFO_COMMENT
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x409, 1200
END
END

27
src/winpthread_internal.h Normal file
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*/

29
src/wpth_ver.h Normal file
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