Merge branch 'fix-changelogs' into 'main'
[tor.git] / src / lib / thread / compat_winthreads.c
blobf28cdcca00c0ed5aafacffda3542befd28a39964
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 */
6 /**
7 * \file compat_winthreads.c
9 * \brief Implementation for the windows-based multithreading backend
10 * functions.
13 #include "orconfig.h"
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
30 #include <windows.h>
31 #include <process.h>
32 #include <time.h>
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"
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.
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.
48 int
49 spawn_func(void (*func)(void *), void *data)
51 int rv;
52 rv = (int)_beginthread(func, 0, data);
53 if (rv == (int)-1)
54 return -1;
55 return 0;
58 /** End the current thread/process.
60 void
61 spawn_exit(void)
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
72 unsigned long
73 tor_get_thread_id(void)
75 return (unsigned long)GetCurrentThreadId();
78 int
79 tor_cond_init(tor_cond_t *cond)
81 InitializeConditionVariable(&cond->cond);
82 return 0;
84 void
85 tor_cond_uninit(tor_cond_t *cond)
87 (void) cond;
90 void
91 tor_cond_signal_one(tor_cond_t *cond)
93 WakeConditionVariable(&cond->cond);
95 void
96 tor_cond_signal_all(tor_cond_t *cond)
98 WakeAllConditionVariable(&cond->cond);
102 tor_threadlocal_init(tor_threadlocal_t *threadlocal)
104 threadlocal->index = TlsAlloc();
105 return (threadlocal->index == TLS_OUT_OF_INDEXES) ? -1 : 0;
108 void
109 tor_threadlocal_destroy(tor_threadlocal_t *threadlocal)
111 TlsFree(threadlocal->index);
112 memset(threadlocal, 0, sizeof(tor_threadlocal_t));
115 void *
116 tor_threadlocal_get(tor_threadlocal_t *threadlocal)
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);
128 return value;
131 void
132 tor_threadlocal_set(tor_threadlocal_t *threadlocal, void *value)
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);
145 tor_cond_wait(tor_cond_t *cond, tor_mutex_t *lock_, const struct timeval *tv)
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;
157 BOOL ok = SleepConditionVariableSRW(&cond->cond, lock, ms, 0);
158 if (!ok) {
159 DWORD err = GetLastError();
160 if (err == ERROR_TIMEOUT) {
161 return 1;
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;
168 return 0;
171 void
172 tor_threads_init(void)
174 set_main_thread();
177 #endif /* defined(_WIN32) */