aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2011-09-21 07:47:03 +0000
committerChristian Grothoff <christian@grothoff.org>2011-09-21 07:47:03 +0000
commit7ef544c9bed6159c46be44a3d130e0de094a345f (patch)
tree5ed9708867336e51f36dbd4e1c9778ae625e22cf
parent211920f3ef774ab6009814d40caca9358881ba34 (diff)
downloadlibmicrohttpd-7ef544c9bed6159c46be44a3d130e0de094a345f.tar.gz
libmicrohttpd-7ef544c9bed6159c46be44a3d130e0de094a345f.zip
From:
Will Bryant <will.bryant@gmail.com> To: libmicrohttpd development and user mailinglist <libmicrohttpd@gnu.org> Date: Yesterday 03:59:23 PM Attachments: 0001-use-a-pipe-to-signal-shutdown-to-select-and-poll.patch I attach my current work. I have attempted to preserve and restore as much of the 'old' pipe shutdown code that was present in earlier versions of the library, but have removed the sections that aren't relevant now that there is a socket-by-socket client shutdown procedure. On OS X, all the 'regular' tests pass. The two perf test programs both fail on a random subset of the tests with "Failed to bind to port 1081: Address already in use" (or the other ports that the perf tests use). I initially thought that this was a problem with this patch, but after I couldn't find any problem with it I tried backporting the perf test programs to the older 0.9.7 version of libmicrohttpd, which is before the listening socket shutdown code went in, and it turned out that the older versions failed in the same way. On OpenIndiana (oi_151a - but should behave the same as other SunOS/Solaris/OpenSolaris/Illumos kernels), the same problem occurs. (I haven't tried the backport there too.) Linux is known to have slightly different behavior for the SOL_REUSEADDR option which might explain this, but it's quite possible that this is just a timing issue with the cleanup of the client threads in these perf test programs (if you wait for 1s between the tests then the problem goes away). On OS X, using both debugging printfs and shelling out to lsof -itcp, I have confirmed that the listening socket has been closed successfully before the error occurs. So I am starting to suspect that it is not possible to bind to an address that was used as a server socket until all the client sockets have also been cleaned up - but that's just a theory at this point. Anyway, as far as this patch goes, OS X looks a lot healthier - as healthy as it was in 0.9.7 (0.9.8 and 0.9.9 both failed to build entirely). There is one further test failure on openindiana, which I believe is not related to this patch - all the same 'regular' tests pass except daemontest_get_response_cleanup, which dies due to an unhandled SIGPIPE when trying to write to the socket after killing the curl process: Program received signal SIGPIPE, Broken pipe. [Switching to Thread 2 (LWP 2)] 0xfed634f7 in __so_send () from /lib/libc.so.1 (gdb) bt #0 0xfed634f7 in __so_send () from /lib/libc.so.1 #1 0xfed511d7 in _so_send () from /lib/libc.so.1 #2 0xfe7dcb26 in send () from /lib/libsocket.so.1 #3 0xfef56d29 in send_param_adapter (connection=0x20, other=0xfe99080f, i=0) at daemon.c:764 #4 0xfef54a0b in do_write (connection=0x8073ad0) at connection.c:1495 #5 0xfef54f6f in MHD_connection_handle_write (connection=0x8073ad0) at connection.c:1909 #6 0xfef57b3c in MHD_select (daemon=0x80737a8, may_block=0) at daemon.c:1367 #7 0xfef57ff4 in MHD_select_thread (cls=0x80737a8) at daemon.c:1615 #8 0xfed5f0f3 in _thrp_setup () from /lib/libc.so.1 #9 0xfed5f3a0 in ?? () from /lib/libc.so.1 #10 0xfe9a0240 in ?? () #11 0x00000000 in ?? () (gdb) info threads * 4 Thread 2 (LWP 2) 0xfed634f7 in __so_send () from /lib/libc.so.1 3 LWP 2 0xfed634f7 in __so_send () from /lib/libc.so.1 2 Thread 1 (LWP 1) 0xfed63e87 in __waitid () from /lib/libc.so.1 1 LWP 1 0xfed63e87 in __waitid () from /lib/libc.so.1 (gdb) thread 2 [Switching to thread 2 (Thread 1 (LWP 1))]#0 0xfed63e87 in __waitid () from /lib/libc.so.1 (gdb) bt #0 0xfed63e87 in __waitid () from /lib/libc.so.1 #1 0xfed515bd in waitid () from /lib/libc.so.1 #2 0xfed00035 in waitpid () from /lib/libc.so.1 #3 0x08051423 in kill_curl (pid=4479) at daemontest_get_response_cleanup.c:70 #4 0x0805157d in main (argc=1, argv=0x6b) at daemontest_get_response_cleanup.c:141 0001-use-a-pipe-to-signal-shutdown-to-select-and-poll.patch
-rw-r--r--AUTHORS1
-rw-r--r--src/daemon/daemon.c92
-rw-r--r--src/daemon/internal.h7
3 files changed, 88 insertions, 12 deletions
diff --git a/AUTHORS b/AUTHORS
index 59dac571..6a59fd52 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -33,6 +33,7 @@ Eivind Sarto <ivan@espial.com>
33Thomas Stalder <gnunet@netsolux.ch> 33Thomas Stalder <gnunet@netsolux.ch>
34Zhimin Huang <zhimin.huang@bqvision.com> 34Zhimin Huang <zhimin.huang@bqvision.com>
35Jan Seeger <jan.seeger@thenybble.de> 35Jan Seeger <jan.seeger@thenybble.de>
36Will Bryant <will.bryant@gmail.com>
36 37
37Documentation contributions also came from: 38Documentation contributions also came from:
38Marco Maggi <marco.maggi-ipsu@poste.it> 39Marco Maggi <marco.maggi-ipsu@poste.it>
diff --git a/src/daemon/daemon.c b/src/daemon/daemon.c
index b0aca594..aedbf76c 100644
--- a/src/daemon/daemon.c
+++ b/src/daemon/daemon.c
@@ -1307,6 +1307,15 @@ MHD_select (struct MHD_Daemon *daemon,
1307 FD_SET (max, &rs); 1307 FD_SET (max, &rs);
1308 } 1308 }
1309 1309
1310#ifndef HAVE_LISTEN_SHUTDOWN
1311 if (-1 == daemon->wpipe[0])
1312 return MHD_NO;
1313 FD_SET (daemon->wpipe[0], &rs);
1314 /* update max file descriptor */
1315 if (max < daemon->wpipe[0])
1316 max = daemon->wpipe[0];
1317#endif
1318
1310 tv = NULL; 1319 tv = NULL;
1311 if (may_block == MHD_NO) 1320 if (may_block == MHD_NO)
1312 { 1321 {
@@ -1389,7 +1398,11 @@ MHD_poll_all (struct MHD_Daemon *daemon,
1389 pos = pos->next; 1398 pos = pos->next;
1390 } 1399 }
1391 { 1400 {
1401 #ifdef HAVE_LISTEN_SHUTDOWN
1392 struct pollfd p[1 + num_connections]; 1402 struct pollfd p[1 + num_connections];
1403 #else
1404 struct pollfd p[2 + num_connections];
1405 #endif
1393 struct MHD_Pollfd mp; 1406 struct MHD_Pollfd mp;
1394 unsigned MHD_LONG_LONG ltimeout; 1407 unsigned MHD_LONG_LONG ltimeout;
1395 unsigned int i; 1408 unsigned int i;
@@ -1399,10 +1412,17 @@ MHD_poll_all (struct MHD_Daemon *daemon,
1399 memset (p, 0, sizeof (p)); 1412 memset (p, 0, sizeof (p));
1400 if ( (daemon->max_connections > 0) && (daemon->socket_fd != -1) ) 1413 if ( (daemon->max_connections > 0) && (daemon->socket_fd != -1) )
1401 { 1414 {
1402 poll_server = 1;
1403 p[0].fd = daemon->socket_fd; 1415 p[0].fd = daemon->socket_fd;
1404 p[0].events = POLLIN; 1416 p[0].events = POLLIN;
1405 p[0].revents = 0; 1417 p[0].revents = 0;
1418#ifdef HAVE_LISTEN_SHUTDOWN
1419 poll_server = 1;
1420#else
1421 p[1].fd = daemon->wpipe[0];
1422 p[1].events = POLLIN;
1423 p[1].revents = 0;
1424 poll_server = 2;
1425#endif
1406 } 1426 }
1407 else 1427 else
1408 { 1428 {
@@ -1464,7 +1484,7 @@ MHD_poll_all (struct MHD_Daemon *daemon,
1464 pos->idle_handler (pos); 1484 pos->idle_handler (pos);
1465 i++; 1485 i++;
1466 } 1486 }
1467 if ( (1 == poll_server) && 1487 if ( (0 != poll_server) &&
1468 (0 != (p[0].revents & POLLIN)) ) 1488 (0 != (p[0].revents & POLLIN)) )
1469 MHD_accept_connection (daemon); 1489 MHD_accept_connection (daemon);
1470 } 1490 }
@@ -1483,22 +1503,27 @@ static int
1483MHD_poll_listen_socket (struct MHD_Daemon *daemon, 1503MHD_poll_listen_socket (struct MHD_Daemon *daemon,
1484 int may_block) 1504 int may_block)
1485{ 1505{
1486 struct pollfd p; 1506#ifdef HAVE_LISTEN_SHUTDOWN
1507 struct pollfd p[1];
1508#else
1509 struct pollfd p[2];
1510#endif
1487 int timeout; 1511 int timeout;
1488 1512
1489 memset (&p, 0, sizeof (p)); 1513 memset (&p, 0, sizeof (p));
1490 p.fd = daemon->socket_fd; 1514 p[0].fd = daemon->socket_fd;
1491 p.events = POLLIN; 1515 p[0].events = POLLIN;
1492 p.revents = 0; 1516 p[0].revents = 0;
1517#ifndef HAVE_LISTEN_SHUTDOWN
1518 p[1].fd = daemon->wpipe[0];
1519 p[1].events = POLLIN;
1520 p[1].revents = 0;
1521#endif
1493 if (may_block == MHD_NO) 1522 if (may_block == MHD_NO)
1494 timeout = 0; 1523 timeout = 0;
1495 else 1524 else
1496 timeout = -1; 1525 timeout = -1;
1497#ifdef __CYGWIN__ 1526 if (poll (p, (sizeof(p)/sizeof(struct pollfd)), timeout) < 0)
1498 /* See https://gnunet.org/bugs/view.php?id=1674 */
1499 timeout = ( (timeout > 2000) || (timeout < 0) ) ? 2000 : timeout;
1500#endif
1501 if (poll (&p, 1, timeout) < 0)
1502 { 1527 {
1503 if (errno == EINTR) 1528 if (errno == EINTR)
1504 return MHD_YES; 1529 return MHD_YES;
@@ -1512,7 +1537,7 @@ MHD_poll_listen_socket (struct MHD_Daemon *daemon,
1512 return MHD_NO; 1537 return MHD_NO;
1513 if (daemon->socket_fd < 0) 1538 if (daemon->socket_fd < 0)
1514 return MHD_YES; 1539 return MHD_YES;
1515 if (0 != (p.revents & POLLIN)) 1540 if (0 != (p[0].revents & POLLIN))
1516 MHD_accept_connection (daemon); 1541 MHD_accept_connection (daemon);
1517 return MHD_YES; 1542 return MHD_YES;
1518} 1543}
@@ -1971,6 +1996,34 @@ MHD_start_daemon_va (unsigned int options,
1971 retVal->pool_size = MHD_POOL_SIZE_DEFAULT; 1996 retVal->pool_size = MHD_POOL_SIZE_DEFAULT;
1972 retVal->unescape_callback = &MHD_http_unescape; 1997 retVal->unescape_callback = &MHD_http_unescape;
1973 retVal->connection_timeout = 0; /* no timeout */ 1998 retVal->connection_timeout = 0; /* no timeout */
1999#ifndef HAVE_LISTEN_SHUTDOWN
2000 retVal->wpipe[0] = -1;
2001 retVal->wpipe[1] = -1;
2002 if (0 != pipe (retVal->wpipe))
2003 {
2004#if HAVE_MESSAGES
2005 FPRINTF(stderr,
2006 "Failed to create control pipe: %s\n",
2007 STRERROR (errno));
2008#endif
2009 free (retVal);
2010 return NULL;
2011 }
2012#ifndef WINDOWS
2013 if ( (0 == (options & MHD_USE_POLL)) &&
2014 (retVal->wpipe[0] >= FD_SETSIZE) )
2015 {
2016#if HAVE_MESSAGES
2017 FPRINTF(stderr,
2018 "file descriptor for control pipe exceeds maximum value\n");
2019#endif
2020 close (retVal->wpipe[0]);
2021 close (retVal->wpipe[1]);
2022 free (retVal);
2023 return NULL;
2024 }
2025#endif
2026#endif
1974#ifdef DAUTH_SUPPORT 2027#ifdef DAUTH_SUPPORT
1975 retVal->digest_auth_rand_size = 0; 2028 retVal->digest_auth_rand_size = 0;
1976 retVal->digest_auth_random = NULL; 2029 retVal->digest_auth_random = NULL;
@@ -2464,12 +2517,15 @@ MHD_stop_daemon (struct MHD_Daemon *daemon)
2464 int fd; 2517 int fd;
2465 unsigned int i; 2518 unsigned int i;
2466 int rc; 2519 int rc;
2520 char c;
2467 2521
2468 if (daemon == NULL) 2522 if (daemon == NULL)
2469 return; 2523 return;
2470 daemon->shutdown = MHD_YES; 2524 daemon->shutdown = MHD_YES;
2471 fd = daemon->socket_fd; 2525 fd = daemon->socket_fd;
2472 daemon->socket_fd = -1; 2526 daemon->socket_fd = -1;
2527 if (daemon->wpipe[1] != -1)
2528 write (daemon->wpipe[1], "e", 1);
2473 2529
2474 /* Prepare workers for shutdown */ 2530 /* Prepare workers for shutdown */
2475 for (i = 0; i < daemon->worker_pool_size; ++i) 2531 for (i = 0; i < daemon->worker_pool_size; ++i)
@@ -2548,6 +2604,18 @@ MHD_stop_daemon (struct MHD_Daemon *daemon)
2548#endif 2604#endif
2549 pthread_mutex_destroy (&daemon->per_ip_connection_mutex); 2605 pthread_mutex_destroy (&daemon->per_ip_connection_mutex);
2550 pthread_mutex_destroy (&daemon->cleanup_connection_mutex); 2606 pthread_mutex_destroy (&daemon->cleanup_connection_mutex);
2607
2608#ifndef HAVE_LISTEN_SHUTDOWN
2609 if (daemon->wpipe[1] != -1)
2610 {
2611 /* just to be sure, remove the one char we
2612 wrote into the pipe */
2613 (void) read (daemon->wpipe[0], &c, 1);
2614 close (daemon->wpipe[0]);
2615 close (daemon->wpipe[1]);
2616 }
2617#endif
2618
2551 free (daemon); 2619 free (daemon);
2552} 2620}
2553 2621
diff --git a/src/daemon/internal.h b/src/daemon/internal.h
index 17f2a05c..1b252d23 100644
--- a/src/daemon/internal.h
+++ b/src/daemon/internal.h
@@ -896,6 +896,13 @@ struct MHD_Daemon
896 */ 896 */
897 int socket_fd; 897 int socket_fd;
898 898
899#ifndef HAVE_LISTEN_SHUTDOWN
900 /**
901 * Pipe we use to signal shutdown.
902 */
903 int wpipe[2];
904#endif
905
899 /** 906 /**
900 * Are we shutting down? 907 * Are we shutting down?
901 */ 908 */