events_windows.c 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  1. /*
  2. * libusb event abstraction on Microsoft Windows
  3. *
  4. * Copyright © 2020 Chris Dickens <christopher.a.dickens@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 "libusbi.h"
  22. #include "windows_common.h"
  23. int usbi_create_event(usbi_event_t *event)
  24. {
  25. event->hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
  26. if (event->hEvent == NULL) {
  27. usbi_err(NULL, "CreateEvent failed: %s", windows_error_str(0));
  28. return LIBUSB_ERROR_OTHER;
  29. }
  30. return 0;
  31. }
  32. void usbi_destroy_event(usbi_event_t *event)
  33. {
  34. if (!CloseHandle(event->hEvent))
  35. usbi_warn(NULL, "CloseHandle failed: %s", windows_error_str(0));
  36. }
  37. void usbi_signal_event(usbi_event_t *event)
  38. {
  39. if (!SetEvent(event->hEvent))
  40. usbi_warn(NULL, "SetEvent failed: %s", windows_error_str(0));
  41. }
  42. void usbi_clear_event(usbi_event_t *event)
  43. {
  44. if (!ResetEvent(event->hEvent))
  45. usbi_warn(NULL, "ResetEvent failed: %s", windows_error_str(0));
  46. }
  47. #ifdef HAVE_OS_TIMER
  48. int usbi_create_timer(usbi_timer_t *timer)
  49. {
  50. timer->hTimer = CreateWaitableTimer(NULL, TRUE, NULL);
  51. if (timer->hTimer == NULL) {
  52. usbi_warn(NULL, "CreateWaitableTimer failed: %s", windows_error_str(0));
  53. return LIBUSB_ERROR_OTHER;
  54. }
  55. return 0;
  56. }
  57. void usbi_destroy_timer(usbi_timer_t *timer)
  58. {
  59. if (!CloseHandle(timer->hTimer))
  60. usbi_warn(NULL, "CloseHandle failed: %s", windows_error_str(0));
  61. }
  62. int usbi_arm_timer(usbi_timer_t *timer, const struct timespec *timeout)
  63. {
  64. struct timespec systime, remaining;
  65. FILETIME filetime;
  66. LARGE_INTEGER dueTime;
  67. /* Transfer timeouts are based on the monotonic clock and the waitable
  68. * timers on the system clock. This requires a conversion between the
  69. * two, so we calculate the remaining time relative to the monotonic
  70. * clock and calculate an absolute system time for the timer expiration.
  71. * Note that if the timeout has already passed, the remaining time will
  72. * be negative and thus an absolute system time in the past will be set.
  73. * This works just as intended because the timer becomes signalled
  74. * immediately. */
  75. usbi_get_monotonic_time(&systime);
  76. TIMESPEC_SUB(timeout, &systime, &remaining);
  77. GetSystemTimeAsFileTime(&filetime);
  78. dueTime.LowPart = filetime.dwLowDateTime;
  79. dueTime.HighPart = filetime.dwHighDateTime;
  80. dueTime.QuadPart += (remaining.tv_sec * 10000000LL) + (remaining.tv_nsec / 100LL);
  81. if (!SetWaitableTimer(timer->hTimer, &dueTime, 0, NULL, NULL, FALSE)) {
  82. usbi_warn(NULL, "SetWaitableTimer failed: %s", windows_error_str(0));
  83. return LIBUSB_ERROR_OTHER;
  84. }
  85. return 0;
  86. }
  87. int usbi_disarm_timer(usbi_timer_t *timer)
  88. {
  89. LARGE_INTEGER dueTime;
  90. /* A manual-reset waitable timer will stay in the signalled state until
  91. * another call to SetWaitableTimer() is made. It is possible that the
  92. * timer has already expired by the time we come in to disarm it, so to
  93. * be entirely sure the timer is disarmed and not in the signalled state,
  94. * we will set it with an impossibly large expiration and immediately
  95. * cancel. */
  96. dueTime.QuadPart = LLONG_MAX;
  97. if (!SetWaitableTimer(timer->hTimer, &dueTime, 0, NULL, NULL, FALSE)) {
  98. usbi_warn(NULL, "SetWaitableTimer failed: %s", windows_error_str(0));
  99. return LIBUSB_ERROR_OTHER;
  100. }
  101. if (!CancelWaitableTimer(timer->hTimer)) {
  102. usbi_warn(NULL, "SetWaitableTimer failed: %s", windows_error_str(0));
  103. return LIBUSB_ERROR_OTHER;
  104. }
  105. return 0;
  106. }
  107. #endif
  108. int usbi_alloc_event_data(struct libusb_context *ctx)
  109. {
  110. struct usbi_event_source *ievent_source;
  111. HANDLE *handles;
  112. size_t i = 0;
  113. /* Event sources are only added during usbi_io_init(). We should not
  114. * be running this function again if the event data has already been
  115. * allocated. */
  116. if (ctx->event_data) {
  117. usbi_warn(ctx, "program assertion failed - event data already allocated");
  118. return LIBUSB_ERROR_OTHER;
  119. }
  120. ctx->event_data_cnt = 0;
  121. for_each_event_source(ctx, ievent_source)
  122. ctx->event_data_cnt++;
  123. /* We only expect up to two HANDLEs to wait on, one for the internal
  124. * signalling event and the other for the timer. */
  125. if (ctx->event_data_cnt != 1 && ctx->event_data_cnt != 2) {
  126. usbi_err(ctx, "program assertion failed - expected exactly 1 or 2 HANDLEs");
  127. return LIBUSB_ERROR_OTHER;
  128. }
  129. handles = calloc(ctx->event_data_cnt, sizeof(HANDLE));
  130. if (!handles)
  131. return LIBUSB_ERROR_NO_MEM;
  132. for_each_event_source(ctx, ievent_source) {
  133. handles[i] = ievent_source->data.os_handle;
  134. i++;
  135. }
  136. ctx->event_data = handles;
  137. return 0;
  138. }
  139. int usbi_wait_for_events(struct libusb_context *ctx,
  140. struct usbi_reported_events *reported_events, int timeout_ms)
  141. {
  142. HANDLE *handles = ctx->event_data;
  143. DWORD num_handles = (DWORD)ctx->event_data_cnt;
  144. DWORD result;
  145. usbi_dbg(ctx, "WaitForMultipleObjects() for %lu HANDLEs with timeout in %dms", ULONG_CAST(num_handles), timeout_ms);
  146. result = WaitForMultipleObjects(num_handles, handles, FALSE, (DWORD)timeout_ms);
  147. usbi_dbg(ctx, "WaitForMultipleObjects() returned %lu", ULONG_CAST(result));
  148. if (result == WAIT_TIMEOUT) {
  149. if (usbi_using_timer(ctx))
  150. goto done;
  151. return LIBUSB_ERROR_TIMEOUT;
  152. } else if (result == WAIT_FAILED) {
  153. usbi_err(ctx, "WaitForMultipleObjects() failed: %s", windows_error_str(0));
  154. return LIBUSB_ERROR_IO;
  155. }
  156. result -= WAIT_OBJECT_0;
  157. /* handles[0] is always the internal signalling event */
  158. if (result == 0)
  159. reported_events->event_triggered = 1;
  160. else
  161. reported_events->event_triggered = 0;
  162. #ifdef HAVE_OS_TIMER
  163. /* on timer configurations, handles[1] is the timer */
  164. if (usbi_using_timer(ctx)) {
  165. /* The WaitForMultipleObjects() function reports the index of
  166. * the first object that became signalled. If the internal
  167. * signalling event was reported, we need to also check and
  168. * report whether the timer is in the signalled state. */
  169. if (result == 1 || WaitForSingleObject(handles[1], 0) == WAIT_OBJECT_0)
  170. reported_events->timer_triggered = 1;
  171. else
  172. reported_events->timer_triggered = 0;
  173. } else {
  174. reported_events->timer_triggered = 0;
  175. }
  176. #endif
  177. done:
  178. /* no events are ever reported to the backend */
  179. reported_events->num_ready = 0;
  180. return LIBUSB_SUCCESS;
  181. }