tor  0.4.1.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-2019, The Tor Project, Inc. */
4 /* See LICENSE for licensing information */
5 
13 #ifdef _WIN32
14 
15 #include <windows.h>
16 #include <process.h>
17 #include "lib/thread/threads.h"
18 #include "lib/log/log.h"
19 #include "lib/log/util_bug.h"
20 #include "lib/log/win32err.h"
21 
22 /* This value is more or less total cargo-cult */
23 #define SPIN_COUNT 2000
24 
34 int
35 spawn_func(void (*func)(void *), void *data)
36 {
37  int rv;
38  rv = (int)_beginthread(func, 0, data);
39  if (rv == (int)-1)
40  return -1;
41  return 0;
42 }
43 
46 void
47 spawn_exit(void)
48 {
49  _endthread();
50  // LCOV_EXCL_START
51  //we should never get here. my compiler thinks that _endthread returns, this
52  //is an attempt to fool it.
53  tor_assert(0);
54  _exit(0); // exit ok: unreachable.
55  // LCOV_EXCL_STOP
56 }
57 
58 unsigned long
60 {
61  return (unsigned long)GetCurrentThreadId();
62 }
63 
64 int
66 {
67  memset(cond, 0, sizeof(tor_cond_t));
68  if (InitializeCriticalSectionAndSpinCount(&cond->lock, SPIN_COUNT)==0) {
69  return -1;
70  }
71  if ((cond->event = CreateEvent(NULL,TRUE,FALSE,NULL)) == NULL) {
72  DeleteCriticalSection(&cond->lock);
73  return -1;
74  }
75  cond->n_waiting = cond->n_to_wake = cond->generation = 0;
76  return 0;
77 }
78 void
80 {
81  DeleteCriticalSection(&cond->lock);
82  CloseHandle(cond->event);
83 }
84 
85 static void
86 tor_cond_signal_impl(tor_cond_t *cond, int broadcast)
87 {
88  EnterCriticalSection(&cond->lock);
89  if (broadcast)
90  cond->n_to_wake = cond->n_waiting;
91  else
92  ++cond->n_to_wake;
93  cond->generation++;
94  SetEvent(cond->event);
95  LeaveCriticalSection(&cond->lock);
96 }
97 void
99 {
100  tor_cond_signal_impl(cond, 0);
101 }
102 void
104 {
105  tor_cond_signal_impl(cond, 1);
106 }
107 
108 int
110 {
111  threadlocal->index = TlsAlloc();
112  return (threadlocal->index == TLS_OUT_OF_INDEXES) ? -1 : 0;
113 }
114 
115 void
117 {
118  TlsFree(threadlocal->index);
119  memset(threadlocal, 0, sizeof(tor_threadlocal_t));
120 }
121 
122 void *
124 {
125  void *value = TlsGetValue(threadlocal->index);
126  if (value == NULL) {
127  DWORD err = GetLastError();
128  if (err != ERROR_SUCCESS) {
129  char *msg = format_win32_error(err);
130  log_err(LD_GENERAL, "Error retrieving thread-local value: %s", msg);
131  tor_free(msg);
132  tor_assert(err == ERROR_SUCCESS);
133  }
134  }
135  return value;
136 }
137 
138 void
139 tor_threadlocal_set(tor_threadlocal_t *threadlocal, void *value)
140 {
141  BOOL ok = TlsSetValue(threadlocal->index, value);
142  if (!ok) {
143  DWORD err = GetLastError();
144  char *msg = format_win32_error(err);
145  log_err(LD_GENERAL, "Error adjusting thread-local value: %s", msg);
146  tor_free(msg);
147  tor_assert(ok);
148  }
149 }
150 
151 int
152 tor_cond_wait(tor_cond_t *cond, tor_mutex_t *lock_, const struct timeval *tv)
153 {
154  CRITICAL_SECTION *lock = &lock_->mutex;
155  int generation_at_start;
156  int waiting = 1;
157  int result = -1;
158  DWORD ms = INFINITE, ms_orig = INFINITE, startTime, endTime;
159  if (tv)
160  ms_orig = ms = tv->tv_sec*1000 + (tv->tv_usec+999)/1000;
161 
162  EnterCriticalSection(&cond->lock);
163  ++cond->n_waiting;
164  generation_at_start = cond->generation;
165  LeaveCriticalSection(&cond->lock);
166 
167  LeaveCriticalSection(lock);
168 
169  startTime = GetTickCount();
170  do {
171  DWORD res;
172  res = WaitForSingleObject(cond->event, ms);
173  EnterCriticalSection(&cond->lock);
174  if (cond->n_to_wake &&
175  cond->generation != generation_at_start) {
176  --cond->n_to_wake;
177  --cond->n_waiting;
178  result = 0;
179  waiting = 0;
180  goto out;
181  } else if (res != WAIT_OBJECT_0) {
182  result = (res==WAIT_TIMEOUT) ? 1 : -1;
183  --cond->n_waiting;
184  waiting = 0;
185  goto out;
186  } else if (ms != INFINITE) {
187  endTime = GetTickCount();
188  if (startTime + ms_orig <= endTime) {
189  result = 1; /* Timeout */
190  --cond->n_waiting;
191  waiting = 0;
192  goto out;
193  } else {
194  ms = startTime + ms_orig - endTime;
195  }
196  }
197  /* If we make it here, we are still waiting. */
198  if (cond->n_to_wake == 0) {
199  /* There is nobody else who should wake up; reset
200  * the event. */
201  ResetEvent(cond->event);
202  }
203  out:
204  LeaveCriticalSection(&cond->lock);
205  } while (waiting);
206 
207  EnterCriticalSection(lock);
208 
209  EnterCriticalSection(&cond->lock);
210  if (!cond->n_waiting)
211  ResetEvent(cond->event);
212  LeaveCriticalSection(&cond->lock);
213 
214  return result;
215 }
216 
217 void
218 tor_threads_init(void)
219 {
220  set_main_thread();
221 }
222 
223 #endif /* defined(_WIN32) */
void spawn_exit(void)
void tor_cond_signal_all(tor_cond_t *cond)
void tor_cond_uninit(tor_cond_t *cond)
Header for win32err.c.
#define LD_GENERAL
Definition: log.h:58
int tor_cond_wait(tor_cond_t *cond, tor_mutex_t *mutex, const struct timeval *tv)
#define tor_free(p)
Definition: malloc.h:52
void tor_threads_init(void)
Header for threads.c.
int tor_threadlocal_init(tor_threadlocal_t *threadlocal)
tor_assert(buffer)
Header for process.c.
void tor_threadlocal_set(tor_threadlocal_t *threadlocal, void *value)
void set_main_thread(void)
int tor_cond_init(tor_cond_t *cond)
void * tor_threadlocal_get(tor_threadlocal_t *threadlocal)
Headers for log.c.
void tor_cond_signal_one(tor_cond_t *cond)
unsigned long tor_get_thread_id(void)
Macros to manage assertions, fatal and non-fatal.
void tor_threadlocal_destroy(tor_threadlocal_t *threadlocal)
int spawn_func(void(*func)(void *), void *data)