From e18185c55f8d1b6d6efe1b6a35b4c8c7bd48754a Mon Sep 17 00:00:00 2001 From: "Evgeny Grin (Karlson2k)" Date: Wed, 10 Aug 2016 13:52:38 +0000 Subject: Moved thread abstraction to mhd_threads.h/mhd_threads.c, minor bugs fixed. --- configure.ac | 10 +- src/include/platform.h | 5 - src/include/platform_interface.h | 35 ---- src/include/w32functions.h | 13 -- src/microhttpd/Makefile.am | 3 +- src/microhttpd/daemon.c | 120 +++----------- src/microhttpd/internal.h | 1 + src/microhttpd/mhd_limits.h | 8 + src/microhttpd/mhd_threads.c | 274 +++++++++++++++++++++++++++++++ src/microhttpd/mhd_threads.h | 151 +++++++++++++++++ src/microhttpd/test_shutdown_select.c | 4 +- src/platform/w32functions.c | 36 ---- w32/common/MHD_config.h | 3 + w32/common/libmicrohttpd-files.vcxproj | 2 + w32/common/libmicrohttpd-filters.vcxproj | 6 + 15 files changed, 481 insertions(+), 190 deletions(-) create mode 100644 src/microhttpd/mhd_threads.c create mode 100644 src/microhttpd/mhd_threads.h diff --git a/configure.ac b/configure.ac index e5ea2590..b9918093 100644 --- a/configure.ac +++ b/configure.ac @@ -247,7 +247,11 @@ test "x$with_threads" = "xpthreads" && with_threads='posix' # Check for posix threads support, regardless of configure parameters as # posix threads are used in some tests even on W32. -AX_PTHREAD([HAVE_POSIX_THREADS='yes'],[HAVE_POSIX_THREADS='no']) +AX_PTHREAD( + [ + HAVE_POSIX_THREADS='yes' + AC_DEFINE([[HAVE_PTHREAD_H]],[[1]],[Define to 1 if you have the header file.]) + ],[[HAVE_POSIX_THREADS='no']]) AM_CONDITIONAL([HAVE_POSIX_THREADS],[test "x$HAVE_POSIX_THREADS" = "xyes"]) HAVE_W32_THREADS='no' @@ -418,10 +422,10 @@ if test "x$HAVE_POSIX_THREADS" = "xyes"; then fi # Check for headers that are ALWAYS required -AC_CHECK_HEADERS([fcntl.h math.h errno.h limits.h stdio.h locale.h sys/stat.h sys/types.h pthread.h],,AC_MSG_ERROR([Compiling libmicrohttpd requires standard UNIX headers files])) +AC_CHECK_HEADERS([fcntl.h math.h errno.h limits.h stdio.h locale.h sys/stat.h sys/types.h],,AC_MSG_ERROR([Compiling libmicrohttpd requires standard UNIX headers files])) # Check for optional headers -AC_CHECK_HEADERS([sys/types.h sys/time.h sys/msg.h netdb.h netinet/in.h netinet/tcp.h time.h sys/socket.h sys/mman.h arpa/inet.h sys/select.h search.h endian.h machine/endian.h sys/endian.h sys/param.h sys/machine.h sys/byteorder.h machine/param.h sys/isa_defs.h inttypes.h]) +AC_CHECK_HEADERS([sys/types.h sys/time.h sys/msg.h netdb.h netinet/in.h netinet/tcp.h time.h sys/socket.h sys/mman.h arpa/inet.h sys/select.h search.h endian.h machine/endian.h sys/endian.h sys/param.h sys/machine.h sys/byteorder.h machine/param.h sys/isa_defs.h inttypes.h stddef.h]) AM_CONDITIONAL([HAVE_TSEARCH], [test "x$ac_cv_header_search_h" = "xyes"]) AC_CHECK_MEMBER([struct sockaddr_in.sin_len], diff --git a/src/include/platform.h b/src/include/platform.h index ed09fc71..5ec2c16f 100644 --- a/src/include/platform.h +++ b/src/include/platform.h @@ -48,11 +48,6 @@ #include #include #include -#ifdef MHD_USE_POSIX_THREADS -#undef HAVE_CONFIG_H -#include -#define HAVE_CONFIG_H 1 -#endif /* MHD_USE_POSIX_THREADS */ /* different OSes have fd_set in a broad range of header files; diff --git a/src/include/platform_interface.h b/src/include/platform_interface.h index eba7612b..13f54530 100644 --- a/src/include/platform_interface.h +++ b/src/include/platform_interface.h @@ -189,41 +189,6 @@ typedef int _MHD_socket_funcs_size; #else #define MHD_random_() MHD_W32_random_() #endif - -#if defined(MHD_USE_POSIX_THREADS) -typedef pthread_t MHD_thread_handle_; -#elif defined(MHD_USE_W32_THREADS) -#include -typedef HANDLE MHD_thread_handle_; -#else -#error "No threading API is available." -#endif - -#if defined(MHD_USE_POSIX_THREADS) -#define MHD_THRD_RTRN_TYPE_ void* -#define MHD_THRD_CALL_SPEC_ -#elif defined(MHD_USE_W32_THREADS) -#define MHD_THRD_RTRN_TYPE_ unsigned -#define MHD_THRD_CALL_SPEC_ __stdcall -#endif - -#if defined(MHD_USE_POSIX_THREADS) -/** - * Wait until specified thread is ended - * @param thread ID to watch - * @return zero on success, nonzero on failure - */ -#define MHD_join_thread_(thread) pthread_join((thread), NULL) -#elif defined(MHD_USE_W32_THREADS) -/** - * Wait until specified thread is ended - * Close thread handle on success - * @param thread handle to watch - * @return zero on success, nonzero on failure - */ -#define MHD_join_thread_(thread) (WAIT_OBJECT_0 == WaitForSingleObject((thread), INFINITE) ? (CloseHandle((thread)), 0) : 1 ) -#endif - #if defined(MHD_USE_W32_THREADS) #define MHD_W32_MUTEX_ 1 #include diff --git a/src/include/w32functions.h b/src/include/w32functions.h index 057a989e..508778c9 100644 --- a/src/include/w32functions.h +++ b/src/include/w32functions.h @@ -194,19 +194,6 @@ int MHD_W32_random_(void); /* Emulate snprintf function on W32 */ int W32_snprintf(char *__restrict s, size_t n, const char *__restrict format, ...); -#ifndef _MSC_FULL_VER -/* Thread name available only for VC-compiler */ -static void W32_SetThreadName(const DWORD thread_id, const char *thread_name) -{ } -#else /* _MSC_FULL_VER */ -/** - * Set thread name - * @param thread_id ID of thread, -1 for current thread - * @param thread_name name to set - */ -void W32_SetThreadName(const DWORD thread_id, const char *thread_name); -#endif - #ifdef __cplusplus } #endif diff --git a/src/microhttpd/Makefile.am b/src/microhttpd/Makefile.am index 6cc40a87..e4b173ca 100644 --- a/src/microhttpd/Makefile.am +++ b/src/microhttpd/Makefile.am @@ -67,6 +67,7 @@ libmicrohttpd_la_SOURCES = \ mhd_limits.h mhd_byteorder.h \ sysfdsetsize.c sysfdsetsize.h \ mhd_str.c mhd_str.h \ + mhd_threads.c mhd_threads.h \ response.c response.h libmicrohttpd_la_CPPFLAGS = \ $(AM_CPPFLAGS) $(MHD_LIB_CPPFLAGS) \ @@ -200,7 +201,7 @@ test_shutdown_select_LDADD = \ endif test_shutdown_poll_SOURCES = \ - test_shutdown_select.c + test_shutdown_select.c mhd_threads.h if USE_POSIX_THREADS test_shutdown_poll_CFLAGS = \ $(AM_CFLAGS) $(PTHREAD_CFLAGS) diff --git a/src/microhttpd/daemon.c b/src/microhttpd/daemon.c index fd8754ce..f493d19d 100644 --- a/src/microhttpd/daemon.c +++ b/src/microhttpd/daemon.c @@ -25,6 +25,7 @@ * @author Christian Grothoff */ #include "platform.h" +#include "mhd_threads.h" #include "internal.h" #include "response.h" #include "connection.h" @@ -61,7 +62,6 @@ #define WIN32_LEAN_AND_MEAN 1 #endif /* !WIN32_LEAN_AND_MEAN */ #include -#include #endif /** @@ -1279,81 +1279,6 @@ send_param_adapter (struct MHD_Connection *connection, } -/** - * Signature of main function for a thread. - * - * @param cls closure argument for the function - * @return termination code from the thread - */ -typedef MHD_THRD_RTRN_TYPE_ -(MHD_THRD_CALL_SPEC_ *ThreadStartRoutine)(void *cls); - - -/** - * Create a thread and set the attributes according to our options. - * - * @param thread handle to initialize - * @param daemon daemon with options - * @param start_routine main function of thread - * @param arg argument for start_routine - * @return 0 on success - */ -static int -create_thread (MHD_thread_handle_ *thread, - const struct MHD_Daemon *daemon, - ThreadStartRoutine start_routine, - void *arg) -{ -#if defined(MHD_USE_POSIX_THREADS) - pthread_attr_t attr; - pthread_attr_t *pattr; - int ret; - - if (0 != daemon->thread_stack_size) - { - if (0 != (ret = pthread_attr_init (&attr))) - goto ERR; - if (0 != (ret = pthread_attr_setstacksize (&attr, daemon->thread_stack_size))) - { - pthread_attr_destroy (&attr); - goto ERR; - } - pattr = &attr; - } - else - { - pattr = NULL; - } - ret = pthread_create (thread, pattr, - start_routine, arg); -#ifdef HAVE_PTHREAD_SETNAME_NP - if (0 == ret) - (void) pthread_setname_np (*thread, "libmicrohttpd"); -#endif /* HAVE_PTHREAD_SETNAME_NP */ - if (0 != daemon->thread_stack_size) - pthread_attr_destroy (&attr); - return ret; - ERR: -#ifdef HAVE_MESSAGES - MHD_DLOG (daemon, - "Failed to set thread stack size\n"); -#endif - errno = EINVAL; - return ret; -#elif defined(MHD_USE_W32_THREADS) - unsigned threadID; - *thread = (HANDLE)_beginthreadex(NULL, (unsigned)daemon->thread_stack_size, start_routine, - arg, 0, &threadID); - if (NULL == (*thread)) - return errno; - - W32_SetThreadName(threadID, "libmicrohttpd"); - - return 0; -#endif -} - - /** * Add another client connection to the set of connections * managed by MHD. This API is usually not needed (since @@ -1388,7 +1313,6 @@ internal_add_connection (struct MHD_Daemon *daemon, int external_add) { struct MHD_Connection *connection; - int res_thread_create; unsigned int i; int eno; struct MHD_Daemon *worker; @@ -1635,17 +1559,17 @@ internal_add_connection (struct MHD_Daemon *daemon, /* attempt to create handler thread */ if (0 != (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) { - res_thread_create = create_thread (&connection->pid, - daemon, - &MHD_handle_connection, - connection); - if (0 != res_thread_create) + if (!MHD_create_named_thread_(&connection->pid, + "MHD-connection", + daemon->thread_stack_size, + &MHD_handle_connection, + connection)) { eno = errno; #ifdef HAVE_MESSAGES MHD_DLOG (daemon, "Failed to create a thread: %s\n", - MHD_strerror_ (res_thread_create)); + MHD_strerror_ (eno)); #endif goto cleanup; } @@ -1723,9 +1647,7 @@ internal_add_connection (struct MHD_Daemon *daemon, MHD_pool_destroy (connection->pool); free (connection->addr); free (connection); -#if EINVAL errno = eno; -#endif return MHD_NO; } @@ -2157,7 +2079,7 @@ MHD_cleanup_connections (struct MHD_Daemon *daemon) if ( (0 != (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) && (MHD_NO == pos->thread_joined) ) { - if (0 != MHD_join_thread_ (pos->pid)) + if (!MHD_join_thread_ (pos->pid)) { MHD_PANIC ("Failed to join a thread\n"); } @@ -3765,7 +3687,6 @@ MHD_start_daemon_va (unsigned int flags, const struct sockaddr *servaddr = NULL; socklen_t addrlen; unsigned int i; - int res_thread_create; int use_pipe; #ifndef HAVE_INET6 @@ -4307,13 +4228,17 @@ MHD_start_daemon_va (unsigned int flags, ( (0 != (flags & MHD_USE_SELECT_INTERNALLY)) && (0 == daemon->worker_pool_size)) ) && (0 == (daemon->options & MHD_USE_NO_LISTEN_SOCKET)) && - (0 != (res_thread_create = - create_thread (&daemon->pid, daemon, &MHD_select_thread, daemon)))) + (!MHD_create_named_thread_ (&daemon->pid, + (flags & MHD_USE_THREAD_PER_CONNECTION) ? + "MHD-listen" : "MHD-single", + daemon->thread_stack_size, + &MHD_select_thread, + daemon) ) ) { #ifdef HAVE_MESSAGES MHD_DLOG (daemon, "Failed to create listen thread: %s\n", - MHD_strerror_ (res_thread_create)); + MHD_strerror_ (errno)); #endif (void) MHD_mutex_destroy_ (&daemon->cleanup_connection_mutex); (void) MHD_mutex_destroy_ (&daemon->per_ip_connection_mutex); @@ -4416,13 +4341,16 @@ MHD_start_daemon_va (unsigned int flags, } /* Spawn the worker thread */ - if (0 != (res_thread_create = - create_thread (&d->pid, daemon, &MHD_select_thread, d))) + if (!MHD_create_named_thread_(&d->pid, + "MHD-worker", + daemon->thread_stack_size, + &MHD_select_thread, + d)) { #ifdef HAVE_MESSAGES MHD_DLOG (daemon, "Failed to create pool thread: %s\n", - MHD_strerror_ (res_thread_create)); + MHD_strerror_ (errno)); #endif /* Free memory for this worker; cleanup below handles * all previously-created workers. */ @@ -4564,7 +4492,7 @@ close_all_connections (struct MHD_Daemon *daemon) { if (MHD_YES != pos->thread_joined) { - if (0 != MHD_join_thread_ (pos->pid)) + if (!MHD_join_thread_ (pos->pid)) MHD_PANIC ("Failed to join a thread\n"); pos->thread_joined = MHD_YES; /* The thread may have concurrently modified the DLL, @@ -4690,7 +4618,7 @@ MHD_stop_daemon (struct MHD_Daemon *daemon) if (1 != MHD_pipe_write_ (daemon->worker_pool[i].wpipe[1], "e", 1)) MHD_PANIC ("failed to signal shutdown via pipe"); } - if (0 != MHD_join_thread_ (daemon->worker_pool[i].pid)) + if (!MHD_join_thread_ (daemon->worker_pool[i].pid)) MHD_PANIC ("Failed to join a thread\n"); close_all_connections (&daemon->worker_pool[i]); (void) MHD_mutex_destroy_ (&daemon->worker_pool[i].cleanup_connection_mutex); @@ -4720,7 +4648,7 @@ MHD_stop_daemon (struct MHD_Daemon *daemon) ( (0 != (daemon->options & MHD_USE_SELECT_INTERNALLY)) && (0 == daemon->worker_pool_size) ) ) { - if (0 != MHD_join_thread_ (daemon->pid)) + if (!MHD_join_thread_ (daemon->pid)) { MHD_PANIC ("Failed to join a thread\n"); } diff --git a/src/microhttpd/internal.h b/src/microhttpd/internal.h index 5c6a8b5d..aef6f17a 100644 --- a/src/microhttpd/internal.h +++ b/src/microhttpd/internal.h @@ -43,6 +43,7 @@ /* for TCP_FASTOPEN */ #include #endif +#include "mhd_threads.h" /** diff --git a/src/microhttpd/mhd_limits.h b/src/microhttpd/mhd_limits.h index 264803b9..f0f0d577 100644 --- a/src/microhttpd/mhd_limits.h +++ b/src/microhttpd/mhd_limits.h @@ -32,6 +32,14 @@ #include #endif /* HAVE_LIMITS_H */ +#ifndef UINT_MAX +#ifdef __UINT_MAX__ +#define UINT_MAX __UINT_MAX__ +#else /* ! __UINT_MAX__ */ +#define UINT_MAX ((unsigned int) ~((unsigned int)0)) +#endif /* ! __UINT_MAX__ */ +#endif /* !UINT_MAX */ + #ifndef LONG_MAX #ifdef __LONG_MAX__ #define LONG_MAX __LONG_MAX__ diff --git a/src/microhttpd/mhd_threads.c b/src/microhttpd/mhd_threads.c new file mode 100644 index 00000000..07da4960 --- /dev/null +++ b/src/microhttpd/mhd_threads.c @@ -0,0 +1,274 @@ +/* + This file is part of libmicrohttpd + Copyright (C) 2016 Karlson2k (Evgeny Grin) + + 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 + +*/ + +/** + * @file microhttpd/mhd_threads.c + * @brief Implementation for thread functions + * @author Karlson2k (Evgeny Grin) + */ + +#include "mhd_threads.h" +#ifdef MHD_USE_W32_THREADS +#include "mhd_limits.h" +#include +#endif +#ifdef MHD_USE_THREAD_NAME_ +#include +#endif /* MHD_USE_THREAD_NAME_ */ +#include + + + +#if defined(MHD_USE_POSIX_THREADS) +typedef pthread_t MHD_thread_ID_; +#elif defined(MHD_USE_W32_THREADS) +typedef DWORD MHD_thread_ID_; +#endif + + +#ifndef MHD_USE_THREAD_NAME_ + +#define MHD_set_thread_name_(t, n) (void) +#define MHD_set_cur_thread_name_(n) (void) + +#else /* MHD_USE_THREAD_NAME_ */ + +#if defined(MHD_USE_POSIX_THREADS) +#ifdef HAVE_PTHREAD_SETNAME_NP +/** + * Set thread name + * @param thread_id ID of thread + * @param thread_name name to set + * @return non-zero on success, zero otherwise + */ +static int MHD_set_thread_name_(const MHD_thread_ID_ thread_id, const char *thread_name) +{ + if (NULL == thread_name) + return 0; + + return !pthread_setname_np (thread_id, thread_name); +} + +/** + * Set current thread name + * @param n name to set + * @return non-zero on success, zero otherwise + */ +#define MHD_set_cur_thread_name_(n) MHD_set_thread_name_(pthread_self(),(n)) +#endif /* HAVE_PTHREAD_SETNAME_NP */ + +#elif defined(MHD_USE_W32_THREADS) +#ifndef _MSC_FULL_VER +/* Thread name available only for VC-compiler */ +#else /* _MSC_FULL_VER */ +/** + * Set thread name + * @param thread_id ID of thread, -1 for current thread + * @param thread_name name to set + * @return non-zero on success, zero otherwise + */ +static int MHD_set_thread_name_(const MHD_thread_ID_ thread_id, const char *thread_name) +{ + static const DWORD VC_SETNAME_EXC = 0x406D1388; +#pragma pack(push,8) + struct thread_info_struct + { + DWORD type; /* Must be 0x1000. */ + LPCSTR name; /* Pointer to name (in user address space). */ + DWORD ID; /* Thread ID (-1 = caller thread). */ + DWORD flags; /* Reserved for future use, must be zero. */ + } thread_info; +#pragma pack(pop) + + if (NULL == thread_name) + return 0; + + thread_info.type = 0x1000; + thread_info.name = thread_name; + thread_info.ID = thread_id; + thread_info.flags = 0; + + __try + { /* This exception is intercepted by debugger */ + RaiseException(VC_SETNAME_EXC, 0, sizeof(thread_info) / sizeof(ULONG_PTR), (ULONG_PTR*)&thread_info); + } + __except (EXCEPTION_EXECUTE_HANDLER) + {} + + return !0; +} + + +/** + * Set current thread name + * @param n name to set + * @return non-zero on success, zero otherwise + */ +#define MHD_set_cur_thread_name_(n) MHD_set_thread_name_(-1,(n)) +#endif /* _MSC_FULL_VER */ +#endif /* MHD_USE_W32_THREADS */ + +#endif /* MHD_USE_THREAD_NAME_ */ + + +/** + * Create a thread and set the attributes according to our options. + * + * @param thread handle to initialize + * @param stack_size size of stack for new thread, 0 for default + * @param start_routine main function of thread + * @param arg argument for start_routine + * @return non-zero on success; zero otherwise (with errno set) + */ +int +MHD_create_thread_ (MHD_thread_handle_ *thread, + size_t stack_size, + MHD_THREAD_START_ROUTINE_ start_routine, + void *arg) +{ +#if defined(MHD_USE_POSIX_THREADS) + int res; + + if (0 != stack_size) + { + pthread_attr_t attr; + res = pthread_attr_init (&attr); + if (0 == res) + { + res = pthread_attr_setstacksize (&attr, stack_size); + if (0 == res) + res = pthread_create (thread, &attr, + start_routine, arg); + pthread_attr_destroy (&attr); + } + } + else + res = pthread_create (thread, NULL, start_routine, arg); + + if (0 != res) + errno = res; + + return !res; +#elif defined(MHD_USE_W32_THREADS) +#if SIZE_MAX != UINT_MAX + if (stack_size > UINT_MAX) + { + errno = EINVAL; + return 0; + } +#endif /* SIZE_MAX != UINT_MAX */ + + *thread = (HANDLE)_beginthreadex(NULL, (unsigned)stack_size, start_routine, + arg, 0, NULL); + if ((MHD_thread_handle_)-1 == (*thread)) + return 0; + + return !0; +#endif +} + +#ifdef MHD_USE_THREAD_NAME_ + +struct MHD_named_helper_param_ +{ + /** + * Real thread start routine + */ + MHD_THREAD_START_ROUTINE_ start_routine; + + /** + * Argument for thread start routine + */ + void *arg; + + /** + * Name for thread + */ + const char *name; +}; + +static MHD_THRD_RTRN_TYPE_ MHD_THRD_CALL_SPEC_ +named_thread_starter (void *data) +{ + struct MHD_named_helper_param_ * const param = + (struct MHD_named_helper_param_ *) data; + void * arg; + MHD_THREAD_START_ROUTINE_ thr_func; + + if (NULL == data) + return (MHD_THRD_RTRN_TYPE_)0; + + MHD_set_cur_thread_name_(param->name); + + arg = param->arg; + thr_func = param->start_routine; + free(data); + + return thr_func(arg); +} + + + +/** + * Create a named thread and set the attributes according to our options. + * + * @param thread handle to initialize + * @param thread_name name for new thread + * @param stack_size size of stack for new thread, 0 for default + * @param start_routine main function of thread + * @param arg argument for start_routine + * @return non-zero on success; zero otherwise (with errno set) + */ +int +MHD_create_named_thread_ (MHD_thread_handle_ *thread, + const char* thread_name, + size_t stack_size, + MHD_THREAD_START_ROUTINE_ start_routine, + void *arg) +{ + struct MHD_named_helper_param_ * param; + + if (NULL == thread_name) + { + errno = EINVAL; + return 0; + } + + param = malloc(sizeof(struct MHD_named_helper_param_)); + if (NULL == param) + return 0; + + param->start_routine = start_routine; + param->arg = arg; + param->name = thread_name; + + /* Set thread name in thread itself to avoid problems with + * threads which terminated before name is set in other thread. + */ + if (!MHD_create_thread_(thread, stack_size, &named_thread_starter, (void*)param)) + { + free(param); + return 0; + } + + return !0; +} + +#endif /* MHD_USE_THREAD_NAME_ */ diff --git a/src/microhttpd/mhd_threads.h b/src/microhttpd/mhd_threads.h new file mode 100644 index 00000000..23f21a28 --- /dev/null +++ b/src/microhttpd/mhd_threads.h @@ -0,0 +1,151 @@ +/* + This file is part of libmicrohttpd + Copyright (C) 2016 Karlson2k (Evgeny Grin) + + 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 + +*/ + +/** + * @file microhttpd/mhd_threads.h + * @brief Header for platform-independent threads abstraction + * @author Karlson2k (Evgeny Grin) + * + * Provides basic abstraction for threads. + * Any functions can be implemented as macro on some platforms + * unless explicitly marked otherwise. + * Any function argument can be skipped in macro, so avoid + * variable modification in function parameters. + * + * @warning Unlike pthread functions, most of functions return + * nonzero on success. + */ + +#ifndef MHD_THREADS_H +#define MHD_THREADS_H 1 + +#include "mhd_options.h" +#ifdef HAVE_STDDEF_H +# include /* for size_t */ +#else /* ! HAVE_STDDEF_H */ +# include /* for size_t */ +#endif /* ! HAVE_STDDEF_H */ + +#if defined(MHD_USE_POSIX_THREADS) +# undef HAVE_CONFIG_H +# include +# define HAVE_CONFIG_H 1 +#elif defined(MHD_USE_W32_THREADS) +# ifndef WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN 1 +# endif /* !WIN32_LEAN_AND_MEAN */ +# include +#else +# error No threading API is available. +#endif + +#ifndef MHD_NO_THREAD_NAMES +# if defined(MHD_USE_POSIX_THREADS) +# ifdef HAVE_PTHREAD_SETNAME_NP +# define MHD_USE_THREAD_NAME_ +# endif /* HAVE_PTHREAD_SETNAME_NP */ +# elif defined(MHD_USE_W32_THREADS) +# ifdef _MSC_FULL_VER + /* Thread names only available with VC compiler */ +# define MHD_USE_THREAD_NAME_ +# endif /* _MSC_FULL_VER */ +# endif +#endif + +#if defined(MHD_USE_POSIX_THREADS) + typedef pthread_t MHD_thread_handle_; +#elif defined(MHD_USE_W32_THREADS) + typedef HANDLE MHD_thread_handle_; +#endif + +#if defined(MHD_USE_POSIX_THREADS) +# define MHD_THRD_RTRN_TYPE_ void* +# define MHD_THRD_CALL_SPEC_ +#elif defined(MHD_USE_W32_THREADS) +# define MHD_THRD_RTRN_TYPE_ unsigned +# define MHD_THRD_CALL_SPEC_ __stdcall +#endif + +#if defined(MHD_USE_POSIX_THREADS) +/** + * Wait until specified thread is ended and free thread handle on success. + * @param thread handle to watch + * @return nonzero on success, zero otherwise + */ +#define MHD_join_thread_(thread) (!pthread_join((thread), NULL)) +#elif defined(MHD_USE_W32_THREADS) +/** + * Wait until specified thread is ended and free thread handle on success. + * @param thread handle to watch + * @return nonzero on success, zero otherwise + */ +#define MHD_join_thread_(thread) (WAIT_OBJECT_0 == WaitForSingleObject((thread), INFINITE) ? (CloseHandle((thread)), !0) : 0) +#endif + +/** + * Signature of main function for a thread. + * + * @param cls closure argument for the function + * @return termination code from the thread + */ +typedef MHD_THRD_RTRN_TYPE_ +(MHD_THRD_CALL_SPEC_ *MHD_THREAD_START_ROUTINE_)(void *cls); + + +/** + * Create a thread and set the attributes according to our options. + * + * If thread is created, thread handle must be freed by #MHD_join_thread_(). + * + * @param thread handle to initialize + * @param stack_size size of stack for new thread, 0 for default + * @param start_routine main function of thread + * @param arg argument for start_routine + * @return non-zero on success; zero otherwise + */ +int +MHD_create_thread_ (MHD_thread_handle_ *thread, + size_t stack_size, + MHD_THREAD_START_ROUTINE_ start_routine, + void *arg); + +#ifndef MHD_USE_THREAD_NAME_ +#define MHD_create_named_thread_(t,n,s,r,a) MHD_create_thread_((t),(s),(r),(a)) +#else /* MHD_USE_THREAD_NAME_ */ +/** + * Create a named thread and set the attributes according to our options. + * + * @param thread handle to initialize + * @param thread_name name for new thread + * @param stack_size size of stack for new thread, 0 for default + * @param start_routine main function of thread + * @param arg argument for start_routine + * @return non-zero on success; zero otherwise + */ +int +MHD_create_named_thread_ (MHD_thread_handle_ *thread, + const char* thread_name, + size_t stack_size, + MHD_THREAD_START_ROUTINE_ start_routine, + void *arg); + +#endif /* MHD_USE_THREAD_NAME_ */ + +#endif /* ! MHD_THREADS_H */ diff --git a/src/microhttpd/test_shutdown_select.c b/src/microhttpd/test_shutdown_select.c index df36b49c..e3aaa20f 100644 --- a/src/microhttpd/test_shutdown_select.c +++ b/src/microhttpd/test_shutdown_select.c @@ -77,6 +77,8 @@ #include #endif /* HAVE_STDBOOL_H */ +#include "mhd_threads.h" + #ifndef SOMAXCONN #define SOMAXCONN 511 #endif /* ! SOMAXCONN */ @@ -346,7 +348,7 @@ main (int argc, char *const *argv) shutdown (listen_socket, SHUT_RDWR); /* fprintf (stdout, "Waiting for thread to finish...\n"); */ - if (0 != MHD_join_thread_(sel_thrd)) + if (!MHD_join_thread_(sel_thrd)) { MHD_socket_close_(listen_socket); fprintf (stderr, "Can't join select() thread\n"); diff --git a/src/platform/w32functions.c b/src/platform/w32functions.c index 0feafa5b..4b1e2c1c 100644 --- a/src/platform/w32functions.c +++ b/src/platform/w32functions.c @@ -667,39 +667,3 @@ int W32_snprintf(char *__restrict s, size_t n, const char *__restrict format, .. return ret; } - -#ifdef _MSC_FULL_VER -/** - * Set thread name - * @param thread_id ID of thread, -1 for current thread - * @param thread_name name to set - */ -void W32_SetThreadName(const DWORD thread_id, const char *thread_name) -{ - static const DWORD VC_SETNAME_EXC = 0x406D1388; -#pragma pack(push,8) - struct thread_info_struct - { - DWORD type; /* Must be 0x1000. */ - LPCSTR name; /* Pointer to name (in user address space). */ - DWORD ID; /* Thread ID (-1=caller thread). */ - DWORD flags; /* Reserved for future use, must be zero. */ - } thread_info; -#pragma pack(pop) - - if (NULL == thread_name) - return; - - thread_info.type = 0x1000; - thread_info.name = thread_name; - thread_info.ID = thread_id; - thread_info.flags = 0; - - __try - { /* This exception is intercepted by debugger */ - RaiseException(VC_SETNAME_EXC, 0, sizeof(thread_info) / sizeof(ULONG_PTR), (ULONG_PTR*)&thread_info); - } - __except (EXCEPTION_EXECUTE_HANDLER) - {} -} -#endif /* _MSC_FULL_VER */ diff --git a/w32/common/MHD_config.h b/w32/common/MHD_config.h index d147e984..c9205115 100644 --- a/w32/common/MHD_config.h +++ b/w32/common/MHD_config.h @@ -144,6 +144,9 @@ /* Define to 1 if you have the header file. */ #define HAVE_TIME_H 1 +/* Define to 1 if you have the header file. */ +#define HAVE_STDDEF_H 1 + /* *** Other useful staff *** */ diff --git a/w32/common/libmicrohttpd-files.vcxproj b/w32/common/libmicrohttpd-files.vcxproj index 4535f006..be50c277 100644 --- a/w32/common/libmicrohttpd-files.vcxproj +++ b/w32/common/libmicrohttpd-files.vcxproj @@ -16,6 +16,7 @@ + @@ -37,6 +38,7 @@ + diff --git a/w32/common/libmicrohttpd-filters.vcxproj b/w32/common/libmicrohttpd-filters.vcxproj index d43683ce..85232458 100644 --- a/w32/common/libmicrohttpd-filters.vcxproj +++ b/w32/common/libmicrohttpd-filters.vcxproj @@ -130,6 +130,12 @@ Source Files + + Source Files + + + Source Files + -- cgit v1.2.3