mhd_threads.c 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367
  1. /*
  2. This file is part of libmicrohttpd
  3. Copyright (C) 2016 Karlson2k (Evgeny Grin)
  4. This library is free software; you can redistribute it and/or
  5. modify it under the terms of the GNU Lesser General Public
  6. License as published by the Free Software Foundation; either
  7. version 2.1 of the License, or (at your option) any later version.
  8. This library is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  11. Lesser General Public License for more details.
  12. You should have received a copy of the GNU Lesser General Public
  13. License along with this library; if not, write to the Free Software
  14. Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  15. */
  16. /**
  17. * @file microhttpd/mhd_threads.c
  18. * @brief Implementation for thread functions
  19. * @author Karlson2k (Evgeny Grin)
  20. */
  21. #include "mhd_threads.h"
  22. #ifdef MHD_USE_W32_THREADS
  23. #include "mhd_limits.h"
  24. #include <process.h>
  25. #endif
  26. #ifdef MHD_USE_THREAD_NAME_
  27. #include <stdlib.h>
  28. #ifdef HAVE_PTHREAD_NP_H
  29. #include <pthread_np.h>
  30. #endif /* HAVE_PTHREAD_NP_H */
  31. #endif /* MHD_USE_THREAD_NAME_ */
  32. #include <errno.h>
  33. #ifndef MHD_USE_THREAD_NAME_
  34. #define MHD_set_thread_name_(t, n) (void)
  35. #define MHD_set_cur_thread_name_(n) (void)
  36. #else /* MHD_USE_THREAD_NAME_ */
  37. #if defined(MHD_USE_POSIX_THREADS)
  38. #if defined(HAVE_PTHREAD_ATTR_SETNAME_NP_NETBSD) || \
  39. defined(HAVE_PTHREAD_ATTR_SETNAME_NP_IBMI)
  40. # define MHD_USE_THREAD_ATTR_SETNAME 1
  41. #endif /* HAVE_PTHREAD_ATTR_SETNAME_NP_NETBSD || HAVE_PTHREAD_ATTR_SETNAME_NP_IBMI */
  42. #if defined(HAVE_PTHREAD_SETNAME_NP_GNU) || \
  43. defined(HAVE_PTHREAD_SET_NAME_NP_FREEBSD) \
  44. || defined(HAVE_PTHREAD_SETNAME_NP_NETBSD)
  45. /**
  46. * Set thread name
  47. *
  48. * @param thread_id ID of thread
  49. * @param thread_name name to set
  50. * @return non-zero on success, zero otherwise
  51. */
  52. static int
  53. MHD_set_thread_name_ (const MHD_thread_ID_ thread_id,
  54. const char *thread_name)
  55. {
  56. if (NULL == thread_name)
  57. return 0;
  58. #if defined(HAVE_PTHREAD_SETNAME_NP_GNU)
  59. return ! pthread_setname_np (thread_id, thread_name);
  60. #elif defined(HAVE_PTHREAD_SET_NAME_NP_FREEBSD)
  61. /* FreeBSD and OpenBSD use different name and void return type */
  62. pthread_set_name_np (thread_id, thread_name);
  63. return ! 0;
  64. #elif defined(HAVE_PTHREAD_SETNAME_NP_NETBSD)
  65. /* NetBSD use 3 arguments: second argument is string in printf-like format,
  66. * third argument is single argument for printf;
  67. * OSF1 use 3 arguments too, but last one always must be zero (NULL).
  68. * MHD doesn't use '%' in thread names, so both form are used in same way.
  69. */return ! pthread_setname_np (thread_id, thread_name, 0);
  70. #endif /* HAVE_PTHREAD_SETNAME_NP_NETBSD */
  71. }
  72. #ifndef __QNXNTO__
  73. /**
  74. * Set current thread name
  75. * @param n name to set
  76. * @return non-zero on success, zero otherwise
  77. */
  78. #define MHD_set_cur_thread_name_(n) MHD_set_thread_name_ (pthread_self (),(n))
  79. #else /* __QNXNTO__ */
  80. /* Special case for QNX Neutrino - using zero for thread ID sets name faster. */
  81. #define MHD_set_cur_thread_name_(n) MHD_set_thread_name_ (0,(n))
  82. #endif /* __QNXNTO__ */
  83. #elif defined(HAVE_PTHREAD_SETNAME_NP_DARWIN)
  84. /**
  85. * Set current thread name
  86. * @param n name to set
  87. * @return non-zero on success, zero otherwise
  88. */
  89. #define MHD_set_cur_thread_name_(n) (! (pthread_setname_np ((n))))
  90. #endif /* HAVE_PTHREAD_SETNAME_NP_DARWIN */
  91. #elif defined(MHD_USE_W32_THREADS)
  92. #ifndef _MSC_FULL_VER
  93. /* Thread name available only for VC-compiler */
  94. #else /* _MSC_FULL_VER */
  95. /**
  96. * Set thread name
  97. *
  98. * @param thread_id ID of thread, -1 for current thread
  99. * @param thread_name name to set
  100. * @return non-zero on success, zero otherwise
  101. */
  102. static int
  103. MHD_set_thread_name_ (const MHD_thread_ID_ thread_id,
  104. const char *thread_name)
  105. {
  106. static const DWORD VC_SETNAME_EXC = 0x406D1388;
  107. #pragma pack(push,8)
  108. struct thread_info_struct
  109. {
  110. DWORD type; /* Must be 0x1000. */
  111. LPCSTR name; /* Pointer to name (in user address space). */
  112. DWORD ID; /* Thread ID (-1 = caller thread). */
  113. DWORD flags; /* Reserved for future use, must be zero. */
  114. } thread_info;
  115. #pragma pack(pop)
  116. if (NULL == thread_name)
  117. return 0;
  118. thread_info.type = 0x1000;
  119. thread_info.name = thread_name;
  120. thread_info.ID = thread_id;
  121. thread_info.flags = 0;
  122. __try
  123. { /* This exception is intercepted by debugger */
  124. RaiseException (VC_SETNAME_EXC,
  125. 0,
  126. sizeof (thread_info) / sizeof(ULONG_PTR),
  127. (ULONG_PTR *) &thread_info);
  128. }
  129. __except (EXCEPTION_EXECUTE_HANDLER)
  130. {}
  131. return ! 0;
  132. }
  133. /**
  134. * Set current thread name
  135. * @param n name to set
  136. * @return non-zero on success, zero otherwise
  137. */
  138. #define MHD_set_cur_thread_name_(n) MHD_set_thread_name_ (-1,(n))
  139. #endif /* _MSC_FULL_VER */
  140. #endif /* MHD_USE_W32_THREADS */
  141. #endif /* MHD_USE_THREAD_NAME_ */
  142. /**
  143. * Create a thread and set the attributes according to our options.
  144. *
  145. * @param thread handle to initialize
  146. * @param stack_size size of stack for new thread, 0 for default
  147. * @param start_routine main function of thread
  148. * @param arg argument for start_routine
  149. * @return non-zero on success; zero otherwise (with errno set)
  150. */
  151. int
  152. MHD_create_thread_ (MHD_thread_handle_ID_ *thread,
  153. size_t stack_size,
  154. MHD_THREAD_START_ROUTINE_ start_routine,
  155. void *arg)
  156. {
  157. #if defined(MHD_USE_POSIX_THREADS)
  158. int res;
  159. if (0 != stack_size)
  160. {
  161. pthread_attr_t attr;
  162. res = pthread_attr_init (&attr);
  163. if (0 == res)
  164. {
  165. res = pthread_attr_setstacksize (&attr,
  166. stack_size);
  167. if (0 == res)
  168. res = pthread_create (&(thread->handle),
  169. &attr,
  170. start_routine,
  171. arg);
  172. pthread_attr_destroy (&attr);
  173. }
  174. }
  175. else
  176. res = pthread_create (&(thread->handle),
  177. NULL,
  178. start_routine,
  179. arg);
  180. if (0 != res)
  181. errno = res;
  182. return ! res;
  183. #elif defined(MHD_USE_W32_THREADS)
  184. #if SIZE_MAX != UINT_MAX
  185. if (stack_size > UINT_MAX)
  186. {
  187. errno = EINVAL;
  188. return 0;
  189. }
  190. #endif /* SIZE_MAX != UINT_MAX */
  191. thread->handle = (MHD_thread_handle_)
  192. _beginthreadex (NULL,
  193. (unsigned int) stack_size,
  194. start_routine,
  195. arg,
  196. 0,
  197. NULL);
  198. if ((MHD_thread_handle_) - 1 == thread->handle)
  199. return 0;
  200. return ! 0;
  201. #endif
  202. }
  203. #ifdef MHD_USE_THREAD_NAME_
  204. #ifndef MHD_USE_THREAD_ATTR_SETNAME
  205. struct MHD_named_helper_param_
  206. {
  207. /**
  208. * Real thread start routine
  209. */
  210. MHD_THREAD_START_ROUTINE_ start_routine;
  211. /**
  212. * Argument for thread start routine
  213. */
  214. void *arg;
  215. /**
  216. * Name for thread
  217. */
  218. const char *name;
  219. };
  220. static MHD_THRD_RTRN_TYPE_ MHD_THRD_CALL_SPEC_
  221. named_thread_starter (void *data)
  222. {
  223. struct MHD_named_helper_param_ *const param =
  224. (struct MHD_named_helper_param_ *) data;
  225. void *arg;
  226. MHD_THREAD_START_ROUTINE_ thr_func;
  227. if (NULL == data)
  228. return (MHD_THRD_RTRN_TYPE_) 0;
  229. MHD_set_cur_thread_name_ (param->name);
  230. arg = param->arg;
  231. thr_func = param->start_routine;
  232. free (data);
  233. return thr_func (arg);
  234. }
  235. #endif /* ! MHD_USE_THREAD_ATTR_SETNAME */
  236. /**
  237. * Create a named thread and set the attributes according to our options.
  238. *
  239. * @param thread handle to initialize
  240. * @param thread_name name for new thread
  241. * @param stack_size size of stack for new thread, 0 for default
  242. * @param start_routine main function of thread
  243. * @param arg argument for start_routine
  244. * @return non-zero on success; zero otherwise (with errno set)
  245. */
  246. int
  247. MHD_create_named_thread_ (MHD_thread_handle_ID_ *thread,
  248. const char*thread_name,
  249. size_t stack_size,
  250. MHD_THREAD_START_ROUTINE_ start_routine,
  251. void *arg)
  252. {
  253. #if defined(MHD_USE_THREAD_ATTR_SETNAME)
  254. int res;
  255. pthread_attr_t attr;
  256. res = pthread_attr_init (&attr);
  257. if (0 == res)
  258. {
  259. #if defined(HAVE_PTHREAD_ATTR_SETNAME_NP_NETBSD)
  260. /* NetBSD use 3 arguments: second argument is string in printf-like format,
  261. * third argument is single argument for printf;
  262. * OSF1 use 3 arguments too, but last one always must be zero (NULL).
  263. * MHD doesn't use '%' in thread names, so both form are used in same way.
  264. */res = pthread_attr_setname_np (&attr, thread_name, 0);
  265. #elif defined(HAVE_PTHREAD_ATTR_SETNAME_NP_IBMI)
  266. res = pthread_attr_setname_np (&attr, thread_name);
  267. #else
  268. #error No pthread_attr_setname_np() function.
  269. #endif
  270. if ((res == 0) && (0 != stack_size) )
  271. res = pthread_attr_setstacksize (&attr,
  272. stack_size);
  273. if (0 == res)
  274. res = pthread_create (&(thread->handle),
  275. &attr,
  276. start_routine,
  277. arg);
  278. pthread_attr_destroy (&attr);
  279. }
  280. if (0 != res)
  281. errno = res;
  282. return ! res;
  283. #else /* ! MHD_USE_THREAD_ATTR_SETNAME */
  284. struct MHD_named_helper_param_ *param;
  285. if (NULL == thread_name)
  286. {
  287. errno = EINVAL;
  288. return 0;
  289. }
  290. param = malloc (sizeof (struct MHD_named_helper_param_));
  291. if (NULL == param)
  292. return 0;
  293. param->start_routine = start_routine;
  294. param->arg = arg;
  295. param->name = thread_name;
  296. /* Set thread name in thread itself to avoid problems with
  297. * threads which terminated before name is set in other thread.
  298. */
  299. if (! MHD_create_thread_ (thread,
  300. stack_size,
  301. &named_thread_starter,
  302. (void*) param))
  303. {
  304. free (param);
  305. return 0;
  306. }
  307. return ! 0;
  308. #endif /* ! MHD_USE_THREAD_ATTR_SETNAME */
  309. }
  310. #endif /* MHD_USE_THREAD_NAME_ */