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 */
7 * \file compat_winthreads.c
9 * \brief Implementation for the windows-based multithreading backend
16 /* For condition variable support */
18 #error "orconfig.h didn't define WINVER"
21 #error "orconfig.h didn't define _WIN32_WINNT"
24 #error "winver too low"
26 #if _WIN32_WINNT < 0x0600
27 #error "winver too low"
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
49 spawn_func(void (*func
)(void *), void *data
)
52 rv
= (int)_beginthread(func
, 0, data
);
58 /** End the current thread/process.
65 //we should never get here. my compiler thinks that _endthread returns, this
66 //is an attempt to fool it.
68 _exit(0); // exit ok: unreachable.
73 tor_get_thread_id(void)
75 return (unsigned long)GetCurrentThreadId();
79 tor_cond_init(tor_cond_t
*cond
)
81 InitializeConditionVariable(&cond
->cond
);
85 tor_cond_uninit(tor_cond_t
*cond
)
91 tor_cond_signal_one(tor_cond_t
*cond
)
93 WakeConditionVariable(&cond
->cond
);
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;
109 tor_threadlocal_destroy(tor_threadlocal_t
*threadlocal
)
111 TlsFree(threadlocal
->index
);
112 memset(threadlocal
, 0, sizeof(tor_threadlocal_t
));
116 tor_threadlocal_get(tor_threadlocal_t
*threadlocal
)
118 void *value
= TlsGetValue(threadlocal
->index
);
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
);
125 tor_assert(err
== ERROR_SUCCESS
);
132 tor_threadlocal_set(tor_threadlocal_t
*threadlocal
, void *value
)
134 BOOL ok
= TlsSetValue(threadlocal
->index
, value
);
136 DWORD err
= GetLastError();
137 char *msg
= format_win32_error(err
);
138 log_err(LD_GENERAL
, "Error adjusting thread-local value: %s", msg
);
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
;
154 ms
= tv
->tv_sec
*1000 + (tv
->tv_usec
+999)/1000;
157 BOOL ok
= SleepConditionVariableSRW(&cond
->cond
, lock
, ms
, 0);
159 DWORD err
= GetLastError();
160 if (err
== ERROR_TIMEOUT
) {
163 char *msg
= format_win32_error(err
);
164 log_err(LD_GENERAL
, "Error waiting for condition variable: %s", msg
);
172 tor_threads_init(void)
177 #endif /* defined(_WIN32) */