1 /** 2 * Copyright (c) 2016 Tino Reichardt 3 * All rights reserved. 4 * 5 * You can contact the author at: 6 * - zstdmt source repository: https://github.com/mcmilk/zstdmt 7 * 8 * This source code is licensed under both the BSD-style license (found in the 9 * LICENSE file in the root directory of this source tree) and the GPLv2 (found 10 * in the COPYING file in the root directory of this source tree). 11 * You may select, at your option, one of the above-listed licenses. 12 */ 13 14 /** 15 * This file will hold wrapper for systems, which do not support pthreads 16 */ 17 18 #include "threading.h" 19 20 /* create fake symbol to avoid empty translation unit warning */ 21 int g_ZSTD_threading_useless_symbol; 22 23 #if defined(ZSTD_MULTITHREAD) && defined(_WIN32) 24 25 /** 26 * Windows minimalist Pthread Wrapper 27 */ 28 29 30 /* === Dependencies === */ 31 #include <process.h> 32 #include <errno.h> 33 34 35 /* === Implementation === */ 36 37 typedef struct { 38 void* (*start_routine)(void*); 39 void* arg; 40 int initialized; 41 ZSTD_pthread_cond_t initialized_cond; 42 ZSTD_pthread_mutex_t initialized_mutex; 43 } ZSTD_thread_params_t; 44 45 static unsigned __stdcall worker(void *arg) 46 { 47 void* (*start_routine)(void*); 48 void* thread_arg; 49 50 /* Initialized thread_arg and start_routine and signal main thread that we don't need it 51 * to wait any longer. 52 */ 53 { 54 ZSTD_thread_params_t* thread_param = (ZSTD_thread_params_t*)arg; 55 thread_arg = thread_param->arg; 56 start_routine = thread_param->start_routine; 57 58 /* Signal main thread that we are running and do not depend on its memory anymore */ 59 ZSTD_pthread_mutex_lock(&thread_param->initialized_mutex); 60 thread_param->initialized = 1; 61 ZSTD_pthread_cond_signal(&thread_param->initialized_cond); 62 ZSTD_pthread_mutex_unlock(&thread_param->initialized_mutex); 63 } 64 65 start_routine(thread_arg); 66 67 return 0; 68 } 69 70 int ZSTD_pthread_create(ZSTD_pthread_t* thread, const void* unused, 71 void* (*start_routine) (void*), void* arg) 72 { 73 ZSTD_thread_params_t thread_param; 74 (void)unused; 75 76 if (thread==NULL) return -1; 77 *thread = NULL; 78 79 thread_param.start_routine = start_routine; 80 thread_param.arg = arg; 81 thread_param.initialized = 0; 82 83 /* Setup thread initialization synchronization */ 84 if(ZSTD_pthread_cond_init(&thread_param.initialized_cond, NULL)) { 85 /* Should never happen on Windows */ 86 return -1; 87 } 88 if(ZSTD_pthread_mutex_init(&thread_param.initialized_mutex, NULL)) { 89 /* Should never happen on Windows */ 90 ZSTD_pthread_cond_destroy(&thread_param.initialized_cond); 91 return -1; 92 } 93 94 /* Spawn thread */ 95 *thread = (HANDLE)_beginthreadex(NULL, 0, worker, &thread_param, 0, NULL); 96 if (*thread==NULL) { 97 ZSTD_pthread_mutex_destroy(&thread_param.initialized_mutex); 98 ZSTD_pthread_cond_destroy(&thread_param.initialized_cond); 99 return errno; 100 } 101 102 /* Wait for thread to be initialized */ 103 ZSTD_pthread_mutex_lock(&thread_param.initialized_mutex); 104 while(!thread_param.initialized) { 105 ZSTD_pthread_cond_wait(&thread_param.initialized_cond, &thread_param.initialized_mutex); 106 } 107 ZSTD_pthread_mutex_unlock(&thread_param.initialized_mutex); 108 ZSTD_pthread_mutex_destroy(&thread_param.initialized_mutex); 109 ZSTD_pthread_cond_destroy(&thread_param.initialized_cond); 110 111 return 0; 112 } 113 114 int ZSTD_pthread_join(ZSTD_pthread_t thread) 115 { 116 DWORD result; 117 118 if (!thread) return 0; 119 120 result = WaitForSingleObject(thread, INFINITE); 121 CloseHandle(thread); 122 123 switch (result) { 124 case WAIT_OBJECT_0: 125 return 0; 126 case WAIT_ABANDONED: 127 return EINVAL; 128 default: 129 return GetLastError(); 130 } 131 } 132 133 #endif /* ZSTD_MULTITHREAD */ 134 135 #if defined(ZSTD_MULTITHREAD) && DEBUGLEVEL >= 1 && !defined(_WIN32) 136 137 #define ZSTD_DEPS_NEED_MALLOC 138 #include "zstd_deps.h" 139 140 int ZSTD_pthread_mutex_init(ZSTD_pthread_mutex_t* mutex, pthread_mutexattr_t const* attr) 141 { 142 assert(mutex != NULL); 143 *mutex = (pthread_mutex_t*)ZSTD_malloc(sizeof(pthread_mutex_t)); 144 if (!*mutex) 145 return 1; 146 return pthread_mutex_init(*mutex, attr); 147 } 148 149 int ZSTD_pthread_mutex_destroy(ZSTD_pthread_mutex_t* mutex) 150 { 151 assert(mutex != NULL); 152 if (!*mutex) 153 return 0; 154 { 155 int const ret = pthread_mutex_destroy(*mutex); 156 ZSTD_free(*mutex); 157 return ret; 158 } 159 } 160 161 int ZSTD_pthread_cond_init(ZSTD_pthread_cond_t* cond, pthread_condattr_t const* attr) 162 { 163 assert(cond != NULL); 164 *cond = (pthread_cond_t*)ZSTD_malloc(sizeof(pthread_cond_t)); 165 if (!*cond) 166 return 1; 167 return pthread_cond_init(*cond, attr); 168 } 169 170 int ZSTD_pthread_cond_destroy(ZSTD_pthread_cond_t* cond) 171 { 172 assert(cond != NULL); 173 if (!*cond) 174 return 0; 175 { 176 int const ret = pthread_cond_destroy(*cond); 177 ZSTD_free(*cond); 178 return ret; 179 } 180 } 181 182 #endif 183