threads_windows.c 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  1. /*
  2. * libusb synchronization on Microsoft Windows
  3. *
  4. * Copyright © 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. #include <config.h>
  21. #include <objbase.h>
  22. #include <errno.h>
  23. #include <stdarg.h>
  24. #include "libusbi.h"
  25. extern const uint64_t epoch_time;
  26. int usbi_mutex_init(usbi_mutex_t *mutex,
  27. const usbi_mutexattr_t *attr) {
  28. UNUSED(attr);
  29. if(! mutex) return ((errno=EINVAL));
  30. *mutex = CreateMutex(NULL, FALSE, NULL);
  31. if(!*mutex) return ((errno=ENOMEM));
  32. return 0;
  33. }
  34. int usbi_mutex_destroy(usbi_mutex_t *mutex) {
  35. // It is not clear if CloseHandle failure is due to failure to unlock.
  36. // If so, this should be errno=EBUSY.
  37. if(!mutex || !CloseHandle(*mutex)) return ((errno=EINVAL));
  38. *mutex = NULL;
  39. return 0;
  40. }
  41. int usbi_mutex_trylock(usbi_mutex_t *mutex) {
  42. DWORD result;
  43. if(!mutex) return ((errno=EINVAL));
  44. result = WaitForSingleObject(*mutex, 0);
  45. if(result == WAIT_OBJECT_0 || result == WAIT_ABANDONED)
  46. return 0; // acquired (ToDo: check that abandoned is ok)
  47. if(result == WAIT_TIMEOUT)
  48. return ((errno=EBUSY));
  49. return ((errno=EINVAL)); // don't know how this would happen
  50. // so don't know proper errno
  51. }
  52. int usbi_mutex_lock(usbi_mutex_t *mutex) {
  53. DWORD result;
  54. if(!mutex) return ((errno=EINVAL));
  55. result = WaitForSingleObject(*mutex, INFINITE);
  56. if(result == WAIT_OBJECT_0 || result == WAIT_ABANDONED)
  57. return 0; // acquired (ToDo: check that abandoned is ok)
  58. return ((errno=EINVAL)); // don't know how this would happen
  59. // so don't know proper errno
  60. }
  61. int usbi_mutex_unlock(usbi_mutex_t *mutex) {
  62. if(!mutex) return ((errno=EINVAL));
  63. if(!ReleaseMutex(*mutex)) return ((errno=EPERM ));
  64. return 0;
  65. }
  66. int usbi_mutex_static_lock(usbi_mutex_static_t *mutex) {
  67. if(!mutex) return ((errno=EINVAL));
  68. while (InterlockedExchange((LONG *)mutex, 1) == 1) {
  69. SleepEx(0, TRUE);
  70. }
  71. return 0;
  72. }
  73. int usbi_mutex_static_unlock(usbi_mutex_static_t *mutex) {
  74. if(!mutex) return ((errno=EINVAL));
  75. *mutex = 0;
  76. return 0;
  77. }
  78. int usbi_cond_init(usbi_cond_t *cond,
  79. const usbi_condattr_t *attr) {
  80. UNUSED(attr);
  81. if(!cond) return ((errno=EINVAL));
  82. list_init(&cond->waiters );
  83. list_init(&cond->not_waiting);
  84. return 0;
  85. }
  86. int usbi_cond_destroy(usbi_cond_t *cond) {
  87. // This assumes no one is using this anymore. The check MAY NOT BE safe.
  88. struct usbi_cond_perthread *pos, *next_pos = NULL;
  89. if(!cond) return ((errno=EINVAL));
  90. if(!list_empty(&cond->waiters)) return ((errno=EBUSY )); // (!see above!)
  91. list_for_each_entry_safe(pos, next_pos, &cond->not_waiting, list, struct usbi_cond_perthread) {
  92. CloseHandle(pos->event);
  93. list_del(&pos->list);
  94. free(pos);
  95. }
  96. return 0;
  97. }
  98. int usbi_cond_broadcast(usbi_cond_t *cond) {
  99. // Assumes mutex is locked; this is not in keeping with POSIX spec, but
  100. // libusb does this anyway, so we simplify by not adding more sync
  101. // primitives to the CV definition!
  102. int fail = 0;
  103. struct usbi_cond_perthread *pos;
  104. if(!cond) return ((errno=EINVAL));
  105. list_for_each_entry(pos, &cond->waiters, list, struct usbi_cond_perthread) {
  106. if(!SetEvent(pos->event))
  107. fail = 1;
  108. }
  109. // The wait function will remove its respective item from the list.
  110. return fail ? ((errno=EINVAL)) : 0;
  111. }
  112. int usbi_cond_signal(usbi_cond_t *cond) {
  113. // Assumes mutex is locked; this is not in keeping with POSIX spec, but
  114. // libusb does this anyway, so we simplify by not adding more sync
  115. // primitives to the CV definition!
  116. struct usbi_cond_perthread *pos;
  117. if(!cond) return ((errno=EINVAL));
  118. if(list_empty(&cond->waiters)) return 0; // no one to wakeup.
  119. pos = list_entry(&cond->waiters.next, struct usbi_cond_perthread, list);
  120. // The wait function will remove its respective item from the list.
  121. return SetEvent(pos->event) ? 0 : ((errno=EINVAL));
  122. }
  123. __inline static int usbi_cond_intwait(usbi_cond_t *cond,
  124. usbi_mutex_t *mutex,
  125. DWORD timeout_ms) {
  126. struct usbi_cond_perthread *pos;
  127. int found = 0, r;
  128. DWORD r2,tid = GetCurrentThreadId();
  129. if(!cond || !mutex) return ((errno=EINVAL));
  130. list_for_each_entry(pos, &cond->not_waiting, list, struct usbi_cond_perthread) {
  131. if(tid == pos->tid) {
  132. found = 1;
  133. break;
  134. }
  135. }
  136. if(!found) {
  137. pos = (struct usbi_cond_perthread*) calloc(1, sizeof(struct usbi_cond_perthread));
  138. if(!pos) return ((errno=ENOMEM)); // This errno is not POSIX-allowed.
  139. pos->tid = tid;
  140. pos->event = CreateEvent(NULL, FALSE, FALSE, NULL); // auto-reset.
  141. if(!pos->event) {
  142. free(pos);
  143. return ((errno=ENOMEM));
  144. }
  145. list_add(&pos->list, &cond->not_waiting);
  146. }
  147. list_del(&pos->list); // remove from not_waiting list.
  148. list_add(&pos->list, &cond->waiters);
  149. r = usbi_mutex_unlock(mutex);
  150. if(r) return r;
  151. r2 = WaitForSingleObject(pos->event, timeout_ms);
  152. r = usbi_mutex_lock(mutex);
  153. if(r) return r;
  154. list_del(&pos->list);
  155. list_add(&pos->list, &cond->not_waiting);
  156. if(r2 == WAIT_TIMEOUT) return ((errno=ETIMEDOUT));
  157. return 0;
  158. }
  159. // N.B.: usbi_cond_*wait() can also return ENOMEM, even though pthread_cond_*wait cannot!
  160. int usbi_cond_wait(usbi_cond_t *cond, usbi_mutex_t *mutex) {
  161. return usbi_cond_intwait(cond, mutex, INFINITE);
  162. }
  163. int usbi_cond_timedwait(usbi_cond_t *cond,
  164. usbi_mutex_t *mutex,
  165. const struct timespec *abstime) {
  166. FILETIME filetime;
  167. ULARGE_INTEGER rtime;
  168. struct timeval targ_time, cur_time, delta_time;
  169. struct timespec cur_time_ns;
  170. DWORD millis;
  171. // GetSystemTimeAsFileTime() is not available on CE
  172. SYSTEMTIME st;
  173. GetSystemTime(&st);
  174. if (!SystemTimeToFileTime(&st, &filetime))
  175. return 0;
  176. rtime.LowPart = filetime.dwLowDateTime;
  177. rtime.HighPart = filetime.dwHighDateTime;
  178. rtime.QuadPart -= epoch_time;
  179. cur_time_ns.tv_sec = (long)(rtime.QuadPart / 10000000);
  180. cur_time_ns.tv_nsec = (long)((rtime.QuadPart % 10000000)*100);
  181. TIMESPEC_TO_TIMEVAL(&cur_time, &cur_time_ns);
  182. TIMESPEC_TO_TIMEVAL(&targ_time, abstime);
  183. timersub(&targ_time, &cur_time, &delta_time);
  184. if(delta_time.tv_sec < 0) // abstime already passed?
  185. millis = 0;
  186. else {
  187. millis = delta_time.tv_usec/1000;
  188. millis += delta_time.tv_sec *1000;
  189. if (delta_time.tv_usec % 1000) // round up to next millisecond
  190. millis++;
  191. }
  192. return usbi_cond_intwait(cond, mutex, millis);
  193. }
  194. int usbi_get_tid(void) {
  195. return GetCurrentThreadId();
  196. }