aboutsummaryrefslogtreecommitdiff
path: root/src/testcurl/daemontest_get.c
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2009-10-14 12:26:42 +0000
committerChristian Grothoff <christian@grothoff.org>2009-10-14 12:26:42 +0000
commit1c56a767212c4808ee892fb967bfc956f2246cdf (patch)
tree1efa5719927c3a9c0ea39b7dd2f5d243aa5ea06e /src/testcurl/daemontest_get.c
parent88dde2121306c6eb3f68980afd9755d7ce001a5e (diff)
downloadlibmicrohttpd-1c56a767212c4808ee892fb967bfc956f2246cdf.tar.gz
libmicrohttpd-1c56a767212c4808ee892fb967bfc956f2246cdf.zip
From:
Mike Crowe <mac@mcrowe.com> To: libmicrohttpd@gnu.org Date: Yesterday 17:41:12 I've found a difficult to reproduce deadlock in v0.4.2 when calling MHD_stop_daemon while a connection is active. I narrowed it down to MHD_handle_connection racing against MHD_cleanup_connections. It can be reproduced much more easily by inserting a sleep just before the call to SELECT in MHD_handle_connection. I'm using MHD_USE_THREAD_PER_CONNECTION. The problem appears to occur when MHD_stop_daemon sets daemon->shutdown and sends SIGALRM signal to the thread running inside MHD_handle_connection while it is between the top of the loop where con->daemon->shutdown is checked and the call to SELECT. The signal has no persistent effect and the thread ends up blocked forever inside select. The only workarounds I can come up with are using an explicit pipe to wake the thread (which is stateful so it can be relied upon to wake the select) or to force the socket closed so that the select wakes up (but this sounds rather more dangerous and is racey if anyone else is opening file descriptors.) Here's a patch which reproduces the problem under 'make check'. I'm running on Debian GNU/Linux 5.0 on amd64 but I've also reproduced the problem on i386. I can clean up the patch to make it suitable for checking in but the chances of hitting the problem without the sleep in MHD_handle_connection are very small.
Diffstat (limited to 'src/testcurl/daemontest_get.c')
-rw-r--r--src/testcurl/daemontest_get.c77
1 files changed, 61 insertions, 16 deletions
diff --git a/src/testcurl/daemontest_get.c b/src/testcurl/daemontest_get.c
index 26feee9e..43870177 100644
--- a/src/testcurl/daemontest_get.c
+++ b/src/testcurl/daemontest_get.c
@@ -1,6 +1,6 @@
1/* 1/*
2 This file is part of libmicrohttpd 2 This file is part of libmicrohttpd
3 (C) 2007 Christian Grothoff 3 (C) 2007, 2009 Christian Grothoff
4 4
5 libmicrohttpd is free software; you can redistribute it and/or modify 5 libmicrohttpd is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published 6 it under the terms of the GNU General Public License as published
@@ -118,9 +118,9 @@ testInternalGet ()
118 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); 118 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
119 else 119 else
120 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0); 120 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
121 // NOTE: use of CONNECTTIMEOUT without also 121 /* NOTE: use of CONNECTTIMEOUT without also
122 // setting NOSIGNAL results in really weird 122 setting NOSIGNAL results in really weird
123 // crashes on my system! 123 crashes on my system!*/
124 curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1); 124 curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1);
125 if (CURLE_OK != (errornum = curl_easy_perform (c))) 125 if (CURLE_OK != (errornum = curl_easy_perform (c)))
126 { 126 {
@@ -167,9 +167,9 @@ testMultithreadedGet ()
167 else 167 else
168 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0); 168 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
169 curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 15L); 169 curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 15L);
170 // NOTE: use of CONNECTTIMEOUT without also 170 /* NOTE: use of CONNECTTIMEOUT without also
171 // setting NOSIGNAL results in really weird 171 setting NOSIGNAL results in really weird
172 // crashes on my system! 172 crashes on my system! */
173 curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1); 173 curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1);
174 if (CURLE_OK != (errornum = curl_easy_perform (c))) 174 if (CURLE_OK != (errornum = curl_easy_perform (c)))
175 { 175 {
@@ -217,9 +217,9 @@ testMultithreadedPoolGet ()
217 else 217 else
218 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0); 218 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
219 curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 15L); 219 curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 15L);
220 // NOTE: use of CONNECTTIMEOUT without also 220 /* NOTE: use of CONNECTTIMEOUT without also
221 // setting NOSIGNAL results in really weird 221 setting NOSIGNAL results in really weird
222 // crashes on my system! 222 crashes on my system!*/
223 curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1); 223 curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1);
224 if (CURLE_OK != (errornum = curl_easy_perform (c))) 224 if (CURLE_OK != (errornum = curl_easy_perform (c)))
225 { 225 {
@@ -276,9 +276,9 @@ testExternalGet ()
276 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0); 276 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
277 curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L); 277 curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
278 curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 15L); 278 curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 15L);
279 // NOTE: use of CONNECTTIMEOUT without also 279 /* NOTE: use of CONNECTTIMEOUT without also
280 // setting NOSIGNAL results in really weird 280 setting NOSIGNAL results in really weird
281 // crashes on my system! 281 crashes on my system! */
282 curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1); 282 curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1);
283 283
284 284
@@ -412,9 +412,9 @@ testUnknownPortGet ()
412 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); 412 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
413 else 413 else
414 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0); 414 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
415 // NOTE: use of CONNECTTIMEOUT without also 415 /* NOTE: use of CONNECTTIMEOUT without also
416 // setting NOSIGNAL results in really weird 416 setting NOSIGNAL results in really weird
417 // crashes on my system! 417 crashes on my system! */
418 curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1); 418 curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1);
419 if (CURLE_OK != (errornum = curl_easy_perform (c))) 419 if (CURLE_OK != (errornum = curl_easy_perform (c)))
420 { 420 {
@@ -435,6 +435,50 @@ testUnknownPortGet ()
435} 435}
436 436
437 437
438static int
439testStopRace ()
440{
441 struct sockaddr_in sin;
442 int fd;
443 struct MHD_Daemon *d;
444
445 d = MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION | MHD_USE_DEBUG,
446 1081, NULL, NULL, &ahc_echo, "GET", MHD_OPTION_END);
447 if (d == NULL)
448 return 16;
449
450 fd = socket(PF_INET, SOCK_STREAM, 0);
451 if (fd < 0)
452 {
453 fprintf(stderr, "socket: %m\n");
454 return 256;
455 }
456
457 memset(&sin, 0, sizeof(sin));
458 sin.sin_family = AF_INET;
459 sin.sin_port = htons(1081);
460 sin.sin_addr.s_addr = htonl(0x7f000001);
461
462 if (connect(fd, (struct sockaddr *)(&sin), sizeof(sin)) < 0)
463 {
464 fprintf(stderr, "connect: %m\n");
465 return 512;
466 }
467
468 /* printf("Waiting\n"); */
469 /* Let the thread get going. */
470 usleep(500000);
471
472 /* printf("Stopping daemon\n"); */
473 MHD_stop_daemon (d);
474
475 close(fd);
476
477 /* printf("good\n"); */
478 return 0;
479}
480
481
438 482
439int 483int
440main (int argc, char *const *argv) 484main (int argc, char *const *argv)
@@ -449,6 +493,7 @@ main (int argc, char *const *argv)
449 errorCount += testMultithreadedPoolGet (); 493 errorCount += testMultithreadedPoolGet ();
450 errorCount += testExternalGet (); 494 errorCount += testExternalGet ();
451 errorCount += testUnknownPortGet (); 495 errorCount += testUnknownPortGet ();
496 errorCount += testStopRace ();
452 if (errorCount != 0) 497 if (errorCount != 0)
453 fprintf (stderr, "Error (code: %u)\n", errorCount); 498 fprintf (stderr, "Error (code: %u)\n", errorCount);
454 curl_global_cleanup (); 499 curl_global_cleanup ();