compat_winthreads.c (4046B)
1 /* Copyright (c) 2003-2004, Roger Dingledine 2 * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. 3 * Copyright (c) 2007-2021, The Tor Project, Inc. */ 4 /* See LICENSE for licensing information */ 5 6 /** 7 * \file compat_winthreads.c 8 * 9 * \brief Implementation for the windows-based multithreading backend 10 * functions. 11 */ 12 13 #include "orconfig.h" 14 15 #ifdef _WIN32 16 /* For condition variable support */ 17 #ifndef WINVER 18 #error "orconfig.h didn't define WINVER" 19 #endif 20 #ifndef _WIN32_WINNT 21 #error "orconfig.h didn't define _WIN32_WINNT" 22 #endif 23 #if WINVER < 0x0600 24 #error "winver too low" 25 #endif 26 #if _WIN32_WINNT < 0x0600 27 #error "winver too low" 28 #endif 29 30 #include <windows.h> 31 #include <process.h> 32 #include <time.h> 33 34 #include "lib/thread/threads.h" 35 #include "lib/log/log.h" 36 #include "lib/log/util_bug.h" 37 #include "lib/log/win32err.h" 38 39 /** Minimalist interface to run a void function in the background. On 40 * Unix calls fork, on win32 calls beginthread. Returns -1 on failure. 41 * func should not return, but rather should call spawn_exit. 42 * 43 * NOTE: if <b>data</b> is used, it should not be allocated on the stack, 44 * since in a multithreaded environment, there is no way to be sure that 45 * the caller's stack will still be around when the called function is 46 * running. 47 */ 48 int 49 spawn_func(void (*func)(void *), void *data) 50 { 51 int rv; 52 rv = (int)_beginthread(func, 0, data); 53 if (rv == (int)-1) 54 return -1; 55 return 0; 56 } 57 58 /** End the current thread/process. 59 */ 60 void 61 spawn_exit(void) 62 { 63 _endthread(); 64 // LCOV_EXCL_START 65 //we should never get here. my compiler thinks that _endthread returns, this 66 //is an attempt to fool it. 67 tor_assert(0); 68 _exit(0); // exit ok: unreachable. 69 // LCOV_EXCL_STOP 70 } 71 72 unsigned long 73 tor_get_thread_id(void) 74 { 75 return (unsigned long)GetCurrentThreadId(); 76 } 77 78 int 79 tor_cond_init(tor_cond_t *cond) 80 { 81 InitializeConditionVariable(&cond->cond); 82 return 0; 83 } 84 void 85 tor_cond_uninit(tor_cond_t *cond) 86 { 87 (void) cond; 88 } 89 90 void 91 tor_cond_signal_one(tor_cond_t *cond) 92 { 93 WakeConditionVariable(&cond->cond); 94 } 95 void 96 tor_cond_signal_all(tor_cond_t *cond) 97 { 98 WakeAllConditionVariable(&cond->cond); 99 } 100 101 int 102 tor_threadlocal_init(tor_threadlocal_t *threadlocal) 103 { 104 threadlocal->index = TlsAlloc(); 105 return (threadlocal->index == TLS_OUT_OF_INDEXES) ? -1 : 0; 106 } 107 108 void 109 tor_threadlocal_destroy(tor_threadlocal_t *threadlocal) 110 { 111 TlsFree(threadlocal->index); 112 memset(threadlocal, 0, sizeof(tor_threadlocal_t)); 113 } 114 115 void * 116 tor_threadlocal_get(tor_threadlocal_t *threadlocal) 117 { 118 void *value = TlsGetValue(threadlocal->index); 119 if (value == NULL) { 120 DWORD err = GetLastError(); 121 if (err != ERROR_SUCCESS) { 122 char *msg = format_win32_error(err); 123 log_err(LD_GENERAL, "Error retrieving thread-local value: %s", msg); 124 tor_free(msg); 125 tor_assert(err == ERROR_SUCCESS); 126 } 127 } 128 return value; 129 } 130 131 void 132 tor_threadlocal_set(tor_threadlocal_t *threadlocal, void *value) 133 { 134 BOOL ok = TlsSetValue(threadlocal->index, value); 135 if (!ok) { 136 DWORD err = GetLastError(); 137 char *msg = format_win32_error(err); 138 log_err(LD_GENERAL, "Error adjusting thread-local value: %s", msg); 139 tor_free(msg); 140 tor_assert(ok); 141 } 142 } 143 144 int 145 tor_cond_wait(tor_cond_t *cond, tor_mutex_t *lock_, const struct timeval *tv) 146 { 147 // recursive SRW locks are not supported because they need extra logic for 148 // acquiring and releasing but SleepConditionVariableSRW will use the OS 149 // lock release function which lacks our extra logic 150 tor_assert(lock_->type == NON_RECURSIVE); 151 SRWLOCK *lock = &lock_->mutex; 152 DWORD ms = INFINITE; 153 if (tv) { 154 ms = tv->tv_sec*1000 + (tv->tv_usec+999)/1000; 155 } 156 157 BOOL ok = SleepConditionVariableSRW(&cond->cond, lock, ms, 0); 158 if (!ok) { 159 DWORD err = GetLastError(); 160 if (err == ERROR_TIMEOUT) { 161 return 1; 162 } 163 char *msg = format_win32_error(err); 164 log_err(LD_GENERAL, "Error waiting for condition variable: %s", msg); 165 tor_free(msg); 166 return -1; 167 } 168 return 0; 169 } 170 171 void 172 tor_threads_init(void) 173 { 174 set_main_thread(); 175 } 176 177 #endif /* defined(_WIN32) */