]> git.proxmox.com Git - libgit2.git/blame - src/win32/pthread.c
Merge pull request #3823 from libgit2/ethomson/checkout_no_index
[libgit2.git] / src / win32 / pthread.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
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. */
17static 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
28int 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
45int 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
73int 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
82int pthread_mutex_destroy(pthread_mutex_t *mutex)
83{
87d9869f
VM
84 DeleteCriticalSection(mutex);
85 return 0;
bbcc7ffc
VM
86}
87
bb3de0c4 88int pthread_mutex_lock(pthread_mutex_t *mutex)
bbcc7ffc 89{
87d9869f
VM
90 EnterCriticalSection(mutex);
91 return 0;
bbcc7ffc
VM
92}
93
bb3de0c4 94int pthread_mutex_unlock(pthread_mutex_t *mutex)
bbcc7ffc 95{
87d9869f
VM
96 LeaveCriticalSection(mutex);
97 return 0;
bbcc7ffc
VM
98}
99
5e4f2b5f
PK
100int 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
115int 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
130int 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
151int 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
169int 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 181typedef void (WINAPI *win32_srwlock_fn)(GIT_SRWLOCK *);
43095341
RB
182
183static win32_srwlock_fn win32_srwlock_initialize;
184static win32_srwlock_fn win32_srwlock_acquire_shared;
185static win32_srwlock_fn win32_srwlock_release_shared;
186static win32_srwlock_fn win32_srwlock_acquire_exclusive;
187static win32_srwlock_fn win32_srwlock_release_exclusive;
188
972bb689
RB
189int 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
203int 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
213int 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
223int 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
233int 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
243int 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
251int 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}