Tor 0.4.9.0-alpha-dev
compat_winthreads.c
Go to the documentation of this file.
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 */
48int
49spawn_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 */
60void
61spawn_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
72unsigned long
74{
75 return (unsigned long)GetCurrentThreadId();
76}
77
78int
80{
81 InitializeConditionVariable(&cond->cond);
82 return 0;
83}
84void
86{
87 (void) cond;
88}
89
90void
92{
93 WakeConditionVariable(&cond->cond);
94}
95void
97{
98 WakeAllConditionVariable(&cond->cond);
99}
100
101int
103{
104 threadlocal->index = TlsAlloc();
105 return (threadlocal->index == TLS_OUT_OF_INDEXES) ? -1 : 0;
106}
107
108void
110{
111 TlsFree(threadlocal->index);
112 memset(threadlocal, 0, sizeof(tor_threadlocal_t));
113}
114
115void *
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
131void
132tor_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
144int
145tor_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
171void
173{
175}
176
177#endif /* defined(_WIN32) */
void tor_cond_signal_all(tor_cond_t *cond)
void * tor_threadlocal_get(tor_threadlocal_t *threadlocal)
int tor_cond_init(tor_cond_t *cond)
void spawn_exit(void)
int spawn_func(void(*func)(void *), void *data)
void tor_threadlocal_destroy(tor_threadlocal_t *threadlocal)
void tor_threadlocal_set(tor_threadlocal_t *threadlocal, void *value)
void tor_threads_init(void)
void tor_cond_uninit(tor_cond_t *cond)
void tor_cond_signal_one(tor_cond_t *cond)
int tor_cond_wait(tor_cond_t *cond, tor_mutex_t *mutex, const struct timeval *tv)
int tor_threadlocal_init(tor_threadlocal_t *threadlocal)
unsigned long tor_get_thread_id(void)
void set_main_thread(void)
Headers for log.c.
#define LD_GENERAL
Definition: log.h:62
#define tor_free(p)
Definition: malloc.h:56
Header for process.c.
Header for threads.c.
Definitions for timing-related constants.
Macros to manage assertions, fatal and non-fatal.
#define tor_assert(expr)
Definition: util_bug.h:103
Header for win32err.c.