aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEvgeny Grin (Karlson2k) <k2k@narod.ru>2016-08-10 13:52:38 +0000
committerEvgeny Grin (Karlson2k) <k2k@narod.ru>2016-08-10 13:52:38 +0000
commite18185c55f8d1b6d6efe1b6a35b4c8c7bd48754a (patch)
treef0944fff5d0918803b202eb40da58b9b942982c3
parenteb46a43bc014b1d5e151fc53996aef14c29fec55 (diff)
downloadlibmicrohttpd-e18185c55f8d1b6d6efe1b6a35b4c8c7bd48754a.tar.gz
libmicrohttpd-e18185c55f8d1b6d6efe1b6a35b4c8c7bd48754a.zip
Moved thread abstraction to mhd_threads.h/mhd_threads.c,
minor bugs fixed.
-rw-r--r--configure.ac10
-rw-r--r--src/include/platform.h5
-rw-r--r--src/include/platform_interface.h35
-rw-r--r--src/include/w32functions.h13
-rw-r--r--src/microhttpd/Makefile.am3
-rw-r--r--src/microhttpd/daemon.c120
-rw-r--r--src/microhttpd/internal.h1
-rw-r--r--src/microhttpd/mhd_limits.h8
-rw-r--r--src/microhttpd/mhd_threads.c274
-rw-r--r--src/microhttpd/mhd_threads.h151
-rw-r--r--src/microhttpd/test_shutdown_select.c4
-rw-r--r--src/platform/w32functions.c36
-rw-r--r--w32/common/MHD_config.h3
-rw-r--r--w32/common/libmicrohttpd-files.vcxproj2
-rw-r--r--w32/common/libmicrohttpd-filters.vcxproj6
15 files changed, 481 insertions, 190 deletions
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'
247 247
248# Check for posix threads support, regardless of configure parameters as 248# Check for posix threads support, regardless of configure parameters as
249# posix threads are used in some tests even on W32. 249# posix threads are used in some tests even on W32.
250AX_PTHREAD([HAVE_POSIX_THREADS='yes'],[HAVE_POSIX_THREADS='no']) 250AX_PTHREAD(
251 [
252 HAVE_POSIX_THREADS='yes'
253 AC_DEFINE([[HAVE_PTHREAD_H]],[[1]],[Define to 1 if you have the <pthread.h> header file.])
254 ],[[HAVE_POSIX_THREADS='no']])
251AM_CONDITIONAL([HAVE_POSIX_THREADS],[test "x$HAVE_POSIX_THREADS" = "xyes"]) 255AM_CONDITIONAL([HAVE_POSIX_THREADS],[test "x$HAVE_POSIX_THREADS" = "xyes"])
252 256
253HAVE_W32_THREADS='no' 257HAVE_W32_THREADS='no'
@@ -418,10 +422,10 @@ if test "x$HAVE_POSIX_THREADS" = "xyes"; then
418fi 422fi
419 423
420# Check for headers that are ALWAYS required 424# Check for headers that are ALWAYS required
421AC_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])) 425AC_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]))
422 426
423# Check for optional headers 427# Check for optional headers
424AC_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]) 428AC_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])
425AM_CONDITIONAL([HAVE_TSEARCH], [test "x$ac_cv_header_search_h" = "xyes"]) 429AM_CONDITIONAL([HAVE_TSEARCH], [test "x$ac_cv_header_search_h" = "xyes"])
426 430
427AC_CHECK_MEMBER([struct sockaddr_in.sin_len], 431AC_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 @@
48#include <fcntl.h> 48#include <fcntl.h>
49#include <signal.h> 49#include <signal.h>
50#include <stddef.h> 50#include <stddef.h>
51#ifdef MHD_USE_POSIX_THREADS
52#undef HAVE_CONFIG_H
53#include <pthread.h>
54#define HAVE_CONFIG_H 1
55#endif /* MHD_USE_POSIX_THREADS */
56 51
57/* different OSes have fd_set in 52/* different OSes have fd_set in
58 a broad range of header files; 53 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;
189#else 189#else
190#define MHD_random_() MHD_W32_random_() 190#define MHD_random_() MHD_W32_random_()
191#endif 191#endif
192
193#if defined(MHD_USE_POSIX_THREADS)
194typedef pthread_t MHD_thread_handle_;
195#elif defined(MHD_USE_W32_THREADS)
196#include <windows.h>
197typedef HANDLE MHD_thread_handle_;
198#else
199#error "No threading API is available."
200#endif
201
202#if defined(MHD_USE_POSIX_THREADS)
203#define MHD_THRD_RTRN_TYPE_ void*
204#define MHD_THRD_CALL_SPEC_
205#elif defined(MHD_USE_W32_THREADS)
206#define MHD_THRD_RTRN_TYPE_ unsigned
207#define MHD_THRD_CALL_SPEC_ __stdcall
208#endif
209
210#if defined(MHD_USE_POSIX_THREADS)
211/**
212 * Wait until specified thread is ended
213 * @param thread ID to watch
214 * @return zero on success, nonzero on failure
215 */
216#define MHD_join_thread_(thread) pthread_join((thread), NULL)
217#elif defined(MHD_USE_W32_THREADS)
218/**
219 * Wait until specified thread is ended
220 * Close thread handle on success
221 * @param thread handle to watch
222 * @return zero on success, nonzero on failure
223 */
224#define MHD_join_thread_(thread) (WAIT_OBJECT_0 == WaitForSingleObject((thread), INFINITE) ? (CloseHandle((thread)), 0) : 1 )
225#endif
226
227#if defined(MHD_USE_W32_THREADS) 192#if defined(MHD_USE_W32_THREADS)
228#define MHD_W32_MUTEX_ 1 193#define MHD_W32_MUTEX_ 1
229#include <windows.h> 194#include <windows.h>
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);
194/* Emulate snprintf function on W32 */ 194/* Emulate snprintf function on W32 */
195int W32_snprintf(char *__restrict s, size_t n, const char *__restrict format, ...); 195int W32_snprintf(char *__restrict s, size_t n, const char *__restrict format, ...);
196 196
197#ifndef _MSC_FULL_VER
198/* Thread name available only for VC-compiler */
199static void W32_SetThreadName(const DWORD thread_id, const char *thread_name)
200{ }
201#else /* _MSC_FULL_VER */
202/**
203 * Set thread name
204 * @param thread_id ID of thread, -1 for current thread
205 * @param thread_name name to set
206 */
207void W32_SetThreadName(const DWORD thread_id, const char *thread_name);
208#endif
209
210#ifdef __cplusplus 197#ifdef __cplusplus
211} 198}
212#endif 199#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 = \
67 mhd_limits.h mhd_byteorder.h \ 67 mhd_limits.h mhd_byteorder.h \
68 sysfdsetsize.c sysfdsetsize.h \ 68 sysfdsetsize.c sysfdsetsize.h \
69 mhd_str.c mhd_str.h \ 69 mhd_str.c mhd_str.h \
70 mhd_threads.c mhd_threads.h \
70 response.c response.h 71 response.c response.h
71libmicrohttpd_la_CPPFLAGS = \ 72libmicrohttpd_la_CPPFLAGS = \
72 $(AM_CPPFLAGS) $(MHD_LIB_CPPFLAGS) \ 73 $(AM_CPPFLAGS) $(MHD_LIB_CPPFLAGS) \
@@ -200,7 +201,7 @@ test_shutdown_select_LDADD = \
200endif 201endif
201 202
202test_shutdown_poll_SOURCES = \ 203test_shutdown_poll_SOURCES = \
203 test_shutdown_select.c 204 test_shutdown_select.c mhd_threads.h
204if USE_POSIX_THREADS 205if USE_POSIX_THREADS
205test_shutdown_poll_CFLAGS = \ 206test_shutdown_poll_CFLAGS = \
206 $(AM_CFLAGS) $(PTHREAD_CFLAGS) 207 $(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 @@
25 * @author Christian Grothoff 25 * @author Christian Grothoff
26 */ 26 */
27#include "platform.h" 27#include "platform.h"
28#include "mhd_threads.h"
28#include "internal.h" 29#include "internal.h"
29#include "response.h" 30#include "response.h"
30#include "connection.h" 31#include "connection.h"
@@ -61,7 +62,6 @@
61#define WIN32_LEAN_AND_MEAN 1 62#define WIN32_LEAN_AND_MEAN 1
62#endif /* !WIN32_LEAN_AND_MEAN */ 63#endif /* !WIN32_LEAN_AND_MEAN */
63#include <windows.h> 64#include <windows.h>
64#include <process.h>
65#endif 65#endif
66 66
67/** 67/**
@@ -1280,81 +1280,6 @@ send_param_adapter (struct MHD_Connection *connection,
1280 1280
1281 1281
1282/** 1282/**
1283 * Signature of main function for a thread.
1284 *
1285 * @param cls closure argument for the function
1286 * @return termination code from the thread
1287 */
1288typedef MHD_THRD_RTRN_TYPE_
1289(MHD_THRD_CALL_SPEC_ *ThreadStartRoutine)(void *cls);
1290
1291
1292/**
1293 * Create a thread and set the attributes according to our options.
1294 *
1295 * @param thread handle to initialize
1296 * @param daemon daemon with options
1297 * @param start_routine main function of thread
1298 * @param arg argument for start_routine
1299 * @return 0 on success
1300 */
1301static int
1302create_thread (MHD_thread_handle_ *thread,
1303 const struct MHD_Daemon *daemon,
1304 ThreadStartRoutine start_routine,
1305 void *arg)
1306{
1307#if defined(MHD_USE_POSIX_THREADS)
1308 pthread_attr_t attr;
1309 pthread_attr_t *pattr;
1310 int ret;
1311
1312 if (0 != daemon->thread_stack_size)
1313 {
1314 if (0 != (ret = pthread_attr_init (&attr)))
1315 goto ERR;
1316 if (0 != (ret = pthread_attr_setstacksize (&attr, daemon->thread_stack_size)))
1317 {
1318 pthread_attr_destroy (&attr);
1319 goto ERR;
1320 }
1321 pattr = &attr;
1322 }
1323 else
1324 {
1325 pattr = NULL;
1326 }
1327 ret = pthread_create (thread, pattr,
1328 start_routine, arg);
1329#ifdef HAVE_PTHREAD_SETNAME_NP
1330 if (0 == ret)
1331 (void) pthread_setname_np (*thread, "libmicrohttpd");
1332#endif /* HAVE_PTHREAD_SETNAME_NP */
1333 if (0 != daemon->thread_stack_size)
1334 pthread_attr_destroy (&attr);
1335 return ret;
1336 ERR:
1337#ifdef HAVE_MESSAGES
1338 MHD_DLOG (daemon,
1339 "Failed to set thread stack size\n");
1340#endif
1341 errno = EINVAL;
1342 return ret;
1343#elif defined(MHD_USE_W32_THREADS)
1344 unsigned threadID;
1345 *thread = (HANDLE)_beginthreadex(NULL, (unsigned)daemon->thread_stack_size, start_routine,
1346 arg, 0, &threadID);
1347 if (NULL == (*thread))
1348 return errno;
1349
1350 W32_SetThreadName(threadID, "libmicrohttpd");
1351
1352 return 0;
1353#endif
1354}
1355
1356
1357/**
1358 * Add another client connection to the set of connections 1283 * Add another client connection to the set of connections
1359 * managed by MHD. This API is usually not needed (since 1284 * managed by MHD. This API is usually not needed (since
1360 * MHD will accept inbound connections on the server socket). 1285 * MHD will accept inbound connections on the server socket).
@@ -1388,7 +1313,6 @@ internal_add_connection (struct MHD_Daemon *daemon,
1388 int external_add) 1313 int external_add)
1389{ 1314{
1390 struct MHD_Connection *connection; 1315 struct MHD_Connection *connection;
1391 int res_thread_create;
1392 unsigned int i; 1316 unsigned int i;
1393 int eno; 1317 int eno;
1394 struct MHD_Daemon *worker; 1318 struct MHD_Daemon *worker;
@@ -1635,17 +1559,17 @@ internal_add_connection (struct MHD_Daemon *daemon,
1635 /* attempt to create handler thread */ 1559 /* attempt to create handler thread */
1636 if (0 != (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) 1560 if (0 != (daemon->options & MHD_USE_THREAD_PER_CONNECTION))
1637 { 1561 {
1638 res_thread_create = create_thread (&connection->pid, 1562 if (!MHD_create_named_thread_(&connection->pid,
1639 daemon, 1563 "MHD-connection",
1640 &MHD_handle_connection, 1564 daemon->thread_stack_size,
1641 connection); 1565 &MHD_handle_connection,
1642 if (0 != res_thread_create) 1566 connection))
1643 { 1567 {
1644 eno = errno; 1568 eno = errno;
1645#ifdef HAVE_MESSAGES 1569#ifdef HAVE_MESSAGES
1646 MHD_DLOG (daemon, 1570 MHD_DLOG (daemon,
1647 "Failed to create a thread: %s\n", 1571 "Failed to create a thread: %s\n",
1648 MHD_strerror_ (res_thread_create)); 1572 MHD_strerror_ (eno));
1649#endif 1573#endif
1650 goto cleanup; 1574 goto cleanup;
1651 } 1575 }
@@ -1723,9 +1647,7 @@ internal_add_connection (struct MHD_Daemon *daemon,
1723 MHD_pool_destroy (connection->pool); 1647 MHD_pool_destroy (connection->pool);
1724 free (connection->addr); 1648 free (connection->addr);
1725 free (connection); 1649 free (connection);
1726#if EINVAL
1727 errno = eno; 1650 errno = eno;
1728#endif
1729 return MHD_NO; 1651 return MHD_NO;
1730} 1652}
1731 1653
@@ -2157,7 +2079,7 @@ MHD_cleanup_connections (struct MHD_Daemon *daemon)
2157 if ( (0 != (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) && 2079 if ( (0 != (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) &&
2158 (MHD_NO == pos->thread_joined) ) 2080 (MHD_NO == pos->thread_joined) )
2159 { 2081 {
2160 if (0 != MHD_join_thread_ (pos->pid)) 2082 if (!MHD_join_thread_ (pos->pid))
2161 { 2083 {
2162 MHD_PANIC ("Failed to join a thread\n"); 2084 MHD_PANIC ("Failed to join a thread\n");
2163 } 2085 }
@@ -3765,7 +3687,6 @@ MHD_start_daemon_va (unsigned int flags,
3765 const struct sockaddr *servaddr = NULL; 3687 const struct sockaddr *servaddr = NULL;
3766 socklen_t addrlen; 3688 socklen_t addrlen;
3767 unsigned int i; 3689 unsigned int i;
3768 int res_thread_create;
3769 int use_pipe; 3690 int use_pipe;
3770 3691
3771#ifndef HAVE_INET6 3692#ifndef HAVE_INET6
@@ -4307,13 +4228,17 @@ MHD_start_daemon_va (unsigned int flags,
4307 ( (0 != (flags & MHD_USE_SELECT_INTERNALLY)) && 4228 ( (0 != (flags & MHD_USE_SELECT_INTERNALLY)) &&
4308 (0 == daemon->worker_pool_size)) ) && 4229 (0 == daemon->worker_pool_size)) ) &&
4309 (0 == (daemon->options & MHD_USE_NO_LISTEN_SOCKET)) && 4230 (0 == (daemon->options & MHD_USE_NO_LISTEN_SOCKET)) &&
4310 (0 != (res_thread_create = 4231 (!MHD_create_named_thread_ (&daemon->pid,
4311 create_thread (&daemon->pid, daemon, &MHD_select_thread, daemon)))) 4232 (flags & MHD_USE_THREAD_PER_CONNECTION) ?
4233 "MHD-listen" : "MHD-single",
4234 daemon->thread_stack_size,
4235 &MHD_select_thread,
4236 daemon) ) )
4312 { 4237 {
4313#ifdef HAVE_MESSAGES 4238#ifdef HAVE_MESSAGES
4314 MHD_DLOG (daemon, 4239 MHD_DLOG (daemon,
4315 "Failed to create listen thread: %s\n", 4240 "Failed to create listen thread: %s\n",
4316 MHD_strerror_ (res_thread_create)); 4241 MHD_strerror_ (errno));
4317#endif 4242#endif
4318 (void) MHD_mutex_destroy_ (&daemon->cleanup_connection_mutex); 4243 (void) MHD_mutex_destroy_ (&daemon->cleanup_connection_mutex);
4319 (void) MHD_mutex_destroy_ (&daemon->per_ip_connection_mutex); 4244 (void) MHD_mutex_destroy_ (&daemon->per_ip_connection_mutex);
@@ -4416,13 +4341,16 @@ MHD_start_daemon_va (unsigned int flags,
4416 } 4341 }
4417 4342
4418 /* Spawn the worker thread */ 4343 /* Spawn the worker thread */
4419 if (0 != (res_thread_create = 4344 if (!MHD_create_named_thread_(&d->pid,
4420 create_thread (&d->pid, daemon, &MHD_select_thread, d))) 4345 "MHD-worker",
4346 daemon->thread_stack_size,
4347 &MHD_select_thread,
4348 d))
4421 { 4349 {
4422#ifdef HAVE_MESSAGES 4350#ifdef HAVE_MESSAGES
4423 MHD_DLOG (daemon, 4351 MHD_DLOG (daemon,
4424 "Failed to create pool thread: %s\n", 4352 "Failed to create pool thread: %s\n",
4425 MHD_strerror_ (res_thread_create)); 4353 MHD_strerror_ (errno));
4426#endif 4354#endif
4427 /* Free memory for this worker; cleanup below handles 4355 /* Free memory for this worker; cleanup below handles
4428 * all previously-created workers. */ 4356 * all previously-created workers. */
@@ -4564,7 +4492,7 @@ close_all_connections (struct MHD_Daemon *daemon)
4564 { 4492 {
4565 if (MHD_YES != pos->thread_joined) 4493 if (MHD_YES != pos->thread_joined)
4566 { 4494 {
4567 if (0 != MHD_join_thread_ (pos->pid)) 4495 if (!MHD_join_thread_ (pos->pid))
4568 MHD_PANIC ("Failed to join a thread\n"); 4496 MHD_PANIC ("Failed to join a thread\n");
4569 pos->thread_joined = MHD_YES; 4497 pos->thread_joined = MHD_YES;
4570 /* The thread may have concurrently modified the DLL, 4498 /* The thread may have concurrently modified the DLL,
@@ -4690,7 +4618,7 @@ MHD_stop_daemon (struct MHD_Daemon *daemon)
4690 if (1 != MHD_pipe_write_ (daemon->worker_pool[i].wpipe[1], "e", 1)) 4618 if (1 != MHD_pipe_write_ (daemon->worker_pool[i].wpipe[1], "e", 1))
4691 MHD_PANIC ("failed to signal shutdown via pipe"); 4619 MHD_PANIC ("failed to signal shutdown via pipe");
4692 } 4620 }
4693 if (0 != MHD_join_thread_ (daemon->worker_pool[i].pid)) 4621 if (!MHD_join_thread_ (daemon->worker_pool[i].pid))
4694 MHD_PANIC ("Failed to join a thread\n"); 4622 MHD_PANIC ("Failed to join a thread\n");
4695 close_all_connections (&daemon->worker_pool[i]); 4623 close_all_connections (&daemon->worker_pool[i]);
4696 (void) MHD_mutex_destroy_ (&daemon->worker_pool[i].cleanup_connection_mutex); 4624 (void) MHD_mutex_destroy_ (&daemon->worker_pool[i].cleanup_connection_mutex);
@@ -4720,7 +4648,7 @@ MHD_stop_daemon (struct MHD_Daemon *daemon)
4720 ( (0 != (daemon->options & MHD_USE_SELECT_INTERNALLY)) && 4648 ( (0 != (daemon->options & MHD_USE_SELECT_INTERNALLY)) &&
4721 (0 == daemon->worker_pool_size) ) ) 4649 (0 == daemon->worker_pool_size) ) )
4722 { 4650 {
4723 if (0 != MHD_join_thread_ (daemon->pid)) 4651 if (!MHD_join_thread_ (daemon->pid))
4724 { 4652 {
4725 MHD_PANIC ("Failed to join a thread\n"); 4653 MHD_PANIC ("Failed to join a thread\n");
4726 } 4654 }
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 @@
43/* for TCP_FASTOPEN */ 43/* for TCP_FASTOPEN */
44#include <netinet/tcp.h> 44#include <netinet/tcp.h>
45#endif 45#endif
46#include "mhd_threads.h"
46 47
47 48
48/** 49/**
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 @@
32#include <limits.h> 32#include <limits.h>
33#endif /* HAVE_LIMITS_H */ 33#endif /* HAVE_LIMITS_H */
34 34
35#ifndef UINT_MAX
36#ifdef __UINT_MAX__
37#define UINT_MAX __UINT_MAX__
38#else /* ! __UINT_MAX__ */
39#define UINT_MAX ((unsigned int) ~((unsigned int)0))
40#endif /* ! __UINT_MAX__ */
41#endif /* !UINT_MAX */
42
35#ifndef LONG_MAX 43#ifndef LONG_MAX
36#ifdef __LONG_MAX__ 44#ifdef __LONG_MAX__
37#define LONG_MAX __LONG_MAX__ 45#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 @@
1/*
2 This file is part of libmicrohttpd
3 Copyright (C) 2016 Karlson2k (Evgeny Grin)
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with this library; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18
19*/
20
21/**
22 * @file microhttpd/mhd_threads.c
23 * @brief Implementation for thread functions
24 * @author Karlson2k (Evgeny Grin)
25 */
26
27#include "mhd_threads.h"
28#ifdef MHD_USE_W32_THREADS
29#include "mhd_limits.h"
30#include <process.h>
31#endif
32#ifdef MHD_USE_THREAD_NAME_
33#include <stdlib.h>
34#endif /* MHD_USE_THREAD_NAME_ */
35#include <errno.h>
36
37
38
39#if defined(MHD_USE_POSIX_THREADS)
40typedef pthread_t MHD_thread_ID_;
41#elif defined(MHD_USE_W32_THREADS)
42typedef DWORD MHD_thread_ID_;
43#endif
44
45
46#ifndef MHD_USE_THREAD_NAME_
47
48#define MHD_set_thread_name_(t, n) (void)
49#define MHD_set_cur_thread_name_(n) (void)
50
51#else /* MHD_USE_THREAD_NAME_ */
52
53#if defined(MHD_USE_POSIX_THREADS)
54#ifdef HAVE_PTHREAD_SETNAME_NP
55/**
56 * Set thread name
57 * @param thread_id ID of thread
58 * @param thread_name name to set
59 * @return non-zero on success, zero otherwise
60 */
61static int MHD_set_thread_name_(const MHD_thread_ID_ thread_id, const char *thread_name)
62{
63 if (NULL == thread_name)
64 return 0;
65
66 return !pthread_setname_np (thread_id, thread_name);
67}
68
69/**
70 * Set current thread name
71 * @param n name to set
72 * @return non-zero on success, zero otherwise
73 */
74#define MHD_set_cur_thread_name_(n) MHD_set_thread_name_(pthread_self(),(n))
75#endif /* HAVE_PTHREAD_SETNAME_NP */
76
77#elif defined(MHD_USE_W32_THREADS)
78#ifndef _MSC_FULL_VER
79/* Thread name available only for VC-compiler */
80#else /* _MSC_FULL_VER */
81/**
82 * Set thread name
83 * @param thread_id ID of thread, -1 for current thread
84 * @param thread_name name to set
85 * @return non-zero on success, zero otherwise
86 */
87static int MHD_set_thread_name_(const MHD_thread_ID_ thread_id, const char *thread_name)
88{
89 static const DWORD VC_SETNAME_EXC = 0x406D1388;
90#pragma pack(push,8)
91 struct thread_info_struct
92 {
93 DWORD type; /* Must be 0x1000. */
94 LPCSTR name; /* Pointer to name (in user address space). */
95 DWORD ID; /* Thread ID (-1 = caller thread). */
96 DWORD flags; /* Reserved for future use, must be zero. */
97 } thread_info;
98#pragma pack(pop)
99
100 if (NULL == thread_name)
101 return 0;
102
103 thread_info.type = 0x1000;
104 thread_info.name = thread_name;
105 thread_info.ID = thread_id;
106 thread_info.flags = 0;
107
108 __try
109 { /* This exception is intercepted by debugger */
110 RaiseException(VC_SETNAME_EXC, 0, sizeof(thread_info) / sizeof(ULONG_PTR), (ULONG_PTR*)&thread_info);
111 }
112 __except (EXCEPTION_EXECUTE_HANDLER)
113 {}
114
115 return !0;
116}
117
118
119/**
120 * Set current thread name
121 * @param n name to set
122 * @return non-zero on success, zero otherwise
123 */
124#define MHD_set_cur_thread_name_(n) MHD_set_thread_name_(-1,(n))
125#endif /* _MSC_FULL_VER */
126#endif /* MHD_USE_W32_THREADS */
127
128#endif /* MHD_USE_THREAD_NAME_ */
129
130
131/**
132 * Create a thread and set the attributes according to our options.
133 *
134 * @param thread handle to initialize
135 * @param stack_size size of stack for new thread, 0 for default
136 * @param start_routine main function of thread
137 * @param arg argument for start_routine
138 * @return non-zero on success; zero otherwise (with errno set)
139 */
140int
141MHD_create_thread_ (MHD_thread_handle_ *thread,
142 size_t stack_size,
143 MHD_THREAD_START_ROUTINE_ start_routine,
144 void *arg)
145{
146#if defined(MHD_USE_POSIX_THREADS)
147 int res;
148
149 if (0 != stack_size)
150 {
151 pthread_attr_t attr;
152 res = pthread_attr_init (&attr);
153 if (0 == res)
154 {
155 res = pthread_attr_setstacksize (&attr, stack_size);
156 if (0 == res)
157 res = pthread_create (thread, &attr,
158 start_routine, arg);
159 pthread_attr_destroy (&attr);
160 }
161 }
162 else
163 res = pthread_create (thread, NULL, start_routine, arg);
164
165 if (0 != res)
166 errno = res;
167
168 return !res;
169#elif defined(MHD_USE_W32_THREADS)
170#if SIZE_MAX != UINT_MAX
171 if (stack_size > UINT_MAX)
172 {
173 errno = EINVAL;
174 return 0;
175 }
176#endif /* SIZE_MAX != UINT_MAX */
177
178 *thread = (HANDLE)_beginthreadex(NULL, (unsigned)stack_size, start_routine,
179 arg, 0, NULL);
180 if ((MHD_thread_handle_)-1 == (*thread))
181 return 0;
182
183 return !0;
184#endif
185}
186
187#ifdef MHD_USE_THREAD_NAME_
188
189struct MHD_named_helper_param_
190{
191 /**
192 * Real thread start routine
193 */
194 MHD_THREAD_START_ROUTINE_ start_routine;
195
196 /**
197 * Argument for thread start routine
198 */
199 void *arg;
200
201 /**
202 * Name for thread
203 */
204 const char *name;
205};
206
207static MHD_THRD_RTRN_TYPE_ MHD_THRD_CALL_SPEC_
208named_thread_starter (void *data)
209{
210 struct MHD_named_helper_param_ * const param =
211 (struct MHD_named_helper_param_ *) data;
212 void * arg;
213 MHD_THREAD_START_ROUTINE_ thr_func;
214
215 if (NULL == data)
216 return (MHD_THRD_RTRN_TYPE_)0;
217
218 MHD_set_cur_thread_name_(param->name);
219
220 arg = param->arg;
221 thr_func = param->start_routine;
222 free(data);
223
224 return thr_func(arg);
225}
226
227
228
229/**
230 * Create a named thread and set the attributes according to our options.
231 *
232 * @param thread handle to initialize
233 * @param thread_name name for new thread
234 * @param stack_size size of stack for new thread, 0 for default
235 * @param start_routine main function of thread
236 * @param arg argument for start_routine
237 * @return non-zero on success; zero otherwise (with errno set)
238 */
239int
240MHD_create_named_thread_ (MHD_thread_handle_ *thread,
241 const char* thread_name,
242 size_t stack_size,
243 MHD_THREAD_START_ROUTINE_ start_routine,
244 void *arg)
245{
246 struct MHD_named_helper_param_ * param;
247
248 if (NULL == thread_name)
249 {
250 errno = EINVAL;
251 return 0;
252 }
253
254 param = malloc(sizeof(struct MHD_named_helper_param_));
255 if (NULL == param)
256 return 0;
257
258 param->start_routine = start_routine;
259 param->arg = arg;
260 param->name = thread_name;
261
262 /* Set thread name in thread itself to avoid problems with
263 * threads which terminated before name is set in other thread.
264 */
265 if (!MHD_create_thread_(thread, stack_size, &named_thread_starter, (void*)param))
266 {
267 free(param);
268 return 0;
269 }
270
271 return !0;
272}
273
274#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 @@
1/*
2 This file is part of libmicrohttpd
3 Copyright (C) 2016 Karlson2k (Evgeny Grin)
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with this library; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18
19*/
20
21/**
22 * @file microhttpd/mhd_threads.h
23 * @brief Header for platform-independent threads abstraction
24 * @author Karlson2k (Evgeny Grin)
25 *
26 * Provides basic abstraction for threads.
27 * Any functions can be implemented as macro on some platforms
28 * unless explicitly marked otherwise.
29 * Any function argument can be skipped in macro, so avoid
30 * variable modification in function parameters.
31 *
32 * @warning Unlike pthread functions, most of functions return
33 * nonzero on success.
34 */
35
36#ifndef MHD_THREADS_H
37#define MHD_THREADS_H 1
38
39#include "mhd_options.h"
40#ifdef HAVE_STDDEF_H
41# include <stddef.h> /* for size_t */
42#else /* ! HAVE_STDDEF_H */
43# include <stdlib.h> /* for size_t */
44#endif /* ! HAVE_STDDEF_H */
45
46#if defined(MHD_USE_POSIX_THREADS)
47# undef HAVE_CONFIG_H
48# include <pthread.h>
49# define HAVE_CONFIG_H 1
50#elif defined(MHD_USE_W32_THREADS)
51# ifndef WIN32_LEAN_AND_MEAN
52# define WIN32_LEAN_AND_MEAN 1
53# endif /* !WIN32_LEAN_AND_MEAN */
54# include <windows.h>
55#else
56# error No threading API is available.
57#endif
58
59#ifndef MHD_NO_THREAD_NAMES
60# if defined(MHD_USE_POSIX_THREADS)
61# ifdef HAVE_PTHREAD_SETNAME_NP
62# define MHD_USE_THREAD_NAME_
63# endif /* HAVE_PTHREAD_SETNAME_NP */
64# elif defined(MHD_USE_W32_THREADS)
65# ifdef _MSC_FULL_VER
66 /* Thread names only available with VC compiler */
67# define MHD_USE_THREAD_NAME_
68# endif /* _MSC_FULL_VER */
69# endif
70#endif
71
72#if defined(MHD_USE_POSIX_THREADS)
73 typedef pthread_t MHD_thread_handle_;
74#elif defined(MHD_USE_W32_THREADS)
75 typedef HANDLE MHD_thread_handle_;
76#endif
77
78#if defined(MHD_USE_POSIX_THREADS)
79# define MHD_THRD_RTRN_TYPE_ void*
80# define MHD_THRD_CALL_SPEC_
81#elif defined(MHD_USE_W32_THREADS)
82# define MHD_THRD_RTRN_TYPE_ unsigned
83# define MHD_THRD_CALL_SPEC_ __stdcall
84#endif
85
86#if defined(MHD_USE_POSIX_THREADS)
87/**
88 * Wait until specified thread is ended and free thread handle on success.
89 * @param thread handle to watch
90 * @return nonzero on success, zero otherwise
91 */
92#define MHD_join_thread_(thread) (!pthread_join((thread), NULL))
93#elif defined(MHD_USE_W32_THREADS)
94/**
95 * Wait until specified thread is ended and free thread handle on success.
96 * @param thread handle to watch
97 * @return nonzero on success, zero otherwise
98 */
99#define MHD_join_thread_(thread) (WAIT_OBJECT_0 == WaitForSingleObject((thread), INFINITE) ? (CloseHandle((thread)), !0) : 0)
100#endif
101
102/**
103 * Signature of main function for a thread.
104 *
105 * @param cls closure argument for the function
106 * @return termination code from the thread
107 */
108typedef MHD_THRD_RTRN_TYPE_
109(MHD_THRD_CALL_SPEC_ *MHD_THREAD_START_ROUTINE_)(void *cls);
110
111
112/**
113 * Create a thread and set the attributes according to our options.
114 *
115 * If thread is created, thread handle must be freed by #MHD_join_thread_().
116 *
117 * @param thread handle to initialize
118 * @param stack_size size of stack for new thread, 0 for default
119 * @param start_routine main function of thread
120 * @param arg argument for start_routine
121 * @return non-zero on success; zero otherwise
122 */
123int
124MHD_create_thread_ (MHD_thread_handle_ *thread,
125 size_t stack_size,
126 MHD_THREAD_START_ROUTINE_ start_routine,
127 void *arg);
128
129#ifndef MHD_USE_THREAD_NAME_
130#define MHD_create_named_thread_(t,n,s,r,a) MHD_create_thread_((t),(s),(r),(a))
131#else /* MHD_USE_THREAD_NAME_ */
132/**
133 * Create a named thread and set the attributes according to our options.
134 *
135 * @param thread handle to initialize
136 * @param thread_name name for new thread
137 * @param stack_size size of stack for new thread, 0 for default
138 * @param start_routine main function of thread
139 * @param arg argument for start_routine
140 * @return non-zero on success; zero otherwise
141 */
142int
143MHD_create_named_thread_ (MHD_thread_handle_ *thread,
144 const char* thread_name,
145 size_t stack_size,
146 MHD_THREAD_START_ROUTINE_ start_routine,
147 void *arg);
148
149#endif /* MHD_USE_THREAD_NAME_ */
150
151#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 @@
77#include <stdbool.h> 77#include <stdbool.h>
78#endif /* HAVE_STDBOOL_H */ 78#endif /* HAVE_STDBOOL_H */
79 79
80#include "mhd_threads.h"
81
80#ifndef SOMAXCONN 82#ifndef SOMAXCONN
81#define SOMAXCONN 511 83#define SOMAXCONN 511
82#endif /* ! SOMAXCONN */ 84#endif /* ! SOMAXCONN */
@@ -346,7 +348,7 @@ main (int argc, char *const *argv)
346 shutdown (listen_socket, SHUT_RDWR); 348 shutdown (listen_socket, SHUT_RDWR);
347 349
348 /* fprintf (stdout, "Waiting for thread to finish...\n"); */ 350 /* fprintf (stdout, "Waiting for thread to finish...\n"); */
349 if (0 != MHD_join_thread_(sel_thrd)) 351 if (!MHD_join_thread_(sel_thrd))
350 { 352 {
351 MHD_socket_close_(listen_socket); 353 MHD_socket_close_(listen_socket);
352 fprintf (stderr, "Can't join select() thread\n"); 354 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, ..
667 667
668 return ret; 668 return ret;
669} 669}
670
671#ifdef _MSC_FULL_VER
672/**
673 * Set thread name
674 * @param thread_id ID of thread, -1 for current thread
675 * @param thread_name name to set
676 */
677void W32_SetThreadName(const DWORD thread_id, const char *thread_name)
678{
679 static const DWORD VC_SETNAME_EXC = 0x406D1388;
680#pragma pack(push,8)
681 struct thread_info_struct
682 {
683 DWORD type; /* Must be 0x1000. */
684 LPCSTR name; /* Pointer to name (in user address space). */
685 DWORD ID; /* Thread ID (-1=caller thread). */
686 DWORD flags; /* Reserved for future use, must be zero. */
687 } thread_info;
688#pragma pack(pop)
689
690 if (NULL == thread_name)
691 return;
692
693 thread_info.type = 0x1000;
694 thread_info.name = thread_name;
695 thread_info.ID = thread_id;
696 thread_info.flags = 0;
697
698 __try
699 { /* This exception is intercepted by debugger */
700 RaiseException(VC_SETNAME_EXC, 0, sizeof(thread_info) / sizeof(ULONG_PTR), (ULONG_PTR*)&thread_info);
701 }
702 __except (EXCEPTION_EXECUTE_HANDLER)
703 {}
704}
705#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 @@
144/* Define to 1 if you have the <time.h> header file. */ 144/* Define to 1 if you have the <time.h> header file. */
145#define HAVE_TIME_H 1 145#define HAVE_TIME_H 1
146 146
147/* Define to 1 if you have the <stddef.h> header file. */
148#define HAVE_STDDEF_H 1
149
147 150
148/* *** Other useful staff *** */ 151/* *** Other useful staff *** */
149 152
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 @@
16 <ClCompile Include="$(MhdSrc)microhttpd\tsearch.c" /> 16 <ClCompile Include="$(MhdSrc)microhttpd\tsearch.c" />
17 <ClCompile Include="$(MhdSrc)microhttpd\sysfdsetsize.c" /> 17 <ClCompile Include="$(MhdSrc)microhttpd\sysfdsetsize.c" />
18 <ClCompile Include="$(MhdSrc)microhttpd\mhd_str.c" /> 18 <ClCompile Include="$(MhdSrc)microhttpd\mhd_str.c" />
19 <ClCompile Include="$(MhdSrc)microhttpd\mhd_threads.c" />
19 <ClCompile Include="$(MhdSrc)platform\w32functions.c" /> 20 <ClCompile Include="$(MhdSrc)platform\w32functions.c" />
20 </ItemGroup> 21 </ItemGroup>
21 <ItemGroup> 22 <ItemGroup>
@@ -37,6 +38,7 @@
37 <ClInclude Include="$(MhdSrc)microhttpd\tsearch.h" /> 38 <ClInclude Include="$(MhdSrc)microhttpd\tsearch.h" />
38 <ClInclude Include="$(MhdSrc)microhttpd\sysfdsetsize.h" /> 39 <ClInclude Include="$(MhdSrc)microhttpd\sysfdsetsize.h" />
39 <ClInclude Include="$(MhdSrc)microhttpd\mhd_str.h" /> 40 <ClInclude Include="$(MhdSrc)microhttpd\mhd_str.h" />
41 <ClInclude Include="$(MhdSrc)microhttpd\mhd_threads.h" />
40 <ClInclude Include="$(MhdW32Common)MHD_config.h" /> 42 <ClInclude Include="$(MhdW32Common)MHD_config.h" />
41 </ItemGroup> 43 </ItemGroup>
42 <ItemGroup> 44 <ItemGroup>
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 @@
130 <ClCompile Include="$(MhdSrc)microhttpd\mhd_str.c"> 130 <ClCompile Include="$(MhdSrc)microhttpd\mhd_str.c">
131 <Filter>Source Files</Filter> 131 <Filter>Source Files</Filter>
132 </ClCompile> 132 </ClCompile>
133 <ClInclude Include="$(MhdSrc)microhttpd\mhd_threads.h">
134 <Filter>Source Files</Filter>
135 </ClInclude>
136 <ClCompile Include="$(MhdSrc)microhttpd\mhd_threads.c">
137 <Filter>Source Files</Filter>
138 </ClCompile>
133 </ItemGroup> 139 </ItemGroup>
134 <ItemGroup> 140 <ItemGroup>
135 <ResourceCompile Include="$(MhdW32Common)microhttpd_dll_res_vc.rc"> 141 <ResourceCompile Include="$(MhdW32Common)microhttpd_dll_res_vc.rc">