]> git.proxmox.com Git - libgit2.git/blob - src/win32/thread.c
Merge pull request #3223 from ethomson/apply
[libgit2.git] / src / win32 / thread.c
1 /*
2 * Copyright (C) the libgit2 contributors. All rights reserved.
3 *
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.
6 */
7
8 #include "thread.h"
9 #include "../global.h"
10
11 #define CLEAN_THREAD_EXIT 0x6F012842
12
13 typedef void (WINAPI *win32_srwlock_fn)(GIT_SRWLOCK *);
14
15 static win32_srwlock_fn win32_srwlock_initialize;
16 static win32_srwlock_fn win32_srwlock_acquire_shared;
17 static win32_srwlock_fn win32_srwlock_release_shared;
18 static win32_srwlock_fn win32_srwlock_acquire_exclusive;
19 static win32_srwlock_fn win32_srwlock_release_exclusive;
20
21 /* The thread procedure stub used to invoke the caller's procedure
22 * and capture the return value for later collection. Windows will
23 * only hold a DWORD, but we need to be able to store an entire
24 * void pointer. This requires the indirection. */
25 static DWORD WINAPI git_win32__threadproc(LPVOID lpParameter)
26 {
27 git_thread *thread = lpParameter;
28
29 thread->result = thread->proc(thread->param);
30
31 git__free_tls_data();
32
33 return CLEAN_THREAD_EXIT;
34 }
35
36 int git_threads_init(void)
37 {
38 HMODULE hModule = GetModuleHandleW(L"kernel32");
39
40 if (hModule) {
41 win32_srwlock_initialize = (win32_srwlock_fn)
42 GetProcAddress(hModule, "InitializeSRWLock");
43 win32_srwlock_acquire_shared = (win32_srwlock_fn)
44 GetProcAddress(hModule, "AcquireSRWLockShared");
45 win32_srwlock_release_shared = (win32_srwlock_fn)
46 GetProcAddress(hModule, "ReleaseSRWLockShared");
47 win32_srwlock_acquire_exclusive = (win32_srwlock_fn)
48 GetProcAddress(hModule, "AcquireSRWLockExclusive");
49 win32_srwlock_release_exclusive = (win32_srwlock_fn)
50 GetProcAddress(hModule, "ReleaseSRWLockExclusive");
51 }
52
53 return 0;
54 }
55
56 int git_thread_create(
57 git_thread *GIT_RESTRICT thread,
58 void *(*start_routine)(void*),
59 void *GIT_RESTRICT arg)
60 {
61 thread->result = NULL;
62 thread->param = arg;
63 thread->proc = start_routine;
64 thread->thread = CreateThread(
65 NULL, 0, git_win32__threadproc, thread, 0, NULL);
66
67 return thread->thread ? 0 : -1;
68 }
69
70 int git_thread_join(
71 git_thread *thread,
72 void **value_ptr)
73 {
74 DWORD exit;
75
76 if (WaitForSingleObject(thread->thread, INFINITE) != WAIT_OBJECT_0)
77 return -1;
78
79 if (!GetExitCodeThread(thread->thread, &exit)) {
80 CloseHandle(thread->thread);
81 return -1;
82 }
83
84 /* Check for the thread having exited uncleanly. If exit was unclean,
85 * then we don't have a return value to give back to the caller. */
86 if (exit != CLEAN_THREAD_EXIT) {
87 assert(false);
88 thread->result = NULL;
89 }
90
91 if (value_ptr)
92 *value_ptr = thread->result;
93
94 CloseHandle(thread->thread);
95 return 0;
96 }
97
98 int git_mutex_init(git_mutex *GIT_RESTRICT mutex)
99 {
100 InitializeCriticalSection(mutex);
101 return 0;
102 }
103
104 int git_mutex_free(git_mutex *mutex)
105 {
106 DeleteCriticalSection(mutex);
107 return 0;
108 }
109
110 int git_mutex_lock(git_mutex *mutex)
111 {
112 EnterCriticalSection(mutex);
113 return 0;
114 }
115
116 int git_mutex_unlock(git_mutex *mutex)
117 {
118 LeaveCriticalSection(mutex);
119 return 0;
120 }
121
122 int git_cond_init(git_cond *cond)
123 {
124 /* This is an auto-reset event. */
125 *cond = CreateEventW(NULL, FALSE, FALSE, NULL);
126 assert(*cond);
127
128 /* If we can't create the event, claim that the reason was out-of-memory.
129 * The actual reason can be fetched with GetLastError(). */
130 return *cond ? 0 : ENOMEM;
131 }
132
133 int git_cond_free(git_cond *cond)
134 {
135 BOOL closed;
136
137 if (!cond)
138 return EINVAL;
139
140 closed = CloseHandle(*cond);
141 assert(closed);
142 GIT_UNUSED(closed);
143
144 *cond = NULL;
145 return 0;
146 }
147
148 int git_cond_wait(git_cond *cond, git_mutex *mutex)
149 {
150 int error;
151 DWORD wait_result;
152
153 if (!cond || !mutex)
154 return EINVAL;
155
156 /* The caller must be holding the mutex. */
157 error = git_mutex_unlock(mutex);
158
159 if (error)
160 return error;
161
162 wait_result = WaitForSingleObject(*cond, INFINITE);
163 assert(WAIT_OBJECT_0 == wait_result);
164 GIT_UNUSED(wait_result);
165
166 return git_mutex_lock(mutex);
167 }
168
169 int git_cond_signal(git_cond *cond)
170 {
171 BOOL signaled;
172
173 if (!cond)
174 return EINVAL;
175
176 signaled = SetEvent(*cond);
177 assert(signaled);
178 GIT_UNUSED(signaled);
179
180 return 0;
181 }
182
183 int git_rwlock_init(git_rwlock *GIT_RESTRICT lock)
184 {
185 if (win32_srwlock_initialize)
186 win32_srwlock_initialize(&lock->native.srwl);
187 else
188 InitializeCriticalSection(&lock->native.csec);
189
190 return 0;
191 }
192
193 int git_rwlock_rdlock(git_rwlock *lock)
194 {
195 if (win32_srwlock_acquire_shared)
196 win32_srwlock_acquire_shared(&lock->native.srwl);
197 else
198 EnterCriticalSection(&lock->native.csec);
199
200 return 0;
201 }
202
203 int git_rwlock_rdunlock(git_rwlock *lock)
204 {
205 if (win32_srwlock_release_shared)
206 win32_srwlock_release_shared(&lock->native.srwl);
207 else
208 LeaveCriticalSection(&lock->native.csec);
209
210 return 0;
211 }
212
213 int git_rwlock_wrlock(git_rwlock *lock)
214 {
215 if (win32_srwlock_acquire_exclusive)
216 win32_srwlock_acquire_exclusive(&lock->native.srwl);
217 else
218 EnterCriticalSection(&lock->native.csec);
219
220 return 0;
221 }
222
223 int git_rwlock_wrunlock(git_rwlock *lock)
224 {
225 if (win32_srwlock_release_exclusive)
226 win32_srwlock_release_exclusive(&lock->native.srwl);
227 else
228 LeaveCriticalSection(&lock->native.csec);
229
230 return 0;
231 }
232
233 int git_rwlock_free(git_rwlock *lock)
234 {
235 if (!win32_srwlock_initialize)
236 DeleteCriticalSection(&lock->native.csec);
237 git__memzero(lock, sizeof(*lock));
238 return 0;
239 }