| 1 | /* |
| 2 | * Copyright (C) 2009 Andrzej K. Haczewski <ahaczewski@gmail.com> |
| 3 | * |
| 4 | * DISCLAIMER: 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->tid = GetCurrentThreadId(); |
| 20 | thread->arg = thread->start_routine(thread->arg); |
| 21 | return 0; |
| 22 | } |
| 23 | |
| 24 | int pthread_create(pthread_t *thread, const void *attr UNUSED, |
| 25 | void *(*start_routine)(void *), void *arg) |
| 26 | { |
| 27 | thread->arg = arg; |
| 28 | thread->start_routine = start_routine; |
| 29 | thread->handle = (HANDLE)_beginthreadex(NULL, 0, win32_start_routine, |
| 30 | thread, 0, NULL); |
| 31 | |
| 32 | if (!thread->handle) |
| 33 | return errno; |
| 34 | else |
| 35 | return 0; |
| 36 | } |
| 37 | |
| 38 | int win32_pthread_join(pthread_t *thread, void **value_ptr) |
| 39 | { |
| 40 | DWORD result = WaitForSingleObject(thread->handle, INFINITE); |
| 41 | switch (result) { |
| 42 | case WAIT_OBJECT_0: |
| 43 | if (value_ptr) |
| 44 | *value_ptr = thread->arg; |
| 45 | CloseHandle(thread->handle); |
| 46 | return 0; |
| 47 | case WAIT_ABANDONED: |
| 48 | CloseHandle(thread->handle); |
| 49 | return EINVAL; |
| 50 | default: |
| 51 | /* the wait failed, so do not detach */ |
| 52 | return err_win_to_posix(GetLastError()); |
| 53 | } |
| 54 | } |
| 55 | |
| 56 | pthread_t pthread_self(void) |
| 57 | { |
| 58 | pthread_t t = { NULL }; |
| 59 | t.tid = GetCurrentThreadId(); |
| 60 | return t; |
| 61 | } |
| 62 | |
| 63 | int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex) |
| 64 | { |
| 65 | if (SleepConditionVariableCS(cond, mutex, INFINITE) == 0) |
| 66 | return err_win_to_posix(GetLastError()); |
| 67 | return 0; |
| 68 | } |
| 69 | |
| 70 | int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex, |
| 71 | const struct timespec *abstime) |
| 72 | { |
| 73 | struct timeval now; |
| 74 | long long now_ms, deadline_ms; |
| 75 | DWORD timeout_ms; |
| 76 | |
| 77 | gettimeofday(&now, NULL); |
| 78 | now_ms = (long long)now.tv_sec * 1000 + now.tv_usec / 1000; |
| 79 | deadline_ms = (long long)abstime->tv_sec * 1000 + |
| 80 | abstime->tv_nsec / 1000000; |
| 81 | |
| 82 | if (deadline_ms <= now_ms) |
| 83 | return ETIMEDOUT; |
| 84 | else |
| 85 | timeout_ms = (DWORD)(deadline_ms - now_ms); |
| 86 | |
| 87 | if (SleepConditionVariableCS(cond, mutex, timeout_ms) == 0) { |
| 88 | DWORD err = GetLastError(); |
| 89 | if (err == ERROR_TIMEOUT) |
| 90 | return ETIMEDOUT; |
| 91 | return err_win_to_posix(err); |
| 92 | } |
| 93 | return 0; |
| 94 | } |