diff options
-rw-r--r-- | common/Makefile.am | 2 | ||||
-rw-r--r-- | common/thread.c | 140 | ||||
-rw-r--r-- | common/thread.h | 76 | ||||
-rw-r--r-- | configure.ac | 16 | ||||
-rw-r--r-- | src/Makefile.am | 2 | ||||
-rw-r--r-- | src/libusbmuxd.c | 45 |
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; } |