diff options
Diffstat (limited to 'src/microhttpd/mhd_threads.c')
-rw-r--r-- | src/microhttpd/mhd_threads.c | 274 |
1 files changed, 274 insertions, 0 deletions
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 <process.h> +#endif +#ifdef MHD_USE_THREAD_NAME_ +#include <stdlib.h> +#endif /* MHD_USE_THREAD_NAME_ */ +#include <errno.h> + + + +#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_ */ |