From a25009872304f17514089afb48a3e860e7cb9cfe Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Wed, 12 Nov 2014 21:58:30 +0100 Subject: common: Add thread+mutex implementation and use it where applicable --- common/Makefile.am | 1 + common/thread.c | 110 +++++++++++++++++++++++++++++++++++++++++++++++++++++ common/thread.h | 57 +++++++++++++++++++++++++++ src/client.c | 33 ++++++++-------- src/device.c | 66 ++++++++++++++++---------------- src/preflight.c | 14 +++---- 6 files changed, 223 insertions(+), 58 deletions(-) create mode 100644 common/thread.c create mode 100644 common/thread.h diff --git a/common/Makefile.am b/common/Makefile.am index b4a65b9..fee26ca 100644 --- a/common/Makefile.am +++ b/common/Makefile.am @@ -7,4 +7,5 @@ noinst_LTLIBRARIES = libinternalcommon.la libinternalcommon_la_LIBADD = libinternalcommon_la_LDFLAGS = $(AM_LDFLAGS) -no-undefined libinternalcommon_la_SOURCES = \ + thread.c thread.h \ utils.c utils.h diff --git a/common/thread.c b/common/thread.c new file mode 100644 index 0000000..a40929b --- /dev/null +++ b/common/thread.c @@ -0,0 +1,110 @@ +/* + * thread.c + * + * Copyright (c) 2012 Martin Szulecki All Rights Reserved. + * Copyright (c) 2012 Nikias Bassen 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 + */ + +#include "thread.h" + +int thread_create(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 +} + +int thread_detach(thread_t thread) +{ +#ifdef WIN32 + CloseHandle(thread); + return 0; +#else + int res = pthread_detach(thread); + return res; +#endif +} + +void thread_join(thread_t thread) +{ + /* wait for thread to complete */ +#ifdef WIN32 + WaitForSingleObject(thread, INFINITE); +#else + pthread_join(thread, NULL); +#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..a271b45 --- /dev/null +++ b/common/thread.h @@ -0,0 +1,57 @@ +/* + * thread.h + * + * Copyright (c) 2012 Martin Szulecki All Rights Reserved. + * Copyright (c) 2012 Nikias Bassen 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 + +#ifdef WIN32 +#include +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() +#else +#include +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() +#endif + +typedef void* (*thread_func_t)(void* data); + +int thread_create(thread_t* thread, thread_func_t thread_func, void* data); +void thread_join(thread_t thread); +int thread_detach(thread_t thread); + +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/src/client.c b/src/client.c index 4ec4025..baef4c8 100644 --- a/src/client.c +++ b/src/client.c @@ -32,7 +32,6 @@ #include #include #include -#include #include #include @@ -43,6 +42,8 @@ #include "device.h" #include "conf.h" +#include "common/thread.h" + #define CMD_BUF_SIZE 0x10000 #define REPLY_BUF_SIZE 0x10000 @@ -71,7 +72,7 @@ struct mux_client { }; static struct collection client_list; -pthread_mutex_t client_list_mutex; +mutex_t client_list_mutex; /** * Receive raw data from the client socket. @@ -185,9 +186,9 @@ int client_accept(int listenfd) client->state = CLIENT_COMMAND; client->events = POLLIN; - pthread_mutex_lock(&client_list_mutex); + mutex_lock(&client_list_mutex); collection_add(&client_list, client); - pthread_mutex_unlock(&client_list_mutex); + mutex_unlock(&client_list_mutex); #ifdef SO_PEERCRED if (log_level >= LL_INFO) { @@ -220,19 +221,19 @@ void client_close(struct mux_client *client) free(client->ob_buf); if(client->ib_buf) free(client->ib_buf); - pthread_mutex_lock(&client_list_mutex); + mutex_lock(&client_list_mutex); collection_remove(&client_list, client); - pthread_mutex_unlock(&client_list_mutex); + mutex_unlock(&client_list_mutex); free(client); } void client_get_fds(struct fdlist *list) { - pthread_mutex_lock(&client_list_mutex); + mutex_lock(&client_list_mutex); FOREACH(struct mux_client *client, &client_list) { fdlist_add(list, FD_CLIENT, client->fd, client->events); } ENDFOREACH - pthread_mutex_unlock(&client_list_mutex); + mutex_unlock(&client_list_mutex); } static int send_pkt(struct mux_client *client, uint32_t tag, enum usbmuxd_msgtype msg, void *payload, int payload_length) @@ -758,14 +759,14 @@ static void process_recv(struct mux_client *client) void client_process(int fd, short events) { struct mux_client *client = NULL; - pthread_mutex_lock(&client_list_mutex); + mutex_lock(&client_list_mutex); FOREACH(struct mux_client *lc, &client_list) { if(lc->fd == fd) { client = lc; break; } } ENDFOREACH - pthread_mutex_unlock(&client_list_mutex); + mutex_unlock(&client_list_mutex); if(!client) { usbmuxd_log(LL_INFO, "client_process: fd %d not found in client list", fd); @@ -787,33 +788,33 @@ void client_process(int fd, short events) void client_device_add(struct device_info *dev) { - pthread_mutex_lock(&client_list_mutex); + mutex_lock(&client_list_mutex); usbmuxd_log(LL_DEBUG, "client_device_add: id %d, location 0x%x, serial %s", dev->id, dev->location, dev->serial); device_set_visible(dev->id); FOREACH(struct mux_client *client, &client_list) { if(client->state == CLIENT_LISTEN) notify_device_add(client, dev); } ENDFOREACH - pthread_mutex_unlock(&client_list_mutex); + mutex_unlock(&client_list_mutex); } void client_device_remove(int device_id) { - pthread_mutex_lock(&client_list_mutex); + mutex_lock(&client_list_mutex); uint32_t id = device_id; usbmuxd_log(LL_DEBUG, "client_device_remove: id %d", device_id); FOREACH(struct mux_client *client, &client_list) { if(client->state == CLIENT_LISTEN) notify_device_remove(client, id); } ENDFOREACH - pthread_mutex_unlock(&client_list_mutex); + mutex_unlock(&client_list_mutex); } void client_init(void) { usbmuxd_log(LL_DEBUG, "client_init"); collection_init(&client_list); - pthread_mutex_init(&client_list_mutex, NULL); + mutex_init(&client_list_mutex); } void client_shutdown(void) @@ -822,6 +823,6 @@ void client_shutdown(void) FOREACH(struct mux_client *client, &client_list) { client_close(client); } ENDFOREACH - pthread_mutex_destroy(&client_list_mutex); + mutex_destroy(&client_list_mutex); collection_free(&client_list); } diff --git a/src/device.c b/src/device.c index ddd1d4a..4188b95 100644 --- a/src/device.c +++ b/src/device.c @@ -31,12 +31,12 @@ #include #include #include -#include #include "device.h" #include "client.h" #include "preflight.h" #include "usb.h" #include "log.h" +#include "common/thread.h" int next_device_id; @@ -125,19 +125,19 @@ struct mux_device }; static struct collection device_list; -pthread_mutex_t device_list_mutex; +mutex_t device_list_mutex; static struct mux_device* get_mux_device_for_id(int device_id) { struct mux_device *dev = NULL; - pthread_mutex_lock(&device_list_mutex); + mutex_lock(&device_list_mutex); FOREACH(struct mux_device *cdev, &device_list) { if(cdev->id == device_id) { dev = cdev; break; } } ENDFOREACH - pthread_mutex_unlock(&device_list_mutex); + mutex_unlock(&device_list_mutex); return dev; } @@ -145,7 +145,7 @@ static struct mux_device* get_mux_device_for_id(int device_id) static struct mux_connection* get_mux_connection(int device_id, struct mux_client *client) { struct mux_connection *conn = NULL; - pthread_mutex_lock(&device_list_mutex); + mutex_lock(&device_list_mutex); FOREACH(struct mux_device *dev, &device_list) { if(dev->id == device_id) { FOREACH(struct mux_connection *lconn, &dev->connections) { @@ -157,7 +157,7 @@ static struct mux_connection* get_mux_connection(int device_id, struct mux_clien break; } } ENDFOREACH - pthread_mutex_unlock(&device_list_mutex); + mutex_unlock(&device_list_mutex); return conn; } @@ -166,7 +166,7 @@ static int get_next_device_id(void) { while(1) { int ok = 1; - pthread_mutex_lock(&device_list_mutex); + mutex_lock(&device_list_mutex); FOREACH(struct mux_device *dev, &device_list) { if(dev->id == next_device_id) { next_device_id++; @@ -174,7 +174,7 @@ static int get_next_device_id(void) break; } } ENDFOREACH - pthread_mutex_unlock(&device_list_mutex); + mutex_unlock(&device_list_mutex); if(ok) return next_device_id++; } @@ -552,9 +552,9 @@ static void device_version_input(struct mux_device *dev, struct version_header * vh->minor = ntohl(vh->minor); if(vh->major != 2 && vh->major != 1) { usbmuxd_log(LL_ERROR, "Device %d has unknown version %d.%d", dev->id, vh->major, vh->minor); - pthread_mutex_lock(&device_list_mutex); + mutex_lock(&device_list_mutex); collection_remove(&device_list, dev); - pthread_mutex_unlock(&device_list_mutex); + mutex_unlock(&device_list_mutex); free(dev); return; } @@ -709,14 +709,14 @@ static void device_tcp_input(struct mux_device *dev, struct tcphdr *th, unsigned void device_data_input(struct usb_device *usbdev, unsigned char *buffer, uint32_t length) { struct mux_device *dev = NULL; - pthread_mutex_lock(&device_list_mutex); + mutex_lock(&device_list_mutex); FOREACH(struct mux_device *tdev, &device_list) { if(tdev->usbdev == usbdev) { dev = tdev; break; } } ENDFOREACH - pthread_mutex_unlock(&device_list_mutex); + mutex_unlock(&device_list_mutex); if(!dev) { usbmuxd_log(LL_WARNING, "Cannot find device entry for RX input from USB device %p on location 0x%x", usbdev, usb_get_location(usbdev)); return; @@ -832,15 +832,15 @@ int device_add(struct usb_device *usbdev) free(dev); return res; } - pthread_mutex_lock(&device_list_mutex); + mutex_lock(&device_list_mutex); collection_add(&device_list, dev); - pthread_mutex_unlock(&device_list_mutex); + mutex_unlock(&device_list_mutex); return 0; } void device_remove(struct usb_device *usbdev) { - pthread_mutex_lock(&device_list_mutex); + mutex_lock(&device_list_mutex); FOREACH(struct mux_device *dev, &device_list) { if(dev->usbdev == usbdev) { usbmuxd_log(LL_NOTICE, "Removed device %d on location 0x%x", dev->id, usb_get_location(usbdev)); @@ -856,48 +856,48 @@ void device_remove(struct usb_device *usbdev) preflight_device_remove_cb(dev->preflight_cb_data); } collection_remove(&device_list, dev); - pthread_mutex_unlock(&device_list_mutex); + mutex_unlock(&device_list_mutex); free(dev->pktbuf); free(dev); return; } } ENDFOREACH - pthread_mutex_unlock(&device_list_mutex); + mutex_unlock(&device_list_mutex); usbmuxd_log(LL_WARNING, "Cannot find device entry while removing USB device %p on location 0x%x", usbdev, usb_get_location(usbdev)); } void device_set_visible(int device_id) { - pthread_mutex_lock(&device_list_mutex); + mutex_lock(&device_list_mutex); FOREACH(struct mux_device *dev, &device_list) { if(dev->id == device_id) { dev->visible = 1; break; } } ENDFOREACH - pthread_mutex_unlock(&device_list_mutex); + mutex_unlock(&device_list_mutex); } void device_set_preflight_cb_data(int device_id, void* data) { - pthread_mutex_lock(&device_list_mutex); + mutex_lock(&device_list_mutex); FOREACH(struct mux_device *dev, &device_list) { if(dev->id == device_id) { dev->preflight_cb_data = data; break; } } ENDFOREACH - pthread_mutex_unlock(&device_list_mutex); + mutex_unlock(&device_list_mutex); } int device_get_count(int include_hidden) { int count = 0; struct collection dev_list = {NULL, 0}; - pthread_mutex_lock(&device_list_mutex); + mutex_lock(&device_list_mutex); collection_copy(&dev_list, &device_list); - pthread_mutex_unlock(&device_list_mutex); + mutex_unlock(&device_list_mutex); FOREACH(struct mux_device *dev, &dev_list) { if((dev->state == MUXDEV_ACTIVE) && (include_hidden || dev->visible)) @@ -912,9 +912,9 @@ int device_get_list(int include_hidden, struct device_info **devices) { int count = 0; struct collection dev_list = {NULL, 0}; - pthread_mutex_lock(&device_list_mutex); + mutex_lock(&device_list_mutex); collection_copy(&dev_list, &device_list); - pthread_mutex_unlock(&device_list_mutex); + mutex_unlock(&device_list_mutex); *devices = malloc(sizeof(struct device_info) * dev_list.capacity); struct device_info *p = *devices; @@ -939,7 +939,7 @@ int device_get_list(int include_hidden, struct device_info **devices) int device_get_timeout(void) { uint64_t oldest = (uint64_t)-1LL; - pthread_mutex_lock(&device_list_mutex); + mutex_lock(&device_list_mutex); FOREACH(struct mux_device *dev, &device_list) { if(dev->state == MUXDEV_ACTIVE) { FOREACH(struct mux_connection *conn, &dev->connections) { @@ -948,7 +948,7 @@ int device_get_timeout(void) } ENDFOREACH } } ENDFOREACH - pthread_mutex_unlock(&device_list_mutex); + mutex_unlock(&device_list_mutex); uint64_t ct = mstime64(); if((int64_t)oldest == -1LL) return 100000; //meh @@ -960,7 +960,7 @@ int device_get_timeout(void) void device_check_timeouts(void) { uint64_t ct = mstime64(); - pthread_mutex_lock(&device_list_mutex); + mutex_lock(&device_list_mutex); FOREACH(struct mux_device *dev, &device_list) { if(dev->state == MUXDEV_ACTIVE) { FOREACH(struct mux_connection *conn, &dev->connections) { @@ -973,14 +973,14 @@ void device_check_timeouts(void) } ENDFOREACH } } ENDFOREACH - pthread_mutex_unlock(&device_list_mutex); + mutex_unlock(&device_list_mutex); } void device_init(void) { usbmuxd_log(LL_DEBUG, "device_init"); collection_init(&device_list); - pthread_mutex_init(&device_list_mutex, NULL); + mutex_init(&device_list_mutex); next_device_id = 1; } @@ -1001,7 +1001,7 @@ void device_kill_connections(void) void device_shutdown(void) { usbmuxd_log(LL_DEBUG, "device_shutdown"); - pthread_mutex_lock(&device_list_mutex); + mutex_lock(&device_list_mutex); FOREACH(struct mux_device *dev, &device_list) { FOREACH(struct mux_connection *conn, &dev->connections) { connection_teardown(conn); @@ -1010,7 +1010,7 @@ void device_shutdown(void) collection_remove(&device_list, dev); free(dev); } ENDFOREACH - pthread_mutex_unlock(&device_list_mutex); - pthread_mutex_destroy(&device_list_mutex); + mutex_unlock(&device_list_mutex); + mutex_destroy(&device_list_mutex); collection_free(&device_list); } diff --git a/src/preflight.c b/src/preflight.c index c74e49d..f83c8b6 100644 --- a/src/preflight.c +++ b/src/preflight.c @@ -26,8 +26,6 @@ #include #include -#include - #include #ifdef HAVE_LIBIMOBILEDEVICE @@ -42,6 +40,8 @@ #include "conf.h" #include "log.h" +#include "common/thread.h" + #ifdef HAVE_LIBIMOBILEDEVICE enum connection_type { CONNECTION_USBMUXD = 1 @@ -344,18 +344,14 @@ void preflight_worker_device_add(struct device_info* info) memcpy(infocopy, info, sizeof(struct device_info)); - pthread_t th; - pthread_attr_t attr; - - pthread_attr_init(&attr); - pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); - - int perr = pthread_create(&th, &attr, preflight_worker_handle_device_add, infocopy); + thread_t th; + int perr = thread_create(&th, preflight_worker_handle_device_add, infocopy); if (perr != 0) { free(infocopy); usbmuxd_log(LL_ERROR, "ERROR: failed to start preflight worker thread for device %s: %s (%d). Invoking client_device_add() directly but things might not work as expected.", info->serial, strerror(perr), perr); client_device_add(info); } + thread_detach(th); #else client_device_add(info); #endif -- cgit v1.1-32-gdbae