1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
|
/* Copyright (c) 2003-2004, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
* Copyright (c) 2007-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "compat.h"
#include <windows.h>
#include <process.h>
#include "util.h"
#include "container.h"
#include "torlog.h"
/** Minimalist interface to run a void function in the background. On
* Unix calls fork, on win32 calls beginthread. Returns -1 on failure.
* func should not return, but rather should call spawn_exit.
*
* NOTE: if <b>data</b> is used, it should not be allocated on the stack,
* since in a multithreaded environment, there is no way to be sure that
* the caller's stack will still be around when the called function is
* running.
*/
int
spawn_func(void (*func)(void *), void *data)
{
int rv;
rv = (int)_beginthread(func, 0, data);
if (rv == (int)-1)
return -1;
return 0;
}
/** End the current thread/process.
*/
void
spawn_exit(void)
{
_endthread();
//we should never get here. my compiler thinks that _endthread returns, this
//is an attempt to fool it.
tor_assert(0);
_exit(0);
}
void
tor_mutex_init(tor_mutex_t *m)
{
InitializeCriticalSection(&m->mutex);
}
void
tor_mutex_uninit(tor_mutex_t *m)
{
DeleteCriticalSection(&m->mutex);
}
void
tor_mutex_acquire(tor_mutex_t *m)
{
tor_assert(m);
EnterCriticalSection(&m->mutex);
}
void
tor_mutex_release(tor_mutex_t *m)
{
LeaveCriticalSection(&m->mutex);
}
unsigned long
tor_get_thread_id(void)
{
return (unsigned long)GetCurrentThreadId();
}
static DWORD cond_event_tls_index;
struct tor_cond_t {
CRITICAL_SECTION mutex;
smartlist_t *events;
};
tor_cond_t *
tor_cond_new(void)
{
tor_cond_t *cond = tor_malloc_zero(sizeof(tor_cond_t));
InitializeCriticalSection(&cond->mutex);
cond->events = smartlist_new();
return cond;
}
void
tor_cond_free(tor_cond_t *cond)
{
if (!cond)
return;
DeleteCriticalSection(&cond->mutex);
/* XXXX notify? */
smartlist_free(cond->events);
tor_free(cond);
}
int
tor_cond_wait(tor_cond_t *cond, tor_mutex_t *mutex)
{
HANDLE event;
int r;
tor_assert(cond);
tor_assert(mutex);
event = TlsGetValue(cond_event_tls_index);
if (!event) {
event = CreateEvent(0, FALSE, FALSE, NULL);
TlsSetValue(cond_event_tls_index, event);
}
EnterCriticalSection(&cond->mutex);
tor_assert(WaitForSingleObject(event, 0) == WAIT_TIMEOUT);
tor_assert(!smartlist_contains(cond->events, event));
smartlist_add(cond->events, event);
LeaveCriticalSection(&cond->mutex);
tor_mutex_release(mutex);
r = WaitForSingleObject(event, INFINITE);
tor_mutex_acquire(mutex);
switch (r) {
case WAIT_OBJECT_0: /* we got the mutex normally. */
break;
case WAIT_ABANDONED: /* holding thread exited. */
case WAIT_TIMEOUT: /* Should never happen. */
tor_assert(0);
break;
case WAIT_FAILED:
log_warn(LD_GENERAL, "Failed to acquire mutex: %d",(int) GetLastError());
}
return 0;
}
void
tor_cond_signal_one(tor_cond_t *cond)
{
HANDLE event;
tor_assert(cond);
EnterCriticalSection(&cond->mutex);
if ((event = smartlist_pop_last(cond->events)))
SetEvent(event);
LeaveCriticalSection(&cond->mutex);
}
void
tor_cond_signal_all(tor_cond_t *cond)
{
tor_assert(cond);
EnterCriticalSection(&cond->mutex);
SMARTLIST_FOREACH(cond->events, HANDLE, event, SetEvent(event));
smartlist_clear(cond->events);
LeaveCriticalSection(&cond->mutex);
}
void
tor_threads_init(void)
{
cond_event_tls_index = TlsAlloc();
set_main_thread();
}
|