]>
Commit | Line | Data |
---|---|---|
bbcc7ffc | 1 | /* |
359fc2d2 | 2 | * Copyright (C) the libgit2 contributors. All rights reserved. |
bbcc7ffc | 3 | * |
bb742ede VM |
4 | * This file is part of libgit2, distributed under the GNU GPL v2 with |
5 | * a Linking Exception. For full terms see the included COPYING file. | |
bbcc7ffc VM |
6 | */ |
7 | ||
8 | #include "pthread.h" | |
eefc32d5 | 9 | #include "../global.h" |
bbcc7ffc | 10 | |
fb591767 PK |
11 | #define CLEAN_THREAD_EXIT 0x6F012842 |
12 | ||
13 | /* The thread procedure stub used to invoke the caller's procedure | |
14 | * and capture the return value for later collection. Windows will | |
15 | * only hold a DWORD, but we need to be able to store an entire | |
16 | * void pointer. This requires the indirection. */ | |
17 | static DWORD WINAPI git_win32__threadproc(LPVOID lpParameter) | |
18 | { | |
19 | git_win32_thread *thread = lpParameter; | |
20 | ||
1b4e29b7 | 21 | thread->result = thread->proc(thread->param); |
fb591767 | 22 | |
06c985d8 | 23 | git__free_tls_data(); |
55c5f756 | 24 | |
fb591767 PK |
25 | return CLEAN_THREAD_EXIT; |
26 | } | |
27 | ||
28 | int git_win32__thread_create( | |
29 | git_win32_thread *GIT_RESTRICT thread, | |
deafee7b RB |
30 | const pthread_attr_t *GIT_RESTRICT attr, |
31 | void *(*start_routine)(void*), | |
32 | void *GIT_RESTRICT arg) | |
bbcc7ffc | 33 | { |
854eccbb | 34 | GIT_UNUSED(attr); |
fb591767 | 35 | |
1b4e29b7 PK |
36 | thread->result = NULL; |
37 | thread->param = arg; | |
fb591767 PK |
38 | thread->proc = start_routine; |
39 | thread->thread = CreateThread( | |
40 | NULL, 0, git_win32__threadproc, thread, 0, NULL); | |
41 | ||
42 | return thread->thread ? 0 : -1; | |
bbcc7ffc VM |
43 | } |
44 | ||
fb591767 PK |
45 | int git_win32__thread_join( |
46 | git_win32_thread *thread, | |
47 | void **value_ptr) | |
bbcc7ffc | 48 | { |
fb591767 PK |
49 | DWORD exit; |
50 | ||
51 | if (WaitForSingleObject(thread->thread, INFINITE) != WAIT_OBJECT_0) | |
52 | return -1; | |
53 | ||
54 | if (!GetExitCodeThread(thread->thread, &exit)) { | |
55 | CloseHandle(thread->thread); | |
56 | return -1; | |
57 | } | |
c6289186 | 58 | |
fb591767 PK |
59 | /* Check for the thread having exited uncleanly. If exit was unclean, |
60 | * then we don't have a return value to give back to the caller. */ | |
61 | if (exit != CLEAN_THREAD_EXIT) { | |
62 | assert(false); | |
1b4e29b7 | 63 | thread->result = NULL; |
c6289186 RB |
64 | } |
65 | ||
fb591767 | 66 | if (value_ptr) |
1b4e29b7 | 67 | *value_ptr = thread->result; |
fb591767 PK |
68 | |
69 | CloseHandle(thread->thread); | |
70 | return 0; | |
bbcc7ffc VM |
71 | } |
72 | ||
38eef611 RB |
73 | int pthread_mutex_init( |
74 | pthread_mutex_t *GIT_RESTRICT mutex, | |
75 | const pthread_mutexattr_t *GIT_RESTRICT mutexattr) | |
bbcc7ffc | 76 | { |
854eccbb | 77 | GIT_UNUSED(mutexattr); |
87d9869f VM |
78 | InitializeCriticalSection(mutex); |
79 | return 0; | |
bbcc7ffc VM |
80 | } |
81 | ||
82 | int pthread_mutex_destroy(pthread_mutex_t *mutex) | |
83 | { | |
87d9869f VM |
84 | DeleteCriticalSection(mutex); |
85 | return 0; | |
bbcc7ffc VM |
86 | } |
87 | ||
bb3de0c4 | 88 | int pthread_mutex_lock(pthread_mutex_t *mutex) |
bbcc7ffc | 89 | { |
87d9869f VM |
90 | EnterCriticalSection(mutex); |
91 | return 0; | |
bbcc7ffc VM |
92 | } |
93 | ||
bb3de0c4 | 94 | int pthread_mutex_unlock(pthread_mutex_t *mutex) |
bbcc7ffc | 95 | { |
87d9869f VM |
96 | LeaveCriticalSection(mutex); |
97 | return 0; | |
bbcc7ffc VM |
98 | } |
99 | ||
5e4f2b5f PK |
100 | int pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr) |
101 | { | |
102 | /* We don't support non-default attributes. */ | |
103 | if (attr) | |
104 | return EINVAL; | |
105 | ||
106 | /* This is an auto-reset event. */ | |
107 | *cond = CreateEventW(NULL, FALSE, FALSE, NULL); | |
108 | assert(*cond); | |
109 | ||
110 | /* If we can't create the event, claim that the reason was out-of-memory. | |
111 | * The actual reason can be fetched with GetLastError(). */ | |
112 | return *cond ? 0 : ENOMEM; | |
113 | } | |
114 | ||
115 | int pthread_cond_destroy(pthread_cond_t *cond) | |
116 | { | |
117 | BOOL closed; | |
118 | ||
119 | if (!cond) | |
120 | return EINVAL; | |
121 | ||
122 | closed = CloseHandle(*cond); | |
123 | assert(closed); | |
b4491b99 | 124 | GIT_UNUSED(closed); |
5e4f2b5f PK |
125 | |
126 | *cond = NULL; | |
127 | return 0; | |
128 | } | |
129 | ||
130 | int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex) | |
131 | { | |
132 | int error; | |
133 | DWORD wait_result; | |
134 | ||
135 | if (!cond || !mutex) | |
136 | return EINVAL; | |
137 | ||
138 | /* The caller must be holding the mutex. */ | |
139 | error = pthread_mutex_unlock(mutex); | |
140 | ||
141 | if (error) | |
142 | return error; | |
143 | ||
144 | wait_result = WaitForSingleObject(*cond, INFINITE); | |
145 | assert(WAIT_OBJECT_0 == wait_result); | |
b4491b99 | 146 | GIT_UNUSED(wait_result); |
5e4f2b5f PK |
147 | |
148 | return pthread_mutex_lock(mutex); | |
149 | } | |
150 | ||
151 | int pthread_cond_signal(pthread_cond_t *cond) | |
152 | { | |
153 | BOOL signaled; | |
154 | ||
155 | if (!cond) | |
156 | return EINVAL; | |
157 | ||
158 | signaled = SetEvent(*cond); | |
159 | assert(signaled); | |
b4491b99 | 160 | GIT_UNUSED(signaled); |
5e4f2b5f PK |
161 | |
162 | return 0; | |
163 | } | |
164 | ||
43095341 RB |
165 | /* pthread_cond_broadcast is not implemented because doing so with just |
166 | * Win32 events is quite complicated, and no caller in libgit2 uses it | |
167 | * yet. | |
168 | */ | |
bbcc7ffc VM |
169 | int pthread_num_processors_np(void) |
170 | { | |
87d9869f VM |
171 | DWORD_PTR p, s; |
172 | int n = 0; | |
bbcc7ffc | 173 | |
87d9869f VM |
174 | if (GetProcessAffinityMask(GetCurrentProcess(), &p, &s)) |
175 | for (; p; p >>= 1) | |
176 | n += p&1; | |
bbcc7ffc | 177 | |
87d9869f | 178 | return n ? n : 1; |
bbcc7ffc VM |
179 | } |
180 | ||
f087bc24 | 181 | typedef void (WINAPI *win32_srwlock_fn)(GIT_SRWLOCK *); |
43095341 RB |
182 | |
183 | static win32_srwlock_fn win32_srwlock_initialize; | |
184 | static win32_srwlock_fn win32_srwlock_acquire_shared; | |
185 | static win32_srwlock_fn win32_srwlock_release_shared; | |
186 | static win32_srwlock_fn win32_srwlock_acquire_exclusive; | |
187 | static win32_srwlock_fn win32_srwlock_release_exclusive; | |
188 | ||
972bb689 RB |
189 | int pthread_rwlock_init( |
190 | pthread_rwlock_t *GIT_RESTRICT lock, | |
191 | const pthread_rwlockattr_t *GIT_RESTRICT attr) | |
192 | { | |
fb591767 | 193 | GIT_UNUSED(attr); |
43095341 RB |
194 | |
195 | if (win32_srwlock_initialize) | |
196 | win32_srwlock_initialize(&lock->native.srwl); | |
197 | else | |
198 | InitializeCriticalSection(&lock->native.csec); | |
199 | ||
972bb689 RB |
200 | return 0; |
201 | } | |
202 | ||
203 | int pthread_rwlock_rdlock(pthread_rwlock_t *lock) | |
204 | { | |
43095341 RB |
205 | if (win32_srwlock_acquire_shared) |
206 | win32_srwlock_acquire_shared(&lock->native.srwl); | |
207 | else | |
208 | EnterCriticalSection(&lock->native.csec); | |
209 | ||
972bb689 RB |
210 | return 0; |
211 | } | |
212 | ||
213 | int pthread_rwlock_rdunlock(pthread_rwlock_t *lock) | |
214 | { | |
43095341 RB |
215 | if (win32_srwlock_release_shared) |
216 | win32_srwlock_release_shared(&lock->native.srwl); | |
217 | else | |
218 | LeaveCriticalSection(&lock->native.csec); | |
219 | ||
972bb689 RB |
220 | return 0; |
221 | } | |
222 | ||
223 | int pthread_rwlock_wrlock(pthread_rwlock_t *lock) | |
224 | { | |
43095341 RB |
225 | if (win32_srwlock_acquire_exclusive) |
226 | win32_srwlock_acquire_exclusive(&lock->native.srwl); | |
227 | else | |
228 | EnterCriticalSection(&lock->native.csec); | |
229 | ||
972bb689 RB |
230 | return 0; |
231 | } | |
232 | ||
233 | int pthread_rwlock_wrunlock(pthread_rwlock_t *lock) | |
234 | { | |
43095341 RB |
235 | if (win32_srwlock_release_exclusive) |
236 | win32_srwlock_release_exclusive(&lock->native.srwl); | |
237 | else | |
238 | LeaveCriticalSection(&lock->native.csec); | |
239 | ||
972bb689 RB |
240 | return 0; |
241 | } | |
242 | ||
243 | int pthread_rwlock_destroy(pthread_rwlock_t *lock) | |
244 | { | |
43095341 RB |
245 | if (!win32_srwlock_initialize) |
246 | DeleteCriticalSection(&lock->native.csec); | |
247 | git__memzero(lock, sizeof(*lock)); | |
248 | return 0; | |
249 | } | |
250 | ||
43095341 RB |
251 | int win32_pthread_initialize(void) |
252 | { | |
fb591767 PK |
253 | HMODULE hModule = GetModuleHandleW(L"kernel32"); |
254 | ||
255 | if (hModule) { | |
256 | win32_srwlock_initialize = (win32_srwlock_fn) | |
257 | GetProcAddress(hModule, "InitializeSRWLock"); | |
258 | win32_srwlock_acquire_shared = (win32_srwlock_fn) | |
259 | GetProcAddress(hModule, "AcquireSRWLockShared"); | |
260 | win32_srwlock_release_shared = (win32_srwlock_fn) | |
261 | GetProcAddress(hModule, "ReleaseSRWLockShared"); | |
262 | win32_srwlock_acquire_exclusive = (win32_srwlock_fn) | |
263 | GetProcAddress(hModule, "AcquireSRWLockExclusive"); | |
264 | win32_srwlock_release_exclusive = (win32_srwlock_fn) | |
265 | GetProcAddress(hModule, "ReleaseSRWLockExclusive"); | |
43095341 RB |
266 | } |
267 | ||
972bb689 RB |
268 | return 0; |
269 | } |