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:
Jef Driesen 2017-09-26 22:58:59 +02:00
parent 7b920f5c42
commit f708eadcfd
2 changed files with 45 additions and 0 deletions

View File

@ -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])

View File

@ -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