diff options
Diffstat (limited to 'include/libusb-1.0/os/threads_windows.c')
| -rw-r--r-- | include/libusb-1.0/os/threads_windows.c | 208 |
1 files changed, 0 insertions, 208 deletions
diff --git a/include/libusb-1.0/os/threads_windows.c b/include/libusb-1.0/os/threads_windows.c deleted file mode 100644 index 8a29920..0000000 --- a/include/libusb-1.0/os/threads_windows.c +++ /dev/null | |||
| @@ -1,208 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * libusb synchronization on Microsoft Windows | ||
| 3 | * | ||
| 4 | * Copyright (C) 2010 Michael Plante <michael.plante@gmail.com> | ||
| 5 | * | ||
| 6 | * This library is free software; you can redistribute it and/or | ||
| 7 | * modify it under the terms of the GNU Lesser General Public | ||
| 8 | * License as published by the Free Software Foundation; either | ||
| 9 | * version 2.1 of the License, or (at your option) any later version. | ||
| 10 | * | ||
| 11 | * This library is distributed in the hope that it will be useful, | ||
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 14 | * Lesser General Public License for more details. | ||
| 15 | * | ||
| 16 | * You should have received a copy of the GNU Lesser General Public | ||
| 17 | * License along with this library; if not, write to the Free Software | ||
| 18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||
| 19 | */ | ||
| 20 | |||
| 21 | #include <config.h> | ||
| 22 | #include <objbase.h> | ||
| 23 | #include <errno.h> | ||
| 24 | #include <stdarg.h> | ||
| 25 | |||
| 26 | #include "libusbi.h" | ||
| 27 | |||
| 28 | |||
| 29 | int usbi_mutex_init(usbi_mutex_t *mutex, | ||
| 30 | const usbi_mutexattr_t *attr) { | ||
| 31 | if(! mutex) return ((errno=EINVAL)); | ||
| 32 | *mutex = CreateMutex(NULL, FALSE, NULL); | ||
| 33 | if(!*mutex) return ((errno=ENOMEM)); | ||
| 34 | return 0; | ||
| 35 | } | ||
| 36 | int usbi_mutex_destroy(usbi_mutex_t *mutex) { | ||
| 37 | // It is not clear if CloseHandle failure is due to failure to unlock. | ||
| 38 | // If so, this should be errno=EBUSY. | ||
| 39 | if(!mutex || !CloseHandle(*mutex)) return ((errno=EINVAL)); | ||
| 40 | *mutex = NULL; | ||
| 41 | return 0; | ||
| 42 | } | ||
| 43 | int usbi_mutex_trylock(usbi_mutex_t *mutex) { | ||
| 44 | DWORD result; | ||
| 45 | if(!mutex) return ((errno=EINVAL)); | ||
| 46 | result = WaitForSingleObject(*mutex, 0); | ||
| 47 | if(result == WAIT_OBJECT_0 || result == WAIT_ABANDONED) | ||
| 48 | return 0; // acquired (ToDo: check that abandoned is ok) | ||
| 49 | if(result == WAIT_TIMEOUT) | ||
| 50 | return ((errno=EBUSY)); | ||
| 51 | return ((errno=EINVAL)); // don't know how this would happen | ||
| 52 | // so don't know proper errno | ||
| 53 | } | ||
| 54 | int usbi_mutex_lock(usbi_mutex_t *mutex) { | ||
| 55 | DWORD result; | ||
| 56 | if(!mutex) return ((errno=EINVAL)); | ||
| 57 | result = WaitForSingleObject(*mutex, INFINITE); | ||
| 58 | if(result == WAIT_OBJECT_0 || result == WAIT_ABANDONED) | ||
| 59 | return 0; // acquired (ToDo: check that abandoned is ok) | ||
| 60 | return ((errno=EINVAL)); // don't know how this would happen | ||
| 61 | // so don't know proper errno | ||
| 62 | } | ||
| 63 | int usbi_mutex_unlock(usbi_mutex_t *mutex) { | ||
| 64 | if(!mutex) return ((errno=EINVAL)); | ||
| 65 | if(!ReleaseMutex(*mutex)) return ((errno=EPERM )); | ||
| 66 | return 0; | ||
| 67 | } | ||
| 68 | |||
| 69 | int usbi_mutex_static_lock(usbi_mutex_static_t *mutex) { | ||
| 70 | if(!mutex) return ((errno=EINVAL)); | ||
| 71 | while (InterlockedExchange((LONG *)mutex, 1) == 1) { | ||
| 72 | SleepEx(0, TRUE); | ||
| 73 | } | ||
| 74 | return 0; | ||
| 75 | } | ||
| 76 | int usbi_mutex_static_unlock(usbi_mutex_static_t *mutex) { | ||
| 77 | if(!mutex) return ((errno=EINVAL)); | ||
| 78 | *mutex = 0; | ||
| 79 | return 0; | ||
| 80 | } | ||
| 81 | |||
| 82 | |||
| 83 | |||
| 84 | int usbi_cond_init(usbi_cond_t *cond, | ||
| 85 | const usbi_condattr_t *attr) { | ||
| 86 | if(!cond) return ((errno=EINVAL)); | ||
| 87 | list_init(&cond->waiters ); | ||
| 88 | list_init(&cond->not_waiting); | ||
| 89 | return 0; | ||
| 90 | } | ||
| 91 | int usbi_cond_destroy(usbi_cond_t *cond) { | ||
| 92 | // This assumes no one is using this anymore. The check MAY NOT BE safe. | ||
| 93 | struct usbi_cond_perthread *pos, *prev_pos = NULL; | ||
| 94 | if(!cond) return ((errno=EINVAL)); | ||
| 95 | if(!list_empty(&cond->waiters)) return ((errno=EBUSY )); // (!see above!) | ||
| 96 | list_for_each_entry(pos, &cond->not_waiting, list, struct usbi_cond_perthread) { | ||
| 97 | free(prev_pos); | ||
| 98 | list_del(&pos->list); | ||
| 99 | prev_pos = pos; | ||
| 100 | } | ||
| 101 | free(prev_pos); | ||
| 102 | prev_pos = pos = NULL; | ||
| 103 | |||
| 104 | return 0; | ||
| 105 | } | ||
| 106 | |||
| 107 | int usbi_cond_broadcast(usbi_cond_t *cond) { | ||
| 108 | // Assumes mutex is locked; this is not in keeping with POSIX spec, but | ||
| 109 | // libusb does this anyway, so we simplify by not adding more sync | ||
| 110 | // primitives to the CV definition! | ||
| 111 | int fail = 0; | ||
| 112 | struct usbi_cond_perthread *pos; | ||
| 113 | if(!cond) return ((errno=EINVAL)); | ||
| 114 | list_for_each_entry(pos, &cond->waiters, list, struct usbi_cond_perthread) { | ||
| 115 | if(!SetEvent(pos->event)) | ||
| 116 | fail = 1; | ||
| 117 | } | ||
| 118 | // The wait function will remove its respective item from the list. | ||
| 119 | return fail ? ((errno=EINVAL)) : 0; | ||
| 120 | } | ||
| 121 | int usbi_cond_signal(usbi_cond_t *cond) { | ||
| 122 | // Assumes mutex is locked; this is not in keeping with POSIX spec, but | ||
| 123 | // libusb does this anyway, so we simplify by not adding more sync | ||
| 124 | // primitives to the CV definition! | ||
| 125 | struct usbi_cond_perthread *pos; | ||
| 126 | if(!cond) return ((errno=EINVAL)); | ||
| 127 | if(list_empty(&cond->waiters)) return 0; // no one to wakeup. | ||
| 128 | pos = list_entry(&cond->waiters.next, struct usbi_cond_perthread, list); | ||
| 129 | // The wait function will remove its respective item from the list. | ||
| 130 | return SetEvent(pos->event) ? 0 : ((errno=EINVAL)); | ||
| 131 | } | ||
| 132 | static int __inline usbi_cond_intwait(usbi_cond_t *cond, | ||
| 133 | usbi_mutex_t *mutex, | ||
| 134 | DWORD timeout_ms) { | ||
| 135 | struct usbi_cond_perthread *pos; | ||
| 136 | int found = 0, r; | ||
| 137 | DWORD r2,tid = GetCurrentThreadId(); | ||
| 138 | if(!cond || !mutex) return ((errno=EINVAL)); | ||
| 139 | list_for_each_entry(pos, &cond->not_waiting, list, struct usbi_cond_perthread) { | ||
| 140 | if(tid == pos->tid) { | ||
| 141 | found = 1; | ||
| 142 | break; | ||
| 143 | } | ||
| 144 | } | ||
| 145 | if(!found) { | ||
| 146 | pos = malloc(sizeof(struct usbi_cond_perthread)); | ||
| 147 | if(!pos) return ((errno=ENOMEM)); // This errno is not POSIX-allowed. | ||
| 148 | pos->tid = tid; | ||
| 149 | pos->event = CreateEvent(NULL, FALSE, FALSE, NULL); // auto-reset. | ||
| 150 | if(!pos->event) { | ||
| 151 | free(pos); | ||
| 152 | return ((errno=ENOMEM)); | ||
| 153 | } | ||
| 154 | list_add(&pos->list, &cond->not_waiting); | ||
| 155 | } | ||
| 156 | |||
| 157 | list_del(&pos->list); // remove from not_waiting list. | ||
| 158 | list_add(&pos->list, &cond->waiters); | ||
| 159 | |||
| 160 | r = usbi_mutex_unlock(mutex); | ||
| 161 | if(r) return r; | ||
| 162 | r2 = WaitForSingleObject(pos->event, timeout_ms); | ||
| 163 | r = usbi_mutex_lock(mutex); | ||
| 164 | if(r) return r; | ||
| 165 | |||
| 166 | list_del(&pos->list); | ||
| 167 | list_add(&pos->list, &cond->not_waiting); | ||
| 168 | |||
| 169 | if(r2 == WAIT_TIMEOUT) return ((errno=ETIMEDOUT)); | ||
| 170 | |||
| 171 | return 0; | ||
| 172 | } | ||
| 173 | // N.B.: usbi_cond_*wait() can also return ENOMEM, even though pthread_cond_*wait cannot! | ||
| 174 | int usbi_cond_wait(usbi_cond_t *cond, usbi_mutex_t *mutex) { | ||
| 175 | return usbi_cond_intwait(cond, mutex, INFINITE); | ||
| 176 | } | ||
| 177 | int usbi_cond_timedwait(usbi_cond_t *cond, | ||
| 178 | usbi_mutex_t *mutex, | ||
| 179 | const struct timespec *abstime) { | ||
| 180 | FILETIME filetime; | ||
| 181 | ULARGE_INTEGER rtime; | ||
| 182 | struct timeval targ_time, cur_time, delta_time; | ||
| 183 | struct timespec cur_time_ns; | ||
| 184 | DWORD millis; | ||
| 185 | extern const uint64_t epoch_time; | ||
| 186 | |||
| 187 | GetSystemTimeAsFileTime(&filetime); | ||
| 188 | rtime.LowPart = filetime.dwLowDateTime; | ||
| 189 | rtime.HighPart = filetime.dwHighDateTime; | ||
| 190 | rtime.QuadPart -= epoch_time; | ||
| 191 | cur_time_ns.tv_sec = (long)(rtime.QuadPart / 10000000); | ||
| 192 | cur_time_ns.tv_nsec = (long)((rtime.QuadPart % 10000000)*100); | ||
| 193 | TIMESPEC_TO_TIMEVAL(&cur_time, &cur_time_ns); | ||
| 194 | |||
| 195 | TIMESPEC_TO_TIMEVAL(&targ_time, abstime); | ||
| 196 | timersub(&targ_time, &cur_time, &delta_time); | ||
| 197 | if(delta_time.tv_sec < 0) // abstime already passed? | ||
| 198 | millis = 0; | ||
| 199 | else { | ||
| 200 | millis = delta_time.tv_usec/1000; | ||
| 201 | millis += delta_time.tv_sec *1000; | ||
| 202 | if (delta_time.tv_usec % 1000) // round up to next millisecond | ||
| 203 | millis++; | ||
| 204 | } | ||
| 205 | |||
| 206 | return usbi_cond_intwait(cond, mutex, millis); | ||
| 207 | } | ||
| 208 | |||
