summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--common/Makefile.am2
-rw-r--r--common/thread.c140
-rw-r--r--common/thread.h76
-rw-r--r--configure.ac16
-rw-r--r--src/Makefile.am2
-rw-r--r--src/libusbmuxd.c45
6 files changed, 241 insertions, 40 deletions
diff --git a/common/Makefile.am b/common/Makefile.am
index 8acf04b..ca8180c 100644
--- a/common/Makefile.am
+++ b/common/Makefile.am
@@ -5,8 +5,10 @@ noinst_LTLIBRARIES = libinternalcommon.la
libinternalcommon_la_LIBADD =
libinternalcommon_la_SOURCES = \
socket.c \
+ thread.c \
collection.c \
socket.h \
+ thread.h \
collection.h
if WIN32
diff --git a/common/thread.c b/common/thread.c
new file mode 100644
index 0000000..da7eb21
--- /dev/null
+++ b/common/thread.c
@@ -0,0 +1,140 @@
+/*
+ * thread.c
+ *
+ * Copyright (c) 2012-2019 Nikias Bassen, All Rights Reserved.
+ * Copyright (c) 2012 Martin Szulecki, All Rights Reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#include "thread.h"
+
+int thread_new(THREAD_T *thread, thread_func_t thread_func, void* data)
+{
+#ifdef WIN32
+ HANDLE th = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)thread_func, data, 0, NULL);
+ if (th == NULL) {
+ return -1;
+ }
+ *thread = th;
+ return 0;
+#else
+ int res = pthread_create(thread, NULL, thread_func, data);
+ return res;
+#endif
+}
+
+void thread_detach(THREAD_T thread)
+{
+#ifdef WIN32
+ CloseHandle(thread);
+#else
+ pthread_detach(thread);
+#endif
+}
+
+void thread_free(THREAD_T thread)
+{
+#ifdef WIN32
+ CloseHandle(thread);
+#endif
+}
+
+int thread_join(THREAD_T thread)
+{
+ /* wait for thread to complete */
+#ifdef WIN32
+ return (int)WaitForSingleObject(thread, INFINITE);
+#else
+ return pthread_join(thread, NULL);
+#endif
+}
+
+int thread_alive(THREAD_T thread)
+{
+#ifdef WIN32
+ return WaitForSingleObject(thread, 0) == WAIT_TIMEOUT;
+#else
+ return pthread_kill(thread, 0) == 0;
+#endif
+}
+
+int thread_cancel(THREAD_T thread)
+{
+#ifdef WIN32
+ return 0;
+#else
+#ifdef HAVE_PTHREAD_CANCEL
+ return pthread_cancel(thread);
+#else
+ return 0;
+#endif
+#endif
+}
+
+void mutex_init(mutex_t* mutex)
+{
+#ifdef WIN32
+ InitializeCriticalSection(mutex);
+#else
+ pthread_mutex_init(mutex, NULL);
+#endif
+}
+
+void mutex_destroy(mutex_t* mutex)
+{
+#ifdef WIN32
+ DeleteCriticalSection(mutex);
+#else
+ pthread_mutex_destroy(mutex);
+#endif
+}
+
+void mutex_lock(mutex_t* mutex)
+{
+#ifdef WIN32
+ EnterCriticalSection(mutex);
+#else
+ pthread_mutex_lock(mutex);
+#endif
+}
+
+void mutex_unlock(mutex_t* mutex)
+{
+#ifdef WIN32
+ LeaveCriticalSection(mutex);
+#else
+ pthread_mutex_unlock(mutex);
+#endif
+}
+
+void thread_once(thread_once_t *once_control, void (*init_routine)(void))
+{
+#ifdef WIN32
+ while (InterlockedExchange(&(once_control->lock), 1) != 0) {
+ Sleep(1);
+ }
+ if (!once_control->state) {
+ once_control->state = 1;
+ init_routine();
+ }
+ InterlockedExchange(&(once_control->lock), 0);
+#else
+ pthread_once(once_control, init_routine);
+#endif
+}
diff --git a/common/thread.h b/common/thread.h
new file mode 100644
index 0000000..23e4510
--- /dev/null
+++ b/common/thread.h
@@ -0,0 +1,76 @@
+/*
+ * thread.h
+ *
+ * Copyright (c) 2012-2019 Nikias Bassen, All Rights Reserved.
+ * Copyright (c) 2012 Martin Szulecki, All Rights Reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef __THREAD_H
+#define __THREAD_H
+
+#include <stddef.h>
+
+#ifdef WIN32
+#include <windows.h>
+typedef HANDLE THREAD_T;
+typedef CRITICAL_SECTION mutex_t;
+typedef volatile struct {
+ LONG lock;
+ int state;
+} thread_once_t;
+#define THREAD_ONCE_INIT {0, 0}
+#define THREAD_ID GetCurrentThreadId()
+#define THREAD_T_NULL (THREAD_T)NULL
+#else
+#include <pthread.h>
+#include <signal.h>
+typedef pthread_t THREAD_T;
+typedef pthread_mutex_t mutex_t;
+typedef pthread_once_t thread_once_t;
+#define THREAD_ONCE_INIT PTHREAD_ONCE_INIT
+#define THREAD_ID pthread_self()
+#define THREAD_T_NULL (THREAD_T)NULL
+#endif
+
+typedef void* (*thread_func_t)(void* data);
+
+int thread_new(THREAD_T* thread, thread_func_t thread_func, void* data);
+void thread_detach(THREAD_T thread);
+void thread_free(THREAD_T thread);
+int thread_join(THREAD_T thread);
+int thread_alive(THREAD_T thread);
+
+int thread_cancel(THREAD_T thread);
+
+#ifdef WIN32
+#undef HAVE_THREAD_CLEANUP
+#else
+#ifdef HAVE_PTHREAD_CANCEL
+#define HAVE_THREAD_CLEANUP 1
+#define thread_cleanup_push(routine, arg) pthread_cleanup_push(routine, arg)
+#define thread_cleanup_pop(execute) pthread_cleanup_pop(execute)
+#endif
+#endif
+
+void mutex_init(mutex_t* mutex);
+void mutex_destroy(mutex_t* mutex);
+void mutex_lock(mutex_t* mutex);
+void mutex_unlock(mutex_t* mutex);
+
+void thread_once(thread_once_t *once_control, void (*init_routine)(void));
+
+#endif
diff --git a/configure.ac b/configure.ac
index d64e116..55ba1cd 100644
--- a/configure.ac
+++ b/configure.ac
@@ -69,20 +69,22 @@ AC_FUNC_REALLOC
AC_CHECK_FUNCS([strcasecmp strdup strerror stpncpy sleep])
# Check for operating system
-AC_MSG_CHECKING([whether we need platform-specific build settings])
+AC_MSG_CHECKING([for platform-specific build settings])
case ${host_os} in
*mingw32*|*cygwin*)
- AC_MSG_RESULT([yes])
+ AC_MSG_RESULT([${host_os}])
win32=true
AC_DEFINE(WINVER, 0x0501, [minimum Windows version])
;;
darwin*)
- AC_MSG_RESULT([no])
+ AC_MSG_RESULT([${host_os}])
+ AX_PTHREAD([], [AC_MSG_ERROR([pthread is required to build $PACKAGE])])
+ AC_CHECK_FUNCS([pthread_cancel])
;;
*)
- AC_MSG_RESULT([yes])
- AX_PTHREAD([], [AC_MSG_ERROR([pthread is required to build libusbmuxd])])
- AC_CHECK_LIB(pthread, [pthread_create, pthread_mutex_lock], [], [AC_MSG_ERROR([pthread is required to build libusbmuxd])])
+ AC_MSG_RESULT([${host_os}])
+ AX_PTHREAD([], [AC_MSG_ERROR([pthread is required to build $PACKAGE])])
+ AC_CHECK_FUNCS([pthread_cancel])
AC_CACHE_CHECK(for program_invocation_short_name, ac_cv_program_invocation_short_name,[
AC_TRY_LINK([extern char* program_invocation_short_name;],[return program_invocation_short_name;],
[ac_cv_program_invocation_short_name=yes],
@@ -105,7 +107,7 @@ case ${host_os} in
esac
AM_CONDITIONAL(WIN32, test x$win32 = xtrue)
-AS_COMPILER_FLAGS(GLOBAL_CFLAGS, "-Wall -Wextra -Wmissing-declarations -Wredundant-decls -Wshadow -Wpointer-arith -Wwrite-strings -Wswitch-default -Wno-unused-parameter -fvisibility=hidden $PTHREAD_CFLAGS")
+AS_COMPILER_FLAGS(GLOBAL_CFLAGS, "-Wall -Wextra -Wmissing-declarations -Wredundant-decls -Wshadow -Wpointer-arith -Wwrite-strings -Wswitch-default -Wno-unused-parameter -fvisibility=hidden $PTHREAD_CFLAGS")
GLOBAL_LDFLAGS="$PTHREAD_LIBS"
AC_SUBST(GLOBAL_CFLAGS)
AC_SUBST(GLOBAL_LDFLAGS)
diff --git a/src/Makefile.am b/src/Makefile.am
index a8b4a7d..38b137b 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -9,6 +9,6 @@ libusbmuxd_la_LIBADD = $(top_builddir)/common/libinternalcommon.la
libusbmuxd_la_SOURCES = libusbmuxd.c
if WIN32
-libusbmuxd_la_LDFLAGS += -avoid-version
+libusbmuxd_la_LDFLAGS += -avoid-version -static-libgcc
libusbmuxd_la_LIBADD += -lws2_32
endif
diff --git a/src/libusbmuxd.c b/src/libusbmuxd.c
index 0a0dc88..62af3e2 100644
--- a/src/libusbmuxd.c
+++ b/src/libusbmuxd.c
@@ -104,6 +104,8 @@ static char *prog_name = NULL;
#include "socket.h"
// misc utility functions
#include "collection.h"
+// threads
+#include "thread.h"
static int libusbmuxd_debug = 0;
#ifndef PACKAGE
@@ -114,11 +116,7 @@ static int libusbmuxd_debug = 0;
static struct collection devices;
static usbmuxd_event_cb_t event_cb = NULL;
-#ifdef WIN32
-HANDLE devmon = NULL;
-#else
-pthread_t devmon;
-#endif
+static THREAD_T devmon = THREAD_T_NULL;
static int listenfd = -1;
static volatile int use_tag = 0;
@@ -1036,8 +1034,8 @@ static void *device_monitor(void *data)
{
collection_init(&devices);
-#ifndef WIN32
- pthread_cleanup_push(device_monitor_cleanup, NULL);
+#ifdef HAVE_THREAD_CLEANUP
+ thread_cleanup_push(device_monitor_cleanup, NULL);
#endif
while (event_cb) {
@@ -1054,8 +1052,8 @@ static void *device_monitor(void *data)
}
}
-#ifndef WIN32
- pthread_cleanup_pop(1);
+#ifdef HAVE_THREAD_CLEANUP
+ thread_cleanup_pop(1);
#else
device_monitor_cleanup(NULL);
#endif
@@ -1071,15 +1069,7 @@ USBMUXD_API int usbmuxd_subscribe(usbmuxd_event_cb_t callback, void *user_data)
}
event_cb = callback;
-#ifdef WIN32
- res = 0;
- devmon = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)device_monitor, user_data, 0, NULL);
- if (devmon == NULL) {
- res = GetLastError();
- }
-#else
- res = pthread_create(&devmon, NULL, device_monitor, user_data);
-#endif
+ res = thread_new(&devmon, device_monitor, user_data);
if (res != 0) {
LIBUSBMUXD_DEBUG(1, "%s: ERROR: Could not start device watcher thread!\n", __func__);
return res;
@@ -1089,28 +1079,19 @@ USBMUXD_API int usbmuxd_subscribe(usbmuxd_event_cb_t callback, void *user_data)
USBMUXD_API int usbmuxd_unsubscribe()
{
- int res;
+ int res = 0;
event_cb = NULL;
socket_shutdown(listenfd, SHUT_RDWR);
-#ifdef WIN32
- if (devmon != NULL) {
- res = WaitForSingleObject(devmon, INFINITE);
- if (res != 0) {
- return res;
- }
- }
-#else
- res = pthread_kill(devmon, 0);
- if (res == 0) {
- pthread_cancel(devmon);
- res = pthread_join(devmon, NULL);
+ if (thread_alive(devmon)) {
+ thread_cancel(devmon);
+ res = thread_join(devmon);
+ thread_free(devmon);
}
if ((res != 0) && (res != ESRCH)) {
return res;
}
-#endif
return 0;
}