Blame src/microhttpd/mhd_threads.c

Packit 875988
/*
Packit 875988
  This file is part of libmicrohttpd
Packit 875988
  Copyright (C) 2016 Karlson2k (Evgeny Grin)
Packit 875988
Packit 875988
  This library is free software; you can redistribute it and/or
Packit 875988
  modify it under the terms of the GNU Lesser General Public
Packit 875988
  License as published by the Free Software Foundation; either
Packit 875988
  version 2.1 of the License, or (at your option) any later version.
Packit 875988
Packit 875988
  This library is distributed in the hope that it will be useful,
Packit 875988
  but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 875988
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 875988
  Lesser General Public License for more details.
Packit 875988
Packit 875988
  You should have received a copy of the GNU Lesser General Public
Packit 875988
  License along with this library; if not, write to the Free Software
Packit 875988
  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
Packit 875988
Packit 875988
*/
Packit 875988
Packit 875988
/**
Packit 875988
 * @file microhttpd/mhd_threads.c
Packit 875988
 * @brief  Implementation for thread functions
Packit 875988
 * @author Karlson2k (Evgeny Grin)
Packit 875988
 */
Packit 875988
Packit 875988
#include "mhd_threads.h"
Packit 875988
#ifdef MHD_USE_W32_THREADS
Packit 875988
#include "mhd_limits.h"
Packit 875988
#include <process.h>
Packit 875988
#endif
Packit 875988
#ifdef MHD_USE_THREAD_NAME_
Packit 875988
#include <stdlib.h>
Packit 875988
#ifdef HAVE_PTHREAD_NP_H
Packit 875988
#include <pthread_np.h>
Packit 875988
#endif /* HAVE_PTHREAD_NP_H */
Packit 875988
#endif /* MHD_USE_THREAD_NAME_ */
Packit 875988
#include <errno.h>
Packit 875988
Packit 875988
Packit 875988
#ifndef MHD_USE_THREAD_NAME_
Packit 875988
Packit 875988
#define MHD_set_thread_name_(t, n) (void)
Packit 875988
#define MHD_set_cur_thread_name_(n) (void)
Packit 875988
Packit 875988
#else  /* MHD_USE_THREAD_NAME_ */
Packit 875988
Packit 875988
#if defined(MHD_USE_POSIX_THREADS)
Packit 875988
#if defined(HAVE_PTHREAD_ATTR_SETNAME_NP_NETBSD) || defined(HAVE_PTHREAD_ATTR_SETNAME_NP_IBMI)
Packit 875988
#  define MHD_USE_THREAD_ATTR_SETNAME 1
Packit 875988
#endif /* HAVE_PTHREAD_ATTR_SETNAME_NP_NETBSD || HAVE_PTHREAD_ATTR_SETNAME_NP_IBMI */
Packit 875988
Packit 875988
#if defined(HAVE_PTHREAD_SETNAME_NP_GNU) || defined(HAVE_PTHREAD_SET_NAME_NP_FREEBSD) \
Packit 875988
    || defined(HAVE_PTHREAD_SETNAME_NP_NETBSD)
Packit 875988
Packit 875988
/**
Packit 875988
 * Set thread name
Packit 875988
 *
Packit 875988
 * @param thread_id ID of thread
Packit 875988
 * @param thread_name name to set
Packit 875988
 * @return non-zero on success, zero otherwise
Packit 875988
 */
Packit 875988
static int
Packit 875988
MHD_set_thread_name_(const MHD_thread_ID_ thread_id,
Packit 875988
                     const char *thread_name)
Packit 875988
{
Packit 875988
  if (NULL == thread_name)
Packit 875988
    return 0;
Packit 875988
Packit 875988
#if defined(HAVE_PTHREAD_SETNAME_NP_GNU)
Packit 875988
  return !pthread_setname_np (thread_id, thread_name);
Packit 875988
#elif defined(HAVE_PTHREAD_SET_NAME_NP_FREEBSD)
Packit 875988
  /* FreeBSD and OpenBSD use different name and void return type */
Packit 875988
  pthread_set_name_np (thread_id, thread_name);
Packit 875988
  return !0;
Packit 875988
#elif defined(HAVE_PTHREAD_SETNAME_NP_NETBSD)
Packit 875988
  /* NetBSD use 3 arguments: second argument is string in printf-like format,
Packit 875988
   *                         third argument is single argument for printf;
Packit 875988
   * OSF1 use 3 arguments too, but last one always must be zero (NULL).
Packit 875988
   * MHD doesn't use '%' in thread names, so both form are used in same way.
Packit 875988
   */
Packit 875988
  return !pthread_setname_np (thread_id, thread_name, 0);
Packit 875988
#endif /* HAVE_PTHREAD_SETNAME_NP_NETBSD */
Packit 875988
}
Packit 875988
Packit 875988
Packit 875988
#ifndef __QNXNTO__
Packit 875988
/**
Packit 875988
 * Set current thread name
Packit 875988
 * @param n name to set
Packit 875988
 * @return non-zero on success, zero otherwise
Packit 875988
 */
Packit 875988
#define MHD_set_cur_thread_name_(n) MHD_set_thread_name_(pthread_self(),(n))
Packit 875988
#else  /* __QNXNTO__ */
Packit 875988
/* Special case for QNX Neutrino - using zero for thread ID sets name faster. */
Packit 875988
#define MHD_set_cur_thread_name_(n) MHD_set_thread_name_(0,(n))
Packit 875988
#endif /* __QNXNTO__ */
Packit 875988
#elif defined(HAVE_PTHREAD_SETNAME_NP_DARWIN)
Packit 875988
Packit 875988
/**
Packit 875988
 * Set current thread name
Packit 875988
 * @param n name to set
Packit 875988
 * @return non-zero on success, zero otherwise
Packit 875988
 */
Packit 875988
#define MHD_set_cur_thread_name_(n) (!(pthread_setname_np((n))))
Packit 875988
#endif /* HAVE_PTHREAD_SETNAME_NP_DARWIN */
Packit 875988
Packit 875988
#elif defined(MHD_USE_W32_THREADS)
Packit 875988
#ifndef _MSC_FULL_VER
Packit 875988
/* Thread name available only for VC-compiler */
Packit 875988
#else  /* _MSC_FULL_VER */
Packit 875988
/**
Packit 875988
 * Set thread name
Packit 875988
 *
Packit 875988
 * @param thread_id ID of thread, -1 for current thread
Packit 875988
 * @param thread_name name to set
Packit 875988
 * @return non-zero on success, zero otherwise
Packit 875988
 */
Packit 875988
static int
Packit 875988
MHD_set_thread_name_(const MHD_thread_ID_ thread_id,
Packit 875988
                     const char *thread_name)
Packit 875988
{
Packit 875988
  static const DWORD VC_SETNAME_EXC = 0x406D1388;
Packit 875988
#pragma pack(push,8)
Packit 875988
  struct thread_info_struct
Packit 875988
  {
Packit 875988
    DWORD type;   /* Must be 0x1000. */
Packit 875988
    LPCSTR name;  /* Pointer to name (in user address space). */
Packit 875988
    DWORD ID;     /* Thread ID (-1 = caller thread). */
Packit 875988
    DWORD flags;  /* Reserved for future use, must be zero. */
Packit 875988
  } thread_info;
Packit 875988
#pragma pack(pop)
Packit 875988
Packit 875988
  if (NULL == thread_name)
Packit 875988
    return 0;
Packit 875988
Packit 875988
  thread_info.type  = 0x1000;
Packit 875988
  thread_info.name  = thread_name;
Packit 875988
  thread_info.ID    = thread_id;
Packit 875988
  thread_info.flags = 0;
Packit 875988
Packit 875988
  __try
Packit 875988
  { /* This exception is intercepted by debugger */
Packit 875988
    RaiseException (VC_SETNAME_EXC,
Packit 875988
                    0,
Packit 875988
                    sizeof (thread_info) / sizeof(ULONG_PTR),
Packit 875988
                    (ULONG_PTR *) &thread_info);
Packit 875988
  }
Packit 875988
  __except (EXCEPTION_EXECUTE_HANDLER)
Packit 875988
  {}
Packit 875988
Packit 875988
  return !0;
Packit 875988
}
Packit 875988
Packit 875988
Packit 875988
/**
Packit 875988
 * Set current thread name
Packit 875988
 * @param n name to set
Packit 875988
 * @return non-zero on success, zero otherwise
Packit 875988
 */
Packit 875988
#define MHD_set_cur_thread_name_(n) MHD_set_thread_name_(-1,(n))
Packit 875988
#endif /* _MSC_FULL_VER */
Packit 875988
#endif /* MHD_USE_W32_THREADS */
Packit 875988
Packit 875988
#endif /* MHD_USE_THREAD_NAME_ */
Packit 875988
Packit 875988
Packit 875988
/**
Packit 875988
 * Create a thread and set the attributes according to our options.
Packit 875988
 *
Packit 875988
 * @param thread        handle to initialize
Packit 875988
 * @param stack_size    size of stack for new thread, 0 for default
Packit 875988
 * @param start_routine main function of thread
Packit 875988
 * @param arg argument  for start_routine
Packit 875988
 * @return non-zero on success; zero otherwise (with errno set)
Packit 875988
 */
Packit 875988
int
Packit 875988
MHD_create_thread_ (MHD_thread_handle_ID_ *thread,
Packit 875988
                    size_t stack_size,
Packit 875988
                    MHD_THREAD_START_ROUTINE_ start_routine,
Packit 875988
                    void *arg)
Packit 875988
{
Packit 875988
#if defined(MHD_USE_POSIX_THREADS)
Packit 875988
  int res;
Packit 875988
Packit 875988
  if (0 != stack_size)
Packit 875988
    {
Packit 875988
      pthread_attr_t attr;
Packit 875988
      res = pthread_attr_init (&attr);
Packit 875988
      if (0 == res)
Packit 875988
        {
Packit 875988
          res = pthread_attr_setstacksize (&attr,
Packit 875988
                                           stack_size);
Packit 875988
          if (0 == res)
Packit 875988
              res = pthread_create (&(thread->handle),
Packit 875988
                                    &attr,
Packit 875988
                                    start_routine,
Packit 875988
                                    arg);
Packit 875988
          pthread_attr_destroy (&attr);
Packit 875988
        }
Packit 875988
    }
Packit 875988
  else
Packit 875988
    res = pthread_create (&(thread->handle),
Packit 875988
                          NULL,
Packit 875988
                          start_routine,
Packit 875988
                          arg);
Packit 875988
Packit 875988
  if (0 != res)
Packit 875988
    errno = res;
Packit 875988
Packit 875988
  return !res;
Packit 875988
#elif defined(MHD_USE_W32_THREADS)
Packit 875988
#if SIZE_MAX != UINT_MAX
Packit 875988
  if (stack_size > UINT_MAX)
Packit 875988
    {
Packit 875988
      errno = EINVAL;
Packit 875988
      return 0;
Packit 875988
    }
Packit 875988
#endif /* SIZE_MAX != UINT_MAX */
Packit 875988
Packit 875988
  thread->handle = (MHD_thread_handle_)
Packit 875988
                     _beginthreadex (NULL,
Packit 875988
                                     (unsigned int) stack_size,
Packit 875988
                                     start_routine,
Packit 875988
                                     arg,
Packit 875988
                                     0,
Packit 875988
                                     NULL);
Packit 875988
Packit 875988
  if ((MHD_thread_handle_)-1 == thread->handle)
Packit 875988
    return 0;
Packit 875988
Packit 875988
  return !0;
Packit 875988
#endif
Packit 875988
}
Packit 875988
Packit 875988
#ifdef MHD_USE_THREAD_NAME_
Packit 875988
Packit 875988
#ifndef MHD_USE_THREAD_ATTR_SETNAME
Packit 875988
struct MHD_named_helper_param_
Packit 875988
{
Packit 875988
  /**
Packit 875988
   * Real thread start routine
Packit 875988
   */
Packit 875988
  MHD_THREAD_START_ROUTINE_ start_routine;
Packit 875988
Packit 875988
  /**
Packit 875988
   * Argument for thread start routine
Packit 875988
   */
Packit 875988
  void *arg;
Packit 875988
Packit 875988
  /**
Packit 875988
   * Name for thread
Packit 875988
   */
Packit 875988
  const char *name;
Packit 875988
};
Packit 875988
Packit 875988
Packit 875988
static MHD_THRD_RTRN_TYPE_ MHD_THRD_CALL_SPEC_
Packit 875988
named_thread_starter (void *data)
Packit 875988
{
Packit 875988
  struct MHD_named_helper_param_ * const param =
Packit 875988
      (struct MHD_named_helper_param_ *) data;
Packit 875988
  void * arg;
Packit 875988
  MHD_THREAD_START_ROUTINE_ thr_func;
Packit 875988
Packit 875988
  if (NULL == data)
Packit 875988
    return (MHD_THRD_RTRN_TYPE_)0;
Packit 875988
Packit 875988
  MHD_set_cur_thread_name_ (param->name);
Packit 875988
Packit 875988
  arg = param->arg;
Packit 875988
  thr_func = param->start_routine;
Packit 875988
  free(data);
Packit 875988
Packit 875988
  return thr_func(arg);
Packit 875988
}
Packit 875988
#endif /* ! MHD_USE_THREAD_ATTR_SETNAME */
Packit 875988
Packit 875988
Packit 875988
/**
Packit 875988
 * Create a named thread and set the attributes according to our options.
Packit 875988
 *
Packit 875988
 * @param thread        handle to initialize
Packit 875988
 * @param thread_name   name for new thread
Packit 875988
 * @param stack_size    size of stack for new thread, 0 for default
Packit 875988
 * @param start_routine main function of thread
Packit 875988
 * @param arg argument  for start_routine
Packit 875988
 * @return non-zero on success; zero otherwise (with errno set)
Packit 875988
 */
Packit 875988
int
Packit 875988
MHD_create_named_thread_ (MHD_thread_handle_ID_ *thread,
Packit 875988
                          const char* thread_name,
Packit 875988
                          size_t stack_size,
Packit 875988
                          MHD_THREAD_START_ROUTINE_ start_routine,
Packit 875988
                          void *arg)
Packit 875988
{
Packit 875988
#if defined(MHD_USE_THREAD_ATTR_SETNAME)
Packit 875988
  int res;
Packit 875988
  pthread_attr_t attr;
Packit 875988
Packit 875988
  res = pthread_attr_init (&attr);
Packit 875988
  if (0 == res)
Packit 875988
    {
Packit 875988
#if defined(HAVE_PTHREAD_ATTR_SETNAME_NP_NETBSD)
Packit 875988
  /* NetBSD use 3 arguments: second argument is string in printf-like format,
Packit 875988
   *                         third argument is single argument for printf;
Packit 875988
   * OSF1 use 3 arguments too, but last one always must be zero (NULL).
Packit 875988
   * MHD doesn't use '%' in thread names, so both form are used in same way.
Packit 875988
   */
Packit 875988
      res = pthread_attr_setname_np (&attr, thread_name, 0);
Packit 875988
#elif defined(HAVE_PTHREAD_ATTR_SETNAME_NP_IBMI)
Packit 875988
      res = pthread_attr_setname_np (&attr, thread_name);
Packit 875988
#else
Packit 875988
#error No pthread_attr_setname_np() function.
Packit 875988
#endif
Packit 875988
      if (res == 0 && 0 != stack_size)
Packit 875988
        res = pthread_attr_setstacksize (&attr,
Packit 875988
                                         stack_size);
Packit 875988
      if (0 == res)
Packit 875988
          res = pthread_create (&(thread->handle),
Packit 875988
                                &attr,
Packit 875988
                                start_routine,
Packit 875988
                                arg);
Packit 875988
      pthread_attr_destroy (&attr);
Packit 875988
    }
Packit 875988
  if (0 != res)
Packit 875988
    errno = res;
Packit 875988
Packit 875988
  return !res;
Packit 875988
#else  /* ! MHD_USE_THREAD_ATTR_SETNAME */
Packit 875988
  struct MHD_named_helper_param_ *param;
Packit 875988
Packit 875988
  if (NULL == thread_name)
Packit 875988
    {
Packit 875988
      errno = EINVAL;
Packit 875988
      return 0;
Packit 875988
    }
Packit 875988
Packit 875988
  param = malloc (sizeof (struct MHD_named_helper_param_));
Packit 875988
  if (NULL == param)
Packit 875988
    return 0;
Packit 875988
Packit 875988
  param->start_routine = start_routine;
Packit 875988
  param->arg = arg;
Packit 875988
  param->name = thread_name;
Packit 875988
Packit 875988
  /* Set thread name in thread itself to avoid problems with
Packit 875988
   * threads which terminated before name is set in other thread.
Packit 875988
   */
Packit 875988
  if (! MHD_create_thread_(thread,
Packit 875988
                           stack_size,
Packit 875988
                           &named_thread_starter,
Packit 875988
                           (void*)param))
Packit 875988
    {
Packit 875988
      free (param);
Packit 875988
      return 0;
Packit 875988
    }
Packit 875988
Packit 875988
  return !0;
Packit 875988
#endif /* ! MHD_USE_THREAD_ATTR_SETNAME */
Packit 875988
}
Packit 875988
Packit 875988
#endif /* MHD_USE_THREAD_NAME_ */