Merge branch 'sp/maint-fast-import-large-blob' into sp/fast-import-large-blob
[git] / compat / win32 / pthread.c
1 /*
2  * Copyright (C) 2009 Andrzej K. Haczewski <ahaczewski@gmail.com>
3  *
4  * DISCLAMER: The implementation is Git-specific, it is subset of original
5  * Pthreads API, without lots of other features that Git doesn't use.
6  * Git also makes sure that the passed arguments are valid, so there's
7  * no need for double-checking.
8  */
9
10 #include "../../git-compat-util.h"
11 #include "pthread.h"
12
13 #include <errno.h>
14 #include <limits.h>
15
16 static unsigned __stdcall win32_start_routine(void *arg)
17 {
18         pthread_t *thread = arg;
19         thread->arg = thread->start_routine(thread->arg);
20         return 0;
21 }
22
23 int pthread_create(pthread_t *thread, const void *unused,
24                    void *(*start_routine)(void*), void *arg)
25 {
26         thread->arg = arg;
27         thread->start_routine = start_routine;
28         thread->handle = (HANDLE)
29                 _beginthreadex(NULL, 0, win32_start_routine, thread, 0, NULL);
30
31         if (!thread->handle)
32                 return errno;
33         else
34                 return 0;
35 }
36
37 int win32_pthread_join(pthread_t *thread, void **value_ptr)
38 {
39         DWORD result = WaitForSingleObject(thread->handle, INFINITE);
40         switch (result) {
41                 case WAIT_OBJECT_0:
42                         if (value_ptr)
43                                 *value_ptr = thread->arg;
44                         return 0;
45                 case WAIT_ABANDONED:
46                         return EINVAL;
47                 default:
48                         return err_win_to_posix(GetLastError());
49         }
50 }
51
52 int pthread_cond_init(pthread_cond_t *cond, const void *unused)
53 {
54         cond->waiters = 0;
55
56         cond->sema = CreateSemaphore(NULL, 0, LONG_MAX, NULL);
57         if (!cond->sema)
58                 die("CreateSemaphore() failed");
59         return 0;
60 }
61
62 int pthread_cond_destroy(pthread_cond_t *cond)
63 {
64         CloseHandle(cond->sema);
65         cond->sema = NULL;
66
67         return 0;
68 }
69
70 int pthread_cond_wait(pthread_cond_t *cond, CRITICAL_SECTION *mutex)
71 {
72         InterlockedIncrement(&cond->waiters);
73
74         /*
75          * Unlock external mutex and wait for signal.
76          * NOTE: we've held mutex locked long enough to increment
77          * waiters count above, so there's no problem with
78          * leaving mutex unlocked before we wait on semaphore.
79          */
80         LeaveCriticalSection(mutex);
81
82         /* let's wait - ignore return value */
83         WaitForSingleObject(cond->sema, INFINITE);
84
85         /* we're done waiting, so make sure we decrease waiters count */
86         InterlockedDecrement(&cond->waiters);
87
88         /* lock external mutex again */
89         EnterCriticalSection(mutex);
90
91         return 0;
92 }
93
94 int pthread_cond_signal(pthread_cond_t *cond)
95 {
96         /*
97          * Access to waiters count is atomic; see "Interlocked Variable Access"
98          * http://msdn.microsoft.com/en-us/library/ms684122(VS.85).aspx
99          */
100         int have_waiters = cond->waiters > 0;
101
102         /*
103          * Signal only when there are waiters
104          */
105         if (have_waiters)
106                 return ReleaseSemaphore(cond->sema, 1, NULL) ?
107                         0 : err_win_to_posix(GetLastError());
108         else
109                 return 0;
110 }