LIBS=""
LTLDFLAGS="${LTLDFLAGS} -avoid-version -Wl,--add-stdcall-alias"
AC_DEFINE([POLL_NFDS_TYPE],[unsigned int],[type of second poll() argument])
- AC_DEFINE([WINVER], 0x0501, [Oldest Windows version supported])
- AC_DEFINE([_WIN32_WINNT], 0x0501, [Oldest Windows version supported])
+ AC_DEFINE([_WIN32_WINNT], [_WIN32_WINNT_VISTA], [Oldest Windows version supported (Vista)])
;;
haiku)
AC_DEFINE(OS_HAIKU, 1, [Haiku backend])
* libusb synchronization on Microsoft Windows
*
* Copyright © 2010 Michael Plante <michael.plante@gmail.com>
+ * Copyright © 2020 Chris Dickens <christopher.a.dickens@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
#include "libusbi.h"
-struct usbi_cond_perthread {
- struct list_head list;
- HANDLE event;
-};
-
-void usbi_cond_init(usbi_cond_t *cond)
-{
- list_init(&cond->waiters);
- list_init(&cond->not_waiting);
-}
-
-static int usbi_cond_intwait(usbi_cond_t *cond,
- usbi_mutex_t *mutex, DWORD timeout_ms)
-{
- struct usbi_cond_perthread *pos;
- DWORD r;
-
- // Same assumption as usbi_cond_broadcast() holds
- if (list_empty(&cond->not_waiting)) {
- pos = malloc(sizeof(*pos));
- if (pos == NULL)
- return ENOMEM; // This errno is not POSIX-allowed.
- pos->event = CreateEvent(NULL, FALSE, FALSE, NULL); // auto-reset.
- if (pos->event == NULL) {
- free(pos);
- return ENOMEM;
- }
- } else {
- pos = list_first_entry(&cond->not_waiting, struct usbi_cond_perthread, list);
- list_del(&pos->list); // remove from not_waiting list.
- // Ensure the event is clear before waiting
- WaitForSingleObject(pos->event, 0);
- }
-
- list_add(&pos->list, &cond->waiters);
-
- LeaveCriticalSection(mutex);
- r = WaitForSingleObject(pos->event, timeout_ms);
- EnterCriticalSection(mutex);
-
- list_del(&pos->list);
- list_add(&pos->list, &cond->not_waiting);
-
- if (r == WAIT_OBJECT_0)
- return 0;
- else if (r == WAIT_TIMEOUT)
- return ETIMEDOUT;
- else
- return EINVAL;
-}
-
-// N.B.: usbi_cond_*wait() can also return ENOMEM, even though pthread_cond_*wait cannot!
-int usbi_cond_wait(usbi_cond_t *cond, usbi_mutex_t *mutex)
-{
- return usbi_cond_intwait(cond, mutex, INFINITE);
-}
-
int usbi_cond_timedwait(usbi_cond_t *cond,
usbi_mutex_t *mutex, const struct timeval *tv)
{
DWORD millis;
- millis = (DWORD)(tv->tv_sec * 1000) + (tv->tv_usec / 1000);
+ millis = (DWORD)(tv->tv_sec * 1000L) + (tv->tv_usec / 1000L);
/* round up to next millisecond */
- if (tv->tv_usec % 1000)
+ if (tv->tv_usec % 1000L)
millis++;
- return usbi_cond_intwait(cond, mutex, millis);
-}
-
-void usbi_cond_broadcast(usbi_cond_t *cond)
-{
- // Assumes mutex is locked; this is not in keeping with POSIX spec, but
- // libusb does this anyway, so we simplify by not adding more sync
- // primitives to the CV definition!
- struct usbi_cond_perthread *pos;
-
- list_for_each_entry(pos, &cond->waiters, list, struct usbi_cond_perthread)
- SetEvent(pos->event);
- // The wait function will remove its respective item from the list.
-}
-void usbi_cond_destroy(usbi_cond_t *cond)
-{
- // This assumes no one is using this anymore. The check MAY NOT BE safe.
- struct usbi_cond_perthread *pos, *next;
-
- if (!list_empty(&cond->waiters))
- return; // (!see above!)
- list_for_each_entry_safe(pos, next, &cond->not_waiting, list, struct usbi_cond_perthread) {
- CloseHandle(pos->event);
- list_del(&pos->list);
- free(pos);
- }
-}
+ if (SleepConditionVariableCS(cond, mutex, millis))
+ return 0;
+ else if (GetLastError() == ERROR_TIMEOUT)
+ return ETIMEDOUT;
+ else
+ return EINVAL;
+}
\ No newline at end of file
}
// We *were* getting timespec from pthread.h:
-#if (!defined(HAVE_STRUCT_TIMESPEC) && !defined(_TIMESPEC_DEFINED))
+#if !defined(HAVE_STRUCT_TIMESPEC) && !defined(_TIMESPEC_DEFINED)
#define HAVE_STRUCT_TIMESPEC 1
#define _TIMESPEC_DEFINED 1
struct timespec {
#define ETIMEDOUT 10060 /* This is the value in winsock.h. */
#endif
-typedef struct usbi_cond {
- // Every time a thread touches the CV, it winds up in one of these lists.
- // It stays there until the CV is destroyed, even if the thread terminates.
- struct list_head waiters;
- struct list_head not_waiting;
-} usbi_cond_t;
-
-void usbi_cond_init(usbi_cond_t *cond);
-int usbi_cond_wait(usbi_cond_t *cond, usbi_mutex_t *mutex);
+typedef CONDITION_VARIABLE usbi_cond_t;
+static inline void usbi_cond_init(usbi_cond_t *cond)
+{
+ InitializeConditionVariable(cond);
+}
+static inline void usbi_cond_wait(usbi_cond_t *cond, usbi_mutex_t *mutex)
+{
+ (void)SleepConditionVariableCS(cond, mutex, INFINITE);
+}
int usbi_cond_timedwait(usbi_cond_t *cond,
usbi_mutex_t *mutex, const struct timeval *tv);
-void usbi_cond_broadcast(usbi_cond_t *cond);
-void usbi_cond_destroy(usbi_cond_t *cond);
+static inline void usbi_cond_broadcast(usbi_cond_t *cond)
+{
+ WakeAllConditionVariable(cond);
+}
+static inline void usbi_cond_destroy(usbi_cond_t *cond)
+{
+ UNUSED(cond);
+}
typedef DWORD usbi_tls_key_t;
static inline void usbi_tls_key_create(usbi_tls_key_t *key)
#define EPOCH_TIME UINT64_C(116444736000000000) // 1970.01.01 00:00:000 in MS Filetime
// Public
-BOOL (WINAPI *pCancelIoEx)(HANDLE, LPOVERLAPPED);
enum windows_version windows_version = WINDOWS_UNDEFINED;
// Global variables for init/exit
static HANDLE timer_thread = NULL;
static DWORD timer_thread_id = 0;
-/* Kernel32 dependencies */
-DLL_DECLARE_HANDLE(Kernel32);
-/* This call is only available from XP SP2 */
-DLL_DECLARE_FUNC_PREFIXED(WINAPI, BOOL, p, IsWow64Process, (HANDLE, PBOOL));
-
/* User32 dependencies */
DLL_DECLARE_HANDLE(User32);
DLL_DECLARE_FUNC_PREFIXED(WINAPI, BOOL, p, GetMessageA, (LPMSG, HWND, UINT, UINT));
static BOOL windows_init_dlls(void)
{
- DLL_GET_HANDLE(Kernel32);
- DLL_LOAD_FUNC_PREFIXED(Kernel32, p, IsWow64Process, FALSE);
- pCancelIoEx = (BOOL (WINAPI *)(HANDLE, LPOVERLAPPED))
- GetProcAddress(DLL_HANDLE_NAME(Kernel32), "CancelIoEx");
- usbi_dbg("Will use CancelIo%s for I/O cancellation", pCancelIoEx ? "Ex" : "");
-
DLL_GET_HANDLE(User32);
DLL_LOAD_FUNC_PREFIXED(User32, p, GetMessageA, TRUE);
DLL_LOAD_FUNC_PREFIXED(User32, p, PeekMessageA, TRUE);
static void windows_exit_dlls(void)
{
- DLL_FREE_HANDLE(Kernel32);
DLL_FREE_HANDLE(User32);
}
// Detect if we're running a 32 or 64 bit system
if (sizeof(uintptr_t) < 8) {
- if (pIsWow64Process != NULL)
- pIsWow64Process(GetCurrentProcess(), &ret);
+ IsWow64Process(GetCurrentProcess(), &ret);
} else {
ret = TRUE;
}
extern enum windows_version windows_version;
-/* This call is only available from Vista */
-extern BOOL (WINAPI *pCancelIoEx)(HANDLE, LPOVERLAPPED);
-
#include <pshpack1.h>
typedef struct USB_DEVICE_DESCRIPTOR {
struct usbdk_transfer_priv *transfer_priv = _usbdk_transfer_priv(itransfer);
struct winfd *pollable_fd = &transfer_priv->pollable_fd;
- if (pCancelIoEx != NULL) {
- // Use CancelIoEx if available to cancel just a single transfer
- if (!pCancelIoEx(priv->system_handle, pollable_fd->overlapped)) {
- usbi_err(ctx, "CancelIoEx failed: %s", windows_error_str(0));
- return LIBUSB_ERROR_NO_DEVICE;
- }
- } else {
- if (!usbdk_helper.AbortPipe(priv->redirector_handle, transfer->endpoint)) {
- usbi_err(ctx, "AbortPipe failed: %s", windows_error_str(0));
- return LIBUSB_ERROR_NO_DEVICE;
- }
- }
+ // Use CancelIoEx to cancel just a single transfer
+ if (CancelIoEx(priv->system_handle, pollable_fd->overlapped))
+ return LIBUSB_SUCCESS;
- return LIBUSB_SUCCESS;
+ usbi_warn(ctx, "CancelIoEx failed: %s", windows_error_str(0));
+ return LIBUSB_ERROR_NOT_FOUND;
}
static int usbdk_cancel_transfer(struct usbi_transfer *itransfer)
if (WinUSBX[i].Initialize != NULL) {
WinUSBX[i].initialized = true;
- // Assume driver supports CancelIoEx() if it is available
- WinUSBX[i].CancelIoEx_supported = (pCancelIoEx != NULL);
+ // Assume driver supports CancelIoEx()
+ WinUSBX[i].CancelIoEx_supported = true;
usbi_dbg("initalized sub API %s", winusbx_driver_names[i]);
} else {
usbi_warn(ctx, "Failed to initalize sub API %s", winusbx_driver_names[i]);
if (WinUSBX[sub_api].CancelIoEx_supported) {
// Try to use CancelIoEx if available to cancel just a single transfer
handle = handle_priv->interface_handle[current_interface].dev_handle;
- if (pCancelIoEx(handle, transfer_priv->pollable_fd.overlapped))
+ if (CancelIoEx(handle, transfer_priv->pollable_fd.overlapped))
return LIBUSB_SUCCESS;
else if (GetLastError() == ERROR_NOT_FOUND)
return LIBUSB_ERROR_NOT_FOUND;
hid_handle = handle_priv->interface_handle[current_interface].api_handle;
- if (pCancelIoEx != NULL) {
- // Use CancelIoEx if available to cancel just a single transfer
- if (pCancelIoEx(hid_handle, transfer_priv->pollable_fd.overlapped))
+ // Use CancelIoEx to cancel just a single transfer
+ if (CancelIoEx(hid_handle, transfer_priv->pollable_fd.overlapped))
return LIBUSB_SUCCESS;
- } else {
- if (CancelIo(hid_handle))
- return LIBUSB_SUCCESS;
- }
- usbi_warn(ctx, "cancel failed: %s", windows_error_str(0));
+ usbi_warn(ctx, "CancelIoEx failed: %s", windows_error_str(0));
return LIBUSB_ERROR_NOT_FOUND;
}
-#define LIBUSB_NANO 11432
+#define LIBUSB_NANO 11433
<ItemDefinitionGroup>
<ClCompile>
<AdditionalIncludeDirectories>.;..\libusb;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
- <PreprocessorDefinitions>WINVER=0x0501;_WIN32_WINNT=0x0501;_LIB;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions>_WIN32_WINNT=_WIN32_WINNT_VISTA;_LIB;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<WarningLevel>Level4</WarningLevel>
</ClCompile>
<ClCompile Condition="'$(Configuration)'=='Debug'">
<ClCompile>
<AdditionalOptions>/utf-8 %(AdditionalOptions)</AdditionalOptions>
<AdditionalIncludeDirectories>.;..\libusb;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
- <PreprocessorDefinitions>WINVER=0x0501;_WIN32_WINNT=0x0501;_LIB;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions>_WIN32_WINNT=_WIN32_WINNT_VISTA;_LIB;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<WarningLevel>Level4</WarningLevel>
</ClCompile>
<ClCompile Condition="'$(Configuration)'=='Debug'">
<ClCompile>
<AdditionalOptions>/utf-8 %(AdditionalOptions)</AdditionalOptions>
<AdditionalIncludeDirectories>.;..\libusb;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
- <PreprocessorDefinitions>WINVER=0x0501;_WIN32_WINNT=0x0501;_LIB;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions>_WIN32_WINNT=_WIN32_WINNT_VISTA;_LIB;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<WarningLevel>Level4</WarningLevel>
</ClCompile>
<ClCompile Condition="'$(Configuration)'=='Debug'">
<ClCompile>
<AdditionalOptions>/utf-8 %(AdditionalOptions)</AdditionalOptions>
<AdditionalIncludeDirectories>.;..\libusb;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
- <PreprocessorDefinitions>WINVER=0x0501;_WIN32_WINNT=0x0501;_LIB;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions>_WIN32_WINNT=_WIN32_WINNT_VISTA;_LIB;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<WarningLevel>Level4</WarningLevel>
</ClCompile>
<ClCompile Condition="'$(Configuration)'=='Debug'">
<ItemDefinitionGroup>
<ClCompile>
<AdditionalIncludeDirectories>.;..\libusb;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
- <PreprocessorDefinitions>WINVER=0x0501;_WIN32_WINNT=0x0501;_LIB;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions>_WIN32_WINNT=_WIN32_WINNT_VISTA;_LIB;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>
<WarningLevel>Level4</WarningLevel>
</ClCompile>
<ClCompile>
<AdditionalOptions>/utf-8 %(AdditionalOptions)</AdditionalOptions>
<AdditionalIncludeDirectories>.;..\libusb;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
- <PreprocessorDefinitions>WINVER=0x0501;_WIN32_WINNT=0x0501;_LIB;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions>_WIN32_WINNT=_WIN32_WINNT_VISTA;_LIB;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>
<WarningLevel>Level4</WarningLevel>
</ClCompile>
<ClCompile>
<AdditionalOptions>/utf-8 %(AdditionalOptions)</AdditionalOptions>
<AdditionalIncludeDirectories>.;..\libusb;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
- <PreprocessorDefinitions>WINVER=0x0501;_WIN32_WINNT=0x0501;_LIB;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions>_WIN32_WINNT=_WIN32_WINNT_VISTA;_LIB;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>
<WarningLevel>Level4</WarningLevel>
</ClCompile>
<ClCompile>
<AdditionalOptions>/utf-8 %(AdditionalOptions)</AdditionalOptions>
<AdditionalIncludeDirectories>.;..\libusb;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
- <PreprocessorDefinitions>WINVER=0x0501;_WIN32_WINNT=0x0501;_LIB;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions>_WIN32_WINNT=_WIN32_WINNT_VISTA;_LIB;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>
<WarningLevel>Level4</WarningLevel>
</ClCompile>