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;  } | 
