Make the initialization thread-safe
Perform the initialization inside a critical section. Unfortunately Windows critical sections, which are the simplest synchronization mechanism available on Windows, do not support static initialization. A call to InitializeCriticalSection is required. Therefore a simple spinlock, with an implementation based on atomic operations, is used as a workaround.
This commit is contained in:
parent
7b920f5c42
commit
f708eadcfd
@ -154,6 +154,7 @@ AC_CHECK_HEADERS([linux/serial.h])
|
||||
AC_CHECK_HEADERS([IOKit/serial/ioss.h])
|
||||
AC_CHECK_HEADERS([getopt.h])
|
||||
AC_CHECK_HEADERS([sys/param.h])
|
||||
AC_CHECK_HEADERS([pthread.h])
|
||||
|
||||
# Checks for global variable declarations.
|
||||
AC_CHECK_DECLS([optreset])
|
||||
|
||||
44
src/usbhid.c
44
src/usbhid.c
@ -24,6 +24,13 @@
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
#ifdef HAVE_PTHREAD_H
|
||||
#include <pthread.h>
|
||||
#endif
|
||||
#ifdef _WIN32
|
||||
#define NOGDI
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_HIDAPI)
|
||||
#define USE_HIDAPI
|
||||
@ -47,6 +54,14 @@
|
||||
#include "context-private.h"
|
||||
#include "platform.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
typedef LONG dc_mutex_t;
|
||||
#define DC_MUTEX_INIT 0
|
||||
#else
|
||||
typedef pthread_mutex_t dc_mutex_t;
|
||||
#define DC_MUTEX_INIT PTHREAD_MUTEX_INITIALIZER
|
||||
#endif
|
||||
|
||||
struct dc_usbhid_t {
|
||||
/* Library context. */
|
||||
dc_context_t *context;
|
||||
@ -87,16 +102,41 @@ syserror(int errcode)
|
||||
#endif
|
||||
|
||||
#ifdef USBHID
|
||||
static dc_mutex_t g_usbhid_mutex = DC_MUTEX_INIT;
|
||||
static size_t g_usbhid_refcount = 0;
|
||||
#ifdef USE_LIBUSB
|
||||
static libusb_context *g_usbhid_ctx = NULL;
|
||||
#endif
|
||||
|
||||
static void
|
||||
dc_mutex_lock (dc_mutex_t *mutex)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
while (InterlockedCompareExchange (mutex, 1, 0) == 1) {
|
||||
SleepEx (0, TRUE);
|
||||
}
|
||||
#else
|
||||
pthread_mutex_lock (mutex);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void
|
||||
dc_mutex_unlock (dc_mutex_t *mutex)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
InterlockedExchange (mutex, 0);
|
||||
#else
|
||||
pthread_mutex_unlock (mutex);
|
||||
#endif
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
dc_usbhid_init (dc_context_t *context)
|
||||
{
|
||||
dc_status_t status = DC_STATUS_SUCCESS;
|
||||
|
||||
dc_mutex_lock (&g_usbhid_mutex);
|
||||
|
||||
if (g_usbhid_refcount == 0) {
|
||||
#if defined(USE_LIBUSB)
|
||||
int rc = libusb_init (&g_usbhid_ctx);
|
||||
@ -119,12 +159,14 @@ dc_usbhid_init (dc_context_t *context)
|
||||
g_usbhid_refcount++;
|
||||
|
||||
error:
|
||||
dc_mutex_unlock (&g_usbhid_mutex);
|
||||
return status;
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
dc_usbhid_exit (void)
|
||||
{
|
||||
dc_mutex_lock (&g_usbhid_mutex);
|
||||
|
||||
if (--g_usbhid_refcount == 0) {
|
||||
#if defined(USE_LIBUSB)
|
||||
@ -135,6 +177,8 @@ dc_usbhid_exit (void)
|
||||
#endif
|
||||
}
|
||||
|
||||
dc_mutex_unlock (&g_usbhid_mutex);
|
||||
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
#endif
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user