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