Tor  0.4.7.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  */
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
74 {
75  return (unsigned long)GetCurrentThreadId();
76 }
77 
78 int
80 {
81  InitializeConditionVariable(&cond->cond);
82  return 0;
83 }
84 void
86 {
87  (void) cond;
88 }
89 
90 void
92 {
93  WakeConditionVariable(&cond->cond);
94 }
95 void
97 {
98  WakeAllConditionVariable(&cond->cond);
99 }
100 
101 int
103 {
104  threadlocal->index = TlsAlloc();
105  return (threadlocal->index == TLS_OUT_OF_INDEXES) ? -1 : 0;
106 }
107 
108 void
110 {
111  TlsFree(threadlocal->index);
112  memset(threadlocal, 0, sizeof(tor_threadlocal_t));
113 }
114 
115 void *
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 relase 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) */
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:52
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:102
Header for win32err.c.