├── .gitignore ├── Makefile ├── README.md ├── default.mk ├── extra ├── crtfix.c ├── int64.c ├── lockex.c └── memory.c ├── include ├── lockex.h ├── pthread.h ├── pthread_compat.h ├── pthread_signal.h ├── pthread_time.h ├── pthread_unistd.h ├── sched.h └── semaphore.h ├── licence.txt └── src ├── barrier.c ├── barrier.h ├── clock.c ├── cond.c ├── cond.h ├── libgcc ├── dll_dependency.S └── dll_math.c ├── misc.c ├── misc.h ├── mutex.c ├── mutex.h ├── nanosleep.c ├── ref.c ├── ref.h ├── rwlock.c ├── rwlock.h ├── sched.c ├── sem.c ├── sem.h ├── spinlock.c ├── thread.c ├── thread.h ├── tryentercriticalsection.c ├── version.rc ├── winpthread_internal.h └── wpth_ver.h /.gitignore: -------------------------------------------------------------------------------- 1 | # syncthing 2 | /.stfolder/ 3 | /.stignore 4 | 5 | # generated and temporary files 6 | *.o 7 | *.bak 8 | *.tmp 9 | *.gen 10 | *.exe 11 | *.a 12 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | 2 | ifeq (,$(wildcard config.mk)) 3 | ifeq (,$(wildcard ../pthread.mk)) 4 | CONFIG=default.mk 5 | else 6 | CONFIG=../pthread.mk 7 | endif 8 | else 9 | CONFIG=config.mk 10 | endif 11 | 12 | $(info Using config: $(CONFIG)) 13 | 14 | include $(CONFIG) 15 | 16 | all: winpthreads_target 17 | .PHONY: all clean winpthreads_target 18 | 19 | DEPS = Makefile $(CONFIG) 20 | 21 | ifdef MSC 22 | # this is only for mingw 23 | OBJ := .obj 24 | else 25 | OBJ := .o 26 | LIBSUFFIX := .a 27 | LIBPREFIX := lib 28 | 29 | INCLUDE = -Iinclude -I. 30 | 31 | DEFS = -DHAVE_CONFIG_H -DIN_WINPTHREAD -Wall -DWIN32_LEAN_AND_MEAN 32 | 33 | ifdef NEW_ALLOC 34 | DEFS += -DNEW_ALLOC 35 | endif 36 | 37 | ifdef DEFAULT_HEAP 38 | DEFS += -DDEFAULT_HEAP 39 | endif 40 | 41 | ifdef MEM_ALIGN 42 | DEFS += -DMEM_ALIGN=$(MEM_ALIGN) 43 | endif 44 | 45 | ifdef MEM_COPY_SSE2 46 | DEFS += -DMEM_COPY_SSE2 47 | endif 48 | 49 | ifdef CS_NATIVE_ONLY 50 | DEFS += -DCS_NATIVE_ONLY 51 | endif 52 | 53 | ifdef NO_STATIC_TLS_REMOVE 54 | DEFS += -DNO_STATIC_TLS_REMOVE 55 | endif 56 | 57 | ifdef SPEED 58 | CFLAGS = -std=gnu99 -O3 -fno-exceptions $(PT_TUNE) $(INCLUDE) -DNDEBUG $(DEFS) 59 | LDLAGS = -fno-exceptions 60 | else 61 | ifdef DEBUG 62 | CFLAGS = -std=gnu99 -O0 $(INCLUDE) $(PT_TUNE) -DDEBUG -DWINPTHREAD_DBG=1 $(DEFS) 63 | LDLAGS = 64 | else 65 | CFLAGS = -std=gnu99 -O0 -fno-exceptions $(PT_TUNE) $(INCLUDE) -DNDEBUG $(DEFS) 66 | LDLAGS = -fno-exceptions 67 | endif 68 | endif 69 | 70 | %.c.o: %.c $(DEPS) 71 | $(CC) $(CFLAGS) -c -o $@ $< 72 | 73 | LIBSTATIC = ar rcs -o $@ 74 | endif 75 | 76 | winpthreads_OBJS = \ 77 | src/barrier.c$(OBJ) \ 78 | src/cond.c$(OBJ) \ 79 | src/misc.c$(OBJ) \ 80 | src/mutex.c$(OBJ) \ 81 | src/rwlock.c$(OBJ) \ 82 | src/spinlock.c$(OBJ) \ 83 | src/thread.c$(OBJ) \ 84 | src/ref.c$(OBJ) \ 85 | src/sem.c$(OBJ) \ 86 | src/sched.c$(OBJ) \ 87 | src/clock.c$(OBJ) \ 88 | src/nanosleep.c$(OBJ) \ 89 | src/tryentercriticalsection.c$(OBJ) \ 90 | extra/memory.c$(OBJ) \ 91 | extra/int64.c$(OBJ) \ 92 | extra/lockex.c$(OBJ) 93 | 94 | 95 | winpthreads_target: $(LIBPREFIX)pthread$(LIBSUFFIX) crtfix$(OBJ) 96 | 97 | crtfix$(OBJ): extra/crtfix.c 98 | $(CC) $(CFLAGS) -c -o $@ $< 99 | 100 | $(LIBPREFIX)pthread$(LIBSUFFIX): $(winpthreads_OBJS) 101 | -$(RM) $@ 102 | $(LIBSTATIC) $(winpthreads_OBJS) 103 | 104 | ifdef OBJ 105 | clean: 106 | -$(RM) $(LIBPREFIX)pthread$(LIBSUFFIX) 107 | -$(RM) $(winpthreads_OBJS) 108 | -$(RM) crtfix$(OBJ) 109 | else 110 | clean: 111 | 112 | endif 113 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # pthread (winpthreads/libpthread) replacement for Windows 9x/NT 2 | 3 | This is mingw binary replacement of pthread library, so you can compile programs for old Windows with newest msys2/mingw-w64. 4 | 5 | ## Usage 6 | 7 | Compile (make) and add link flags to your program: 8 | 9 | ```/crtfix.o -static -L -lpthread``` 10 | 11 | `-lpthread` should be at first place, so GCC use symbols from this lib in first place. 12 | 13 | ## Configuration 14 | 15 | Copy `default.mk` to `config.mk`. See this file for more information. 16 | 17 | ## Source 18 | 19 | Original sources is from older mingw release (winpthreads), `TryEnterCriticalSection` code is from KernelEx code. 20 | -------------------------------------------------------------------------------- /default.mk: -------------------------------------------------------------------------------- 1 | # compiler names 2 | CC = $(PREFIX)gcc 3 | LD = $(PREFIX)gcc 4 | 5 | # optimize for speed 6 | SPEED=1 7 | 8 | # replace default MSVCRT.dll default malloc/calloc/realloc/free 9 | # other related functions 10 | NEW_ALLOC=1 11 | 12 | # use program default heap instead of creating new ones 13 | DEFAULT_HEAP=1 14 | 15 | # allign malloced return memory to specific allign (must be power of 2) 16 | # 8 is highly recomended, 16 you can use directly with SSE, 32 for AVX 17 | #MEM_ALIGN=16 18 | 19 | # allow enable faster realloc copy, or calloc zeroing accelerated 20 | # by SSE, if your OS/HW allows it, enable in runtime by crt_enable_sse2() 21 | # function. 22 | # TIP: You can call crt_sse2_is_safe() and check if SSE2 is safe 23 | #MEM_COPY_SSE2=1 24 | 25 | # disable Windows 98/Me code for TryEnterCriticalSection and call TryEnterCritical instead 26 | #CS_NATIVE_ONLY=1 27 | 28 | # disable static TLS remove if it break something important 29 | #NO_STATIC_TLS_REMOVE=1 30 | 31 | # Pass exta CFLAGS, please don't use -march= for old mingw, SSE runtime 32 | # is broken here! 33 | #TUNE=-march=core2 34 | -------------------------------------------------------------------------------- /extra/crtfix.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | typedef BOOL (WINAPI *IsProcessorFeaturePresent_func)(DWORD ProcessorFeature); 6 | static IsProcessorFeaturePresent_func IsProcessorFeaturePresent_proc = NULL; 7 | static BOOL IsProcessorFeaturePresent_set = FALSE; 8 | 9 | BOOL WINAPI IsProcessorFeaturePresent95(DWORD ProcessorFeature) 10 | { 11 | HMODULE hK = NULL; 12 | 13 | if(!IsProcessorFeaturePresent_set) 14 | { 15 | hK = GetModuleHandleA("kernel32.dll"); 16 | if(hK) 17 | { 18 | IsProcessorFeaturePresent_proc = 19 | (IsProcessorFeaturePresent_func)GetProcAddress(hK, "IsProcessorFeaturePresent"); 20 | } 21 | IsProcessorFeaturePresent_set = TRUE; 22 | } 23 | 24 | if(IsProcessorFeaturePresent_proc) 25 | { 26 | return IsProcessorFeaturePresent_proc(ProcessorFeature); 27 | } 28 | 29 | return FALSE; 30 | } 31 | 32 | BOOL WINAPI IsProcessorFeaturePresent(DWORD ProcessorFeature) 33 | { 34 | return IsProcessorFeaturePresent95(ProcessorFeature); 35 | } 36 | 37 | /* Don't use this on mingw 4.x.x */ 38 | #if __GNUC__ > 4 39 | 40 | void __fastfail(unsigned int code); 41 | 42 | void __cdecl __attribute__((__noreturn__)) __chk_fail(void) { 43 | if (IsProcessorFeaturePresent95(PF_FASTFAIL_AVAILABLE)) { 44 | __fastfail(FAST_FAIL_RANGE_CHECK_FAILURE); 45 | } else { 46 | TerminateProcess(GetCurrentProcess(), STATUS_STACK_BUFFER_OVERRUN); 47 | __builtin_unreachable(); 48 | } 49 | } 50 | 51 | #endif 52 | 53 | #ifdef NEW_ALLOC 54 | 55 | /* replace CRT with */ 56 | 57 | #define _EXIT_LOCK1 13 /* lock #1 for exit code */ 58 | 59 | #define ONEXITTBLINCR 4 60 | 61 | #ifndef _MT 62 | #define _MT 63 | #endif 64 | 65 | typedef void (__cdecl *_PVFV)(void); 66 | typedef int (__cdecl *_PIFV)(void); 67 | 68 | /* msvcrt imports */ 69 | void __cdecl _lock(int); 70 | void __cdecl _unlock(int); 71 | 72 | void _lockexit (void) 73 | { 74 | _lock(_EXIT_LOCK1); 75 | } 76 | 77 | void _unlockexit(void) 78 | { 79 | _unlock(_EXIT_LOCK1); 80 | } 81 | 82 | size_t _msize_int(void* ptr); 83 | 84 | _onexit_t __dllonexit (_onexit_t func, _PVFV ** pbegin, _PVFV ** pend) 85 | { 86 | _PVFV *p; 87 | unsigned oldsize; 88 | 89 | #ifdef _MT 90 | _lockexit(); /* lock the exit code */ 91 | #endif /* _MT */ 92 | 93 | /* 94 | * First, make sure the table has room for a new entry 95 | */ 96 | if ( (oldsize = _msize_int( *pbegin )) <= (unsigned)((char *)(*pend) - (char *)(*pbegin)) ) 97 | { 98 | /* 99 | * not enough room, try to grow the table 100 | */ 101 | if ( (p = (_PVFV *) realloc((*pbegin), oldsize + 102 | ONEXITTBLINCR * sizeof(_PVFV))) == NULL ) 103 | { 104 | /* 105 | * didn't work. don't do anything rash, just fail 106 | */ 107 | #ifdef _MT 108 | _unlockexit(); 109 | #endif /* _MT */ 110 | 111 | return NULL; 112 | } 113 | 114 | /* 115 | * update (*pend) and (*pbegin) 116 | */ 117 | (*pend) = p + ((*pend) - (*pbegin)); 118 | (*pbegin) = p; 119 | } 120 | 121 | /* 122 | * Put the new entry into the table and update the end-of-table 123 | * pointer. 124 | */ 125 | *((*pend)++) = (_PVFV)func; 126 | 127 | #ifdef _MT 128 | _unlockexit(); 129 | #endif /* _MT */ 130 | 131 | return func; 132 | 133 | } 134 | 135 | #if 0 136 | /* no in use yet */ 137 | void *_aligned_malloc9x(size_t size, size_t alignment); 138 | void *_aligned_realloc9x(void *memblock, size_t size, size_t alignment); 139 | void _aligned_free9x(void *memblock); 140 | 141 | __declspec(dllimport) void *_aligned_malloc(size_t size, size_t alignment) 142 | { 143 | return _aligned_malloc9x(size, alignment); 144 | } 145 | 146 | __declspec(dllimport) void *_aligned_realloc(void *memblock, size_t size, size_t alignment) 147 | { 148 | return _aligned_realloc9x(memblock, size, alignment); 149 | } 150 | 151 | __declspec(dllimport) void _aligned_free(void *memblock) 152 | { 153 | _aligned_free9x(memblock); 154 | } 155 | #endif 156 | 157 | #endif /* #ifdef NEW_ALLOC */ 158 | 159 | #ifndef NO_STATIC_TLS_REMOVE 160 | 161 | BOOL WINAPI __dyn_tls_init (HANDLE hDllHandle, DWORD dwReason, LPVOID lpreserved) 162 | { 163 | return TRUE; 164 | } 165 | 166 | const PIMAGE_TLS_CALLBACK __dyn_tls_init_callback = (const PIMAGE_TLS_CALLBACK) __dyn_tls_init; 167 | 168 | int __mingw_initltsdrot_force = 0; 169 | int __mingw_initltsdyn_force = 0; 170 | int __mingw_initltssuo_force = 0; 171 | int mingw_initltsdrot_force = 0; 172 | int mingw_initltsdyn_force = 0; 173 | int mingw_initltssuo_force = 0; 174 | 175 | #endif 176 | 177 | #include "int64.c" 178 | -------------------------------------------------------------------------------- /extra/int64.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | /* 9 | From: https://github.com/gcc-mirror/gcc/blob/master/libiberty/ 10 | */ 11 | 12 | #ifndef ERANGE 13 | #define ERANGE 34 14 | #endif 15 | 16 | uint64_t strtoull(const char *nptr, char **endptr, register int base) 17 | { 18 | register const char *s = nptr; 19 | register uint64_t acc; 20 | register int c; 21 | register uint64_t cutoff; 22 | register int neg = 0, any, cutlim; 23 | 24 | /* 25 | * See strtol for comments as to the logic used. 26 | */ 27 | do { 28 | c = *s++; 29 | } while (isspace(c)); 30 | if (c == '-') { 31 | neg = 1; 32 | c = *s++; 33 | } else if (c == '+') 34 | c = *s++; 35 | if ((base == 0 || base == 16) && 36 | c == '0' && (*s == 'x' || *s == 'X')) { 37 | c = s[1]; 38 | s += 2; 39 | base = 16; 40 | } 41 | if (base == 0) 42 | base = c == '0' ? 8 : 10; 43 | cutoff = (uint64_t)ULLONG_MAX / (uint64_t)base; 44 | cutlim = (uint64_t)ULLONG_MAX % (uint64_t)base; 45 | for (acc = 0, any = 0;; c = *s++) { 46 | if (isdigit(c)) 47 | c -= '0'; 48 | else if (isalpha(c)) 49 | c -= isupper(c) ? 'A' - 10 : 'a' - 10; 50 | else 51 | break; 52 | if (c >= base) 53 | break; 54 | if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim)) 55 | any = -1; 56 | else { 57 | any = 1; 58 | acc *= base; 59 | acc += c; 60 | } 61 | } 62 | if (any < 0) { 63 | acc = ULLONG_MAX; 64 | errno = ERANGE; 65 | } else if (neg) 66 | acc = -acc; 67 | if (endptr != 0) 68 | *endptr = (char *) (any ? s - 1 : nptr); 69 | return (acc); 70 | } 71 | 72 | int64_t strtoll(const char *nptr, char **endptr, register int base) 73 | { 74 | register const char *s = nptr; 75 | register uint64_t acc; 76 | register int c; 77 | register uint64_t cutoff; 78 | register int neg = 0, any, cutlim; 79 | 80 | /* 81 | * Skip white space and pick up leading +/- sign if any. 82 | * If base is 0, allow 0x for hex and 0 for octal, else 83 | * assume decimal; if base is already 16, allow 0x. 84 | */ 85 | do { 86 | c = *s++; 87 | } while (isspace(c)); 88 | if (c == '-') { 89 | neg = 1; 90 | c = *s++; 91 | } else if (c == '+') 92 | c = *s++; 93 | if ((base == 0 || base == 16) && 94 | c == '0' && (*s == 'x' || *s == 'X')) { 95 | c = s[1]; 96 | s += 2; 97 | base = 16; 98 | } 99 | if (base == 0) 100 | base = c == '0' ? 8 : 10; 101 | 102 | /* 103 | * Compute the cutoff value between legal numbers and illegal 104 | * numbers. That is the largest legal value, divided by the 105 | * base. An input number that is greater than this value, if 106 | * followed by a legal input character, is too big. One that 107 | * is equal to this value may be valid or not; the limit 108 | * between valid and invalid numbers is then based on the last 109 | * digit. For instance, if the range for longs is 110 | * [-2147483648..2147483647] and the input base is 10, 111 | * cutoff will be set to 214748364 and cutlim to either 112 | * 7 (neg==0) or 8 (neg==1), meaning that if we have accumulated 113 | * a value > 214748364, or equal but the next digit is > 7 (or 8), 114 | * the number is too big, and we will return a range error. 115 | * 116 | * Set any if any `digits' consumed; make it negative to indicate 117 | * overflow. 118 | */ 119 | cutoff = neg ? -(uint64_t)LLONG_MIN : LLONG_MAX; 120 | cutlim = cutoff % (uint64_t)base; 121 | cutoff /= (uint64_t)base; 122 | for (acc = 0, any = 0;; c = *s++) { 123 | if (isdigit(c)) 124 | c -= '0'; 125 | else if (isalpha(c)) 126 | c -= isupper(c) ? 'A' - 10 : 'a' - 10; 127 | else 128 | break; 129 | if (c >= base) 130 | break; 131 | if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim)) 132 | any = -1; 133 | else { 134 | any = 1; 135 | acc *= base; 136 | acc += c; 137 | } 138 | } 139 | if (any < 0) { 140 | acc = neg ? LLONG_MIN : LLONG_MAX; 141 | errno = ERANGE; 142 | } else if (neg) 143 | acc = -acc; 144 | if (endptr != 0) 145 | *endptr = (char *) (any ? s - 1 : nptr); 146 | return (acc); 147 | } 148 | -------------------------------------------------------------------------------- /extra/lockex.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | BOOL WINAPI TryEnterCriticalSection9x(CRITICAL_SECTION* cs); 10 | 11 | __declspec(dllimport) BOOL WINAPI TryEnterCriticalSection(LPCRITICAL_SECTION lpCriticalSection) 12 | { 13 | return TryEnterCriticalSection9x(lpCriticalSection); 14 | } 15 | 16 | static unsigned int crt_locks_num = 0; 17 | static CRITICAL_SECTION crt_locks[LOCK_TOTAL_MAX]; 18 | static int crt_locks_cnt[LOCK_TOTAL_MAX] = {0}; /* number of 'init' of individual locks */ 19 | 20 | void crt_locks_init(int count) 21 | { 22 | int i; 23 | int count_in = count+LOCK_INTERNAL_CNT; 24 | 25 | if(count_in > LOCK_TOTAL_MAX) 26 | { 27 | count_in = LOCK_TOTAL_MAX; 28 | } 29 | 30 | for(i = 0; i < count_in; i++) 31 | { 32 | if(crt_locks_cnt[i] <= 0) 33 | { 34 | crt_locks_cnt[i] = 0; 35 | InitializeCriticalSection(&crt_locks[i]); 36 | } 37 | 38 | crt_locks_cnt[i]++; 39 | } 40 | 41 | if(count_in > crt_locks_num) 42 | { 43 | crt_locks_num = count_in; 44 | } 45 | } 46 | 47 | void crt_locks_destroy() 48 | { 49 | int i; 50 | for(i = 0; i < crt_locks_num; i++) 51 | { 52 | if(--crt_locks_cnt[i] <= 0) 53 | { 54 | DeleteCriticalSection(&crt_locks[i]); 55 | } 56 | } 57 | } 58 | 59 | void crt_lock(int lock_no) 60 | { 61 | int lock_no_in = lock_no + LOCK_INTERNAL_CNT; 62 | if(lock_no_in < crt_locks_num) 63 | { 64 | EnterCriticalSection(&crt_locks[lock_no_in]); 65 | } 66 | } 67 | 68 | void crt_unlock(int lock_no) 69 | { 70 | int lock_no_in = lock_no + LOCK_INTERNAL_CNT; 71 | if(lock_no_in < crt_locks_num) 72 | { 73 | LeaveCriticalSection(&crt_locks[lock_no_in]); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /extra/memory.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | #include 10 | 11 | // include SSE2 intrinsics require some target switching 12 | #ifdef MEM_COPY_SSE2 13 | #pragma GCC push_options 14 | #pragma GCC target ("arch=core2") 15 | #include 16 | // restore the target selection 17 | #pragma GCC pop_options 18 | #endif 19 | 20 | #ifndef MEM_ALIGN 21 | #define MEM_ALIGN 16 22 | #endif 23 | 24 | #ifndef MEM_MIN_ALIGN 25 | #define MEM_MIN_ALIGN MEM_ALIGN 26 | #endif 27 | 28 | #if MEM_ALIGN != 4 && MEM_ALIGN != 8 && MEM_ALIGN != 16 && MEM_ALIGN != 32 && MEM_ALIGN != 64 && MEM_ALIGN != 128 29 | #error "Wrong memory aligment!" 30 | #endif 31 | 32 | #define MEM_R1 64 33 | #define MEM_R2 1024 34 | #define MEM_R3 8*1024 35 | #define MEM_R4 64*1024 36 | 37 | typedef void(*memcpy_func)(void *dst, void *src, size_t size); 38 | typedef void(*zeromem_func)(void *dst, size_t size); 39 | 40 | #define AROUND(_s, _a) _s = ((_s + _a - 1) & (~(size_t)(_a - 1))) 41 | 42 | #ifndef DEFAULT_HEAP 43 | static HANDLE glHeaps[4] = {NULL, NULL, NULL, NULL}; 44 | 45 | static HANDLE NewHeap() 46 | { 47 | SYSTEM_INFO si; 48 | GetSystemInfo(&si); 49 | 50 | return HeapCreate(0, si.dwPageSize*32, 0); 51 | } 52 | #endif 53 | 54 | typedef struct _memblk_t 55 | { 56 | HANDLE heap; 57 | uint8_t *heap_ptr; 58 | size_t mem_size; 59 | } memblk_t; 60 | 61 | static HANDLE GetHeap(size_t memsize) 62 | { 63 | #ifndef DEFAULT_HEAP 64 | int sel = 3; 65 | 66 | if(memsize < MEM_R2) 67 | { 68 | sel = 0; 69 | } 70 | else if(memsize < MEM_R3) 71 | { 72 | sel = 1; 73 | } 74 | else if(memsize < MEM_R4) 75 | { 76 | sel = 2; 77 | } 78 | 79 | if(glHeaps[sel] == NULL) 80 | { 81 | glHeaps[sel] = NewHeap(); 82 | } 83 | 84 | return glHeaps[sel]; 85 | #else 86 | return GetProcessHeap(); 87 | #endif 88 | } 89 | 90 | static void memcpy_c(void *dst, void *src, size_t size) 91 | { 92 | size_t bsize = size/4; 93 | 94 | uint32_t *psrc = src; 95 | uint32_t *pdst = dst; 96 | 97 | for (; bsize > 0; bsize--, psrc++, pdst++) 98 | { 99 | *pdst = *psrc; 100 | } 101 | } 102 | 103 | static void zeromem_c(void *dst, size_t size) 104 | { 105 | size_t bsize = size/4; 106 | 107 | uint32_t *pdst = dst; 108 | 109 | for (; bsize > 0; bsize--, pdst++) 110 | { 111 | *pdst = 0; 112 | } 113 | } 114 | 115 | static memcpy_func memcpy_fast = memcpy_c; 116 | static zeromem_func zeromem_fast = zeromem_c; 117 | 118 | #ifdef MEM_COPY_SSE2 119 | # pragma GCC push_options 120 | # if __GNUC__ > 4 121 | # pragma GCC target("sse2") 122 | # else 123 | # pragma GCC target ("arch=core2") 124 | # endif 125 | 126 | static void memcpy_sse2(void *dst, void *src, size_t size) 127 | { 128 | size_t bsize = size/16; 129 | 130 | __m128i *psrc = (__m128i*)src; 131 | __m128i *pdst = (__m128i*)dst; 132 | 133 | for (; bsize > 0; bsize--, psrc++, pdst++) 134 | { 135 | const __m128i t = _mm_load_si128(psrc); 136 | _mm_store_si128(pdst, t); 137 | //pdst* = *psrc; 138 | } 139 | } 140 | 141 | static void zeromem_sse2(void *dst, size_t size) 142 | { 143 | size_t bsize = size/16; 144 | __m128i t = _mm_setzero_si128(); 145 | __m128i *pdst = (__m128i*)dst; 146 | 147 | for (; bsize > 0; bsize--, pdst++) 148 | { 149 | _mm_store_si128(pdst, t); 150 | } 151 | } 152 | 153 | # pragma GCC pop_options 154 | #endif 155 | 156 | void crt_enable_sse2() 157 | { 158 | #ifdef MEM_COPY_SSE2 159 | # if MEM_ALIGN >= 16 160 | memcpy_fast = memcpy_sse2; 161 | zeromem_fast = zeromem_sse2; 162 | # endif 163 | #endif 164 | } 165 | 166 | typedef DWORD (WINAPI *GetVersionFunc)(void); 167 | 168 | static int windows_sse_support() 169 | { 170 | HANDLE h = GetModuleHandleA("kernel32.dll"); 171 | if(h) 172 | { 173 | GetVersionFunc GetVersionPtr = (GetVersionFunc)GetProcAddress(h, "GetVersion"); 174 | DWORD dwVersion = 0; 175 | DWORD dwMajorVersion = 0; 176 | DWORD dwMinorVersion = 0; 177 | 178 | if(GetVersionPtr == NULL) 179 | { 180 | /* windows >= 8.1 don't have this function */ 181 | return 3; 182 | } 183 | 184 | dwVersion = GetVersionPtr(); 185 | 186 | dwMajorVersion = (DWORD)(LOBYTE(LOWORD(dwVersion))); 187 | dwMinorVersion = (DWORD)(HIBYTE(LOWORD(dwVersion))); 188 | // 95 - 4.0 189 | // NT 4.0 - 4.0 190 | // 98 - 4.10 191 | // ME - 4.90 192 | // 2k - 5.0 193 | //printf("Version is %d.%d (%d)\n", dwMajorVersion, dwMinorVersion, dwBuild); 194 | 195 | if(dwMajorVersion >= 5) 196 | { 197 | return 1; 198 | } 199 | 200 | if(dwMajorVersion == 4) 201 | { 202 | if(dwMinorVersion >= 10) 203 | { 204 | return 1; 205 | } 206 | } 207 | 208 | return 0; 209 | } 210 | 211 | return 0; 212 | } 213 | 214 | int crt_sse2_is_safe() 215 | { 216 | if(windows_sse_support() != 0) 217 | { 218 | uint32_t ceax, cebx, cecx, cedx; 219 | 220 | if(__get_cpuid (1, &ceax, &cebx, &cecx, &cedx)) 221 | { 222 | if(cedx & (1 << 26)) // SSE2 support bit 223 | { 224 | return 1; 225 | } 226 | } 227 | } 228 | 229 | return 0; 230 | } 231 | 232 | static inline void *malloc_int(size_t size, int alignment) 233 | { 234 | size_t hsize; 235 | uint8_t *hptr; 236 | memblk_t *mem; 237 | uintptr_t p; 238 | HANDLE heap; 239 | 240 | hsize = size + sizeof(memblk_t) + alignment - 1; 241 | 242 | crt_lock(LOCK_INTERNAL_MEM); 243 | heap = GetHeap(size); 244 | 245 | hptr = HeapAlloc(heap, 0, hsize); 246 | if(hptr != NULL) 247 | { 248 | p = (uintptr_t)hptr; 249 | p += alignment - 1; 250 | p += sizeof(memblk_t); 251 | p &= ~((uintptr_t)(alignment - 1)); 252 | 253 | mem = ((memblk_t*)p)-1; 254 | mem->heap = heap; 255 | mem->heap_ptr = hptr; 256 | mem->mem_size = size; 257 | 258 | crt_unlock(LOCK_INTERNAL_MEM); 259 | return mem+1; 260 | } 261 | 262 | crt_unlock(LOCK_INTERNAL_MEM); 263 | return NULL; 264 | } 265 | 266 | static inline void *realloc_int(void *ptr, size_t new_size, size_t alignment) 267 | { 268 | memblk_t *mem; 269 | size_t hsize; 270 | void *tmp; 271 | 272 | if(new_size == 0 && ptr == NULL) 273 | { 274 | new_size = alignment; 275 | AROUND(new_size, alignment); 276 | return malloc_int(new_size, alignment); 277 | } 278 | else if(new_size == 0) 279 | { 280 | free(ptr); 281 | return NULL; 282 | } 283 | else if(ptr == NULL) 284 | { 285 | AROUND(new_size, alignment); 286 | return malloc_int(new_size, alignment); 287 | } 288 | 289 | AROUND(new_size, alignment); 290 | 291 | mem = ((memblk_t*)ptr)-1; 292 | if(new_size == mem->mem_size) 293 | { 294 | return ptr; 295 | } 296 | 297 | hsize = (uint8_t*)ptr - mem->heap_ptr + new_size; 298 | tmp = HeapReAlloc(mem->heap, HEAP_REALLOC_IN_PLACE_ONLY, mem->heap_ptr, hsize); 299 | 300 | if(tmp != NULL) 301 | { 302 | mem->mem_size = new_size; 303 | return ptr; 304 | } 305 | else 306 | { 307 | tmp = malloc_int(new_size, alignment); 308 | if(tmp) 309 | { 310 | memcpy_fast(tmp, ptr, mem->mem_size); 311 | free(ptr); 312 | 313 | return tmp; 314 | } 315 | } 316 | 317 | return NULL; 318 | } 319 | 320 | #ifdef NEW_ALLOC 321 | 322 | void *malloc(size_t size) 323 | { 324 | if(size == 0) 325 | { 326 | size = MEM_ALIGN; 327 | } 328 | AROUND(size, MEM_ALIGN); 329 | 330 | return malloc_int(size, MEM_ALIGN); 331 | } 332 | 333 | void *realloc(void *ptr, size_t new_size) 334 | { 335 | return realloc_int(ptr, new_size, MEM_ALIGN); 336 | } 337 | 338 | void *calloc(size_t num, size_t size) 339 | { 340 | size_t total = num*size; 341 | void *ptr; 342 | if(total == 0) 343 | { 344 | total = MEM_ALIGN; 345 | } 346 | AROUND(total, MEM_ALIGN); 347 | 348 | ptr = malloc_int(total, MEM_ALIGN); 349 | if(ptr != NULL) 350 | { 351 | zeromem_fast(ptr, total); 352 | } 353 | 354 | return ptr; 355 | } 356 | 357 | void free(void *ptr) 358 | { 359 | if(ptr != NULL) 360 | { 361 | memblk_t *mem = ((memblk_t*)ptr)-1; 362 | 363 | crt_lock(LOCK_INTERNAL_MEM); 364 | HeapFree(mem->heap, 0, mem->heap_ptr); 365 | crt_unlock(LOCK_INTERNAL_MEM); 366 | } 367 | } 368 | 369 | __declspec(dllimport) void* _expand(void* ptr, size_t new_size) 370 | { 371 | if(ptr != NULL) 372 | { 373 | size_t hsize; 374 | void *tmp; 375 | memblk_t *mem = ((memblk_t*)ptr)-1; 376 | 377 | hsize = (uint8_t*)ptr - mem->heap_ptr + new_size; 378 | 379 | crt_lock(LOCK_INTERNAL_MEM); 380 | tmp = HeapReAlloc(mem->heap, HEAP_REALLOC_IN_PLACE_ONLY, mem->heap_ptr, hsize); 381 | 382 | if(tmp) 383 | { 384 | mem->mem_size = new_size; 385 | crt_unlock(LOCK_INTERNAL_MEM); 386 | return ptr; 387 | } 388 | crt_unlock(LOCK_INTERNAL_MEM); 389 | } 390 | 391 | return NULL; 392 | //return HeapReAlloc(GetHeap(), HEAP_REALLOC_IN_PLACE_ONLY, ptr, new_size); 393 | } 394 | 395 | size_t _msize_int(void* ptr) 396 | { 397 | if(ptr != NULL) 398 | { 399 | //return HeapSize(GetHeap(), 0, ptr); 400 | memblk_t *mem = (memblk_t*)ptr; 401 | mem--; 402 | 403 | return mem->mem_size; 404 | } 405 | 406 | return 0; 407 | } 408 | 409 | __declspec(dllimport) size_t _msize(void* ptr) 410 | { 411 | return _msize_int(ptr); 412 | } 413 | 414 | char *strdup(const char *str1) 415 | { 416 | size_t len = strlen(str1); 417 | char *str2 = malloc(len+1); 418 | if(str2 != NULL) 419 | { 420 | memcpy(str2, str1, len+1); 421 | } 422 | 423 | return str2; 424 | } 425 | 426 | __declspec(dllimport) char *_strdup(const char *str1) 427 | { 428 | size_t len = strlen(str1); 429 | char *str2 = malloc(len+1); 430 | if(str2 != NULL) 431 | { 432 | memcpy(str2, str1, len+1); 433 | } 434 | 435 | return str2; 436 | } 437 | 438 | char *strndup(const char *str1, size_t size) 439 | { 440 | size_t len; 441 | for(len = 0; len < size; len++) 442 | { 443 | if(str1[len] == '\0') 444 | { 445 | break; 446 | } 447 | } 448 | 449 | if(size == 0 || len == 0) 450 | { 451 | return NULL; 452 | } 453 | 454 | char *str2 = malloc(len+1); 455 | if(str2 != NULL) 456 | { 457 | memcpy(str2, str1, len); 458 | str2[len] = '\0'; 459 | } 460 | return str2; 461 | } 462 | 463 | void *_aligned_malloc9x(size_t size, size_t alignment) 464 | { 465 | if(alignment < MEM_MIN_ALIGN) 466 | { 467 | alignment = MEM_MIN_ALIGN; 468 | } 469 | 470 | if(size == 0) 471 | { 472 | size = alignment; 473 | } 474 | AROUND(size, alignment); 475 | 476 | return malloc_int(size, alignment); 477 | } 478 | 479 | void *_aligned_realloc9x(void *memblock, size_t size, size_t alignment) 480 | { 481 | if(alignment < 4) 482 | { 483 | alignment = 4; 484 | } 485 | 486 | return realloc_int(memblock, size, alignment); 487 | } 488 | 489 | void _aligned_free9x(void *memblock) 490 | { 491 | free(memblock); 492 | } 493 | 494 | #endif /* NEW_ALLOC */ 495 | -------------------------------------------------------------------------------- /include/lockex.h: -------------------------------------------------------------------------------- 1 | #ifndef __9X__LOCKEX_H__INCLUDED__ 2 | #define __9X__LOCKEX_H__INCLUDED__ 3 | 4 | #define LOCK_INTERNAL_MEM -1 5 | #define LOCK_INTERNAL_CNT 1 6 | 7 | #define LOCK_TOTAL_MAX 32 8 | 9 | void crt_locks_init(int count); 10 | void crt_locks_destroy(); 11 | void crt_lock(int lock_no); 12 | void crt_unlock(int lock_no); 13 | 14 | #endif /* __9X__LOCKEX_H__INCLUDED__ */ 15 | -------------------------------------------------------------------------------- /include/pthread_compat.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2011 mingw-w64 project 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a 5 | copy of this software and associated documentation files (the "Software"), 6 | to deal in the Software without restriction, including without limitation 7 | the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 | and/or sell copies of the Software, and to permit persons to whom the 9 | Software is furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in 12 | all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 20 | DEALINGS IN THE SOFTWARE. 21 | */ 22 | 23 | /* 24 | * Parts of this library are derived by: 25 | * 26 | * Posix Threads library for Microsoft Windows 27 | * 28 | * Use at own risk, there is no implied warranty to this code. 29 | * It uses undocumented features of Microsoft Windows that can change 30 | * at any time in the future. 31 | * 32 | * (C) 2010 Lockless Inc. 33 | * All rights reserved. 34 | * 35 | * Redistribution and use in source and binary forms, with or without modification, 36 | * are permitted provided that the following conditions are met: 37 | * 38 | * 39 | * * Redistributions of source code must retain the above copyright notice, 40 | * this list of conditions and the following disclaimer. 41 | * * Redistributions in binary form must reproduce the above copyright notice, 42 | * this list of conditions and the following disclaimer in the documentation 43 | * and/or other materials provided with the distribution. 44 | * * Neither the name of Lockless Inc. nor the names of its contributors may be 45 | * used to endorse or promote products derived from this software without 46 | * specific prior written permission. 47 | * 48 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AN 49 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 50 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 51 | * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 52 | * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 53 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 54 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 55 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 56 | * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 57 | * OF THE POSSIBILITY OF SUCH DAMAGE. 58 | */ 59 | 60 | #ifndef WIN_PTHREADS_PTHREAD_COMPAT_H 61 | #define WIN_PTHREADS_PTHREAD_COMPAT_H 62 | 63 | #ifdef __GNUC__ 64 | 65 | #define WINPTHREADS_INLINE inline 66 | #define WINPTHREADS_ATTRIBUTE(X) __attribute__(X) 67 | #define WINPTHREADS_SECTION(X) __section__(X) 68 | 69 | #elif _MSC_VER 70 | 71 | #include "pthread_time.h" 72 | 73 | #ifdef _WIN64 74 | typedef __int64 pid_t; 75 | #else 76 | typedef int pid_t; 77 | #endif 78 | typedef int clockid_t; 79 | 80 | #define WINPTHREADS_INLINE __inline 81 | #define WINPTHREADS_ATTRIBUTE(X) __declspec X 82 | #define WINPTHREADS_SECTION(X) allocate(X) 83 | 84 | #endif 85 | 86 | #endif 87 | -------------------------------------------------------------------------------- /include/pthread_signal.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2013 mingw-w64 project 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a 5 | copy of this software and associated documentation files (the "Software"), 6 | to deal in the Software without restriction, including without limitation 7 | the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 | and/or sell copies of the Software, and to permit persons to whom the 9 | Software is furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in 12 | all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 20 | DEALINGS IN THE SOFTWARE. 21 | */ 22 | 23 | #ifndef WIN_PTHREADS_SIGNAL_H 24 | #define WIN_PTHREADS_SIGNAL_H 25 | 26 | /* Windows has rudimentary signals support. */ 27 | #define pthread_sigmask(H, S1, S2) 0 28 | 29 | #endif /* WIN_PTHREADS_SIGNAL_H */ 30 | -------------------------------------------------------------------------------- /include/pthread_time.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2011 mingw-w64 project 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a 5 | copy of this software and associated documentation files (the "Software"), 6 | to deal in the Software without restriction, including without limitation 7 | the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 | and/or sell copies of the Software, and to permit persons to whom the 9 | Software is furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in 12 | all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 20 | DEALINGS IN THE SOFTWARE. 21 | */ 22 | 23 | #include 24 | 25 | #ifndef WIN_PTHREADS_TIME_H 26 | #define WIN_PTHREADS_TIME_H 27 | 28 | /* Posix timers are supported */ 29 | #ifndef _POSIX_TIMERS 30 | #define _POSIX_TIMERS 200809L 31 | #endif 32 | 33 | /* Monotonic clocks are available. */ 34 | #ifndef _POSIX_MONOTONIC_CLOCK 35 | #define _POSIX_MONOTONIC_CLOCK 200809L 36 | #endif 37 | 38 | /* CPU-time clocks are available. */ 39 | #ifndef _POSIX_CPUTIME 40 | #define _POSIX_CPUTIME 200809L 41 | #endif 42 | 43 | /* Clock support in threads are available. */ 44 | #ifndef _POSIX_THREAD_CPUTIME 45 | #define _POSIX_THREAD_CPUTIME 200809L 46 | #endif 47 | 48 | #ifndef __clockid_t_defined 49 | typedef int clockid_t; 50 | #define __clockid_t_defined 1 51 | #endif /* __clockid_t_defined */ 52 | 53 | #ifndef TIMER_ABSTIME 54 | #define TIMER_ABSTIME 1 55 | #endif 56 | 57 | #ifndef CLOCK_REALTIME 58 | #define CLOCK_REALTIME 0 59 | #endif 60 | 61 | #ifndef CLOCK_MONOTONIC 62 | #define CLOCK_MONOTONIC 1 63 | #endif 64 | 65 | #ifndef CLOCK_PROCESS_CPUTIME_ID 66 | #define CLOCK_PROCESS_CPUTIME_ID 2 67 | #endif 68 | 69 | #ifndef CLOCK_THREAD_CPUTIME_ID 70 | #define CLOCK_THREAD_CPUTIME_ID 3 71 | #endif 72 | 73 | #ifdef __cplusplus 74 | extern "C" { 75 | #endif 76 | 77 | /* Make sure we provide default for WINPTHREAD_API, if not defined. */ 78 | #pragma push_macro("WINPTHREAD_API") 79 | #ifndef WINPTHREAD_API 80 | #define WINPTHREAD_API 81 | #endif 82 | 83 | /* These should really be dllimport'ed if using winpthread dll */ 84 | int __cdecl WINPTHREAD_API nanosleep(const struct timespec *request, struct timespec *remain); 85 | 86 | int __cdecl WINPTHREAD_API clock_nanosleep(clockid_t clock_id, int flags, const struct timespec *request, struct timespec *remain); 87 | int __cdecl WINPTHREAD_API clock_getres(clockid_t clock_id, struct timespec *res); 88 | int __cdecl WINPTHREAD_API clock_gettime(clockid_t clock_id, struct timespec *tp); 89 | int __cdecl WINPTHREAD_API clock_settime(clockid_t clock_id, const struct timespec *tp); 90 | 91 | #pragma pop_macro("WINPTHREAD_API") 92 | 93 | #ifdef __cplusplus 94 | } 95 | #endif 96 | 97 | #endif /* WIN_PTHREADS_TIME_H */ 98 | 99 | -------------------------------------------------------------------------------- /include/pthread_unistd.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2011 mingw-w64 project 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a 5 | copy of this software and associated documentation files (the "Software"), 6 | to deal in the Software without restriction, including without limitation 7 | the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 | and/or sell copies of the Software, and to permit persons to whom the 9 | Software is furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in 12 | all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 20 | DEALINGS IN THE SOFTWARE. 21 | */ 22 | 23 | #ifndef WIN_PTHREADS_UNISTD_H 24 | #define WIN_PTHREADS_UNISTD_H 25 | 26 | /* Set defines described by the POSIX Threads Extension (1003.1c-1995) */ 27 | /* _SC_THREADS 28 | Basic support for POSIX threads is available. The functions 29 | 30 | pthread_atfork(), 31 | pthread_attr_destroy(), 32 | pthread_attr_getdetachstate(), 33 | pthread_attr_getschedparam(), 34 | pthread_attr_init(), 35 | pthread_attr_setdetachstate(), 36 | pthread_attr_setschedparam(), 37 | pthread_cancel(), 38 | pthread_cleanup_push(), 39 | pthread_cleanup_pop(), 40 | pthread_cond_broadcast(), 41 | pthread_cond_destroy(), 42 | pthread_cond_init(), 43 | pthread_cond_signal(), 44 | pthread_cond_timedwait(), 45 | pthread_cond_wait(), 46 | pthread_condattr_destroy(), 47 | pthread_condattr_init(), 48 | pthread_create(), 49 | pthread_detach(), 50 | pthread_equal(), 51 | pthread_exit(), 52 | pthread_getspecific(), 53 | pthread_join(, 54 | pthread_key_create(), 55 | pthread_key_delete(), 56 | pthread_mutex_destroy(), 57 | pthread_mutex_init(), 58 | pthread_mutex_lock(), 59 | pthread_mutex_trylock(), 60 | pthread_mutex_unlock(), 61 | pthread_mutexattr_destroy(), 62 | pthread_mutexattr_init(), 63 | pthread_once(), 64 | pthread_rwlock_destroy(), 65 | pthread_rwlock_init(), 66 | pthread_rwlock_rdlock(), 67 | pthread_rwlock_tryrdlock(), 68 | pthread_rwlock_trywrlock(), 69 | pthread_rwlock_unlock(), 70 | pthread_rwlock_wrlock(), 71 | pthread_rwlockattr_destroy(), 72 | pthread_rwlockattr_init(), 73 | pthread_self(), 74 | pthread_setcancelstate(), 75 | pthread_setcanceltype(), 76 | pthread_setspecific(), 77 | pthread_testcancel() 78 | 79 | are present. */ 80 | #undef _POSIX_THREADS 81 | #define _POSIX_THREADS 200112L 82 | 83 | /* _SC_READER_WRITER_LOCKS 84 | This option implies the _POSIX_THREADS option. Conversely, under 85 | POSIX 1003.1-2001 the _POSIX_THREADS option implies this option. 86 | 87 | The functions 88 | pthread_rwlock_destroy(), 89 | pthread_rwlock_init(), 90 | pthread_rwlock_rdlock(), 91 | pthread_rwlock_tryrdlock(), 92 | pthread_rwlock_trywrlock(), 93 | pthread_rwlock_unlock(), 94 | pthread_rwlock_wrlock(), 95 | pthread_rwlockattr_destroy(), 96 | pthread_rwlockattr_init() 97 | 98 | are present. 99 | */ 100 | #undef _POSIX_READER_WRITER_LOCKS 101 | #define _POSIX_READER_WRITER_LOCKS 200112L 102 | 103 | /* _SC_SPIN_LOCKS 104 | This option implies the _POSIX_THREADS and _POSIX_THREAD_SAFE_FUNCTIONS 105 | options. The functions 106 | 107 | pthread_spin_destroy(), 108 | pthread_spin_init(), 109 | pthread_spin_lock(), 110 | pthread_spin_trylock(), 111 | pthread_spin_unlock() 112 | 113 | are present. */ 114 | #undef _POSIX_SPIN_LOCKS 115 | #define _POSIX_SPIN_LOCKS 200112L 116 | 117 | /* _SC_BARRIERS 118 | This option implies the _POSIX_THREADS and _POSIX_THREAD_SAFE_FUNCTIONS 119 | options. The functions 120 | 121 | pthread_barrier_destroy(), 122 | pthread_barrier_init(), 123 | pthread_barrier_wait(), 124 | pthread_barrierattr_destroy(), 125 | pthread_barrierattr_init() 126 | 127 | are present. 128 | */ 129 | #undef _POSIX_BARRIERS 130 | #define _POSIX_BARRIERS 200112L 131 | 132 | /* _SC_THREAD_SAFE_FUNCTIONS 133 | Affected functions are 134 | 135 | readdir_r(), 136 | getgrgid_r(), 137 | getgrnam_r(), 138 | getpwnam_r(), 139 | getpwuid_r(), 140 | flockfile(), 141 | ftrylockfile(), 142 | funlockfile(), 143 | getc_unlocked(), 144 | getchar_unlocked(), 145 | putc_unlocked(), 146 | putchar_unlocked(), 147 | strerror_r(), 148 | */ 149 | #undef _POSIX_THREAD_SAFE_FUNCTIONS 150 | #define _POSIX_THREAD_SAFE_FUNCTIONS 200112L 151 | 152 | /* _SC_TIMEOUTS 153 | The functions 154 | 155 | mq_timedreceive(), - not supported 156 | mq_timedsend(), - not supported 157 | posix_trace_timedgetnext_event(), - not supported 158 | pthread_mutex_timedlock(), 159 | pthread_rwlock_timedrdlock(), 160 | pthread_rwlock_timedwrlock(), 161 | sem_timedwait(), 162 | 163 | are present. */ 164 | #undef _POSIX_TIMEOUTS 165 | #define _POSIX_TIMEOUTS 200112L 166 | 167 | /* _SC_TIMERS - not supported 168 | The functions 169 | 170 | clock_getres(), 171 | clock_gettime(), 172 | clock_settime(), 173 | nanosleep(), 174 | timer_create(), 175 | timer_delete(), 176 | timer_gettime(), 177 | timer_getoverrun(), 178 | timer_settime() 179 | 180 | are present. */ 181 | /* #undef _POSIX_TIMERS */ 182 | 183 | /* _SC_CLOCK_SELECTION 184 | This option implies the _POSIX_TIMERS option. The functions 185 | 186 | pthread_condattr_getclock(), 187 | pthread_condattr_setclock(), 188 | clock_nanosleep() 189 | 190 | are present. 191 | */ 192 | #undef _POSIX_CLOCK_SELECTION 193 | #define _POSIX_CLOCK_SELECTION 200112 194 | 195 | /* _SC_SEMAPHORES 196 | The include file is present. The functions 197 | 198 | sem_close(), 199 | sem_destroy(), 200 | sem_getvalue(), 201 | sem_init(), 202 | sem_open(), 203 | sem_post(), 204 | sem_trywait(), 205 | sem_unlink(), 206 | sem_wait() 207 | 208 | are present. */ 209 | #undef _POSIX_SEMAPHORES 210 | #define _POSIX_SEMAPHORES 200112 211 | 212 | #endif /* WIN_PTHREADS_UNISTD_H */ 213 | -------------------------------------------------------------------------------- /include/sched.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2011-2013 mingw-w64 project 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a 5 | copy of this software and associated documentation files (the "Software"), 6 | to deal in the Software without restriction, including without limitation 7 | the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 | and/or sell copies of the Software, and to permit persons to whom the 9 | Software is furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in 12 | all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 20 | DEALINGS IN THE SOFTWARE. 21 | */ 22 | 23 | #include 24 | #include 25 | #include 26 | 27 | #include 28 | #include 29 | #include 30 | 31 | #include 32 | 33 | #ifndef WIN_PTHREADS_SCHED_H 34 | #define WIN_PTHREADS_SCHED_H 35 | 36 | #ifndef SCHED_OTHER 37 | /* Some POSIX realtime extensions, mostly stubbed */ 38 | #define SCHED_OTHER 0 39 | #define SCHED_FIFO 1 40 | #define SCHED_RR 2 41 | #define SCHED_MIN SCHED_OTHER 42 | #define SCHED_MAX SCHED_RR 43 | 44 | struct sched_param { 45 | int sched_priority; 46 | }; 47 | 48 | #ifdef __cplusplus 49 | extern "C" { 50 | #endif 51 | 52 | #if defined DLL_EXPORT && !defined (WINPTHREAD_EXPORT_ALL_DEBUG) 53 | #ifdef IN_WINPTHREAD 54 | #define WINPTHREAD_SCHED_API __declspec(dllexport) 55 | #else 56 | #define WINPTHREAD_SCHED_API __declspec(dllimport) 57 | #endif 58 | #else 59 | #define WINPTHREAD_SCHED_API 60 | #endif 61 | 62 | int WINPTHREAD_SCHED_API sched_yield(void); 63 | int WINPTHREAD_SCHED_API sched_get_priority_min(int pol); 64 | int WINPTHREAD_SCHED_API sched_get_priority_max(int pol); 65 | int WINPTHREAD_SCHED_API sched_getscheduler(pid_t pid); 66 | int WINPTHREAD_SCHED_API sched_setscheduler(pid_t pid, int pol, const struct sched_param *param); 67 | 68 | #ifdef __cplusplus 69 | } 70 | #endif 71 | 72 | #endif 73 | 74 | #ifndef sched_rr_get_interval 75 | #define sched_rr_get_interval(_p, _i) \ 76 | ( errno = ENOTSUP, (int) -1 ) 77 | #endif 78 | 79 | #endif /* WIN_PTHREADS_SCHED_H */ 80 | -------------------------------------------------------------------------------- /include/semaphore.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2011 mingw-w64 project 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a 5 | copy of this software and associated documentation files (the "Software"), 6 | to deal in the Software without restriction, including without limitation 7 | the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 | and/or sell copies of the Software, and to permit persons to whom the 9 | Software is furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in 12 | all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 20 | DEALINGS IN THE SOFTWARE. 21 | */ 22 | 23 | #ifndef WIN_PTHREADS_SEMAPHORE_H 24 | #define WIN_PTHREADS_SEMAPHORE_H 25 | 26 | #ifdef __cplusplus 27 | extern "C" { 28 | #endif 29 | 30 | #if defined DLL_EXPORT && !defined (WINPTHREAD_EXPORT_ALL_DEBUG) 31 | #ifdef IN_WINPTHREAD 32 | #define WINPTHREAD_SEMA_API __declspec(dllexport) 33 | #else 34 | #define WINPTHREAD_SEMA_API __declspec(dllimport) 35 | #endif 36 | #else 37 | #define WINPTHREAD_SEMA_API 38 | #endif 39 | 40 | /* Set this to 0 to disable it */ 41 | #define USE_SEM_CriticalSection_SpinCount 100 42 | 43 | //#define SEM_VALUE_MAX INT_MAX 44 | #define SEM_VALUE_MAX (INT_MAX/2) 45 | 46 | #ifndef _MODE_T_ 47 | #define _MODE_T_ 48 | typedef unsigned short mode_t; 49 | #endif 50 | 51 | typedef void *sem_t; 52 | 53 | #define SEM_FAILED NULL 54 | 55 | int WINPTHREAD_SEMA_API sem_init(sem_t * sem, int pshared, unsigned int value); 56 | 57 | int WINPTHREAD_SEMA_API sem_destroy(sem_t *sem); 58 | 59 | int WINPTHREAD_SEMA_API sem_trywait(sem_t *sem); 60 | 61 | int WINPTHREAD_SEMA_API sem_wait(sem_t *sem); 62 | 63 | int WINPTHREAD_SEMA_API sem_timedwait(sem_t * sem, const struct timespec *t); 64 | 65 | int WINPTHREAD_SEMA_API sem_post(sem_t *sem); 66 | 67 | int WINPTHREAD_SEMA_API sem_post_multiple(sem_t *sem, int count); 68 | 69 | /* yes, it returns a semaphore (or SEM_FAILED) */ 70 | sem_t * WINPTHREAD_SEMA_API sem_open(const char * name, int oflag, mode_t mode, unsigned int value); 71 | 72 | int WINPTHREAD_SEMA_API sem_close(sem_t * sem); 73 | 74 | int WINPTHREAD_SEMA_API sem_unlink(const char * name); 75 | 76 | int WINPTHREAD_SEMA_API sem_getvalue(sem_t * sem, int * sval); 77 | 78 | #ifdef __cplusplus 79 | } 80 | #endif 81 | 82 | #endif /* WIN_PTHREADS_SEMAPHORE_H */ 83 | -------------------------------------------------------------------------------- /licence.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2011 mingw-w64 project 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a 4 | copy of this software and associated documentation files (the "Software"), 5 | to deal in the Software without restriction, including without limitation 6 | the rights to use, copy, modify, merge, publish, distribute, sublicense, 7 | and/or sell copies of the Software, and to permit persons to whom the 8 | Software is furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 19 | DEALINGS IN THE SOFTWARE. 20 | 21 | 22 | /* 23 | * Parts of this library are derived by: 24 | * 25 | * Posix Threads library for Microsoft Windows 26 | * 27 | * Use at own risk, there is no implied warranty to this code. 28 | * It uses undocumented features of Microsoft Windows that can change 29 | * at any time in the future. 30 | * 31 | * (C) 2010 Lockless Inc. 32 | * All rights reserved. 33 | * 34 | * Redistribution and use in source and binary forms, with or without modification, 35 | * are permitted provided that the following conditions are met: 36 | * 37 | * 38 | * * Redistributions of source code must retain the above copyright notice, 39 | * this list of conditions and the following disclaimer. 40 | * * Redistributions in binary form must reproduce the above copyright notice, 41 | * this list of conditions and the following disclaimer in the documentation 42 | * and/or other materials provided with the distribution. 43 | * * Neither the name of Lockless Inc. nor the names of its contributors may be 44 | * used to endorse or promote products derived from this software without 45 | * specific prior written permission. 46 | * 47 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AN 48 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 49 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 50 | * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 51 | * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 52 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 53 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 54 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 55 | * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 56 | * OF THE POSSIBILITY OF SUCH DAMAGE. 57 | */ 58 | -------------------------------------------------------------------------------- /src/barrier.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2011 mingw-w64 project 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a 5 | copy of this software and associated documentation files (the "Software"), 6 | to deal in the Software without restriction, including without limitation 7 | the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 | and/or sell copies of the Software, and to permit persons to whom the 9 | Software is furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in 12 | all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 20 | DEALINGS IN THE SOFTWARE. 21 | */ 22 | 23 | #include 24 | #include 25 | #include 26 | #include "pthread.h" 27 | #include "barrier.h" 28 | #include "ref.h" 29 | #include "misc.h" 30 | 31 | static pthread_spinlock_t barrier_global = PTHREAD_SPINLOCK_INITIALIZER; 32 | 33 | static WINPTHREADS_ATTRIBUTE((noinline)) int 34 | barrier_unref(volatile pthread_barrier_t *barrier, int res) 35 | { 36 | pthread_spin_lock(&barrier_global); 37 | #ifdef WINPTHREAD_DBG 38 | assert((((barrier_t *)*barrier)->valid == LIFE_BARRIER) && (((barrier_t *)*barrier)->busy > 0)); 39 | #endif 40 | ((barrier_t *)*barrier)->busy -= 1; 41 | pthread_spin_unlock(&barrier_global); 42 | return res; 43 | } 44 | 45 | static WINPTHREADS_ATTRIBUTE((noinline)) int barrier_ref(volatile pthread_barrier_t *barrier) 46 | { 47 | int r = 0; 48 | pthread_spin_lock(&barrier_global); 49 | 50 | if (!barrier || !*barrier || ((barrier_t *)*barrier)->valid != LIFE_BARRIER) r = EINVAL; 51 | else { 52 | ((barrier_t *)*barrier)->busy += 1; 53 | } 54 | 55 | pthread_spin_unlock(&barrier_global); 56 | 57 | return r; 58 | } 59 | 60 | static WINPTHREADS_ATTRIBUTE((noinline)) int 61 | barrier_ref_destroy(volatile pthread_barrier_t *barrier, pthread_barrier_t *bDestroy) 62 | { 63 | int r = 0; 64 | 65 | *bDestroy = NULL; 66 | pthread_spin_lock(&barrier_global); 67 | 68 | if (!barrier || !*barrier || ((barrier_t *)*barrier)->valid != LIFE_BARRIER) r = EINVAL; 69 | else { 70 | barrier_t *b_ = (barrier_t *)*barrier; 71 | if (b_->busy) r = EBUSY; 72 | else { 73 | *bDestroy = *barrier; 74 | *barrier = NULL; 75 | } 76 | } 77 | 78 | pthread_spin_unlock(&barrier_global); 79 | return r; 80 | } 81 | 82 | static WINPTHREADS_ATTRIBUTE((noinline)) void 83 | barrier_ref_set (volatile pthread_barrier_t *barrier, void *v) 84 | { 85 | pthread_spin_lock(&barrier_global); 86 | *barrier = v; 87 | pthread_spin_unlock(&barrier_global); 88 | } 89 | 90 | int pthread_barrier_destroy(pthread_barrier_t *b_) 91 | { 92 | pthread_barrier_t bDestroy; 93 | barrier_t *b; 94 | int r; 95 | 96 | while ((r = barrier_ref_destroy(b_,&bDestroy)) == EBUSY) 97 | Sleep(0); 98 | 99 | if (r) 100 | return r; 101 | 102 | b = (barrier_t *)bDestroy; 103 | 104 | pthread_mutex_lock(&b->m); 105 | 106 | if (sem_destroy(&b->sems[0]) != 0) 107 | { 108 | /* Could this happen? */ 109 | *b_ = bDestroy; 110 | pthread_mutex_unlock (&b->m); 111 | return EBUSY; 112 | } 113 | if (sem_destroy(&b->sems[1]) != 0) 114 | { 115 | sem_init (&b->sems[0], b->share, 0); 116 | *b_ = bDestroy; 117 | pthread_mutex_unlock (&b->m); 118 | return -1; 119 | } 120 | pthread_mutex_unlock(&b->m); 121 | if(pthread_mutex_destroy(&b->m) != 0) { 122 | sem_init (&b->sems[0], b->share, 0); 123 | sem_init (&b->sems[1], b->share, 0); 124 | *b_ = bDestroy; 125 | return -1; 126 | } 127 | b->valid = DEAD_BARRIER; 128 | free(bDestroy); 129 | return 0; 130 | 131 | } 132 | 133 | int 134 | pthread_barrier_init (pthread_barrier_t *b_, const void *attr, 135 | unsigned int count) 136 | { 137 | barrier_t *b; 138 | 139 | if (!count || !b_) 140 | return EINVAL; 141 | 142 | if (!(b = (pthread_barrier_t)calloc(1,sizeof(*b)))) 143 | return ENOMEM; 144 | if (!attr || *((int **)attr) == NULL) 145 | b->share = PTHREAD_PROCESS_PRIVATE; 146 | else 147 | memcpy (&b->share, *((void **) attr), sizeof (int)); 148 | b->total = count; 149 | b->count = count; 150 | b->valid = LIFE_BARRIER; 151 | b->sel = 0; 152 | 153 | if (pthread_mutex_init(&b->m, NULL) != 0) 154 | { 155 | free (b); 156 | return ENOMEM; 157 | } 158 | 159 | if (sem_init(&b->sems[0], b->share, 0) != 0) 160 | { 161 | pthread_mutex_destroy(&b->m); 162 | free (b); 163 | return ENOMEM; 164 | } 165 | if (sem_init(&b->sems[1], b->share, 0) != 0) 166 | { 167 | pthread_mutex_destroy(&b->m); 168 | sem_destroy(&b->sems[0]); 169 | free (b); 170 | return ENOMEM; 171 | } 172 | barrier_ref_set (b_,b); 173 | 174 | return 0; 175 | } 176 | 177 | int pthread_barrier_wait(pthread_barrier_t *b_) 178 | { 179 | long sel; 180 | int r, e, rslt; 181 | barrier_t *b; 182 | 183 | r = barrier_ref(b_); 184 | if(r) return r; 185 | 186 | b = (barrier_t *)*b_; 187 | 188 | if ((r = pthread_mutex_lock(&b->m))) return barrier_unref(b_,EINVAL); 189 | sel = b->sel; 190 | InterlockedDecrement((long*)&b->total); 191 | if (b->total == 0) 192 | { 193 | b->total = b->count; 194 | b->sel = (sel != 0 ? 0 : 1); 195 | e = 1; 196 | rslt = PTHREAD_BARRIER_SERIAL_THREAD; 197 | r = (b->count > 1 ? sem_post_multiple (&b->sems[sel], b->count - 1) : 0); 198 | } 199 | else { e = 0; rslt= 0; } 200 | pthread_mutex_unlock(&b->m); 201 | if (!e) 202 | r = sem_wait(&b->sems[sel]); 203 | 204 | if (!r) r = rslt; 205 | return barrier_unref(b_,r); 206 | } 207 | 208 | int pthread_barrierattr_init(void **attr) 209 | { 210 | int *p; 211 | 212 | if (!(p = (int *) calloc (1, sizeof (int)))) 213 | return ENOMEM; 214 | 215 | *p = PTHREAD_PROCESS_PRIVATE; 216 | *attr = p; 217 | 218 | return 0; 219 | } 220 | 221 | int pthread_barrierattr_destroy(void **attr) 222 | { 223 | void *p; 224 | if (!attr || (p = *attr) == NULL) 225 | return EINVAL; 226 | *attr = NULL; 227 | free (p); 228 | return 0; 229 | } 230 | 231 | int pthread_barrierattr_setpshared(void **attr, int s) 232 | { 233 | if (!attr || *attr == NULL 234 | || (s != PTHREAD_PROCESS_SHARED && s != PTHREAD_PROCESS_PRIVATE)) 235 | return EINVAL; 236 | memcpy (*attr, &s, sizeof (int)); 237 | return 0; 238 | } 239 | 240 | int pthread_barrierattr_getpshared(void **attr, int *s) 241 | { 242 | if (!attr || !s || *attr == NULL) 243 | return EINVAL; 244 | memcpy (s, *attr, sizeof (int)); 245 | return 0; 246 | } 247 | -------------------------------------------------------------------------------- /src/barrier.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2011 mingw-w64 project 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a 5 | copy of this software and associated documentation files (the "Software"), 6 | to deal in the Software without restriction, including without limitation 7 | the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 | and/or sell copies of the Software, and to permit persons to whom the 9 | Software is furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in 12 | all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 20 | DEALINGS IN THE SOFTWARE. 21 | */ 22 | 23 | #ifndef WIN_PTHREADS_BARRIER_H 24 | #define WIN_PTHREADS_BARRIER_H 25 | 26 | #define LIFE_BARRIER 0xBAB1FEED 27 | #define DEAD_BARRIER 0xDEADB00F 28 | 29 | #define _PTHREAD_BARRIER_FLAG (1<<30) 30 | 31 | #define CHECK_BARRIER(b) { \ 32 | if (!(b) || ( ((barrier_t *)(*b))->valid != (unsigned int)LIFE_BARRIER ) ) return EINVAL; } 33 | 34 | #include "../include/semaphore.h" 35 | 36 | typedef struct barrier_t barrier_t; 37 | struct barrier_t 38 | { 39 | int valid; 40 | int busy; 41 | int count; 42 | int total; 43 | int share; 44 | long sel; 45 | pthread_mutex_t m; 46 | sem_t sems[2]; 47 | }; 48 | 49 | #endif 50 | -------------------------------------------------------------------------------- /src/clock.c: -------------------------------------------------------------------------------- 1 | /** 2 | * This file has no copyright assigned and is placed in the Public Domain. 3 | * This file is part of the w64 mingw-runtime package. 4 | * No warranty is given; refer to the file DISCLAIMER.PD within this package. 5 | */ 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #ifndef IN_WINPTHREAD 12 | #define IN_WINPTHREAD 1 13 | #endif 14 | #include "pthread.h" 15 | #include "pthread_time.h" 16 | 17 | #define POW10_7 10000000 18 | #define POW10_9 1000000000 19 | 20 | /* Number of 100ns-seconds between the beginning of the Windows epoch 21 | * (Jan. 1, 1601) and the Unix epoch (Jan. 1, 1970) 22 | */ 23 | #define DELTA_EPOCH_IN_100NS INT64_C(116444736000000000) 24 | 25 | static WINPTHREADS_INLINE int lc_set_errno(int result) 26 | { 27 | if (result != 0) { 28 | errno = result; 29 | return -1; 30 | } 31 | return 0; 32 | } 33 | 34 | /** 35 | * Get the resolution of the specified clock clock_id and 36 | * stores it in the struct timespec pointed to by res. 37 | * @param clock_id The clock_id argument is the identifier of the particular 38 | * clock on which to act. The following clocks are supported: 39 | *
 40 |  *     CLOCK_REALTIME  System-wide real-time clock. Setting this clock
 41 |  *                 requires appropriate privileges.
 42 |  *     CLOCK_MONOTONIC Clock that cannot be set and represents monotonic
 43 |  *                 time since some unspecified starting point.
 44 |  *     CLOCK_PROCESS_CPUTIME_ID High-resolution per-process timer from the CPU.
 45 |  *     CLOCK_THREAD_CPUTIME_ID  Thread-specific CPU-time clock.
 46 |  * 
47 | * @param res The pointer to a timespec structure to receive the time 48 | * resolution. 49 | * @return If the function succeeds, the return value is 0. 50 | * If the function fails, the return value is -1, 51 | * with errno set to indicate the error. 52 | */ 53 | int clock_getres(clockid_t clock_id, struct timespec *res) 54 | { 55 | switch(clock_id) { 56 | case CLOCK_MONOTONIC: 57 | { 58 | LARGE_INTEGER pf; 59 | 60 | if (QueryPerformanceFrequency(&pf) == 0) 61 | return lc_set_errno(EINVAL); 62 | 63 | res->tv_sec = 0; 64 | res->tv_nsec = (int) ((POW10_9 + (pf.QuadPart >> 1)) / pf.QuadPart); 65 | if (res->tv_nsec < 1) 66 | res->tv_nsec = 1; 67 | 68 | return 0; 69 | } 70 | 71 | case CLOCK_REALTIME: 72 | case CLOCK_PROCESS_CPUTIME_ID: 73 | case CLOCK_THREAD_CPUTIME_ID: 74 | { 75 | DWORD timeAdjustment, timeIncrement; 76 | BOOL isTimeAdjustmentDisabled; 77 | 78 | (void) GetSystemTimeAdjustment(&timeAdjustment, &timeIncrement, &isTimeAdjustmentDisabled); 79 | res->tv_sec = 0; 80 | res->tv_nsec = timeIncrement * 100; 81 | 82 | return 0; 83 | } 84 | default: 85 | break; 86 | } 87 | 88 | return lc_set_errno(EINVAL); 89 | } 90 | 91 | /** 92 | * Get the time of the specified clock clock_id and stores it in the struct 93 | * timespec pointed to by tp. 94 | * @param clock_id The clock_id argument is the identifier of the particular 95 | * clock on which to act. The following clocks are supported: 96 | *
 97 |  *     CLOCK_REALTIME  System-wide real-time clock. Setting this clock
 98 |  *                 requires appropriate privileges.
 99 |  *     CLOCK_MONOTONIC Clock that cannot be set and represents monotonic
100 |  *                 time since some unspecified starting point.
101 |  *     CLOCK_PROCESS_CPUTIME_ID High-resolution per-process timer from the CPU.
102 |  *     CLOCK_THREAD_CPUTIME_ID  Thread-specific CPU-time clock.
103 |  * 
104 | * @param tp The pointer to a timespec structure to receive the time. 105 | * @return If the function succeeds, the return value is 0. 106 | * If the function fails, the return value is -1, 107 | * with errno set to indicate the error. 108 | */ 109 | int clock_gettime(clockid_t clock_id, struct timespec *tp) 110 | { 111 | unsigned __int64 t; 112 | LARGE_INTEGER pf, pc; 113 | union { 114 | unsigned __int64 u64; 115 | FILETIME ft; 116 | } ct, et, kt, ut; 117 | 118 | switch(clock_id) { 119 | case CLOCK_REALTIME: 120 | { 121 | GetSystemTimeAsFileTime(&ct.ft); 122 | t = ct.u64 - DELTA_EPOCH_IN_100NS; 123 | tp->tv_sec = t / POW10_7; 124 | tp->tv_nsec = ((int) (t % POW10_7)) * 100; 125 | 126 | return 0; 127 | } 128 | 129 | case CLOCK_MONOTONIC: 130 | { 131 | if (QueryPerformanceFrequency(&pf) == 0) 132 | return lc_set_errno(EINVAL); 133 | 134 | if (QueryPerformanceCounter(&pc) == 0) 135 | return lc_set_errno(EINVAL); 136 | 137 | tp->tv_sec = pc.QuadPart / pf.QuadPart; 138 | tp->tv_nsec = (int) (((pc.QuadPart % pf.QuadPart) * POW10_9 + (pf.QuadPart >> 1)) / pf.QuadPart); 139 | if (tp->tv_nsec >= POW10_9) { 140 | tp->tv_sec ++; 141 | tp->tv_nsec -= POW10_9; 142 | } 143 | 144 | return 0; 145 | } 146 | 147 | case CLOCK_PROCESS_CPUTIME_ID: 148 | { 149 | if(0 == GetProcessTimes(GetCurrentProcess(), &ct.ft, &et.ft, &kt.ft, &ut.ft)) 150 | return lc_set_errno(EINVAL); 151 | t = kt.u64 + ut.u64; 152 | tp->tv_sec = t / POW10_7; 153 | tp->tv_nsec = ((int) (t % POW10_7)) * 100; 154 | 155 | return 0; 156 | } 157 | 158 | case CLOCK_THREAD_CPUTIME_ID: 159 | { 160 | if(0 == GetThreadTimes(GetCurrentThread(), &ct.ft, &et.ft, &kt.ft, &ut.ft)) 161 | return lc_set_errno(EINVAL); 162 | t = kt.u64 + ut.u64; 163 | tp->tv_sec = t / POW10_7; 164 | tp->tv_nsec = ((int) (t % POW10_7)) * 100; 165 | 166 | return 0; 167 | } 168 | 169 | default: 170 | break; 171 | } 172 | 173 | return lc_set_errno(EINVAL); 174 | } 175 | 176 | /** 177 | * Sleep for the specified time. 178 | * @param clock_id This argument should always be CLOCK_REALTIME (0). 179 | * @param flags 0 for relative sleep interval, others for absolute waking up. 180 | * @param request The desired sleep interval or absolute waking up time. 181 | * @param remain The remain amount of time to sleep. 182 | * The current implemention just ignore it. 183 | * @return If the function succeeds, the return value is 0. 184 | * If the function fails, the return value is -1, 185 | * with errno set to indicate the error. 186 | */ 187 | int clock_nanosleep(clockid_t clock_id, int flags, 188 | const struct timespec *request, 189 | struct timespec *remain) 190 | { 191 | struct timespec tp; 192 | 193 | if (clock_id != CLOCK_REALTIME) 194 | return lc_set_errno(EINVAL); 195 | 196 | if (flags == 0) 197 | return nanosleep(request, remain); 198 | 199 | /* TIMER_ABSTIME = 1 */ 200 | clock_gettime(CLOCK_REALTIME, &tp); 201 | 202 | tp.tv_sec = request->tv_sec - tp.tv_sec; 203 | tp.tv_nsec = request->tv_nsec - tp.tv_nsec; 204 | if (tp.tv_nsec < 0) { 205 | tp.tv_nsec += POW10_9; 206 | tp.tv_sec --; 207 | } 208 | 209 | return nanosleep(&tp, remain); 210 | } 211 | 212 | /** 213 | * Set the time of the specified clock clock_id. 214 | * @param clock_id This argument should always be CLOCK_REALTIME (0). 215 | * @param tp The requested time. 216 | * @return If the function succeeds, the return value is 0. 217 | * If the function fails, the return value is -1, 218 | * with errno set to indicate the error. 219 | */ 220 | int clock_settime(clockid_t clock_id, const struct timespec *tp) 221 | { 222 | SYSTEMTIME st; 223 | 224 | union { 225 | unsigned __int64 u64; 226 | FILETIME ft; 227 | } t; 228 | 229 | if (clock_id != CLOCK_REALTIME) 230 | return lc_set_errno(EINVAL); 231 | 232 | t.u64 = tp->tv_sec * (__int64) POW10_7 + tp->tv_nsec / 100 + DELTA_EPOCH_IN_100NS; 233 | if (FileTimeToSystemTime(&t.ft, &st) == 0) 234 | return lc_set_errno(EINVAL); 235 | 236 | if (SetSystemTime(&st) == 0) 237 | return lc_set_errno(EPERM); 238 | 239 | return 0; 240 | } 241 | -------------------------------------------------------------------------------- /src/cond.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2011 mingw-w64 project 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a 5 | copy of this software and associated documentation files (the "Software"), 6 | to deal in the Software without restriction, including without limitation 7 | the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 | and/or sell copies of the Software, and to permit persons to whom the 9 | Software is furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in 12 | all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 20 | DEALINGS IN THE SOFTWARE. 21 | */ 22 | 23 | /* 24 | * Posix Condition Variables for Microsoft Windows. 25 | * 22-9-2010 Partly based on the ACE framework implementation. 26 | */ 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include "pthread.h" 32 | #include "pthread_time.h" 33 | #include "ref.h" 34 | #include "cond.h" 35 | #include "mutex.h" 36 | #include "thread.h" 37 | #include "misc.h" 38 | #include "winpthread_internal.h" 39 | 40 | #include "pthread_compat.h" 41 | 42 | int __pthread_shallcancel (void); 43 | 44 | static int do_sema_b_wait (HANDLE sema, int nointerrupt, DWORD timeout,CRITICAL_SECTION *cs, LONG *val); 45 | static int do_sema_b_release(HANDLE sema, LONG count,CRITICAL_SECTION *cs, LONG *val); 46 | static void cleanup_wait(void *arg); 47 | 48 | typedef struct sCondWaitHelper { 49 | cond_t *c; 50 | pthread_mutex_t *external_mutex; 51 | int *r; 52 | } sCondWaitHelper; 53 | 54 | int do_sema_b_wait_intern (HANDLE sema, int nointerrupt, DWORD timeout); 55 | 56 | #ifdef WINPTHREAD_DBG 57 | static int print_state = 0; 58 | static FILE *fo; 59 | void cond_print_set(int state, FILE *f) 60 | { 61 | if (f) fo = f; 62 | if (!fo) fo = stdout; 63 | print_state = state; 64 | } 65 | 66 | void cond_print(volatile pthread_cond_t *c, char *txt) 67 | { 68 | if (!print_state) return; 69 | cond_t *c_ = (cond_t *)*c; 70 | if (c_ == NULL) { 71 | fprintf(fo,"C%p %d %s\n",*c,(int)GetCurrentThreadId(),txt); 72 | } else { 73 | fprintf(fo,"C%p %d V=%0X w=%ld %s\n", 74 | *c, 75 | (int)GetCurrentThreadId(), 76 | (int)c_->valid, 77 | c_->waiters_count_, 78 | txt 79 | ); 80 | } 81 | } 82 | #endif 83 | 84 | static pthread_spinlock_t cond_locked = PTHREAD_SPINLOCK_INITIALIZER; 85 | 86 | static int 87 | cond_static_init (pthread_cond_t *c) 88 | { 89 | int r = 0; 90 | 91 | pthread_spin_lock (&cond_locked); 92 | if (c == NULL) 93 | r = EINVAL; 94 | else if (*c == PTHREAD_COND_INITIALIZER) 95 | r = pthread_cond_init (c, NULL); 96 | else 97 | /* We assume someone was faster ... */ 98 | r = 0; 99 | pthread_spin_unlock (&cond_locked); 100 | return r; 101 | } 102 | 103 | int 104 | pthread_condattr_destroy (pthread_condattr_t *a) 105 | { 106 | if (!a) 107 | return EINVAL; 108 | *a = 0; 109 | return 0; 110 | } 111 | 112 | int 113 | pthread_condattr_init (pthread_condattr_t *a) 114 | { 115 | if (!a) 116 | return EINVAL; 117 | *a = 0; 118 | return 0; 119 | } 120 | 121 | int 122 | pthread_condattr_getpshared (const pthread_condattr_t *a, int *s) 123 | { 124 | if (!a || !s) 125 | return EINVAL; 126 | *s = *a; 127 | return 0; 128 | } 129 | 130 | int 131 | pthread_condattr_getclock (const pthread_condattr_t *a, clockid_t *clock_id) 132 | { 133 | if (!a || !clock_id) 134 | return EINVAL; 135 | *clock_id = 0; 136 | return 0; 137 | } 138 | 139 | int 140 | pthread_condattr_setclock(pthread_condattr_t *a, clockid_t clock_id) 141 | { 142 | if (!a || clock_id != 0) 143 | return EINVAL; 144 | return 0; 145 | } 146 | 147 | int 148 | __pthread_clock_nanosleep (clockid_t clock_id, int flags, const struct timespec *rqtp, 149 | struct timespec *rmtp) 150 | { 151 | unsigned long long tick, tick2; 152 | unsigned long long delay; 153 | DWORD dw; 154 | 155 | if (clock_id != CLOCK_REALTIME 156 | && clock_id != CLOCK_MONOTONIC 157 | && clock_id != CLOCK_PROCESS_CPUTIME_ID) 158 | return EINVAL; 159 | if ((flags & TIMER_ABSTIME) != 0) 160 | delay = _pthread_rel_time_in_ms (rqtp); 161 | else 162 | delay = _pthread_time_in_ms_from_timespec (rqtp); 163 | do 164 | { 165 | dw = (DWORD) (delay >= 99999ULL ? 99999ULL : delay); 166 | tick = _pthread_time_in_ms (); 167 | pthread_delay_np_ms (dw); 168 | tick2 = _pthread_time_in_ms (); 169 | tick2 -= tick; 170 | if (tick2 >= delay) 171 | delay = 0; 172 | else 173 | delay -= tick2; 174 | } 175 | while (delay != 0ULL); 176 | if (rmtp) 177 | memset (rmtp, 0, sizeof (*rmtp)); 178 | return 0; 179 | } 180 | 181 | int 182 | pthread_condattr_setpshared (pthread_condattr_t *a, int s) 183 | { 184 | if (!a || (s != PTHREAD_PROCESS_SHARED && s != PTHREAD_PROCESS_PRIVATE)) 185 | return EINVAL; 186 | if (s == PTHREAD_PROCESS_SHARED) 187 | { 188 | *a = PTHREAD_PROCESS_PRIVATE; 189 | return ENOSYS; 190 | } 191 | *a = s; 192 | return 0; 193 | } 194 | 195 | static HANDLE CreateSemaphoreWin() 196 | { 197 | HANDLE h = CreateSemaphoreA(NULL, /* no security */ 198 | 0, /* initially 0 */ 199 | SEM_VALUE_MAX, /* max count */ 200 | NULL); /* unnamed */ 201 | 202 | #if 0 203 | FILE *f; 204 | 205 | f = fopen("cond.log", "ab"); 206 | if(f) 207 | { 208 | fprintf(f, "CreateSemaphoreA: 0x%p\r\n", h); 209 | fclose(f); 210 | } 211 | #endif 212 | 213 | return h; 214 | } 215 | 216 | static void DestroySemaphoreWin(HANDLE sem) 217 | { 218 | #if 0 219 | FILE *f; 220 | 221 | f = fopen("cond.log", "ab"); 222 | if(f) 223 | { 224 | fprintf(f, "CloseHandle: 0x%p\r\n", sem); 225 | fclose(f); 226 | } 227 | #endif 228 | 229 | CloseHandle(sem); 230 | } 231 | 232 | int 233 | pthread_cond_init (pthread_cond_t *c, const pthread_condattr_t *a) 234 | { 235 | cond_t *_c; 236 | int r = 0; 237 | 238 | if (!c) 239 | return EINVAL; 240 | if (a && *a == PTHREAD_PROCESS_SHARED) 241 | return ENOSYS; 242 | 243 | if ( !(_c = (pthread_cond_t)calloc(1,sizeof(*_c))) ) { 244 | return ENOMEM; 245 | } 246 | _c->valid = DEAD_COND; 247 | _c->busy = 0; 248 | _c->waiters_count_ = 0; 249 | _c->waiters_count_gone_ = 0; 250 | _c->waiters_count_unblock_ = 0; 251 | 252 | //_c->sema_q = CreateSemaphore (NULL, /* no security */ 253 | // 0, /* initially 0 */ 254 | // SEM_VALUE_MAX, /* max count */ 255 | // NULL); /* unnamed */ 256 | //_c->sema_b = CreateSemaphore (NULL, /* no security */ 257 | // 0, /* initially 0 */ 258 | // SEM_VALUE_MAX, /* max count */ 259 | // NULL); 260 | _c->sema_q = CreateSemaphoreWin(); 261 | _c->sema_b = CreateSemaphoreWin(); 262 | 263 | if (_c->sema_q == NULL || _c->sema_b == NULL) { 264 | if (_c->sema_q != NULL) 265 | CloseHandle (_c->sema_q); 266 | if (_c->sema_b != NULL) 267 | CloseHandle (_c->sema_b); 268 | free (_c); 269 | r = EAGAIN; 270 | } else { 271 | InitializeCriticalSection(&_c->waiters_count_lock_); 272 | InitializeCriticalSection(&_c->waiters_b_lock_); 273 | InitializeCriticalSection(&_c->waiters_q_lock_); 274 | _c->value_q = 0; 275 | _c->value_b = 1; 276 | } 277 | if (!r) 278 | { 279 | _c->valid = LIFE_COND; 280 | *c = _c; 281 | } 282 | else 283 | *c = NULL; 284 | return r; 285 | } 286 | 287 | int 288 | pthread_cond_destroy (pthread_cond_t *c) 289 | { 290 | cond_t *_c; 291 | int r; 292 | if (!c || !*c) 293 | return EINVAL; 294 | if (*c == PTHREAD_COND_INITIALIZER) 295 | { 296 | pthread_spin_lock (&cond_locked); 297 | if (*c == PTHREAD_COND_INITIALIZER) 298 | { 299 | *c = NULL; 300 | r = 0; 301 | } 302 | else r = EBUSY; 303 | 304 | pthread_spin_unlock (&cond_locked); 305 | return r; 306 | } 307 | _c = (cond_t *) *c; 308 | r = do_sema_b_wait(_c->sema_b, 0, INFINITE,&_c->waiters_b_lock_,&_c->value_b); 309 | if (r != 0) 310 | return r; 311 | /* 312 | if (!TryEnterCriticalSection (&_c->waiters_count_lock_)) 313 | { 314 | do_sema_b_release (_c->sema_b, 1,&_c->waiters_b_lock_,&_c->value_b); 315 | return EBUSY; 316 | }*/ 317 | //EnterCriticalSection (&_c->waiters_count_lock_); 318 | //do_sema_b_release (_c->sema_b, 1,&_c->waiters_b_lock_,&_c->value_b); 319 | if (!TryEnterCriticalSection9x (&_c->waiters_count_lock_)) 320 | { 321 | do_sema_b_release (_c->sema_b, 1,&_c->waiters_b_lock_,&_c->value_b); 322 | return EBUSY; 323 | } 324 | 325 | if (_c->waiters_count_ > _c->waiters_count_gone_) 326 | { 327 | r = do_sema_b_release (_c->sema_b, 1,&_c->waiters_b_lock_,&_c->value_b); 328 | if (!r) r = EBUSY; 329 | LeaveCriticalSection(&_c->waiters_count_lock_); 330 | return r; 331 | } 332 | *c = NULL; 333 | do_sema_b_release (_c->sema_b, 1,&_c->waiters_b_lock_,&_c->value_b); 334 | 335 | /*if (!CloseHandle (_c->sema_q) && !r) 336 | r = EINVAL; 337 | if (!CloseHandle (_c->sema_b) && !r) 338 | r = EINVAL;*/ 339 | DestroySemaphoreWin(_c->sema_q); 340 | DestroySemaphoreWin(_c->sema_b); 341 | 342 | LeaveCriticalSection (&_c->waiters_count_lock_); 343 | DeleteCriticalSection(&_c->waiters_count_lock_); 344 | DeleteCriticalSection(&_c->waiters_b_lock_); 345 | DeleteCriticalSection(&_c->waiters_q_lock_); 346 | _c->valid = DEAD_COND; 347 | free(_c); 348 | return 0; 349 | } 350 | 351 | int 352 | pthread_cond_signal (pthread_cond_t *c) 353 | { 354 | cond_t *_c; 355 | int r; 356 | 357 | if (!c || !*c) 358 | return EINVAL; 359 | _c = (cond_t *)*c; 360 | if (_c == (cond_t *)PTHREAD_COND_INITIALIZER) 361 | return 0; 362 | else if (_c->valid != (unsigned int)LIFE_COND) 363 | return EINVAL; 364 | 365 | EnterCriticalSection (&_c->waiters_count_lock_); 366 | /* If there aren't any waiters, then this is a no-op. */ 367 | if (_c->waiters_count_unblock_ != 0) 368 | { 369 | if (_c->waiters_count_ == 0) 370 | { 371 | LeaveCriticalSection (&_c->waiters_count_lock_); 372 | /* pthread_testcancel(); */ 373 | return 0; 374 | } 375 | _c->waiters_count_ -= 1; 376 | _c->waiters_count_unblock_ += 1; 377 | } 378 | else if (_c->waiters_count_ > _c->waiters_count_gone_) 379 | { 380 | r = do_sema_b_wait (_c->sema_b, 1, INFINITE,&_c->waiters_b_lock_,&_c->value_b); 381 | if (r != 0) 382 | { 383 | LeaveCriticalSection (&_c->waiters_count_lock_); 384 | /* pthread_testcancel(); */ 385 | return r; 386 | } 387 | if (_c->waiters_count_gone_ != 0) 388 | { 389 | _c->waiters_count_ -= _c->waiters_count_gone_; 390 | _c->waiters_count_gone_ = 0; 391 | } 392 | _c->waiters_count_ -= 1; 393 | _c->waiters_count_unblock_ = 1; 394 | } 395 | else 396 | { 397 | LeaveCriticalSection (&_c->waiters_count_lock_); 398 | /* pthread_testcancel(); */ 399 | return 0; 400 | } 401 | LeaveCriticalSection (&_c->waiters_count_lock_); 402 | r = do_sema_b_release(_c->sema_q, 1,&_c->waiters_q_lock_,&_c->value_q); 403 | /* pthread_testcancel(); */ 404 | return r; 405 | } 406 | 407 | int 408 | pthread_cond_broadcast (pthread_cond_t *c) 409 | { 410 | cond_t *_c; 411 | int r; 412 | int relCnt = 0; 413 | 414 | if (!c || !*c) 415 | return EINVAL; 416 | _c = (cond_t *)*c; 417 | if (_c == (cond_t*)PTHREAD_COND_INITIALIZER) 418 | return 0; 419 | else if (_c->valid != (unsigned int)LIFE_COND) 420 | return EINVAL; 421 | 422 | EnterCriticalSection (&_c->waiters_count_lock_); 423 | /* If there aren't any waiters, then this is a no-op. */ 424 | if (_c->waiters_count_unblock_ != 0) 425 | { 426 | if (_c->waiters_count_ == 0) 427 | { 428 | LeaveCriticalSection (&_c->waiters_count_lock_); 429 | /* pthread_testcancel(); */ 430 | return 0; 431 | } 432 | relCnt = _c->waiters_count_; 433 | _c->waiters_count_ = 0; 434 | _c->waiters_count_unblock_ += relCnt; 435 | } 436 | else if (_c->waiters_count_ > _c->waiters_count_gone_) 437 | { 438 | r = do_sema_b_wait (_c->sema_b, 1, INFINITE,&_c->waiters_b_lock_,&_c->value_b); 439 | if (r != 0) 440 | { 441 | LeaveCriticalSection (&_c->waiters_count_lock_); 442 | /* pthread_testcancel(); */ 443 | return r; 444 | } 445 | if (_c->waiters_count_gone_ != 0) 446 | { 447 | _c->waiters_count_ -= _c->waiters_count_gone_; 448 | _c->waiters_count_gone_ = 0; 449 | } 450 | relCnt = _c->waiters_count_; 451 | _c->waiters_count_ = 0; 452 | _c->waiters_count_unblock_ = relCnt; 453 | } 454 | else 455 | { 456 | LeaveCriticalSection (&_c->waiters_count_lock_); 457 | /* pthread_testcancel(); */ 458 | return 0; 459 | } 460 | LeaveCriticalSection (&_c->waiters_count_lock_); 461 | r = do_sema_b_release(_c->sema_q, relCnt,&_c->waiters_q_lock_,&_c->value_q); 462 | /* pthread_testcancel(); */ 463 | return r; 464 | } 465 | 466 | int 467 | pthread_cond_wait (pthread_cond_t *c, pthread_mutex_t *external_mutex) 468 | { 469 | sCondWaitHelper ch; 470 | cond_t *_c; 471 | int r; 472 | 473 | /* pthread_testcancel(); */ 474 | 475 | if (!c || *c == NULL) 476 | return EINVAL; 477 | _c = (cond_t *)*c; 478 | if (*c == PTHREAD_COND_INITIALIZER) 479 | { 480 | r = cond_static_init(c); 481 | if (r != 0 && r != EBUSY) 482 | return r; 483 | _c = (cond_t *) *c; 484 | } else if (_c->valid != (unsigned int)LIFE_COND) 485 | return EINVAL; 486 | 487 | r = do_sema_b_wait (_c->sema_b, 0, INFINITE,&_c->waiters_b_lock_,&_c->value_b); 488 | if (r != 0) 489 | return r; 490 | EnterCriticalSection (&_c->waiters_count_lock_); 491 | _c->waiters_count_++; 492 | LeaveCriticalSection(&_c->waiters_count_lock_); 493 | r = do_sema_b_release (_c->sema_b, 1,&_c->waiters_b_lock_,&_c->value_b); 494 | if (r != 0) 495 | return r; 496 | 497 | ch.c = _c; 498 | ch.r = &r; 499 | ch.external_mutex = external_mutex; 500 | 501 | pthread_cleanup_push(cleanup_wait, (void *) &ch); 502 | r = pthread_mutex_unlock(external_mutex); 503 | if (!r) 504 | r = do_sema_b_wait (_c->sema_q, 0, INFINITE,&_c->waiters_q_lock_,&_c->value_q); 505 | 506 | pthread_cleanup_pop(1); 507 | return r; 508 | } 509 | 510 | static int 511 | pthread_cond_timedwait_impl (pthread_cond_t *c, pthread_mutex_t *external_mutex, const struct timespec *t, int rel) 512 | { 513 | sCondWaitHelper ch; 514 | DWORD dwr; 515 | int r; 516 | cond_t *_c; 517 | 518 | /* pthread_testcancel(); */ 519 | 520 | if (!c || !*c) 521 | return EINVAL; 522 | _c = (cond_t *)*c; 523 | if (_c == (cond_t *)PTHREAD_COND_INITIALIZER) 524 | { 525 | r = cond_static_init(c); 526 | if (r && r != EBUSY) 527 | return r; 528 | _c = (cond_t *) *c; 529 | } else if ((_c)->valid != (unsigned int)LIFE_COND) 530 | return EINVAL; 531 | 532 | if (rel == 0) 533 | { 534 | dwr = dwMilliSecs(_pthread_rel_time_in_ms(t)); 535 | } 536 | else 537 | { 538 | dwr = dwMilliSecs(_pthread_time_in_ms_from_timespec(t)); 539 | } 540 | 541 | r = do_sema_b_wait (_c->sema_b, 0, INFINITE,&_c->waiters_b_lock_,&_c->value_b); 542 | if (r != 0) 543 | return r; 544 | _c->waiters_count_++; 545 | r = do_sema_b_release (_c->sema_b, 1,&_c->waiters_b_lock_,&_c->value_b); 546 | if (r != 0) 547 | return r; 548 | 549 | ch.c = _c; 550 | ch.r = &r; 551 | ch.external_mutex = external_mutex; 552 | { 553 | pthread_cleanup_push(cleanup_wait, (void *) &ch); 554 | 555 | r = pthread_mutex_unlock(external_mutex); 556 | if (!r) 557 | r = do_sema_b_wait (_c->sema_q, 0, dwr,&_c->waiters_q_lock_,&_c->value_q); 558 | 559 | pthread_cleanup_pop(1); 560 | } 561 | return r; 562 | } 563 | 564 | int 565 | pthread_cond_timedwait(pthread_cond_t *c, pthread_mutex_t *m, const struct timespec *t) 566 | { 567 | return pthread_cond_timedwait_impl(c, m, t, 0); 568 | } 569 | 570 | int 571 | pthread_cond_timedwait_relative_np(pthread_cond_t *c, pthread_mutex_t *m, const struct timespec *t) 572 | { 573 | return pthread_cond_timedwait_impl(c, m, t, 1); 574 | } 575 | 576 | static void 577 | cleanup_wait (void *arg) 578 | { 579 | int n, r; 580 | sCondWaitHelper *ch = (sCondWaitHelper *) arg; 581 | cond_t *_c; 582 | 583 | _c = ch->c; 584 | EnterCriticalSection (&_c->waiters_count_lock_); 585 | n = _c->waiters_count_unblock_; 586 | if (n != 0) 587 | _c->waiters_count_unblock_ -= 1; 588 | else if ((INT_MAX/2) - 1 == _c->waiters_count_gone_) 589 | { 590 | _c->waiters_count_gone_ += 1; 591 | r = do_sema_b_wait (_c->sema_b, 1, INFINITE,&_c->waiters_b_lock_,&_c->value_b); 592 | if (r != 0) 593 | { 594 | LeaveCriticalSection(&_c->waiters_count_lock_); 595 | ch->r[0] = r; 596 | return; 597 | } 598 | _c->waiters_count_ -= _c->waiters_count_gone_; 599 | r = do_sema_b_release (_c->sema_b, 1,&_c->waiters_b_lock_,&_c->value_b); 600 | if (r != 0) 601 | { 602 | LeaveCriticalSection(&_c->waiters_count_lock_); 603 | ch->r[0] = r; 604 | return; 605 | } 606 | _c->waiters_count_gone_ = 0; 607 | } 608 | else 609 | _c->waiters_count_gone_ += 1; 610 | LeaveCriticalSection (&_c->waiters_count_lock_); 611 | 612 | if (n == 1) 613 | { 614 | r = do_sema_b_release (_c->sema_b, 1,&_c->waiters_b_lock_,&_c->value_b); 615 | if (r != 0) 616 | { 617 | ch->r[0] = r; 618 | return; 619 | } 620 | } 621 | r = pthread_mutex_lock(ch->external_mutex); 622 | if (r != 0) 623 | ch->r[0] = r; 624 | } 625 | 626 | static int 627 | do_sema_b_wait (HANDLE sema, int nointerrupt, DWORD timeout,CRITICAL_SECTION *cs, LONG *val) 628 | { 629 | int r; 630 | LONG v; 631 | EnterCriticalSection(cs); 632 | InterlockedDecrement(val); 633 | v = val[0]; 634 | LeaveCriticalSection(cs); 635 | if (v >= 0) 636 | return 0; 637 | r = do_sema_b_wait_intern (sema, nointerrupt, timeout); 638 | EnterCriticalSection(cs); 639 | if (r != 0) 640 | InterlockedIncrement(val); 641 | LeaveCriticalSection(cs); 642 | return r; 643 | } 644 | 645 | int 646 | do_sema_b_wait_intern (HANDLE sema, int nointerrupt, DWORD timeout) 647 | { 648 | HANDLE arr[2]; 649 | DWORD maxH = 1; 650 | int r = 0; 651 | DWORD res, dt; 652 | if (nointerrupt == 1) 653 | { 654 | res = WaitForSingleObject(sema, timeout); 655 | switch (res) { 656 | case WAIT_TIMEOUT: 657 | r = ETIMEDOUT; 658 | break; 659 | case WAIT_ABANDONED: 660 | r = EPERM; 661 | break; 662 | case WAIT_OBJECT_0: 663 | break; 664 | default: 665 | /*We can only return EINVAL though it might not be posix compliant */ 666 | r = EINVAL; 667 | } 668 | if (r != 0 && r != EINVAL && WaitForSingleObject(sema, 0) == WAIT_OBJECT_0) 669 | r = 0; 670 | return r; 671 | } 672 | arr[0] = sema; 673 | arr[1] = (HANDLE) pthread_getevent (); 674 | if (arr[1] != NULL) maxH += 1; 675 | if (maxH == 2) 676 | { 677 | redo: 678 | res = WaitForMultipleObjects(maxH, arr, 0, timeout); 679 | switch (res) { 680 | case WAIT_TIMEOUT: 681 | r = ETIMEDOUT; 682 | break; 683 | case (WAIT_OBJECT_0 + 1): 684 | ResetEvent(arr[1]); 685 | if (nointerrupt != 2) 686 | { 687 | pthread_testcancel(); 688 | return EINVAL; 689 | } 690 | pthread_testcancel (); 691 | goto redo; 692 | case WAIT_ABANDONED: 693 | r = EPERM; 694 | break; 695 | case WAIT_OBJECT_0: 696 | r = 0; 697 | break; 698 | default: 699 | /*We can only return EINVAL though it might not be posix compliant */ 700 | r = EINVAL; 701 | } 702 | if (r != 0 && r != EINVAL && WaitForSingleObject(arr[0], 0) == WAIT_OBJECT_0) 703 | r = 0; 704 | if (r != 0 && nointerrupt != 2 && __pthread_shallcancel ()) 705 | return EINVAL; 706 | return r; 707 | } 708 | if (timeout == INFINITE) 709 | { 710 | do { 711 | res = WaitForSingleObject(sema, 40); 712 | switch (res) { 713 | case WAIT_TIMEOUT: 714 | r = ETIMEDOUT; 715 | break; 716 | case WAIT_ABANDONED: 717 | r = EPERM; 718 | break; 719 | case WAIT_OBJECT_0: 720 | r = 0; 721 | break; 722 | default: 723 | /*We can only return EINVAL though it might not be posix compliant */ 724 | r = EINVAL; 725 | } 726 | if (r != 0 && __pthread_shallcancel ()) 727 | { 728 | if (nointerrupt != 2) 729 | pthread_testcancel(); 730 | return EINVAL; 731 | } 732 | } while (r == ETIMEDOUT); 733 | if (r != 0 && r != EINVAL && WaitForSingleObject(sema, 0) == WAIT_OBJECT_0) 734 | r = 0; 735 | return r; 736 | } 737 | dt = 20; 738 | do { 739 | if (dt > timeout) dt = timeout; 740 | res = WaitForSingleObject(sema, dt); 741 | switch (res) { 742 | case WAIT_TIMEOUT: 743 | r = ETIMEDOUT; 744 | break; 745 | case WAIT_ABANDONED: 746 | r = EPERM; 747 | break; 748 | case WAIT_OBJECT_0: 749 | r = 0; 750 | break; 751 | default: 752 | /*We can only return EINVAL though it might not be posix compliant */ 753 | r = EINVAL; 754 | } 755 | timeout -= dt; 756 | if (timeout != 0 && r != 0 && __pthread_shallcancel ()) 757 | return EINVAL; 758 | } while (r == ETIMEDOUT && timeout != 0); 759 | if (r != 0 && r == ETIMEDOUT && WaitForSingleObject(sema, 0) == WAIT_OBJECT_0) 760 | r = 0; 761 | if (r != 0 && nointerrupt != 2) 762 | pthread_testcancel(); 763 | return r; 764 | } 765 | 766 | static int 767 | do_sema_b_release(HANDLE sema, LONG count,CRITICAL_SECTION *cs, LONG *val) 768 | { 769 | int wc; 770 | EnterCriticalSection(cs); 771 | if (((long long) val[0] + (long long) count) > (long long) 0x7fffffffLL) 772 | { 773 | LeaveCriticalSection(cs); 774 | return ERANGE; 775 | } 776 | wc = -val[0]; 777 | InterlockedExchangeAdd(val, count); 778 | if (wc <= 0 || ReleaseSemaphore(sema, (wc < count ? wc : count), NULL)) 779 | { 780 | LeaveCriticalSection(cs); 781 | return 0; 782 | } 783 | InterlockedExchangeAdd(val, -count); 784 | LeaveCriticalSection(cs); 785 | return EINVAL; 786 | } 787 | -------------------------------------------------------------------------------- /src/cond.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2011 mingw-w64 project 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a 5 | copy of this software and associated documentation files (the "Software"), 6 | to deal in the Software without restriction, including without limitation 7 | the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 | and/or sell copies of the Software, and to permit persons to whom the 9 | Software is furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in 12 | all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 20 | DEALINGS IN THE SOFTWARE. 21 | */ 22 | 23 | #ifndef WIN_PTHREADS_COND_H 24 | #define WIN_PTHREADS_COND_H 25 | 26 | #include 27 | 28 | #define CHECK_COND(c) { \ 29 | if (!(c) || !*c || (*c == PTHREAD_COND_INITIALIZER) \ 30 | || ( ((cond_t *)(*c))->valid != (unsigned int)LIFE_COND ) ) \ 31 | return EINVAL; } 32 | 33 | #define LIFE_COND 0xC0BAB1FD 34 | #define DEAD_COND 0xC0DEADBF 35 | 36 | #define STATIC_COND_INITIALIZER(x) ((pthread_cond_t)(x) == ((pthread_cond_t)PTHREAD_COND_INITIALIZER)) 37 | 38 | typedef struct cond_t cond_t; 39 | struct cond_t 40 | { 41 | unsigned int valid; 42 | int busy; 43 | LONG waiters_count_; /* Number of waiting threads. */ 44 | LONG waiters_count_unblock_; /* Number of waiting threads whitch can be unblocked. */ 45 | LONG waiters_count_gone_; /* Number of waiters which are gone. */ 46 | CRITICAL_SECTION waiters_count_lock_; /* Serialize access to . */ 47 | CRITICAL_SECTION waiters_q_lock_; /* Serialize access to sema_q. */ 48 | LONG value_q; 49 | CRITICAL_SECTION waiters_b_lock_; /* Serialize access to sema_b. */ 50 | LONG value_b; 51 | HANDLE sema_q; /* Semaphore used to queue up threads waiting for the condition to 52 | become signaled. */ 53 | HANDLE sema_b; /* Semaphore used to queue up threads waiting for the condition which 54 | became signaled. */ 55 | }; 56 | 57 | void cond_print_set(int state, FILE *f); 58 | 59 | void cond_print(volatile pthread_cond_t *c, char *txt); 60 | 61 | #endif 62 | -------------------------------------------------------------------------------- /src/libgcc/dll_dependency.S: -------------------------------------------------------------------------------- 1 | /* Implementation for gcc's internal stack-allocation routines. */ 2 | .global ___chkstk 3 | .global __alloca 4 | 5 | .global ___chkstk_ms 6 | ___chkstk_ms: 7 | #ifdef _WIN64 8 | pushq %rax 9 | pushq %rcx 10 | cmpq $0x1000, %rax 11 | leaq 24(%rsp), %rcx 12 | jb .Lchkstk_ms_end 13 | .Lchkstk_ms_loop: 14 | subq $0x1000, %rcx 15 | subq $0x1000, %rax 16 | orq $0x0, (%rcx) 17 | cmpq $0x1000, %rax 18 | ja .Lchkstk_ms_loop 19 | .Lchkstk_ms_end: 20 | subq %rax, %rcx 21 | orq $0x0, (%rcx) 22 | popq %rcx 23 | popq %rax 24 | ret 25 | #else 26 | pushl %eax 27 | pushl %ecx 28 | cmpl $0x1000, %eax 29 | leal 12(%esp), %ecx 30 | jb chkstk_ms_end 31 | chkstk_ms_loop: 32 | subl $0x1000, %ecx 33 | subl $0x1000, %eax 34 | orl $0x0, (%ecx) 35 | cmpl $0x1000, %eax 36 | ja chkstk_ms_loop 37 | chkstk_ms_end: 38 | subl %eax, %ecx 39 | orl $0x0, (%ecx) 40 | popl %ecx 41 | popl %eax 42 | ret 43 | #endif 44 | 45 | #ifdef _WIN64 46 | __alloca: 47 | movq %rcx, %rax 48 | .align 4 49 | ___chkstk: 50 | popq %r11 51 | movq %rsp, %r10 52 | cmpq $0x1000, %rax 53 | jb .Lchkstk_end 54 | .Lchkstk_loop: 55 | subq $0x1000, %r10 56 | subq $0x1000, %rax 57 | orl $0x0, (%r10) 58 | cmpq $0x1000, %rax 59 | ja .Lchkstk_loop 60 | .Lchkstk_end: 61 | subq %rax, %r10 62 | movq %rsp, %rax 63 | orl $0x0, (%r10) 64 | movq %r10, %rsp 65 | pushq %r11 66 | ret 67 | #else 68 | ___chkstk: 69 | __alloca: 70 | pushl %ecx 71 | leal 8(%esp), %ecx 72 | cmpl $0x1000, %eax /* > 4k ?*/ 73 | jb chkstk_end 74 | chkstk_loop: 75 | subl $0x1000, %ecx 76 | subl $0x1000, %eax 77 | orl $0x0, (%ecx) 78 | cmpl $0x1000, %eax 79 | ja chkstk_loop 80 | chkstk_end: 81 | subl %eax, %ecx 82 | orl $0x0, (%ecx) 83 | movl %esp, %eax 84 | movl %ecx, %esp 85 | movl (%eax), %ecx 86 | pushl 4(%eax) 87 | ret 88 | #endif 89 | -------------------------------------------------------------------------------- /src/libgcc/dll_math.c: -------------------------------------------------------------------------------- 1 | /*- 2 | * Copyright (c) 1992, 1993 3 | * The Regents of the University of California. All rights reserved. 4 | * 5 | * This software was developed by the Computer Systems Engineering group 6 | * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and 7 | * contributed to Berkeley. 8 | * 9 | * Redistribution and use in source and binary forms, with or without 10 | * modification, are permitted provided that the following conditions 11 | * are met: 12 | * 1. Redistributions of source code must retain the above copyright 13 | * notice, this list of conditions and the following disclaimer. 14 | * 2. Redistributions in binary form must reproduce the above copyright 15 | * notice, this list of conditions and the following disclaimer in the 16 | * documentation and/or other materials provided with the distribution. 17 | * 4. Neither the name of the University nor the names of its contributors 18 | * may be used to endorse or promote products derived from this software 19 | * without specific prior written permission. 20 | * 21 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 | * SUCH DAMAGE. 32 | */ 33 | 34 | #ifndef _LIBKERN_QUAD_H_ 35 | #define _LIBKERN_QUAD_H_ 36 | 37 | /* 38 | * Quad arithmetic. 39 | * 40 | * This library makes the following assumptions: 41 | * 42 | * - The type long long (aka quad_t) exists. 43 | * 44 | * - A quad variable is exactly twice as long as `long'. 45 | * 46 | * - The machine's arithmetic is two's complement. 47 | * 48 | * This library can provide 128-bit arithmetic on a machine with 128-bit 49 | * quads and 64-bit longs, for instance, or 96-bit arithmetic on machines 50 | * with 48-bit longs. 51 | */ 52 | /* 53 | #include 54 | #include 55 | #include 56 | #include 57 | */ 58 | 59 | #include 60 | typedef long long quad_t; 61 | typedef unsigned long long u_quad_t; 62 | typedef unsigned long u_long; 63 | #define CHAR_BIT __CHAR_BIT__ 64 | 65 | /* 66 | * Define the order of 32-bit words in 64-bit words. 67 | * For little endian only. 68 | */ 69 | #define _QUAD_HIGHWORD 1 70 | #define _QUAD_LOWWORD 0 71 | 72 | /* 73 | * Depending on the desired operation, we view a `long long' (aka quad_t) in 74 | * one or more of the following formats. 75 | */ 76 | union uu { 77 | quad_t q; /* as a (signed) quad */ 78 | quad_t uq; /* as an unsigned quad */ 79 | long sl[2]; /* as two signed longs */ 80 | u_long ul[2]; /* as two unsigned longs */ 81 | }; 82 | 83 | /* 84 | * Define high and low longwords. 85 | */ 86 | #define H _QUAD_HIGHWORD 87 | #define L _QUAD_LOWWORD 88 | 89 | /* 90 | * Total number of bits in a quad_t and in the pieces that make it up. 91 | * These are used for shifting, and also below for halfword extraction 92 | * and assembly. 93 | */ 94 | #define QUAD_BITS (sizeof(quad_t) * CHAR_BIT) 95 | #define LONG_BITS (sizeof(long) * CHAR_BIT) 96 | #define HALF_BITS (sizeof(long) * CHAR_BIT / 2) 97 | 98 | /* 99 | * Extract high and low shortwords from longword, and move low shortword of 100 | * longword to upper half of long, i.e., produce the upper longword of 101 | * ((quad_t)(x) << (number_of_bits_in_long/2)). (`x' must actually be u_long.) 102 | * 103 | * These are used in the multiply code, to split a longword into upper 104 | * and lower halves, and to reassemble a product as a quad_t, shifted left 105 | * (sizeof(long)*CHAR_BIT/2). 106 | */ 107 | #define HHALF(x) ((x) >> HALF_BITS) 108 | #define LHALF(x) ((x) & ((1 << HALF_BITS) - 1)) 109 | #define LHUP(x) ((x) << HALF_BITS) 110 | 111 | typedef unsigned int qshift_t; 112 | 113 | quad_t __ashldi3(quad_t, qshift_t); 114 | quad_t __ashrdi3(quad_t, qshift_t); 115 | int __cmpdi2(quad_t a, quad_t b); 116 | quad_t __divdi3(quad_t a, quad_t b); 117 | quad_t __lshrdi3(quad_t, qshift_t); 118 | quad_t __moddi3(quad_t a, quad_t b); 119 | u_quad_t __qdivrem(u_quad_t u, u_quad_t v, u_quad_t *rem); 120 | u_quad_t __udivdi3(u_quad_t a, u_quad_t b); 121 | u_quad_t __umoddi3(u_quad_t a, u_quad_t b); 122 | int __ucmpdi2(u_quad_t a, u_quad_t b); 123 | 124 | #endif /* !_LIBKERN_QUAD_H_ */ 125 | 126 | #if defined (_X86_) && !defined (__x86_64__) 127 | /* 128 | * Shift a (signed) quad value left (arithmetic shift left). 129 | * This is the same as logical shift left! 130 | */ 131 | quad_t 132 | __ashldi3(a, shift) 133 | quad_t a; 134 | qshift_t shift; 135 | { 136 | union uu aa; 137 | 138 | aa.q = a; 139 | if (shift >= LONG_BITS) { 140 | aa.ul[H] = shift >= QUAD_BITS ? 0 : 141 | aa.ul[L] << (shift - LONG_BITS); 142 | aa.ul[L] = 0; 143 | } else if (shift > 0) { 144 | aa.ul[H] = (aa.ul[H] << shift) | 145 | (aa.ul[L] >> (LONG_BITS - shift)); 146 | aa.ul[L] <<= shift; 147 | } 148 | return (aa.q); 149 | } 150 | 151 | /* 152 | * Shift a (signed) quad value right (arithmetic shift right). 153 | */ 154 | quad_t 155 | __ashrdi3(a, shift) 156 | quad_t a; 157 | qshift_t shift; 158 | { 159 | union uu aa; 160 | 161 | aa.q = a; 162 | if (shift >= LONG_BITS) { 163 | long s; 164 | 165 | /* 166 | * Smear bits rightward using the machine's right-shift 167 | * method, whether that is sign extension or zero fill, 168 | * to get the `sign word' s. Note that shifting by 169 | * LONG_BITS is undefined, so we shift (LONG_BITS-1), 170 | * then 1 more, to get our answer. 171 | */ 172 | s = (aa.sl[H] >> (LONG_BITS - 1)) >> 1; 173 | aa.ul[L] = shift >= QUAD_BITS ? s : 174 | aa.sl[H] >> (shift - LONG_BITS); 175 | aa.ul[H] = s; 176 | } else if (shift > 0) { 177 | aa.ul[L] = (aa.ul[L] >> shift) | 178 | (aa.ul[H] << (LONG_BITS - shift)); 179 | aa.sl[H] >>= shift; 180 | } 181 | return (aa.q); 182 | } 183 | 184 | /* 185 | * Return 0, 1, or 2 as a <, =, > b respectively. 186 | * Both a and b are considered signed---which means only the high word is 187 | * signed. 188 | */ 189 | int 190 | __cmpdi2(a, b) 191 | quad_t a, b; 192 | { 193 | union uu aa, bb; 194 | 195 | aa.q = a; 196 | bb.q = b; 197 | return (aa.sl[H] < bb.sl[H] ? 0 : aa.sl[H] > bb.sl[H] ? 2 : 198 | aa.ul[L] < bb.ul[L] ? 0 : aa.ul[L] > bb.ul[L] ? 2 : 1); 199 | } 200 | 201 | /* 202 | * Divide two signed quads. 203 | * ??? if -1/2 should produce -1 on this machine, this code is wrong 204 | */ 205 | quad_t 206 | __divdi3(a, b) 207 | quad_t a, b; 208 | { 209 | u_quad_t ua, ub, uq; 210 | int neg; 211 | 212 | if (a < 0) 213 | ua = -(u_quad_t)a, neg = 1; 214 | else 215 | ua = a, neg = 0; 216 | if (b < 0) 217 | ub = -(u_quad_t)b, neg ^= 1; 218 | else 219 | ub = b; 220 | uq = __qdivrem(ua, ub, (u_quad_t *)0); 221 | return (neg ? -uq : uq); 222 | } 223 | 224 | /* 225 | * Shift an (unsigned) quad value right (logical shift right). 226 | */ 227 | quad_t 228 | __lshrdi3(a, shift) 229 | quad_t a; 230 | qshift_t shift; 231 | { 232 | union uu aa; 233 | 234 | aa.q = a; 235 | if (shift >= LONG_BITS) { 236 | aa.ul[L] = shift >= QUAD_BITS ? 0 : 237 | aa.ul[H] >> (shift - LONG_BITS); 238 | aa.ul[H] = 0; 239 | } else if (shift > 0) { 240 | aa.ul[L] = (aa.ul[L] >> shift) | 241 | (aa.ul[H] << (LONG_BITS - shift)); 242 | aa.ul[H] >>= shift; 243 | } 244 | return (aa.q); 245 | } 246 | 247 | /* 248 | * Return remainder after dividing two signed quads. 249 | * 250 | * XXX 251 | * If -1/2 should produce -1 on this machine, this code is wrong. 252 | */ 253 | quad_t 254 | __moddi3(a, b) 255 | quad_t a, b; 256 | { 257 | u_quad_t ua, ub, ur; 258 | int neg; 259 | 260 | if (a < 0) 261 | ua = -(u_quad_t)a, neg = 1; 262 | else 263 | ua = a, neg = 0; 264 | if (b < 0) 265 | ub = -(u_quad_t)b; 266 | else 267 | ub = b; 268 | (void)__qdivrem(ua, ub, &ur); 269 | return (neg ? -ur : ur); 270 | } 271 | 272 | 273 | /* 274 | * Multiprecision divide. This algorithm is from Knuth vol. 2 (2nd ed), 275 | * section 4.3.1, pp. 257--259. 276 | */ 277 | 278 | #define B (1 << HALF_BITS) /* digit base */ 279 | 280 | /* Combine two `digits' to make a single two-digit number. */ 281 | #define COMBINE(a, b) (((u_long)(a) << HALF_BITS) | (b)) 282 | 283 | /* select a type for digits in base B: use unsigned short if they fit */ 284 | #if ULONG_MAX == 0xffffffff && USHRT_MAX >= 0xffff 285 | typedef unsigned short digit; 286 | #else 287 | typedef u_long digit; 288 | #endif 289 | 290 | /* 291 | * Shift p[0]..p[len] left `sh' bits, ignoring any bits that 292 | * `fall out' the left (there never will be any such anyway). 293 | * We may assume len >= 0. NOTE THAT THIS WRITES len+1 DIGITS. 294 | */ 295 | static void 296 | __shl(register digit *p, register int len, register int sh) 297 | { 298 | register int i; 299 | 300 | for (i = 0; i < len; i++) 301 | p[i] = LHALF(p[i] << sh) | (p[i + 1] >> (HALF_BITS - sh)); 302 | p[i] = LHALF(p[i] << sh); 303 | } 304 | 305 | /* 306 | * __qdivrem(u, v, rem) returns u/v and, optionally, sets *rem to u%v. 307 | * 308 | * We do this in base 2-sup-HALF_BITS, so that all intermediate products 309 | * fit within u_long. As a consequence, the maximum length dividend and 310 | * divisor are 4 `digits' in this base (they are shorter if they have 311 | * leading zeros). 312 | */ 313 | u_quad_t 314 | __qdivrem(uq, vq, arq) 315 | u_quad_t uq, vq, *arq; 316 | { 317 | union uu tmp; 318 | digit *u, *v, *q; 319 | register digit v1, v2; 320 | u_long qhat, rhat, t; 321 | int m, n, d, j, i; 322 | digit uspace[5], vspace[5], qspace[5]; 323 | 324 | /* 325 | * Take care of special cases: divide by zero, and u < v. 326 | */ 327 | if (vq == 0) { 328 | /* divide by zero. */ 329 | static volatile const unsigned int zero = 0; 330 | 331 | tmp.ul[H] = tmp.ul[L] = 1 / zero; 332 | if (arq) 333 | *arq = uq; 334 | return (tmp.q); 335 | } 336 | if (uq < vq) { 337 | if (arq) 338 | *arq = uq; 339 | return (0); 340 | } 341 | u = &uspace[0]; 342 | v = &vspace[0]; 343 | q = &qspace[0]; 344 | 345 | /* 346 | * Break dividend and divisor into digits in base B, then 347 | * count leading zeros to determine m and n. When done, we 348 | * will have: 349 | * u = (u[1]u[2]...u[m+n]) sub B 350 | * v = (v[1]v[2]...v[n]) sub B 351 | * v[1] != 0 352 | * 1 < n <= 4 (if n = 1, we use a different division algorithm) 353 | * m >= 0 (otherwise u < v, which we already checked) 354 | * m + n = 4 355 | * and thus 356 | * m = 4 - n <= 2 357 | */ 358 | tmp.uq = uq; 359 | u[0] = 0; 360 | u[1] = HHALF(tmp.ul[H]); 361 | u[2] = LHALF(tmp.ul[H]); 362 | u[3] = HHALF(tmp.ul[L]); 363 | u[4] = LHALF(tmp.ul[L]); 364 | tmp.uq = vq; 365 | v[1] = HHALF(tmp.ul[H]); 366 | v[2] = LHALF(tmp.ul[H]); 367 | v[3] = HHALF(tmp.ul[L]); 368 | v[4] = LHALF(tmp.ul[L]); 369 | for (n = 4; v[1] == 0; v++) { 370 | if (--n == 1) { 371 | u_long rbj; /* r*B+u[j] (not root boy jim) */ 372 | digit q1, q2, q3, q4; 373 | 374 | /* 375 | * Change of plan, per exercise 16. 376 | * r = 0; 377 | * for j = 1..4: 378 | * q[j] = floor((r*B + u[j]) / v), 379 | * r = (r*B + u[j]) % v; 380 | * We unroll this completely here. 381 | */ 382 | t = v[2]; /* nonzero, by definition */ 383 | q1 = u[1] / t; 384 | rbj = COMBINE(u[1] % t, u[2]); 385 | q2 = rbj / t; 386 | rbj = COMBINE(rbj % t, u[3]); 387 | q3 = rbj / t; 388 | rbj = COMBINE(rbj % t, u[4]); 389 | q4 = rbj / t; 390 | if (arq) 391 | *arq = rbj % t; 392 | tmp.ul[H] = COMBINE(q1, q2); 393 | tmp.ul[L] = COMBINE(q3, q4); 394 | return (tmp.q); 395 | } 396 | } 397 | 398 | /* 399 | * By adjusting q once we determine m, we can guarantee that 400 | * there is a complete four-digit quotient at &qspace[1] when 401 | * we finally stop. 402 | */ 403 | for (m = 4 - n; u[1] == 0; u++) 404 | m--; 405 | for (i = 4 - m; --i >= 0;) 406 | q[i] = 0; 407 | q += 4 - m; 408 | 409 | /* 410 | * Here we run Program D, translated from MIX to C and acquiring 411 | * a few minor changes. 412 | * 413 | * D1: choose multiplier 1 << d to ensure v[1] >= B/2. 414 | */ 415 | d = 0; 416 | for (t = v[1]; t < B / 2; t <<= 1) 417 | d++; 418 | if (d > 0) { 419 | __shl(&u[0], m + n, d); /* u <<= d */ 420 | __shl(&v[1], n - 1, d); /* v <<= d */ 421 | } 422 | /* 423 | * D2: j = 0. 424 | */ 425 | j = 0; 426 | v1 = v[1]; /* for D3 -- note that v[1..n] are constant */ 427 | v2 = v[2]; /* for D3 */ 428 | do { 429 | register digit uj0, uj1, uj2; 430 | 431 | /* 432 | * D3: Calculate qhat (\^q, in TeX notation). 433 | * Let qhat = min((u[j]*B + u[j+1])/v[1], B-1), and 434 | * let rhat = (u[j]*B + u[j+1]) mod v[1]. 435 | * While rhat < B and v[2]*qhat > rhat*B+u[j+2], 436 | * decrement qhat and increase rhat correspondingly. 437 | * Note that if rhat >= B, v[2]*qhat < rhat*B. 438 | */ 439 | uj0 = u[j + 0]; /* for D3 only -- note that u[j+...] change */ 440 | uj1 = u[j + 1]; /* for D3 only */ 441 | uj2 = u[j + 2]; /* for D3 only */ 442 | if (uj0 == v1) { 443 | qhat = B; 444 | rhat = uj1; 445 | goto qhat_too_big; 446 | } else { 447 | u_long nn = COMBINE(uj0, uj1); 448 | qhat = nn / v1; 449 | rhat = nn % v1; 450 | } 451 | while (v2 * qhat > COMBINE(rhat, uj2)) { 452 | qhat_too_big: 453 | qhat--; 454 | if ((rhat += v1) >= B) 455 | break; 456 | } 457 | /* 458 | * D4: Multiply and subtract. 459 | * The variable `t' holds any borrows across the loop. 460 | * We split this up so that we do not require v[0] = 0, 461 | * and to eliminate a final special case. 462 | */ 463 | for (t = 0, i = n; i > 0; i--) { 464 | t = u[i + j] - v[i] * qhat - t; 465 | u[i + j] = LHALF(t); 466 | t = (B - HHALF(t)) & (B - 1); 467 | } 468 | t = u[j] - t; 469 | u[j] = LHALF(t); 470 | /* 471 | * D5: test remainder. 472 | * There is a borrow if and only if HHALF(t) is nonzero; 473 | * in that (rare) case, qhat was too large (by exactly 1). 474 | * Fix it by adding v[1..n] to u[j..j+n]. 475 | */ 476 | if (HHALF(t)) { 477 | qhat--; 478 | for (t = 0, i = n; i > 0; i--) { /* D6: add back. */ 479 | t += u[i + j] + v[i]; 480 | u[i + j] = LHALF(t); 481 | t = HHALF(t); 482 | } 483 | u[j] = LHALF(u[j] + t); 484 | } 485 | q[j] = qhat; 486 | } while (++j <= m); /* D7: loop on j. */ 487 | 488 | /* 489 | * If caller wants the remainder, we have to calculate it as 490 | * u[m..m+n] >> d (this is at most n digits and thus fits in 491 | * u[m+1..m+n], but we may need more source digits). 492 | */ 493 | if (arq) { 494 | if (d) { 495 | for (i = m + n; i > m; --i) 496 | u[i] = (u[i] >> d) | 497 | LHALF(u[i - 1] << (HALF_BITS - d)); 498 | u[i] = 0; 499 | } 500 | tmp.ul[H] = COMBINE(uspace[1], uspace[2]); 501 | tmp.ul[L] = COMBINE(uspace[3], uspace[4]); 502 | *arq = tmp.q; 503 | } 504 | 505 | tmp.ul[H] = COMBINE(qspace[1], qspace[2]); 506 | tmp.ul[L] = COMBINE(qspace[3], qspace[4]); 507 | return (tmp.q); 508 | } 509 | 510 | /* 511 | * Return 0, 1, or 2 as a <, =, > b respectively. 512 | * Neither a nor b are considered signed. 513 | */ 514 | int 515 | __ucmpdi2(a, b) 516 | u_quad_t a, b; 517 | { 518 | union uu aa, bb; 519 | 520 | aa.uq = a; 521 | bb.uq = b; 522 | return (aa.ul[H] < bb.ul[H] ? 0 : aa.ul[H] > bb.ul[H] ? 2 : 523 | aa.ul[L] < bb.ul[L] ? 0 : aa.ul[L] > bb.ul[L] ? 2 : 1); 524 | } 525 | 526 | /* 527 | * Divide two unsigned quads. 528 | */ 529 | u_quad_t 530 | __udivdi3(a, b) 531 | u_quad_t a, b; 532 | { 533 | 534 | return (__qdivrem(a, b, (u_quad_t *)0)); 535 | } 536 | 537 | /* 538 | * Return remainder after dividing two unsigned quads. 539 | */ 540 | u_quad_t 541 | __umoddi3(a, b) 542 | u_quad_t a, b; 543 | { 544 | u_quad_t r; 545 | 546 | (void)__qdivrem(a, b, &r); 547 | return (r); 548 | } 549 | #else 550 | static int __attribute__((unused)) dummy; 551 | #endif /*deined (_X86_) && !defined (__x86_64__)*/ 552 | 553 | -------------------------------------------------------------------------------- /src/misc.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2011 mingw-w64 project 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a 5 | copy of this software and associated documentation files (the "Software"), 6 | to deal in the Software without restriction, including without limitation 7 | the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 | and/or sell copies of the Software, and to permit persons to whom the 9 | Software is furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in 12 | all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 20 | DEALINGS IN THE SOFTWARE. 21 | */ 22 | 23 | #include "pthread.h" 24 | #include "windows.h" 25 | #include "misc.h" 26 | 27 | unsigned long long _pthread_time_in_ms(void) 28 | { 29 | FILETIME ft; 30 | 31 | GetSystemTimeAsFileTime(&ft); 32 | return (((unsigned long long)ft.dwHighDateTime << 32) + ft.dwLowDateTime 33 | - 0x19DB1DED53E8000ULL) / 10000ULL; 34 | } 35 | 36 | unsigned long long _pthread_time_in_ms_from_timespec(const struct timespec *ts) 37 | { 38 | unsigned long long t = (unsigned long long) ts->tv_sec * 1000LL; 39 | t += (unsigned long long) (ts->tv_nsec / 1000000); 40 | 41 | return t; 42 | } 43 | 44 | unsigned long long _pthread_rel_time_in_ms(const struct timespec *ts) 45 | { 46 | unsigned long long t1 = _pthread_time_in_ms_from_timespec(ts); 47 | unsigned long long t2 = _pthread_time_in_ms(); 48 | 49 | /* Prevent underflow */ 50 | if (t1 < t2) return 0; 51 | return t1 - t2; 52 | } 53 | 54 | -------------------------------------------------------------------------------- /src/misc.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2011 mingw-w64 project 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a 5 | copy of this software and associated documentation files (the "Software"), 6 | to deal in the Software without restriction, including without limitation 7 | the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 | and/or sell copies of the Software, and to permit persons to whom the 9 | Software is furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in 12 | all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 20 | DEALINGS IN THE SOFTWARE. 21 | */ 22 | 23 | #ifndef WIN_PTHREADS_MISC_H 24 | #define WIN_PTHREADS_MISC_H 25 | 26 | #include "pthread_compat.h" 27 | 28 | #ifndef assert 29 | 30 | #ifndef ASSERT_TRACE 31 | # define ASSERT_TRACE 0 32 | #else 33 | # undef ASSERT_TRACE 34 | # define ASSERT_TRACE 0 35 | #endif 36 | 37 | # define assert(e) \ 38 | ((e) ? ((ASSERT_TRACE) ? fprintf(stderr, \ 39 | "Assertion succeeded: (%s), file %s, line %d\n", \ 40 | #e, __FILE__, (int) __LINE__), \ 41 | fflush(stderr) : \ 42 | 0) : \ 43 | (fprintf(stderr, "Assertion failed: (%s), file %s, line %d\n", \ 44 | #e, __FILE__, (int) __LINE__), exit(1), 0)) 45 | 46 | # define fixme(e) \ 47 | ((e) ? ((ASSERT_TRACE) ? fprintf(stderr, \ 48 | "Assertion succeeded: (%s), file %s, line %d\n", \ 49 | #e, __FILE__, (int) __LINE__), \ 50 | fflush(stderr) : \ 51 | 0) : \ 52 | (fprintf(stderr, "FIXME: (%s), file %s, line %d\n", \ 53 | #e, __FILE__, (int) __LINE__), 0, 0)) 54 | 55 | #endif 56 | 57 | #define PTR2INT(x) ((int)(uintptr_t)(x)) 58 | 59 | #if SIZE_MAX>UINT_MAX 60 | typedef long long LONGBAG; 61 | #else 62 | typedef long LONGBAG; 63 | #endif 64 | 65 | #define CHECK_HANDLE(h) { DWORD dwFlags; \ 66 | if (!(h) || ((h) == INVALID_HANDLE_VALUE) || !GetHandleInformation((h), &dwFlags)) \ 67 | return EINVAL; } 68 | 69 | #define CHECK_PTR(p) if (!(p)) return EINVAL; 70 | 71 | #define UPD_RESULT(x,r) { int _r=(x); r = r ? r : _r; } 72 | 73 | #define CHECK_THREAD(t) { \ 74 | CHECK_PTR(t); \ 75 | CHECK_HANDLE(t->h); } 76 | 77 | #define CHECK_OBJECT(o, e) { DWORD dwFlags; \ 78 | if (!(o)) return e; \ 79 | if (!((o)->h) || (((o)->h) == INVALID_HANDLE_VALUE) || !GetHandleInformation(((o)->h), &dwFlags)){ \ 80 | (void)dwFlags; return e; } } 81 | 82 | #define VALID(x) if (!(p)) return EINVAL; 83 | 84 | /* ms can be 64 bit, solve wrap-around issues: */ 85 | static WINPTHREADS_INLINE unsigned long dwMilliSecs(unsigned long long ms) 86 | { 87 | if (ms >= 0xffffffffULL) return 0xfffffffful; 88 | return (unsigned long) ms; 89 | } 90 | 91 | #ifndef _mm_pause 92 | #define _mm_pause() {__asm__ __volatile__("pause");} 93 | #endif 94 | 95 | #ifndef _ReadWriteBarrier 96 | #define _ReadWriteBarrier __sync_synchronize 97 | #endif 98 | 99 | #ifndef YieldProcessor 100 | #define YieldProcessor _mm_pause 101 | #endif 102 | 103 | unsigned long long _pthread_time_in_ms(void); 104 | unsigned long long _pthread_time_in_ms_from_timespec(const struct timespec *ts); 105 | unsigned long long _pthread_rel_time_in_ms(const struct timespec *ts); 106 | 107 | #endif 108 | -------------------------------------------------------------------------------- /src/mutex.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2011, 2014 mingw-w64 project 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a 5 | copy of this software and associated documentation files (the "Software"), 6 | to deal in the Software without restriction, including without limitation 7 | the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 | and/or sell copies of the Software, and to permit persons to whom the 9 | Software is furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in 12 | all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 20 | DEALINGS IN THE SOFTWARE. 21 | */ 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include "pthread.h" 28 | #include "ref.h" 29 | #include "mutex.h" 30 | #include "misc.h" 31 | 32 | extern int do_sema_b_wait_intern (HANDLE sema, int nointerrupt, DWORD timeout); 33 | static WINPTHREADS_ATTRIBUTE((noinline)) int mutex_static_init(pthread_mutex_t *m); 34 | static WINPTHREADS_ATTRIBUTE((noinline)) int _mutex_trylock(pthread_mutex_t *m); 35 | 36 | static pthread_spinlock_t mutex_global = PTHREAD_SPINLOCK_INITIALIZER; 37 | static pthread_spinlock_t mutex_global_static = PTHREAD_SPINLOCK_INITIALIZER; 38 | 39 | static WINPTHREADS_ATTRIBUTE((noinline)) int 40 | mutex_unref (pthread_mutex_t *m, int r) 41 | { 42 | mutex_t *m_ = (mutex_t *)*m; 43 | pthread_spin_lock (&mutex_global); 44 | #ifdef WINPTHREAD_DBG 45 | assert((m_->valid == LIFE_MUTEX) && (m_->busy > 0)); 46 | #endif 47 | if (m_->valid == LIFE_MUTEX && m_->busy > 0) 48 | m_->busy -= 1; 49 | pthread_spin_unlock (&mutex_global); 50 | return r; 51 | } 52 | 53 | /* Set the mutex to busy in a thread-safe way */ 54 | /* A busy mutex can't be destroyed */ 55 | static WINPTHREADS_ATTRIBUTE((noinline)) int 56 | mutex_ref (pthread_mutex_t *m) 57 | { 58 | int r = 0; 59 | 60 | pthread_spin_lock (&mutex_global); 61 | 62 | if (!m || !*m) 63 | { 64 | pthread_spin_unlock (&mutex_global); 65 | return EINVAL; 66 | } 67 | 68 | if (STATIC_INITIALIZER(*m)) 69 | { 70 | pthread_spin_unlock (&mutex_global); 71 | r = mutex_static_init (m); 72 | pthread_spin_lock (&mutex_global); 73 | 74 | if (r != 0 && r != EBUSY) 75 | { 76 | pthread_spin_unlock (&mutex_global); 77 | return r; 78 | } 79 | } 80 | 81 | r = 0; 82 | 83 | if (!m || !*m || ((mutex_t *)*m)->valid != LIFE_MUTEX) 84 | r = EINVAL; 85 | else 86 | ((mutex_t *)*m)->busy += 1; 87 | 88 | pthread_spin_unlock (&mutex_global); 89 | 90 | return r; 91 | } 92 | 93 | /* An unlock can simply fail with EPERM instead of auto-init (can't be owned) */ 94 | static WINPTHREADS_ATTRIBUTE((noinline)) int 95 | mutex_ref_unlock (pthread_mutex_t *m) 96 | { 97 | int r = 0; 98 | mutex_t *m_ = (mutex_t *)*m; 99 | 100 | pthread_spin_lock (&mutex_global); 101 | 102 | if (!m || !*m || ((mutex_t *)*m)->valid != LIFE_MUTEX) 103 | r = EINVAL; 104 | else if (STATIC_INITIALIZER(*m) || !COND_LOCKED(m_)) 105 | r = EPERM; 106 | else 107 | ((mutex_t *)*m)->busy ++; 108 | 109 | pthread_spin_unlock (&mutex_global); 110 | 111 | return r; 112 | } 113 | 114 | /* doesn't lock the mutex but set it to invalid in a thread-safe way */ 115 | /* A busy mutex can't be destroyed -> EBUSY */ 116 | static WINPTHREADS_ATTRIBUTE((noinline)) int 117 | mutex_ref_destroy (pthread_mutex_t *m, pthread_mutex_t *mDestroy) 118 | { 119 | pthread_mutex_t mx; 120 | mutex_t *m_; 121 | int r = 0; 122 | 123 | if (!m || !*m) 124 | return EINVAL; 125 | 126 | *mDestroy = NULL; 127 | /* also considered as busy, any concurrent access prevents destruction: */ 128 | mx = *m; 129 | r = pthread_mutex_trylock (&mx); 130 | if (r) 131 | return r; 132 | 133 | pthread_spin_lock (&mutex_global); 134 | 135 | if (!*m) 136 | r = EINVAL; 137 | else 138 | { 139 | m_ = (mutex_t *)*m; 140 | if (STATIC_INITIALIZER(*m)) 141 | *m = NULL; 142 | else if (m_->valid != LIFE_MUTEX) 143 | r = EINVAL; 144 | else if (m_->busy) 145 | r = 0xbeef; 146 | else 147 | { 148 | *mDestroy = *m; 149 | *m = NULL; 150 | } 151 | } 152 | 153 | if (r) 154 | { 155 | pthread_spin_unlock (&mutex_global); 156 | pthread_mutex_unlock (&mx); 157 | } 158 | return r; 159 | } 160 | 161 | static WINPTHREADS_ATTRIBUTE((noinline)) int 162 | mutex_ref_init (pthread_mutex_t *m) 163 | { 164 | int r = 0; 165 | 166 | pthread_spin_lock (&mutex_global); 167 | 168 | if (!m) r = EINVAL; 169 | 170 | if (r) 171 | pthread_spin_unlock (&mutex_global); 172 | return r; 173 | } 174 | 175 | #ifdef WINPTHREAD_DBG 176 | static int print_state = 1; 177 | 178 | void mutex_print_set (int state) 179 | { 180 | print_state = state; 181 | } 182 | 183 | void mutex_print (volatile pthread_mutex_t *m, char *txt) 184 | { 185 | if (!print_state) 186 | return; 187 | mutex_t *m_ = (mutex_t *)*m; 188 | if (m_ == NULL) { 189 | printf("M%p %d %s\n",*m,(int)GetCurrentThreadId(),txt); 190 | } else { 191 | printf("M%p %d V=%0X B=%d t=%d o=%d C=%d R=%d H=%p %s\n", 192 | *m, 193 | (int)GetCurrentThreadId(), 194 | (int)m_->valid, 195 | (int)m_->busy, 196 | m_->type, 197 | (int)GET_OWNER(m_),(int)(m_->count),(int)GET_RCNT(m_),GET_HANDLE(m_),txt); 198 | } 199 | } 200 | #endif 201 | 202 | static WINPTHREADS_ATTRIBUTE((noinline)) int 203 | mutex_static_init (pthread_mutex_t *m) 204 | { 205 | static pthread_mutexattr_t mxattr_recursive = PTHREAD_MUTEX_RECURSIVE; 206 | static pthread_mutexattr_t mxattr_errorcheck = PTHREAD_MUTEX_ERRORCHECK; 207 | 208 | int r; 209 | 210 | pthread_spin_lock (&mutex_global_static); 211 | if (!STATIC_INITIALIZER(*m)) 212 | /* Assume someone crept in between: */ 213 | r = 0; 214 | else 215 | { 216 | if (*m == PTHREAD_MUTEX_INITIALIZER) 217 | r = pthread_mutex_init (m, NULL); 218 | else if (*m == PTHREAD_RECURSIVE_MUTEX_INITIALIZER) 219 | r = pthread_mutex_init (m, &mxattr_recursive); 220 | else if (*m == PTHREAD_ERRORCHECK_MUTEX_INITIALIZER) 221 | r = pthread_mutex_init (m, &mxattr_errorcheck); 222 | else if (*m == NULL) 223 | r = EINVAL; 224 | else 225 | r = pthread_mutex_init (m, NULL); 226 | } 227 | 228 | pthread_spin_unlock (&mutex_global_static); 229 | return r; 230 | } 231 | 232 | static int pthread_mutex_lock_intern(pthread_mutex_t *m, DWORD timeout); 233 | 234 | int 235 | pthread_mutex_lock (pthread_mutex_t *m) 236 | { 237 | return pthread_mutex_lock_intern (m, INFINITE); 238 | } 239 | 240 | static int 241 | pthread_mutex_lock_intern (pthread_mutex_t *m, DWORD timeout) 242 | { 243 | mutex_t *_m; 244 | int r; 245 | HANDLE h; 246 | 247 | r = mutex_ref (m); 248 | if (r) 249 | return r; 250 | 251 | _m = (mutex_t *) *m; 252 | if (_m->type != PTHREAD_MUTEX_NORMAL) 253 | { 254 | if (COND_LOCKED(_m)) 255 | { 256 | if (COND_OWNER(_m)) 257 | { 258 | if (_m->type == PTHREAD_MUTEX_RECURSIVE) 259 | { 260 | InterlockedIncrement(&_m->count); 261 | return mutex_unref(m,0); 262 | } 263 | 264 | return mutex_unref(m, EDEADLK); 265 | } 266 | } 267 | } 268 | 269 | h = _m->h; 270 | mutex_unref (m, 0); 271 | 272 | r = do_sema_b_wait_intern (h, 1, timeout); 273 | 274 | if (r != 0) 275 | return r; 276 | 277 | r = mutex_ref (m); 278 | if (r) 279 | return r; 280 | 281 | _m->count = 1; 282 | SET_OWNER(_m); 283 | 284 | return mutex_unref (m, r); 285 | } 286 | 287 | int pthread_mutex_timedlock(pthread_mutex_t *m, const struct timespec *ts) 288 | { 289 | unsigned long long t, ct; 290 | int r; 291 | mutex_t *_m; 292 | 293 | if (!ts) 294 | return pthread_mutex_lock(m); 295 | 296 | r = mutex_ref(m); 297 | if (r) 298 | return r; 299 | 300 | /* Try to lock it without waiting */ 301 | r = _mutex_trylock (m); 302 | if (r != EBUSY) 303 | return mutex_unref(m,r); 304 | 305 | _m = (mutex_t *)*m; 306 | if (_m->type != PTHREAD_MUTEX_NORMAL && COND_LOCKED(_m) && COND_OWNER(_m)) 307 | return mutex_unref(m,EDEADLK); 308 | 309 | ct = _pthread_time_in_ms(); 310 | t = _pthread_time_in_ms_from_timespec(ts); 311 | mutex_unref(m,r); 312 | r = pthread_mutex_lock_intern(m, (ct > t ? 0 : (t - ct))); 313 | return r; 314 | } 315 | 316 | int pthread_mutex_unlock(pthread_mutex_t *m) 317 | { 318 | mutex_t *_m; 319 | int r = mutex_ref_unlock(m); 320 | 321 | if(r) { 322 | return r; 323 | } 324 | 325 | _m = (mutex_t *)*m; 326 | 327 | if (_m->type == PTHREAD_MUTEX_NORMAL) 328 | { 329 | if (!COND_LOCKED(_m)) 330 | { 331 | return mutex_unref(m, EPERM); 332 | } 333 | } 334 | else if (!COND_LOCKED(_m) || !COND_OWNER(_m)) { 335 | return mutex_unref(m,EPERM); 336 | } 337 | 338 | if (_m->type == PTHREAD_MUTEX_RECURSIVE) 339 | { 340 | if(InterlockedDecrement(&_m->count)) { 341 | return mutex_unref(m,0); 342 | } 343 | } 344 | UNSET_OWNER(_m); 345 | 346 | if (_m->h != NULL && !ReleaseSemaphore(_m->h, 1, NULL)) { 347 | SET_OWNER(_m); 348 | /* restore our own bookkeeping */ 349 | return mutex_unref(m,EPERM); 350 | } 351 | 352 | return mutex_unref(m,0); 353 | } 354 | 355 | static WINPTHREADS_ATTRIBUTE((noinline)) int 356 | _mutex_trylock(pthread_mutex_t *m) 357 | { 358 | int r = 0; 359 | mutex_t *_m = (mutex_t *)*m; 360 | 361 | if (_m->type != PTHREAD_MUTEX_NORMAL) 362 | { 363 | if (COND_LOCKED(_m)) 364 | { 365 | if (_m->type == PTHREAD_MUTEX_RECURSIVE && COND_OWNER(_m)) 366 | { 367 | InterlockedIncrement(&_m->count); 368 | return 0; 369 | } 370 | 371 | return EBUSY; 372 | } 373 | } else if (COND_LOCKED(_m)) 374 | return EBUSY; 375 | 376 | r = do_sema_b_wait_intern (_m->h, 1, 0); 377 | 378 | if (r == ETIMEDOUT) 379 | r = EBUSY; 380 | else if (!r) 381 | { 382 | _m->count = 1; 383 | SET_OWNER(_m); 384 | } 385 | 386 | return r; 387 | } 388 | 389 | int pthread_mutex_trylock(pthread_mutex_t *m) 390 | { 391 | int r = mutex_ref(m); 392 | if(r) 393 | return r; 394 | 395 | return mutex_unref(m,_mutex_trylock(m)); 396 | } 397 | 398 | int 399 | pthread_mutex_init (pthread_mutex_t *m, const pthread_mutexattr_t *a) 400 | { 401 | mutex_t *_m; 402 | 403 | int r = mutex_ref_init (m); 404 | if (r) 405 | return r; 406 | 407 | if (!(_m = (pthread_mutex_t)calloc(1,sizeof(*_m)))) 408 | { 409 | pthread_spin_unlock (&mutex_global); 410 | return ENOMEM; 411 | } 412 | 413 | _m->type = PTHREAD_MUTEX_DEFAULT; 414 | _m->count = 0; 415 | _m->busy = 0; 416 | 417 | if (a) 418 | { 419 | int share = PTHREAD_PROCESS_PRIVATE; 420 | r = pthread_mutexattr_gettype (a, &_m->type); 421 | if (!r) 422 | r = pthread_mutexattr_getpshared(a, &share); 423 | 424 | if (!r && share == PTHREAD_PROCESS_SHARED) 425 | r = ENOSYS; 426 | } 427 | 428 | if (!r) 429 | { 430 | if ((_m->h = CreateSemaphore(NULL, 1, 0x7fffffff, NULL)) == NULL) 431 | { 432 | switch (GetLastError()) { 433 | case ERROR_ACCESS_DENIED: 434 | r = EPERM; 435 | break; 436 | default: /* We assume this, to keep it simple: */ 437 | r = ENOMEM; 438 | } 439 | } 440 | } 441 | 442 | if (r) 443 | { 444 | _m->valid = DEAD_MUTEX; 445 | free(_m); 446 | *m = NULL; 447 | pthread_spin_unlock (&mutex_global); 448 | return r; 449 | } 450 | 451 | _m->valid = LIFE_MUTEX; 452 | *m = _m; 453 | pthread_spin_unlock (&mutex_global); 454 | 455 | return 0; 456 | } 457 | 458 | int pthread_mutex_destroy (pthread_mutex_t *m) 459 | { 460 | mutex_t *_m; 461 | pthread_mutex_t mDestroy; 462 | int r; 463 | 464 | while ((r = mutex_ref_destroy (m, &mDestroy)) == 0xbeef) 465 | Sleep (0); 466 | if (r) 467 | return r; 468 | 469 | if (!mDestroy) 470 | { 471 | pthread_spin_unlock (&mutex_global); 472 | return 0; /* destroyed a (still) static initialized mutex */ 473 | } 474 | 475 | /* now the mutex is invalid, and no one can touch it */ 476 | _m = (mutex_t *)mDestroy; 477 | 478 | CloseHandle (_m->h); 479 | _m->valid = DEAD_MUTEX; 480 | _m->type = 0; 481 | _m->count = 0; 482 | _m->busy = 0; 483 | free (mDestroy); 484 | *m = NULL; 485 | pthread_spin_unlock (&mutex_global); 486 | 487 | return 0; 488 | } 489 | 490 | int pthread_mutexattr_init(pthread_mutexattr_t *a) 491 | { 492 | *a = PTHREAD_MUTEX_NORMAL | (PTHREAD_PROCESS_PRIVATE << 3); 493 | return 0; 494 | } 495 | 496 | int pthread_mutexattr_destroy(pthread_mutexattr_t *a) 497 | { 498 | if (!a) 499 | return EINVAL; 500 | 501 | return 0; 502 | } 503 | 504 | int pthread_mutexattr_gettype(const pthread_mutexattr_t *a, int *type) 505 | { 506 | if (!a || !type) 507 | return EINVAL; 508 | 509 | *type = *a & 3; 510 | 511 | return 0; 512 | } 513 | 514 | int pthread_mutexattr_settype(pthread_mutexattr_t *a, int type) 515 | { 516 | if (!a || (type != PTHREAD_MUTEX_NORMAL && type != PTHREAD_MUTEX_RECURSIVE && type != PTHREAD_MUTEX_ERRORCHECK)) 517 | return EINVAL; 518 | *a &= ~3; 519 | *a |= type; 520 | 521 | return 0; 522 | } 523 | 524 | int pthread_mutexattr_getpshared(const pthread_mutexattr_t *a, int *type) 525 | { 526 | if (!a || !type) 527 | return EINVAL; 528 | *type = (*a & 4 ? PTHREAD_PROCESS_SHARED : PTHREAD_PROCESS_PRIVATE); 529 | 530 | return 0; 531 | } 532 | 533 | int pthread_mutexattr_setpshared(pthread_mutexattr_t * a, int type) 534 | { 535 | int r = 0; 536 | if (!a || (type != PTHREAD_PROCESS_SHARED 537 | && type != PTHREAD_PROCESS_PRIVATE)) 538 | return EINVAL; 539 | if (type == PTHREAD_PROCESS_SHARED) 540 | { 541 | type = PTHREAD_PROCESS_PRIVATE; 542 | r = ENOSYS; 543 | } 544 | type = (type == PTHREAD_PROCESS_SHARED ? 4 : 0); 545 | 546 | *a &= ~4; 547 | *a |= type; 548 | 549 | return r; 550 | } 551 | 552 | int pthread_mutexattr_getprotocol(const pthread_mutexattr_t *a, int *type) 553 | { 554 | *type = *a & (8 + 16); 555 | 556 | return 0; 557 | } 558 | 559 | int pthread_mutexattr_setprotocol(pthread_mutexattr_t *a, int type) 560 | { 561 | if ((type & (8 + 16)) != 8 + 16) return EINVAL; 562 | 563 | *a &= ~(8 + 16); 564 | *a |= type; 565 | 566 | return 0; 567 | } 568 | 569 | int pthread_mutexattr_getprioceiling(const pthread_mutexattr_t *a, int * prio) 570 | { 571 | *prio = *a / PTHREAD_PRIO_MULT; 572 | return 0; 573 | } 574 | 575 | int pthread_mutexattr_setprioceiling(pthread_mutexattr_t *a, int prio) 576 | { 577 | *a &= (PTHREAD_PRIO_MULT - 1); 578 | *a += prio * PTHREAD_PRIO_MULT; 579 | 580 | return 0; 581 | } 582 | -------------------------------------------------------------------------------- /src/mutex.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2011 mingw-w64 project 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a 5 | copy of this software and associated documentation files (the "Software"), 6 | to deal in the Software without restriction, including without limitation 7 | the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 | and/or sell copies of the Software, and to permit persons to whom the 9 | Software is furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in 12 | all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 20 | DEALINGS IN THE SOFTWARE. 21 | */ 22 | 23 | #ifndef WIN_PTHREADS_MUTEX_H 24 | #define WIN_PTHREADS_MUTEX_H 25 | 26 | #define COND_LOCKED(m) (m->owner != 0) 27 | #define COND_OWNER(m) (m->owner == GetCurrentThreadId()) 28 | #define COND_DEADLK(m) COND_OWNER(m) 29 | #define GET_OWNER(m) (m->owner) 30 | #define GET_HANDLE(m) (m->h) 31 | #define GET_LOCKCNT(m) (m->count) 32 | #define GET_RCNT(m) (m->count) /* not accurate! */ 33 | #define SET_OWNER(m) (m->owner = GetCurrentThreadId()) 34 | #define UNSET_OWNER(m) { m->owner = 0; } 35 | #define LOCK_UNDO(m) 36 | #define COND_DEADLK_NR(m) ((m->type != PTHREAD_MUTEX_RECURSIVE) && COND_DEADLK(m)) 37 | #define CHECK_DEADLK(m) { if (COND_DEADLK_NR(m)) return EDEADLK; } 38 | 39 | #define STATIC_INITIALIZER(x) ((intptr_t)(x) >= -3 && (intptr_t)(x) <= -1) 40 | #define MUTEX_INITIALIZER2TYPE(x) ((LONGBAG)PTHREAD_NORMAL_MUTEX_INITIALIZER - (LONGBAG)(x)) 41 | 42 | #define LIFE_MUTEX 0xBAB1F00D 43 | #define DEAD_MUTEX 0xDEADBEEF 44 | 45 | typedef struct mutex_t mutex_t; 46 | struct mutex_t 47 | { 48 | LONG valid; 49 | volatile LONG busy; 50 | int type; 51 | volatile LONG count; 52 | LONG lockOwner; 53 | DWORD owner; 54 | HANDLE h; 55 | }; 56 | 57 | void mutex_print(volatile pthread_mutex_t *m, char *txt); 58 | void mutex_print_set(int state); 59 | 60 | #endif 61 | -------------------------------------------------------------------------------- /src/nanosleep.c: -------------------------------------------------------------------------------- 1 | /** 2 | * This file has no copyright assigned and is placed in the Public Domain. 3 | * This file is part of the w64 mingw-runtime package. 4 | * No warranty is given; refer to the file DISCLAIMER.PD within this package. 5 | */ 6 | 7 | #include 8 | #include 9 | #include 10 | #include "pthread.h" 11 | #include "pthread_time.h" 12 | #include "winpthread_internal.h" 13 | 14 | #define POW10_3 1000 15 | #define POW10_4 10000 16 | #define POW10_6 1000000 17 | #define POW10_9 1000000000 18 | #define MAX_SLEEP_IN_MS 4294967294UL 19 | 20 | /** 21 | * Sleep for the specified time. 22 | * @param request The desired amount of time to sleep. 23 | * @param remain The remain amount of time to sleep. 24 | * @return If the function succeeds, the return value is 0. 25 | * If the function fails, the return value is -1, 26 | * with errno set to indicate the error. 27 | */ 28 | int nanosleep(const struct timespec *request, struct timespec *remain) 29 | { 30 | unsigned long ms, rc = 0; 31 | unsigned __int64 u64, want, real; 32 | 33 | union { 34 | unsigned __int64 ns100; 35 | FILETIME ft; 36 | } _start, _end; 37 | 38 | if (request->tv_sec < 0 || request->tv_nsec < 0 || request->tv_nsec >= POW10_9) { 39 | errno = EINVAL; 40 | return -1; 41 | } 42 | 43 | if (remain != NULL) GetSystemTimeAsFileTime(&_start.ft); 44 | 45 | want = u64 = request->tv_sec * POW10_3 + request->tv_nsec / POW10_6; 46 | while (u64 > 0 && rc == 0) { 47 | if (u64 >= MAX_SLEEP_IN_MS) ms = MAX_SLEEP_IN_MS; 48 | else ms = (unsigned long) u64; 49 | 50 | u64 -= ms; 51 | rc = pthread_delay_np_ms(ms); 52 | } 53 | 54 | if (rc != 0) { /* WAIT_IO_COMPLETION (192) */ 55 | if (remain != NULL) { 56 | GetSystemTimeAsFileTime(&_end.ft); 57 | real = (_end.ns100 - _start.ns100) / POW10_4; 58 | 59 | if (real >= want) u64 = 0; 60 | else u64 = want - real; 61 | 62 | remain->tv_sec = u64 / POW10_3; 63 | remain->tv_nsec = (long) (u64 % POW10_3) * POW10_6; 64 | } 65 | 66 | errno = EINTR; 67 | return -1; 68 | } 69 | 70 | return 0; 71 | } 72 | -------------------------------------------------------------------------------- /src/ref.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2011 mingw-w64 project 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a 5 | copy of this software and associated documentation files (the "Software"), 6 | to deal in the Software without restriction, including without limitation 7 | the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 | and/or sell copies of the Software, and to permit persons to whom the 9 | Software is furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in 12 | all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 20 | DEALINGS IN THE SOFTWARE. 21 | */ 22 | 23 | #include 24 | #include 25 | #include 26 | #include "pthread.h" 27 | #include "semaphore.h" 28 | #include "mutex.h" 29 | #include "rwlock.h" 30 | #include "cond.h" 31 | #include "barrier.h" 32 | #include "sem.h" 33 | #include "ref.h" 34 | #include "misc.h" 35 | 36 | -------------------------------------------------------------------------------- /src/ref.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2011 mingw-w64 project 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a 5 | copy of this software and associated documentation files (the "Software"), 6 | to deal in the Software without restriction, including without limitation 7 | the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 | and/or sell copies of the Software, and to permit persons to whom the 9 | Software is furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in 12 | all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 20 | DEALINGS IN THE SOFTWARE. 21 | */ 22 | 23 | #ifndef WIN_PTHREADS_REF_H 24 | #define WIN_PTHREADS_REF_H 25 | #include "pthread.h" 26 | #include "semaphore.h" 27 | 28 | #endif 29 | 30 | -------------------------------------------------------------------------------- /src/rwlock.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2011 mingw-w64 project 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a 5 | copy of this software and associated documentation files (the "Software"), 6 | to deal in the Software without restriction, including without limitation 7 | the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 | and/or sell copies of the Software, and to permit persons to whom the 9 | Software is furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in 12 | all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 20 | DEALINGS IN THE SOFTWARE. 21 | */ 22 | 23 | #include 24 | #include 25 | #include 26 | #include "pthread.h" 27 | #include "thread.h" 28 | #include "ref.h" 29 | #include "rwlock.h" 30 | #include "misc.h" 31 | 32 | static pthread_spinlock_t rwl_global = PTHREAD_SPINLOCK_INITIALIZER; 33 | 34 | static WINPTHREADS_ATTRIBUTE((noinline)) int rwlock_static_init(pthread_rwlock_t *rw); 35 | 36 | static WINPTHREADS_ATTRIBUTE((noinline)) int rwl_unref(volatile pthread_rwlock_t *rwl, int res) 37 | { 38 | pthread_spin_lock(&rwl_global); 39 | #ifdef WINPTHREAD_DBG 40 | assert((((rwlock_t *)*rwl)->valid == LIFE_RWLOCK) && (((rwlock_t *)*rwl)->busy > 0)); 41 | #endif 42 | ((rwlock_t *)*rwl)->busy--; 43 | pthread_spin_unlock(&rwl_global); 44 | return res; 45 | } 46 | 47 | static WINPTHREADS_ATTRIBUTE((noinline)) int rwl_ref(pthread_rwlock_t *rwl, int f ) 48 | { 49 | int r = 0; 50 | INIT_RWLOCK(rwl); 51 | pthread_spin_lock(&rwl_global); 52 | 53 | if (!rwl || !*rwl || ((rwlock_t *)*rwl)->valid != LIFE_RWLOCK) r = EINVAL; 54 | else { 55 | ((rwlock_t *)*rwl)->busy ++; 56 | } 57 | 58 | pthread_spin_unlock(&rwl_global); 59 | 60 | return r; 61 | } 62 | 63 | static WINPTHREADS_ATTRIBUTE((noinline)) int rwl_ref_unlock(pthread_rwlock_t *rwl ) 64 | { 65 | int r = 0; 66 | 67 | pthread_spin_lock(&rwl_global); 68 | 69 | if (!rwl || !*rwl || ((rwlock_t *)*rwl)->valid != LIFE_RWLOCK) r = EINVAL; 70 | else if (STATIC_RWL_INITIALIZER(*rwl)) r= EPERM; 71 | else { 72 | ((rwlock_t *)*rwl)->busy ++; 73 | } 74 | 75 | pthread_spin_unlock(&rwl_global); 76 | 77 | return r; 78 | } 79 | 80 | static WINPTHREADS_ATTRIBUTE((noinline)) int rwl_ref_destroy(pthread_rwlock_t *rwl, pthread_rwlock_t *rDestroy ) 81 | { 82 | int r = 0; 83 | 84 | *rDestroy = NULL; 85 | pthread_spin_lock(&rwl_global); 86 | 87 | if (!rwl || !*rwl) r = EINVAL; 88 | else { 89 | rwlock_t *r_ = (rwlock_t *)*rwl; 90 | if (STATIC_RWL_INITIALIZER(*rwl)) *rwl = NULL; 91 | else if (r_->valid != LIFE_RWLOCK) r = EINVAL; 92 | else if (r_->busy) r = EBUSY; 93 | else { 94 | *rDestroy = *rwl; 95 | *rwl = NULL; 96 | } 97 | } 98 | 99 | pthread_spin_unlock(&rwl_global); 100 | return r; 101 | } 102 | 103 | static int rwlock_gain_both_locks(rwlock_t *rwlock) 104 | { 105 | int ret; 106 | ret = pthread_mutex_lock(&rwlock->mex); 107 | if (ret != 0) 108 | return ret; 109 | ret = pthread_mutex_lock(&rwlock->mcomplete); 110 | if (ret != 0) 111 | pthread_mutex_unlock(&rwlock->mex); 112 | return ret; 113 | } 114 | 115 | static int rwlock_free_both_locks(rwlock_t *rwlock, int last_fail) 116 | { 117 | int ret, ret2; 118 | ret = pthread_mutex_unlock(&rwlock->mcomplete); 119 | ret2 = pthread_mutex_unlock(&rwlock->mex); 120 | if (last_fail && ret2 != 0) 121 | ret = ret2; 122 | else if (!last_fail && !ret) 123 | ret = ret2; 124 | return ret; 125 | } 126 | 127 | #ifdef WINPTHREAD_DBG 128 | static int print_state = 0; 129 | void rwl_print_set(int state) 130 | { 131 | print_state = state; 132 | } 133 | 134 | void rwl_print(volatile pthread_rwlock_t *rwl, char *txt) 135 | { 136 | if (!print_state) return; 137 | rwlock_t *r = (rwlock_t *)*rwl; 138 | if (r == NULL) { 139 | printf("RWL%p %d %s\n",*rwl,(int)GetCurrentThreadId(),txt); 140 | } else { 141 | printf("RWL%p %d V=%0X B=%d r=%ld w=%ld L=%p %s\n", 142 | *rwl, 143 | (int)GetCurrentThreadId(), 144 | (int)r->valid, 145 | (int)r->busy, 146 | 0L,0L,NULL,txt); 147 | } 148 | } 149 | #endif 150 | 151 | static pthread_spinlock_t cond_locked = PTHREAD_SPINLOCK_INITIALIZER; 152 | 153 | static WINPTHREADS_ATTRIBUTE((noinline)) int rwlock_static_init(pthread_rwlock_t *rw) 154 | { 155 | int r; 156 | pthread_spin_lock(&cond_locked); 157 | if (*rw != PTHREAD_RWLOCK_INITIALIZER) 158 | { 159 | pthread_spin_unlock(&cond_locked); 160 | return EINVAL; 161 | } 162 | r = pthread_rwlock_init (rw, NULL); 163 | pthread_spin_unlock(&cond_locked); 164 | 165 | return r; 166 | } 167 | 168 | int pthread_rwlock_init (pthread_rwlock_t *rwlock_, const pthread_rwlockattr_t *attr) 169 | { 170 | rwlock_t *rwlock; 171 | int r; 172 | 173 | if(!rwlock_) 174 | return EINVAL; 175 | *rwlock_ = NULL; 176 | if ((rwlock = (pthread_rwlock_t)calloc(1, sizeof(*rwlock))) == NULL) 177 | return ENOMEM; 178 | rwlock->valid = DEAD_RWLOCK; 179 | 180 | rwlock->nex_count = rwlock->nsh_count = rwlock->ncomplete = 0; 181 | if ((r = pthread_mutex_init (&rwlock->mex, NULL)) != 0) 182 | { 183 | free(rwlock); 184 | return r; 185 | } 186 | if ((r = pthread_mutex_init (&rwlock->mcomplete, NULL)) != 0) 187 | { 188 | pthread_mutex_destroy(&rwlock->mex); 189 | free(rwlock); 190 | return r; 191 | } 192 | if ((r = pthread_cond_init (&rwlock->ccomplete, NULL)) != 0) 193 | { 194 | pthread_mutex_destroy(&rwlock->mex); 195 | pthread_mutex_destroy (&rwlock->mcomplete); 196 | free(rwlock); 197 | return r; 198 | } 199 | rwlock->valid = LIFE_RWLOCK; 200 | *rwlock_ = rwlock; 201 | return r; 202 | } 203 | 204 | int pthread_rwlock_destroy (pthread_rwlock_t *rwlock_) 205 | { 206 | rwlock_t *rwlock; 207 | pthread_rwlock_t rDestroy; 208 | int r, r2; 209 | 210 | pthread_spin_lock(&cond_locked); 211 | r = rwl_ref_destroy(rwlock_,&rDestroy); 212 | pthread_spin_unlock(&cond_locked); 213 | 214 | if(r) return r; 215 | if(!rDestroy) return 0; /* destroyed a (still) static initialized rwl */ 216 | 217 | rwlock = (rwlock_t *)rDestroy; 218 | r = rwlock_gain_both_locks (rwlock); 219 | if (r != 0) 220 | { 221 | *rwlock_ = rDestroy; 222 | return r; 223 | } 224 | if (rwlock->nsh_count > rwlock->ncomplete || rwlock->nex_count > 0) 225 | { 226 | *rwlock_ = rDestroy; 227 | r = rwlock_free_both_locks(rwlock, 1); 228 | if (!r) 229 | r = EBUSY; 230 | return r; 231 | } 232 | rwlock->valid = DEAD_RWLOCK; 233 | r = rwlock_free_both_locks(rwlock, 0); 234 | if (r != 0) { *rwlock_ = rDestroy; return r; } 235 | 236 | r = pthread_cond_destroy(&rwlock->ccomplete); 237 | r2 = pthread_mutex_destroy(&rwlock->mex); 238 | if (!r) r = r2; 239 | r2 = pthread_mutex_destroy(&rwlock->mcomplete); 240 | if (!r) r = r2; 241 | rwlock->valid = DEAD_RWLOCK; 242 | free(rDestroy); 243 | return 0; 244 | } 245 | 246 | int pthread_rwlock_rdlock (pthread_rwlock_t *rwlock_) 247 | { 248 | rwlock_t *rwlock; 249 | int ret; 250 | 251 | /* pthread_testcancel(); */ 252 | 253 | ret = rwl_ref(rwlock_,0); 254 | if(ret != 0) return ret; 255 | 256 | rwlock = (rwlock_t *)*rwlock_; 257 | 258 | ret = pthread_mutex_lock(&rwlock->mex); 259 | if (ret != 0) return rwl_unref(rwlock_, ret); 260 | InterlockedIncrement((long*)&rwlock->nsh_count); 261 | if (rwlock->nsh_count == INT_MAX) 262 | { 263 | ret = pthread_mutex_lock(&rwlock->mcomplete); 264 | if (ret != 0) 265 | { 266 | pthread_mutex_unlock(&rwlock->mex); 267 | return rwl_unref(rwlock_,ret); 268 | } 269 | rwlock->nsh_count -= rwlock->ncomplete; 270 | rwlock->ncomplete = 0; 271 | ret = rwlock_free_both_locks(rwlock, 0); 272 | return rwl_unref(rwlock_, ret); 273 | } 274 | ret = pthread_mutex_unlock(&rwlock->mex); 275 | return rwl_unref(rwlock_, ret); 276 | } 277 | 278 | int pthread_rwlock_timedrdlock (pthread_rwlock_t *rwlock_, const struct timespec *ts) 279 | { 280 | rwlock_t *rwlock; 281 | int ret; 282 | 283 | /* pthread_testcancel(); */ 284 | 285 | ret = rwl_ref(rwlock_,0); 286 | if(ret != 0) return ret; 287 | 288 | rwlock = (rwlock_t *)*rwlock_; 289 | if ((ret = pthread_mutex_timedlock (&rwlock->mex, ts)) != 0) 290 | return rwl_unref(rwlock_, ret); 291 | InterlockedIncrement(&rwlock->nsh_count); 292 | if (rwlock->nsh_count == INT_MAX) 293 | { 294 | ret = pthread_mutex_timedlock(&rwlock->mcomplete, ts); 295 | if (ret != 0) 296 | { 297 | if (ret == ETIMEDOUT) 298 | InterlockedIncrement(&rwlock->ncomplete); 299 | pthread_mutex_unlock(&rwlock->mex); 300 | return rwl_unref(rwlock_, ret); 301 | } 302 | rwlock->nsh_count -= rwlock->ncomplete; 303 | rwlock->ncomplete = 0; 304 | ret = rwlock_free_both_locks(rwlock, 0); 305 | return rwl_unref(rwlock_, ret); 306 | } 307 | ret = pthread_mutex_unlock(&rwlock->mex); 308 | return rwl_unref(rwlock_, ret); 309 | } 310 | 311 | int pthread_rwlock_tryrdlock (pthread_rwlock_t *rwlock_) 312 | { 313 | rwlock_t *rwlock; 314 | int ret; 315 | 316 | ret = rwl_ref(rwlock_,RWL_TRY); 317 | if(ret != 0) return ret; 318 | 319 | rwlock = (rwlock_t *)*rwlock_; 320 | ret = pthread_mutex_trylock(&rwlock->mex); 321 | if (ret != 0) 322 | return rwl_unref(rwlock_, ret); 323 | InterlockedIncrement(&rwlock->nsh_count); 324 | if (rwlock->nsh_count == INT_MAX) 325 | { 326 | ret = pthread_mutex_lock(&rwlock->mcomplete); 327 | if (ret != 0) 328 | { 329 | pthread_mutex_unlock(&rwlock->mex); 330 | return rwl_unref(rwlock_, ret); 331 | } 332 | rwlock->nsh_count -= rwlock->ncomplete; 333 | rwlock->ncomplete = 0; 334 | ret = rwlock_free_both_locks(rwlock, 0); 335 | return rwl_unref(rwlock_, ret); 336 | } 337 | ret = pthread_mutex_unlock(&rwlock->mex); 338 | return rwl_unref(rwlock_,ret); 339 | } 340 | 341 | int pthread_rwlock_trywrlock (pthread_rwlock_t *rwlock_) 342 | { 343 | rwlock_t *rwlock; 344 | int ret; 345 | 346 | ret = rwl_ref(rwlock_,RWL_TRY); 347 | if(ret != 0) return ret; 348 | 349 | rwlock = (rwlock_t *)*rwlock_; 350 | ret = pthread_mutex_trylock (&rwlock->mex); 351 | if (ret != 0) 352 | return rwl_unref(rwlock_, ret); 353 | ret = pthread_mutex_trylock(&rwlock->mcomplete); 354 | if (ret != 0) 355 | { 356 | int r1 = pthread_mutex_unlock(&rwlock->mex); 357 | if (r1 != 0) 358 | ret = r1; 359 | return rwl_unref(rwlock_, ret); 360 | } 361 | if (rwlock->nex_count != 0) 362 | return rwl_unref(rwlock_, EBUSY); 363 | if (rwlock->ncomplete > 0) 364 | { 365 | rwlock->nsh_count -= rwlock->ncomplete; 366 | rwlock->ncomplete = 0; 367 | } 368 | if (rwlock->nsh_count > 0) 369 | { 370 | ret = rwlock_free_both_locks(rwlock, 0); 371 | if (!ret) 372 | ret = EBUSY; 373 | return rwl_unref(rwlock_, ret); 374 | } 375 | rwlock->nex_count = 1; 376 | return rwl_unref(rwlock_, 0); 377 | } 378 | 379 | int pthread_rwlock_unlock (pthread_rwlock_t *rwlock_) 380 | { 381 | rwlock_t *rwlock; 382 | int ret; 383 | 384 | ret = rwl_ref_unlock(rwlock_); 385 | if(ret != 0) return ret; 386 | 387 | rwlock = (rwlock_t *)*rwlock_; 388 | if (rwlock->nex_count == 0) 389 | { 390 | ret = pthread_mutex_lock(&rwlock->mcomplete); 391 | if (!ret) 392 | { 393 | int r1; 394 | InterlockedIncrement(&rwlock->ncomplete); 395 | if (rwlock->ncomplete == 0) 396 | ret = pthread_cond_signal(&rwlock->ccomplete); 397 | r1 = pthread_mutex_unlock(&rwlock->mcomplete); 398 | if (!ret) 399 | ret = r1; 400 | } 401 | } 402 | else 403 | { 404 | InterlockedDecrement(&rwlock->nex_count); 405 | ret = rwlock_free_both_locks(rwlock, 0); 406 | } 407 | return rwl_unref(rwlock_, ret); 408 | } 409 | 410 | static void st_cancelwrite (void *arg) 411 | { 412 | rwlock_t *rwlock = (rwlock_t *)arg; 413 | 414 | rwlock->nsh_count = - rwlock->ncomplete; 415 | rwlock->ncomplete = 0; 416 | rwlock_free_both_locks(rwlock, 0); 417 | } 418 | 419 | int pthread_rwlock_wrlock (pthread_rwlock_t *rwlock_) 420 | { 421 | rwlock_t *rwlock; 422 | int ret; 423 | 424 | /* pthread_testcancel(); */ 425 | ret = rwl_ref(rwlock_,0); 426 | if(ret != 0) return ret; 427 | 428 | rwlock = (rwlock_t *)*rwlock_; 429 | ret = rwlock_gain_both_locks(rwlock); 430 | if (ret != 0) 431 | return rwl_unref(rwlock_,ret); 432 | 433 | if (rwlock->nex_count == 0) 434 | { 435 | if (rwlock->ncomplete > 0) 436 | { 437 | rwlock->nsh_count -= rwlock->ncomplete; 438 | rwlock->ncomplete = 0; 439 | } 440 | if (rwlock->nsh_count > 0) 441 | { 442 | rwlock->ncomplete = -rwlock->nsh_count; 443 | pthread_cleanup_push(st_cancelwrite, (void *) rwlock); 444 | do { 445 | ret = pthread_cond_wait(&rwlock->ccomplete, &rwlock->mcomplete); 446 | } while (!ret && rwlock->ncomplete < 0); 447 | 448 | pthread_cleanup_pop(!ret ? 0 : 1); 449 | if (!ret) 450 | rwlock->nsh_count = 0; 451 | } 452 | } 453 | if(!ret) 454 | InterlockedIncrement((long*)&rwlock->nex_count); 455 | return rwl_unref(rwlock_,ret); 456 | } 457 | 458 | int pthread_rwlock_timedwrlock (pthread_rwlock_t *rwlock_, const struct timespec *ts) 459 | { 460 | int ret; 461 | rwlock_t *rwlock; 462 | 463 | /* pthread_testcancel(); */ 464 | if (!rwlock_ || !ts) 465 | return EINVAL; 466 | if ((ret = rwl_ref(rwlock_,0)) != 0) 467 | return ret; 468 | rwlock = (rwlock_t *)*rwlock_; 469 | 470 | ret = pthread_mutex_timedlock(&rwlock->mex, ts); 471 | if (ret != 0) 472 | return rwl_unref(rwlock_,ret); 473 | ret = pthread_mutex_timedlock (&rwlock->mcomplete, ts); 474 | if (ret != 0) 475 | { 476 | pthread_mutex_unlock(&rwlock->mex); 477 | return rwl_unref(rwlock_,ret); 478 | } 479 | if (rwlock->nex_count == 0) 480 | { 481 | if (rwlock->ncomplete > 0) 482 | { 483 | rwlock->nsh_count -= rwlock->ncomplete; 484 | rwlock->ncomplete = 0; 485 | } 486 | if (rwlock->nsh_count > 0) 487 | { 488 | rwlock->ncomplete = -rwlock->nsh_count; 489 | pthread_cleanup_push(st_cancelwrite, (void *) rwlock); 490 | do { 491 | ret = pthread_cond_timedwait(&rwlock->ccomplete, &rwlock->mcomplete, ts); 492 | } while (rwlock->ncomplete < 0 && !ret); 493 | pthread_cleanup_pop(!ret ? 0 : 1); 494 | 495 | if (!ret) 496 | rwlock->nsh_count = 0; 497 | } 498 | } 499 | if(!ret) 500 | InterlockedIncrement((long*)&rwlock->nex_count); 501 | return rwl_unref(rwlock_,ret); 502 | } 503 | 504 | int pthread_rwlockattr_destroy(pthread_rwlockattr_t *a) 505 | { 506 | if (!a) 507 | return EINVAL; 508 | return 0; 509 | } 510 | 511 | int pthread_rwlockattr_init(pthread_rwlockattr_t *a) 512 | { 513 | if (!a) 514 | return EINVAL; 515 | *a = PTHREAD_PROCESS_PRIVATE; 516 | return 0; 517 | } 518 | 519 | int pthread_rwlockattr_getpshared(pthread_rwlockattr_t *a, int *s) 520 | { 521 | if (!a || !s) 522 | return EINVAL; 523 | *s = *a; 524 | return 0; 525 | } 526 | 527 | int pthread_rwlockattr_setpshared(pthread_rwlockattr_t *a, int s) 528 | { 529 | if (!a || (s != PTHREAD_PROCESS_SHARED && s != PTHREAD_PROCESS_PRIVATE)) 530 | return EINVAL; 531 | *a = s; 532 | return 0; 533 | } 534 | -------------------------------------------------------------------------------- /src/rwlock.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2011 mingw-w64 project 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a 5 | copy of this software and associated documentation files (the "Software"), 6 | to deal in the Software without restriction, including without limitation 7 | the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 | and/or sell copies of the Software, and to permit persons to whom the 9 | Software is furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in 12 | all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 20 | DEALINGS IN THE SOFTWARE. 21 | */ 22 | 23 | #ifndef WIN_PTHREADS_RWLOCK_H 24 | #define WIN_PTHREADS_RWLOCK_H 25 | 26 | #define LIFE_RWLOCK 0xBAB1F0ED 27 | #define DEAD_RWLOCK 0xDEADB0EF 28 | 29 | #define INIT_RWLOCK(rwl) { int r; \ 30 | if (STATIC_RWL_INITIALIZER(*rwl)) { if ((r = rwlock_static_init(rwl))) { if (r != EBUSY) return r; }}} 31 | 32 | #define STATIC_RWL_INITIALIZER(x) ((pthread_rwlock_t)(x) == ((pthread_rwlock_t)PTHREAD_RWLOCK_INITIALIZER)) 33 | 34 | typedef struct rwlock_t rwlock_t; 35 | struct rwlock_t { 36 | unsigned int valid; 37 | int busy; 38 | LONG nex_count; /* Exclusive access counter. */ 39 | LONG nsh_count; /* Shared access counter. */ 40 | LONG ncomplete; /* Shared completed counter. */ 41 | pthread_mutex_t mex; /* Exclusive access protection. */ 42 | pthread_mutex_t mcomplete; /* Shared completed protection. */ 43 | pthread_cond_t ccomplete; /* Shared access completed queue. */ 44 | }; 45 | 46 | #define RWL_SET 0x01 47 | #define RWL_TRY 0x02 48 | 49 | void rwl_print(volatile pthread_rwlock_t *rwl, char *txt); 50 | void rwl_print_set(int state); 51 | 52 | #endif 53 | -------------------------------------------------------------------------------- /src/sched.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2011-2013 mingw-w64 project 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a 5 | copy of this software and associated documentation files (the "Software"), 6 | to deal in the Software without restriction, including without limitation 7 | the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 | and/or sell copies of the Software, and to permit persons to whom the 9 | Software is furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in 12 | all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 20 | DEALINGS IN THE SOFTWARE. 21 | */ 22 | 23 | #include 24 | #include 25 | #include "pthread.h" 26 | #include "thread.h" 27 | 28 | #include "misc.h" 29 | 30 | int sched_get_priority_min(int pol) 31 | { 32 | if (pol < SCHED_MIN || pol > SCHED_MAX) { 33 | errno = EINVAL; 34 | return -1; 35 | } 36 | 37 | return THREAD_PRIORITY_IDLE; 38 | } 39 | 40 | int sched_get_priority_max(int pol) 41 | { 42 | if (pol < SCHED_MIN || pol > SCHED_MAX) { 43 | errno = EINVAL; 44 | return -1; 45 | } 46 | 47 | return THREAD_PRIORITY_TIME_CRITICAL; 48 | } 49 | 50 | int pthread_attr_setschedparam(pthread_attr_t *attr, const struct sched_param *p) 51 | { 52 | int r = 0; 53 | 54 | if (attr == NULL || p == NULL) { 55 | return EINVAL; 56 | } 57 | memcpy(&attr->param, p, sizeof (*p)); 58 | return r; 59 | } 60 | 61 | int pthread_attr_getschedparam(const pthread_attr_t *attr, struct sched_param *p) 62 | { 63 | int r = 0; 64 | 65 | if (attr == NULL || p == NULL) { 66 | return EINVAL; 67 | } 68 | memcpy(p, &attr->param, sizeof (*p)); 69 | return r; 70 | } 71 | 72 | int pthread_attr_setschedpolicy (pthread_attr_t *attr, int pol) 73 | { 74 | if (!attr || pol < SCHED_MIN || pol > SCHED_MAX) 75 | return EINVAL; 76 | if (pol != SCHED_OTHER) 77 | return ENOTSUP; 78 | return 0; 79 | } 80 | 81 | int pthread_attr_getschedpolicy (pthread_attr_t *attr, int *pol) 82 | { 83 | if (!attr || !pol) 84 | return EINVAL; 85 | *pol = SCHED_OTHER; 86 | return 0; 87 | } 88 | 89 | static int pthread_check(pthread_t t) 90 | { 91 | struct _pthread_v *pv; 92 | DWORD dwFlags; 93 | if (!t) 94 | return ESRCH; 95 | pv = __pth_gpointer_locked (t); 96 | if (!(pv->h) || pv->h == INVALID_HANDLE_VALUE) 97 | { 98 | if (pv->ended == 0) 99 | return 0; 100 | return ESRCH; 101 | } 102 | else if ((!GetHandleInformation(pv->h, &dwFlags) && pv->ended)) 103 | return ESRCH; 104 | return 0; 105 | } 106 | 107 | int pthread_getschedparam(pthread_t t, int *pol, struct sched_param *p) 108 | { 109 | int r; 110 | //if (!t) 111 | // t = pthread_self(); 112 | 113 | if ((r = pthread_check(t)) != 0) 114 | { 115 | return r; 116 | } 117 | 118 | if (!p || !pol) 119 | { 120 | return EINVAL; 121 | } 122 | *pol = __pth_gpointer_locked (t)->sched_pol; 123 | p->sched_priority = __pth_gpointer_locked (t)->sched.sched_priority; 124 | 125 | return 0; 126 | } 127 | 128 | int pthread_setschedparam(pthread_t t, int pol, const struct sched_param *p) 129 | { 130 | struct _pthread_v *pv; 131 | int r, pr = 0; 132 | //if (!t.p) t = pthread_self(); 133 | 134 | if ((r = pthread_check(t)) != 0) 135 | return r; 136 | 137 | if (pol < SCHED_MIN || pol > SCHED_MAX || p == NULL) 138 | return EINVAL; 139 | if (pol != SCHED_OTHER) 140 | return ENOTSUP; 141 | pr = p->sched_priority; 142 | if (pr < sched_get_priority_min(pol) || pr > sched_get_priority_max(pol)) 143 | return EINVAL; 144 | 145 | /* See msdn: there are actually 7 priorities: 146 | THREAD_PRIORITY_IDLE - -15 147 | THREAD_PRIORITY_LOWEST -2 148 | THREAD_PRIORITY_BELOW_NORMAL -1 149 | THREAD_PRIORITY_NORMAL 0 150 | THREAD_PRIORITY_ABOVE_NORMAL 1 151 | THREAD_PRIORITY_HIGHEST 2 152 | THREAD_PRIORITY_TIME_CRITICAL 15 153 | */ 154 | if (pr <= THREAD_PRIORITY_IDLE) { 155 | pr = THREAD_PRIORITY_IDLE; 156 | } else if (pr <= THREAD_PRIORITY_LOWEST) { 157 | pr = THREAD_PRIORITY_LOWEST; 158 | } else if (pr >= THREAD_PRIORITY_TIME_CRITICAL) { 159 | pr = THREAD_PRIORITY_TIME_CRITICAL; 160 | } else if (pr >= THREAD_PRIORITY_HIGHEST) { 161 | pr = THREAD_PRIORITY_HIGHEST; 162 | } 163 | pv = __pth_gpointer_locked (t); 164 | if (SetThreadPriority(pv->h, pr)) { 165 | pv->sched_pol = pol; 166 | pv->sched.sched_priority = p->sched_priority; 167 | } else 168 | r = EINVAL; 169 | return r; 170 | } 171 | 172 | int sched_getscheduler(pid_t pid) 173 | { 174 | if (pid != 0) 175 | { 176 | HANDLE h = NULL; 177 | int selfPid = (int) GetCurrentProcessId (); 178 | 179 | if (pid != (pid_t) selfPid && (h = OpenProcess (PROCESS_QUERY_INFORMATION, 0, (DWORD) pid)) == NULL) 180 | { 181 | errno = (GetLastError () == (0xFF & ERROR_ACCESS_DENIED)) ? EPERM : ESRCH; 182 | return -1; 183 | } 184 | if (h) 185 | CloseHandle (h); 186 | } 187 | return SCHED_OTHER; 188 | } 189 | 190 | int sched_setscheduler(pid_t pid, int pol, const struct sched_param *param) 191 | { 192 | if (!param) 193 | { 194 | errno = EINVAL; 195 | return -1; 196 | } 197 | if (pid != 0) 198 | { 199 | HANDLE h = NULL; 200 | int selfPid = (int) GetCurrentProcessId (); 201 | 202 | if (pid != (pid_t) selfPid && (h = OpenProcess (PROCESS_SET_INFORMATION, 0, (DWORD) pid)) == NULL) 203 | { 204 | errno = (GetLastError () == (0xFF & ERROR_ACCESS_DENIED)) ? EPERM : ESRCH; 205 | return -1; 206 | } 207 | if (h) 208 | CloseHandle (h); 209 | } 210 | 211 | if (pol != SCHED_OTHER) 212 | { 213 | errno = ENOSYS; 214 | return -1; 215 | } 216 | return SCHED_OTHER; 217 | } 218 | 219 | int sched_yield(void) 220 | { 221 | Sleep(0); 222 | return 0; 223 | } 224 | -------------------------------------------------------------------------------- /src/sem.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2011 mingw-w64 project 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a 5 | copy of this software and associated documentation files (the "Software"), 6 | to deal in the Software without restriction, including without limitation 7 | the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 | and/or sell copies of the Software, and to permit persons to whom the 9 | Software is furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in 12 | all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 20 | DEALINGS IN THE SOFTWARE. 21 | */ 22 | 23 | #include 24 | #include 25 | #include 26 | #include "pthread.h" 27 | #include "thread.h" 28 | #include "misc.h" 29 | #include "semaphore.h" 30 | #include "sem.h" 31 | #include "mutex.h" 32 | #include "ref.h" 33 | 34 | int do_sema_b_wait_intern (HANDLE sema, int nointerrupt, DWORD timeout); 35 | 36 | static int 37 | sem_result (int res) 38 | { 39 | if (res != 0) { 40 | errno = res; 41 | return -1; 42 | } 43 | return 0; 44 | } 45 | 46 | int 47 | sem_init (sem_t *sem, int pshared, unsigned int value) 48 | { 49 | _sem_t *sv; 50 | 51 | if (!sem || value > (unsigned int)SEM_VALUE_MAX) 52 | return sem_result (EINVAL); 53 | if (pshared != PTHREAD_PROCESS_PRIVATE) 54 | return sem_result (EPERM); 55 | 56 | if (!(sv = (sem_t) calloc (1,sizeof (*sv)))) 57 | return sem_result (ENOMEM); 58 | 59 | sv->value = value; 60 | if (pthread_mutex_init (&sv->vlock, NULL) != 0) 61 | { 62 | free (sv); 63 | return sem_result (ENOSPC); 64 | } 65 | if ((sv->s = CreateSemaphore (NULL, 0, SEM_VALUE_MAX, NULL)) == NULL) 66 | { 67 | pthread_mutex_destroy (&sv->vlock); 68 | free (sv); 69 | return sem_result (ENOSPC); 70 | } 71 | 72 | sv->valid = LIFE_SEM; 73 | *sem = sv; 74 | return 0; 75 | } 76 | 77 | int 78 | sem_destroy (sem_t *sem) 79 | { 80 | int r; 81 | _sem_t *sv = NULL; 82 | 83 | if (!sem || (sv = *sem) == NULL) 84 | return sem_result (EINVAL); 85 | if ((r = pthread_mutex_lock (&sv->vlock)) != 0) 86 | return sem_result (r); 87 | 88 | #if 0 89 | /* We don't wait for destroying a semaphore ... 90 | or? */ 91 | if (sv->value < 0) 92 | { 93 | pthread_mutex_unlock (&sv->vlock); 94 | return sem_result (EBUSY); 95 | } 96 | #endif 97 | 98 | if (!CloseHandle (sv->s)) 99 | { 100 | pthread_mutex_unlock (&sv->vlock); 101 | return sem_result (EINVAL); 102 | } 103 | *sem = NULL; 104 | sv->value = SEM_VALUE_MAX; 105 | pthread_mutex_unlock(&sv->vlock); 106 | Sleep (0); 107 | while (pthread_mutex_destroy (&sv->vlock) == EBUSY) 108 | Sleep (0); 109 | sv->valid = DEAD_SEM; 110 | free (sv); 111 | return 0; 112 | } 113 | 114 | static int 115 | sem_std_enter (sem_t *sem,_sem_t **svp, int do_test) 116 | { 117 | int r; 118 | _sem_t *sv; 119 | 120 | if (do_test) 121 | pthread_testcancel (); 122 | if (!sem) 123 | return sem_result (EINVAL); 124 | sv = *sem; 125 | if (sv == NULL) 126 | return sem_result (EINVAL); 127 | 128 | if ((r = pthread_mutex_lock (&sv->vlock)) != 0) 129 | return sem_result (r); 130 | 131 | if (*sem == NULL) 132 | { 133 | pthread_mutex_unlock(&sv->vlock); 134 | return sem_result (EINVAL); 135 | } 136 | *svp = sv; 137 | return 0; 138 | } 139 | 140 | int 141 | sem_trywait (sem_t *sem) 142 | { 143 | _sem_t *sv; 144 | 145 | if (sem_std_enter (sem, &sv, 0) != 0) 146 | return -1; 147 | if (sv->value <= 0) 148 | { 149 | pthread_mutex_unlock (&sv->vlock); 150 | return sem_result (EAGAIN); 151 | } 152 | sv->value--; 153 | pthread_mutex_unlock (&sv->vlock); 154 | 155 | return 0; 156 | } 157 | 158 | struct sSemTimedWait 159 | { 160 | sem_t *p; 161 | int *ret; 162 | }; 163 | 164 | static void 165 | clean_wait_sem (void *s) 166 | { 167 | struct sSemTimedWait *p = (struct sSemTimedWait *) s; 168 | _sem_t *sv = NULL; 169 | 170 | if (sem_std_enter (p->p, &sv, 0) != 0) 171 | return; 172 | 173 | if (WaitForSingleObject (sv->s, 0) != WAIT_OBJECT_0) 174 | InterlockedIncrement (&sv->value); 175 | else if (p->ret) 176 | p->ret[0] = 0; 177 | pthread_mutex_unlock (&sv->vlock); 178 | } 179 | 180 | int 181 | sem_wait (sem_t *sem) 182 | { 183 | long cur_v; 184 | int ret = 0; 185 | _sem_t *sv; 186 | HANDLE semh; 187 | struct sSemTimedWait arg; 188 | 189 | if (sem_std_enter (sem, &sv, 1) != 0) 190 | return -1; 191 | 192 | arg.ret = &ret; 193 | arg.p = sem; 194 | InterlockedDecrement (&sv->value); 195 | cur_v = sv->value; 196 | semh = sv->s; 197 | pthread_mutex_unlock (&sv->vlock); 198 | 199 | if (cur_v >= 0) 200 | return 0; 201 | else 202 | { 203 | pthread_cleanup_push (clean_wait_sem, (void *) &arg); 204 | ret = do_sema_b_wait_intern (semh, 2, INFINITE); 205 | pthread_cleanup_pop (ret); 206 | if (ret == EINVAL) 207 | return 0; 208 | } 209 | 210 | if (!ret) 211 | return 0; 212 | 213 | return sem_result (ret); 214 | } 215 | 216 | int 217 | sem_timedwait (sem_t *sem, const struct timespec *t) 218 | { 219 | int cur_v, ret = 0; 220 | DWORD dwr; 221 | HANDLE semh; 222 | _sem_t *sv; 223 | struct sSemTimedWait arg; 224 | 225 | if (!t) 226 | return sem_wait (sem); 227 | dwr = dwMilliSecs(_pthread_rel_time_in_ms (t)); 228 | 229 | if (sem_std_enter (sem, &sv, 1) != 0) 230 | return -1; 231 | 232 | arg.ret = &ret; 233 | arg.p = sem; 234 | InterlockedDecrement (&sv->value); 235 | cur_v = sv->value; 236 | semh = sv->s; 237 | pthread_mutex_unlock(&sv->vlock); 238 | 239 | if (cur_v >= 0) 240 | return 0; 241 | else 242 | { 243 | pthread_cleanup_push (clean_wait_sem, (void *) &arg); 244 | ret = do_sema_b_wait_intern (semh, 2, dwr); 245 | pthread_cleanup_pop (ret); 246 | if (ret == EINVAL) 247 | return 0; 248 | } 249 | 250 | if (!ret) 251 | return 0; 252 | return sem_result (ret); 253 | } 254 | 255 | int 256 | sem_post (sem_t *sem) 257 | { 258 | _sem_t *sv;; 259 | 260 | if (sem_std_enter (sem, &sv, 0) != 0) 261 | return -1; 262 | 263 | if (sv->value >= SEM_VALUE_MAX) 264 | { 265 | pthread_mutex_unlock (&sv->vlock); 266 | return sem_result (ERANGE); 267 | } 268 | InterlockedIncrement (&sv->value); 269 | if (sv->value > 0 || ReleaseSemaphore (sv->s, 1, NULL)) 270 | { 271 | pthread_mutex_unlock (&sv->vlock); 272 | return 0; 273 | } 274 | InterlockedDecrement (&sv->value); 275 | pthread_mutex_unlock (&sv->vlock); 276 | 277 | return sem_result (EINVAL); 278 | } 279 | 280 | int 281 | sem_post_multiple (sem_t *sem, int count) 282 | { 283 | int waiters_count; 284 | _sem_t *sv;; 285 | 286 | if (count <= 0) 287 | return sem_result (EINVAL); 288 | if (sem_std_enter (sem, &sv, 0) != 0) 289 | return -1; 290 | 291 | if (sv->value > (SEM_VALUE_MAX - count)) 292 | { 293 | pthread_mutex_unlock (&sv->vlock); 294 | return sem_result (ERANGE); 295 | } 296 | waiters_count = -sv->value; 297 | sv->value += count; 298 | /*InterlockedExchangeAdd((long*)&sv->value, (long) count);*/ 299 | if (waiters_count <= 0 300 | || ReleaseSemaphore (sv->s, 301 | (waiters_count < count ? waiters_count 302 | : count), NULL)) 303 | { 304 | pthread_mutex_unlock(&sv->vlock); 305 | return 0; 306 | } 307 | /*InterlockedExchangeAdd((long*)&sv->value, -((long) count));*/ 308 | sv->value -= count; 309 | pthread_mutex_unlock(&sv->vlock); 310 | return sem_result (EINVAL); 311 | } 312 | 313 | sem_t * 314 | sem_open (const char *name, int oflag, mode_t mode, unsigned int value) 315 | { 316 | sem_result (ENOSYS); 317 | return NULL; 318 | } 319 | 320 | int 321 | sem_close (sem_t *sem) 322 | { 323 | return sem_result (ENOSYS); 324 | } 325 | 326 | int 327 | sem_unlink (const char *name) 328 | { 329 | return sem_result (ENOSYS); 330 | } 331 | 332 | int 333 | sem_getvalue (sem_t *sem, int *sval) 334 | { 335 | _sem_t *sv; 336 | int r; 337 | 338 | if (!sval) 339 | return sem_result (EINVAL); 340 | 341 | if (!sem || (sv = *sem) == NULL) 342 | return sem_result (EINVAL); 343 | 344 | if ((r = pthread_mutex_lock (&sv->vlock)) != 0) 345 | return sem_result (r); 346 | if (*sem == NULL) 347 | { 348 | pthread_mutex_unlock (&sv->vlock); 349 | return sem_result (EINVAL); 350 | } 351 | 352 | *sval = (int) sv->value; 353 | pthread_mutex_unlock (&sv->vlock); 354 | return 0; 355 | } 356 | -------------------------------------------------------------------------------- /src/sem.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2011 mingw-w64 project 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a 5 | copy of this software and associated documentation files (the "Software"), 6 | to deal in the Software without restriction, including without limitation 7 | the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 | and/or sell copies of the Software, and to permit persons to whom the 9 | Software is furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in 12 | all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 20 | DEALINGS IN THE SOFTWARE. 21 | */ 22 | 23 | #ifndef WIN_SEM 24 | #define WIN_SEM 25 | 26 | #include 27 | #include "mutex.h" 28 | 29 | #define LIFE_SEM 0xBAB1F00D 30 | #define DEAD_SEM 0xDEADBEEF 31 | 32 | typedef struct _sem_t _sem_t; 33 | struct _sem_t 34 | { 35 | unsigned int valid; 36 | HANDLE s; 37 | volatile long value; 38 | pthread_mutex_t vlock; 39 | }; 40 | 41 | #endif /* WIN_SEM */ -------------------------------------------------------------------------------- /src/spinlock.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2013 mingw-w64 project 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a 5 | copy of this software and associated documentation files (the "Software"), 6 | to deal in the Software without restriction, including without limitation 7 | the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 | and/or sell copies of the Software, and to permit persons to whom the 9 | Software is furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in 12 | all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 20 | DEALINGS IN THE SOFTWARE. 21 | */ 22 | 23 | #include 24 | #include 25 | #include 26 | #include "pthread.h" 27 | #include "misc.h" 28 | 29 | /* In theory, owner and locks are in CRITICAL_SECTION as well. 30 | In practise, however, the implementation of CRITICAL_SECTION 31 | should be regarded as opaque. That's why we replicate these 32 | members. */ 33 | typedef struct spin_t { 34 | DWORD owner; 35 | DWORD locks; 36 | CRITICAL_SECTION section; 37 | } spin_t; 38 | 39 | /* Per the MSDN documentation, Windows components such as the heap manager 40 | use a spin count of 4000. */ 41 | static const DWORD kSpinCount = 4000; 42 | 43 | static volatile LONG global_lock = 0; 44 | 45 | static void 46 | enter_global_cs (void) 47 | { 48 | while (global_lock || InterlockedExchange (&global_lock, 1)) 49 | asm volatile ("pause"); 50 | } 51 | 52 | static void 53 | leave_global_cs (void) 54 | { 55 | InterlockedExchange (&global_lock, 0); 56 | } 57 | 58 | static int 59 | static_spin_init (pthread_spinlock_t* lock) 60 | { 61 | if (PTHREAD_SPINLOCK_INITIALIZER == *lock) 62 | { 63 | enter_global_cs (); 64 | if (PTHREAD_SPINLOCK_INITIALIZER == *lock) 65 | { 66 | int initrv = pthread_spin_init (lock, PTHREAD_PROCESS_PRIVATE); 67 | if (initrv < 0) 68 | { 69 | leave_global_cs (); 70 | return initrv; 71 | } 72 | } 73 | leave_global_cs (); 74 | } 75 | return 0; 76 | } 77 | 78 | 79 | /* Windows 98/Me hasn't SetCriticalSectionSpinCount but has 80 | InitializeCriticalSectionAndSpinCount 81 | Windows NT/95 hasn't enyone, so call SetCritical only. 82 | MSDN: "On single-processor systems, the spin count is ignored and the critical section spin count is set to zero (0)." 83 | ... so for Win9x ignore it anyway and call only InitializeCriticalSection 84 | */ 85 | typedef BOOL (WINAPI *ICSASCFunc)(LPCRITICAL_SECTION lpCriticalSection, DWORD dwSpinCount); 86 | static ICSASCFunc ICSASCProc = NULL; 87 | static BOOL ICSASCSearch = FALSE; 88 | 89 | int 90 | pthread_spin_init (pthread_spinlock_t *lock, int pshared) 91 | { 92 | spin_t *spin; 93 | 94 | if (!lock) 95 | return EINVAL; 96 | 97 | if (pshared != PTHREAD_PROCESS_PRIVATE) 98 | return ENOTSUP; 99 | 100 | if (!(spin = (spin_t*) calloc (1, sizeof(*spin)))) 101 | return ENOMEM; 102 | 103 | // InitializeCriticalSection (&spin->section); 104 | // SetCriticalSectionSpinCount (&spin->section, kSpinCount); 105 | 106 | if(!ICSASCSearch) 107 | { 108 | DWORD GV = GetVersion(); 109 | if((DWORD)(LOBYTE(LOWORD(GV))) >= 5) /* only for 2k, XP ... */ 110 | { 111 | HANDLE hKernel32 = GetModuleHandleA("kernel32.dll"); 112 | if(hKernel32) 113 | { 114 | ICSASCProc = (ICSASCFunc)GetProcAddress(hKernel32, "InitializeCriticalSectionAndSpinCount"); 115 | } 116 | } 117 | ICSASCSearch = TRUE; 118 | } 119 | 120 | #if 1 121 | if(ICSASCProc) 122 | { 123 | ICSASCProc(&spin->section, kSpinCount); 124 | } 125 | else 126 | { 127 | InitializeCriticalSection (&spin->section); 128 | //SetCriticalSectionSpinCount (&spin->section, kSpinCount); 129 | } 130 | #else 131 | InitializeCriticalSectionAndSpinCount(&spin->section, kSpinCount); 132 | #endif 133 | 134 | *lock = spin; 135 | return 0; 136 | } 137 | 138 | 139 | int 140 | pthread_spin_destroy (pthread_spinlock_t *lock) 141 | { 142 | spin_t *spin; 143 | 144 | if (!lock || !*lock) 145 | return EINVAL; 146 | 147 | enter_global_cs (); 148 | if (*lock == PTHREAD_SPINLOCK_INITIALIZER) 149 | { 150 | *lock = NULL; 151 | leave_global_cs (); 152 | return 0; 153 | } 154 | 155 | spin = (spin_t*)*lock; 156 | if (spin->owner && spin->owner != GetCurrentThreadId ()) 157 | { 158 | leave_global_cs (); 159 | return EPERM; 160 | } 161 | 162 | DeleteCriticalSection (&spin->section); 163 | free (spin); 164 | *lock = NULL; 165 | leave_global_cs (); 166 | return 0; 167 | } 168 | 169 | int 170 | pthread_spin_lock (pthread_spinlock_t *lock) 171 | { 172 | spin_t *spin; 173 | int rv = 0; 174 | 175 | if (!lock || !*lock) 176 | return EINVAL; 177 | 178 | rv = static_spin_init (lock); 179 | if (rv < 0) 180 | return rv; 181 | 182 | spin = (spin_t*)*lock; 183 | EnterCriticalSection (&spin->section); 184 | spin->owner = GetCurrentThreadId (); 185 | spin->locks++; 186 | return 0; 187 | } 188 | 189 | int 190 | pthread_spin_trylock (pthread_spinlock_t *lock) 191 | { 192 | spin_t *spin; 193 | int rv = 0; 194 | 195 | if (!lock || !*lock) 196 | return EINVAL; 197 | 198 | rv = static_spin_init (lock); 199 | if (rv < 0) 200 | return rv; 201 | 202 | spin = (spin_t*)*lock; 203 | /*if (!TryEnterCriticalSection (&spin->section)) 204 | return EBUSY;*/ 205 | //EnterCriticalSection(&spin->section); 206 | if (!TryEnterCriticalSection9x (&spin->section)) 207 | return EBUSY; 208 | 209 | spin->owner = GetCurrentThreadId (); 210 | spin->locks++; 211 | return 0; 212 | } 213 | 214 | 215 | int 216 | pthread_spin_unlock (pthread_spinlock_t *lock) 217 | { 218 | spin_t *spin; 219 | 220 | if (!lock || !*lock) 221 | return EINVAL; 222 | 223 | if (*lock == PTHREAD_SPINLOCK_INITIALIZER) 224 | return EPERM; 225 | 226 | spin = (spin_t*)*lock; 227 | if (spin->owner != GetCurrentThreadId ()) 228 | return EPERM; 229 | 230 | if (!--spin->locks) 231 | spin->owner = 0; 232 | LeaveCriticalSection (&spin->section); 233 | return 0; 234 | } 235 | -------------------------------------------------------------------------------- /src/thread.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2011 mingw-w64 project 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a 5 | copy of this software and associated documentation files (the "Software"), 6 | to deal in the Software without restriction, including without limitation 7 | the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 | and/or sell copies of the Software, and to permit persons to whom the 9 | Software is furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in 12 | all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 20 | DEALINGS IN THE SOFTWARE. 21 | */ 22 | 23 | #ifndef WIN_PTHREAD_H 24 | #define WIN_PTHREAD_H 25 | 26 | #include 27 | #include 28 | #include "rwlock.h" 29 | 30 | #define LIFE_THREAD 0xBAB1F00D 31 | #define DEAD_THREAD 0xDEADBEEF 32 | #define EXCEPTION_SET_THREAD_NAME ((DWORD) 0x406D1388) 33 | 34 | typedef struct _pthread_v _pthread_v; 35 | struct _pthread_v 36 | { 37 | unsigned int valid; 38 | void *ret_arg; 39 | void *(* func)(void *); 40 | _pthread_cleanup *clean; 41 | int nobreak; 42 | HANDLE h; 43 | HANDLE evStart; 44 | pthread_mutex_t p_clock; 45 | int cancelled : 2; 46 | int in_cancel : 2; 47 | int thread_noposix : 2; 48 | unsigned int p_state; 49 | unsigned int keymax; 50 | void **keyval; 51 | unsigned char *keyval_set; 52 | char *thread_name; 53 | pthread_spinlock_t spin_keys; 54 | DWORD tid; 55 | int rwlc; 56 | pthread_rwlock_t rwlq[RWLS_PER_THREAD]; 57 | int sched_pol; 58 | int ended; 59 | struct sched_param sched; 60 | jmp_buf jb; 61 | struct _pthread_v *next; 62 | pthread_t x; /* Internal posix handle. */ 63 | }; 64 | 65 | typedef struct __pthread_idlist { 66 | struct _pthread_v *ptr; 67 | pthread_t id; 68 | } __pthread_idlist; 69 | 70 | int _pthread_tryjoin(pthread_t t, void **res); 71 | void _pthread_setnobreak(int); 72 | #ifdef WINPTHREAD_DBG 73 | void thread_print_set(int state); 74 | void thread_print(volatile pthread_t t, char *txt); 75 | #endif 76 | int __pthread_shallcancel(void); 77 | struct _pthread_v *__pth_gpointer_locked (pthread_t id); 78 | 79 | #endif 80 | -------------------------------------------------------------------------------- /src/tryentercriticalsection.c: -------------------------------------------------------------------------------- 1 | /* 2 | * KernelEx 3 | * Copyright (C) 2008, Xeno86 4 | * 5 | * This file is part of KernelEx source code. 6 | * 7 | * KernelEx is free software; you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published 9 | * by the Free Software Foundation; version 2 of the License. 10 | * 11 | * KernelEx is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with GNU Make; see the file COPYING. If not, write to 18 | * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. 19 | * 20 | */ 21 | 22 | #include 23 | 24 | #define K32OBJ_CRITICAL_SECTION 4 25 | 26 | typedef struct _CRIT_SECT // Size = 0x20 27 | { 28 | BYTE Type; // 00 = 4: K32_OBJECT_CRITICAL_SECTION 29 | int RecursionCount; // 04 initially 0, incremented on lock 30 | void* OwningThread; // 08 pointer to TDBX 31 | DWORD un3; // 0C 32 | int LockCount; // 10 initially 1, decremented on lock 33 | struct _CRIT_SECT* Next; // 14 34 | void* PLst; // 18 list of processes using it? 35 | struct _WIN_CRITICAL_SECTION* UserCS; // 1C pointer to user defined CRITICAL_SECTION 36 | } CRIT_SECT, *PCRIT_SECT; 37 | 38 | typedef struct _WIN_CRITICAL_SECTION 39 | { 40 | BYTE Type; //= 4: K32_OBJECT_CRITICAL_SECTION 41 | PCRIT_SECT crit; 42 | DWORD un1; 43 | DWORD un2; 44 | DWORD un3; 45 | DWORD un4; 46 | } WIN_CRITICAL_SECTION, *PWIN_CRITICAL_SECTION; 47 | 48 | //static DWORD _offset; 49 | DWORD tesc_offset = 0; 50 | 51 | static BOOL init_tryentercritsec() 52 | { 53 | DWORD GV = GetVersion(); 54 | 55 | if (GV == 0xc0000a04) //98 56 | { 57 | tesc_offset = 0x58 - 0x8; 58 | return TRUE; 59 | } 60 | if (GV == 0xc0005a04) //Me 61 | { 62 | tesc_offset = 0x88 - 0x8; 63 | return TRUE; 64 | } 65 | // FIXME: 95 66 | return FALSE; 67 | } 68 | 69 | #ifdef __GNUC__ 70 | # ifdef __i386__ 71 | 72 | BOOL WINAPI TryEnterCrst(CRIT_SECT* crit); 73 | 74 | __asm__(".text\n\t" 75 | ".align 4\n\t" 76 | ".globl _TryEnterCrst@4\n\t" 77 | ".def _TryEnterCrst@4; .scl 2; .type 32; .endef\n" 78 | "_TryEnterCrst@4:\n\t" 79 | "movl 4(%esp),%edx\n\t" 80 | "xorl %eax,%eax\n\t" 81 | "incl %eax\n\t" 82 | "xorl %ecx,%ecx\n\t" 83 | "cmpxchgl %ecx,0x10(%edx)\n\t" /* if (OP1==eax) { OP1=OP2; ZF=1; } else { eax=OP1; ZF=0 } */ 84 | "movl %fs:0x18, %ecx\n\t" 85 | "addl _tesc_offset,%ecx\n\t" 86 | "movl (%ecx),%ecx\n\t" /* ecx will contain TDBX now */ 87 | "cmpl $1,%eax\n\t" 88 | "jnz .L1\n\t" 89 | /* critical section was unowned => successful lock */ 90 | "movl %ecx,8(%edx)\n\t" 91 | "incl 4(%edx)\n\t" 92 | "ret $4\n\t" 93 | ".L1: \n\t" 94 | "cmpl %ecx,8(%edx)\n\t" 95 | "jnz .L2\n\t" 96 | /* critical section owned by this thread */ 97 | "decl 0x10(%edx)\n\t" 98 | "incl 4(%edx)\n\t" 99 | "xorl %eax,%eax\n\t" 100 | "incl %eax\n\t" 101 | "ret $4\n\t" 102 | ".L2: \n\t" 103 | /* critical section owned by other thread - do nothing */ 104 | "xorl %eax,%eax\n\t" 105 | "ret $4\n\t" 106 | ); 107 | # else 108 | # define CS_NATIVE_ONLY 109 | # endif 110 | #elif !(defined(_WIN64) || defined(_M_ARM)) 111 | 112 | __declspec(naked) BOOL WINAPI TryEnterCrst(CRIT_SECT* crit) 113 | { 114 | __asm { 115 | mov edx, [esp+4] 116 | xor eax, eax 117 | inc eax 118 | xor ecx, ecx 119 | cmpxchg [edx+10h], ecx ;if (OP1==eax) { OP1=OP2; ZF=1; } else { eax=OP1; ZF=0 } 120 | ;mov ecx, ppTDBXCur 121 | mov ecx, fs:[18h] 122 | add ecx, [tesc_offset] 123 | mov ecx, [ecx] ;ecx will contain TDBX now 124 | cmp eax, 1 125 | jnz L1 126 | ;critical section was unowned => successful lock 127 | mov [edx+8], ecx 128 | inc dword ptr [edx+4] 129 | ret 4 130 | L1: 131 | cmp [edx+8], ecx 132 | jnz L2 133 | ;critical section owned by this thread 134 | dec dword ptr [edx+10h] 135 | inc dword ptr [edx+4] 136 | xor eax, eax 137 | inc eax 138 | ret 4 139 | L2: 140 | ;critical section owned by other thread - do nothing 141 | xor eax, eax 142 | ret 4 143 | } 144 | } 145 | 146 | #endif 147 | 148 | typedef BOOL (WINAPI *tecs_f)(CRITICAL_SECTION* cs); 149 | 150 | static tecs_f tecs_p = NULL; 151 | 152 | BOOL WINAPI TryEnterCriticalSectionNative(CRITICAL_SECTION* cs) 153 | { 154 | #if !(defined(_WIN64) || defined(_M_ARM)) 155 | DWORD GV = GetVersion(); 156 | DWORD major = (DWORD)(LOBYTE(LOWORD(GV))); 157 | DWORD minor = (DWORD)(HIBYTE(LOWORD(GV))); 158 | DWORD isNT = (int) GV >= 0; 159 | 160 | if(!isNT || major < 4) 161 | { 162 | #ifndef CS_NATIVE_ONLY 163 | if(minor == 10 || minor == 90) /* 98 + Me*/ 164 | { 165 | WIN_CRITICAL_SECTION* mycs = (WIN_CRITICAL_SECTION*) cs; 166 | if (mycs->Type != K32OBJ_CRITICAL_SECTION) 167 | { 168 | //RaiseException(STATUS_ACCESS_VIOLATION, 0, 0, NULL); 169 | // JH: maybe CS isn't iniciated yet... 170 | InitializeCriticalSection(cs); 171 | } 172 | 173 | if(init_tryentercritsec()) 174 | { 175 | return TryEnterCrst(mycs->crit); 176 | } 177 | } 178 | // else FIXME: 95, NT3, Win32s 179 | #endif 180 | EnterCriticalSection(cs); 181 | return TRUE; 182 | } 183 | else 184 | { 185 | if(tecs_p == NULL) 186 | { 187 | HMODULE hK = GetModuleHandleA("kernel32.dll"); 188 | if(hK) 189 | { 190 | tecs_p = (tecs_f)GetProcAddress(hK, "TryEnterCriticalSection"); // Note: 98 & ME exports this as a stub 191 | } 192 | } 193 | 194 | if(tecs_p != NULL) 195 | { 196 | return tecs_p(cs); 197 | } 198 | } 199 | 200 | RaiseException(STATUS_ACCESS_VIOLATION, 0, 0, NULL); 201 | 202 | return FALSE; 203 | #else 204 | return TryEnterCriticalSection(cs); 205 | #endif 206 | } 207 | 208 | /* MAKE_EXPORT TryEnterCriticalSection_new=TryEnterCriticalSection */ 209 | BOOL WINAPI TryEnterCriticalSection9x(CRITICAL_SECTION* cs) 210 | { 211 | return TryEnterCriticalSectionNative(cs); 212 | } 213 | -------------------------------------------------------------------------------- /src/version.rc: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2011 mingw-w64 project 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a 5 | copy of this software and associated documentation files (the "Software"), 6 | to deal in the Software without restriction, including without limitation 7 | the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 | and/or sell copies of the Software, and to permit persons to whom the 9 | Software is furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in 12 | all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 20 | DEALINGS IN THE SOFTWARE. 21 | */ 22 | 23 | #include 24 | #include "wpth_ver.h" 25 | 26 | #define WPTH_VERSIONINFO_NAME "WinPthreadGC\0" 27 | #ifdef _WIN64 28 | #define WPTH_VERSIONINFO_COMMENT "GNU C build -- MinGW-w64 64-bit\0" 29 | #else 30 | #define WPTH_VERSIONINFO_COMMENT "GNU C build -- MinGW-w64 32-bit\0" 31 | #endif 32 | 33 | VS_VERSION_INFO VERSIONINFO 34 | FILEVERSION WPTH_VERSION 35 | PRODUCTVERSION WPTH_VERSION 36 | FILEFLAGSMASK VS_FFI_FILEFLAGSMASK 37 | FILEFLAGS 0 38 | FILEOS VOS__WINDOWS32 39 | FILETYPE VFT_DLL 40 | BEGIN 41 | BLOCK "StringFileInfo" 42 | BEGIN 43 | BLOCK "040904b0" 44 | BEGIN 45 | VALUE "FileDescription", "POSIX WinThreads for Windows\0" 46 | VALUE "ProductVersion", WPTH_VERSION_STRING 47 | VALUE "FileVersion", WPTH_VERSION_STRING 48 | VALUE "InternalName", WPTH_VERSIONINFO_NAME 49 | VALUE "OriginalFilename", WPTH_VERSIONINFO_NAME 50 | VALUE "CompanyName", "MingW-W64 Project. All rights reserved.\0" 51 | VALUE "LegalCopyright", "Copyright (C) MingW-W64 Project Members 2010-2011\0" 52 | VALUE "Licence", "ZPL\0" 53 | VALUE "Info", "http://mingw-w64.sourceforge.net/\0" 54 | VALUE "Comment", WPTH_VERSIONINFO_COMMENT 55 | END 56 | END 57 | BLOCK "VarFileInfo" 58 | BEGIN 59 | VALUE "Translation", 0x409, 1200 60 | END 61 | END 62 | 63 | -------------------------------------------------------------------------------- /src/winpthread_internal.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2011 mingw-w64 project 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a 5 | copy of this software and associated documentation files (the "Software"), 6 | to deal in the Software without restriction, including without limitation 7 | the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 | and/or sell copies of the Software, and to permit persons to whom the 9 | Software is furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in 12 | all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 20 | DEALINGS IN THE SOFTWARE. 21 | */ 22 | 23 | #ifndef WINPTHREAD_INTERNAL_H 24 | #define WINPTHREAD_INTERNAL_H 25 | struct _pthread_v * WINPTHREAD_API __pth_gpointer_locked (pthread_t id); 26 | int pthread_delay_np_ms (DWORD to); 27 | 28 | #define NO_VEH 29 | 30 | #define WIN9X 31 | 32 | #ifdef WIN9X 33 | #undef GetHandleInformation 34 | #define GetHandleInformation(h,f) (1) 35 | 36 | #endif 37 | 38 | #endif /*WINPTHREAD_INTERNAL_H*/ 39 | -------------------------------------------------------------------------------- /src/wpth_ver.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2011 mingw-w64 project 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a 5 | copy of this software and associated documentation files (the "Software"), 6 | to deal in the Software without restriction, including without limitation 7 | the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 | and/or sell copies of the Software, and to permit persons to whom the 9 | Software is furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in 12 | all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 20 | DEALINGS IN THE SOFTWARE. 21 | */ 22 | 23 | #ifndef __WPTHREADS_VERSION__ 24 | #define __WPTHREADS_VERSION__ 25 | 26 | #define WPTH_VERSION 1,0,0,0 27 | #define WPTH_VERSION_STRING "1, 0, 0, 0\0" 28 | 29 | #endif 30 | --------------------------------------------------------------------------------