diff options
author | Christian Grothoff <christian@grothoff.org> | 2011-03-01 15:09:14 +0000 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2011-03-01 15:09:14 +0000 |
commit | 260dd93fdabe89e8c715286c20e23124a79c2b54 (patch) | |
tree | bca1fd848f95def607f35e1dabad90eab106e7b0 | |
parent | d4a325b3edd24ba5ac1957898fd089b3a810a84f (diff) | |
download | libmicrohttpd-260dd93fdabe89e8c715286c20e23124a79c2b54.tar.gz libmicrohttpd-260dd93fdabe89e8c715286c20e23124a79c2b54.zip |
enable poll more broadly, fix timeout, use pipe instead of signal
-rw-r--r-- | ChangeLog | 5 | ||||
-rw-r--r-- | src/daemon/daemon.c | 380 | ||||
-rw-r--r-- | src/daemon/internal.h | 5 | ||||
-rw-r--r-- | src/examples/minimal_example.c | 5 | ||||
-rw-r--r-- | src/include/microhttpd.h | 2 |
5 files changed, 237 insertions, 160 deletions
@@ -1,3 +1,8 @@ | |||
1 | Tue Mar 1 13:58:04 CET 2011 | ||
2 | Allow use of 'poll' in combination with the external select mode. | ||
3 | Avoid using pthread signals (SIGALRM), use pipe instead. | ||
4 | Corrected timeout calculation (s vs. ms). -CG | ||
5 | |||
1 | Wed Feb 23 14:21:44 CET 2011 | 6 | Wed Feb 23 14:21:44 CET 2011 |
2 | Removing useless code pointed out by Eivind Sarto. -CG | 7 | Removing useless code pointed out by Eivind Sarto. -CG |
3 | 8 | ||
diff --git a/src/daemon/daemon.c b/src/daemon/daemon.c index d2e356a9..460e057e 100644 --- a/src/daemon/daemon.c +++ b/src/daemon/daemon.c | |||
@@ -80,14 +80,6 @@ | |||
80 | #endif | 80 | #endif |
81 | #endif | 81 | #endif |
82 | 82 | ||
83 | #ifdef __SYMBIAN32__ | ||
84 | static void pthread_kill (int, int) { | ||
85 | // Symbian doesn't have signals. The user of the library is required to | ||
86 | // run it in an external select loop. | ||
87 | abort(); | ||
88 | } | ||
89 | #endif // __SYMBIAN32__ | ||
90 | |||
91 | /** | 83 | /** |
92 | * Default implementation of the panic function | 84 | * Default implementation of the panic function |
93 | */ | 85 | */ |
@@ -572,45 +564,54 @@ MHD_handle_connection (void *data) | |||
572 | fd_set es; | 564 | fd_set es; |
573 | int max; | 565 | int max; |
574 | struct timeval tv; | 566 | struct timeval tv; |
567 | struct timeval *tvp; | ||
575 | unsigned int timeout; | 568 | unsigned int timeout; |
569 | time_t now; | ||
576 | #ifdef HAVE_POLL_H | 570 | #ifdef HAVE_POLL_H |
577 | struct MHD_Pollfd mp; | 571 | struct MHD_Pollfd mp; |
578 | struct pollfd p; | 572 | struct pollfd p[2]; |
579 | #endif | 573 | #endif |
580 | 574 | ||
581 | timeout = con->daemon->connection_timeout; | 575 | timeout = con->daemon->connection_timeout; |
582 | while ((!con->daemon->shutdown) && (con->socket_fd != -1)) { | 576 | while ((!con->daemon->shutdown) && (con->socket_fd != -1)) { |
583 | tv.tv_usec = 0; | 577 | tvp = NULL; |
584 | if ( (timeout > (time (NULL) - con->last_activity)) || | 578 | if (timeout > 0) |
585 | (timeout == 0) ) | ||
586 | { | 579 | { |
587 | /* in case we are missing the SIGALRM, keep going after | 580 | now = time (NULL); |
588 | at most 1s; see http://lists.gnu.org/archive/html/libmicrohttpd/2009-10/msg00013.html */ | 581 | if (now - con->last_activity > timeout) |
589 | tv.tv_sec = 1; | 582 | tv.tv_sec = 0; |
590 | if ((con->state == MHD_CONNECTION_NORMAL_BODY_UNREADY) || | 583 | else |
591 | (con->state == MHD_CONNECTION_CHUNKED_BODY_UNREADY)) | 584 | tv.tv_sec = timeout - (now - con->last_activity); |
592 | { | 585 | tvp = &tv; |
593 | /* do not block (we're waiting for our callback to succeed) */ | ||
594 | tv.tv_sec = 0; | ||
595 | } | ||
596 | } | 586 | } |
597 | else | 587 | if ((con->state == MHD_CONNECTION_NORMAL_BODY_UNREADY) || |
588 | (con->state == MHD_CONNECTION_CHUNKED_BODY_UNREADY)) | ||
598 | { | 589 | { |
590 | /* do not block (we're waiting for our callback to succeed) */ | ||
599 | tv.tv_sec = 0; | 591 | tv.tv_sec = 0; |
592 | tv.tv_usec = 0; | ||
593 | tvp = &tv; | ||
600 | } | 594 | } |
601 | #ifdef HAVE_POLL_H | 595 | #ifdef HAVE_POLL_H |
602 | if (0 == (con->daemon->options & MHD_USE_POLL)) { | 596 | if (0 == (con->daemon->options & MHD_USE_POLL)) |
597 | { | ||
603 | #else | 598 | #else |
604 | { | 599 | { |
605 | #endif | 600 | #endif |
606 | /* use select */ | 601 | /* use select */ |
607 | FD_ZERO (&rs); | 602 | FD_ZERO (&rs); |
608 | FD_ZERO (&ws); | 603 | FD_ZERO (&ws); |
609 | FD_ZERO (&es); | 604 | FD_ZERO (&es); |
610 | max = 0; | 605 | if (-1 != con->daemon->wpipe[0]) |
611 | MHD_connection_get_fdset (con, &rs, &ws, &es, &max); | 606 | { |
612 | num_ready = SELECT (max + 1, &rs, &ws, &es, &tv); | 607 | max = con->daemon->wpipe[0]; |
613 | if (num_ready < 0) { | 608 | FD_SET (con->daemon->wpipe[0], &rs); |
609 | } | ||
610 | else | ||
611 | max = 0; | ||
612 | MHD_connection_get_fdset (con, &rs, &ws, &es, &max); | ||
613 | num_ready = SELECT (max + 1, &rs, &ws, &es, tvp); | ||
614 | if (num_ready < 0) { | ||
614 | if (errno == EINTR) | 615 | if (errno == EINTR) |
615 | continue; | 616 | continue; |
616 | #if HAVE_MESSAGES | 617 | #if HAVE_MESSAGES |
@@ -618,52 +619,54 @@ MHD_handle_connection (void *data) | |||
618 | STRERROR (errno)); | 619 | STRERROR (errno)); |
619 | #endif | 620 | #endif |
620 | break; | 621 | break; |
621 | } | 622 | } |
622 | /* call appropriate connection handler if necessary */ | 623 | /* call appropriate connection handler if necessary */ |
623 | if ((con->socket_fd != -1) && (FD_ISSET (con->socket_fd, &rs))) | 624 | if ((con->socket_fd != -1) && (FD_ISSET (con->socket_fd, &rs))) |
624 | con->read_handler (con); | 625 | con->read_handler (con); |
625 | if ((con->socket_fd != -1) && (FD_ISSET (con->socket_fd, &ws))) | 626 | if ((con->socket_fd != -1) && (FD_ISSET (con->socket_fd, &ws))) |
626 | con->write_handler (con); | 627 | con->write_handler (con); |
627 | if (con->socket_fd != -1) | 628 | if (con->socket_fd != -1) |
628 | con->idle_handler (con); | 629 | con->idle_handler (con); |
629 | } | 630 | } |
630 | #ifdef HAVE_POLL_H | 631 | #ifdef HAVE_POLL_H |
631 | else | 632 | else |
632 | { | 633 | { |
633 | /* use poll */ | 634 | /* use poll */ |
634 | memset(&mp, 0, sizeof (struct MHD_Pollfd)); | 635 | memset(&mp, 0, sizeof (struct MHD_Pollfd)); |
635 | MHD_connection_get_pollfd(con, &mp); | 636 | MHD_connection_get_pollfd(con, &mp); |
636 | memset(&p, 0, sizeof (struct pollfd)); | 637 | memset(&p, 0, sizeof (p)); |
637 | p.fd = mp.fd; | 638 | p[0].fd = mp.fd; |
638 | if (mp.events & MHD_POLL_ACTION_IN) | 639 | if (mp.events & MHD_POLL_ACTION_IN) |
639 | p.events |= POLLIN; | 640 | p[0].events |= POLLIN; |
640 | if (mp.events & MHD_POLL_ACTION_OUT) | 641 | if (mp.events & MHD_POLL_ACTION_OUT) |
641 | p.events |= POLLOUT; | 642 | p[0].events |= POLLOUT; |
642 | /* in case we are missing the SIGALRM, keep going after | 643 | p[1].fd = con->daemon->wpipe[0]; |
643 | at most 1s */ | 644 | p[1].events |= POLLIN; |
644 | if (poll (&p, 1, 1000) < 0) { | 645 | |
645 | if (errno == EINTR) | 646 | if (poll (p, 2, (tvp == NULL) ? -1 : (tv.tv_sec * 1000)) < 0) |
646 | continue; | 647 | { |
648 | if (errno == EINTR) | ||
649 | continue; | ||
647 | #if HAVE_MESSAGES | 650 | #if HAVE_MESSAGES |
648 | MHD_DLOG (con->daemon, "Error during poll: `%s'\n", | 651 | MHD_DLOG (con->daemon, "Error during poll: `%s'\n", |
649 | STRERROR (errno)); | 652 | STRERROR (errno)); |
650 | #endif | 653 | #endif |
651 | break; | 654 | break; |
652 | } | 655 | } |
653 | if ( (con->socket_fd != -1) && | 656 | if ( (con->socket_fd != -1) && |
654 | (0 != (p.revents & POLLIN)) ) | 657 | (0 != (p[0].revents & POLLIN)) ) |
655 | con->read_handler (con); | 658 | con->read_handler (con); |
656 | if ( (con->socket_fd != -1) && | 659 | if ( (con->socket_fd != -1) && |
657 | (0 != (p.revents & POLLOUT)) ) | 660 | (0 != (p[0].revents & POLLOUT)) ) |
658 | con->write_handler (con); | 661 | con->write_handler (con); |
659 | if (con->socket_fd != -1) | 662 | if (con->socket_fd != -1) |
660 | con->idle_handler (con); | 663 | con->idle_handler (con); |
661 | if ( (con->socket_fd != -1) && | 664 | if ( (con->socket_fd != -1) && |
662 | (0 != (p.revents & (POLLERR | POLLHUP))) ) | 665 | (0 != (p[0].revents & (POLLERR | POLLHUP))) ) |
663 | MHD_connection_close (con, MHD_REQUEST_TERMINATED_WITH_ERROR); | 666 | MHD_connection_close (con, MHD_REQUEST_TERMINATED_WITH_ERROR); |
664 | } | 667 | } |
665 | #endif | 668 | #endif |
666 | } | 669 | } |
667 | if (con->socket_fd != -1) | 670 | if (con->socket_fd != -1) |
668 | { | 671 | { |
669 | #if DEBUG_CLOSE | 672 | #if DEBUG_CLOSE |
@@ -1085,7 +1088,7 @@ MHD_cleanup_connections (struct MHD_Daemon *daemon) | |||
1085 | prev->next = pos->next; | 1088 | prev->next = pos->next; |
1086 | if (0 != (pos->daemon->options & MHD_USE_THREAD_PER_CONNECTION)) | 1089 | if (0 != (pos->daemon->options & MHD_USE_THREAD_PER_CONNECTION)) |
1087 | { | 1090 | { |
1088 | pthread_kill (pos->pid, SIGALRM); | 1091 | |
1089 | if (0 != (rc = pthread_join (pos->pid, &unused))) | 1092 | if (0 != (rc = pthread_join (pos->pid, &unused))) |
1090 | { | 1093 | { |
1091 | #if HAVE_MESSAGES | 1094 | #if HAVE_MESSAGES |
@@ -1148,7 +1151,7 @@ MHD_get_timeout (struct MHD_Daemon *daemon, unsigned MHD_LONG_LONG *timeout) | |||
1148 | return MHD_NO; /* no connections */ | 1151 | return MHD_NO; /* no connections */ |
1149 | now = time (NULL); | 1152 | now = time (NULL); |
1150 | /* start with conservative estimate */ | 1153 | /* start with conservative estimate */ |
1151 | earliest_deadline = now + dto; | 1154 | earliest_deadline = now + dto + 1; |
1152 | while (pos != NULL) | 1155 | while (pos != NULL) |
1153 | { | 1156 | { |
1154 | if (earliest_deadline > pos->last_activity + dto) | 1157 | if (earliest_deadline > pos->last_activity + dto) |
@@ -1163,7 +1166,7 @@ MHD_get_timeout (struct MHD_Daemon *daemon, unsigned MHD_LONG_LONG *timeout) | |||
1163 | if (earliest_deadline < now) | 1166 | if (earliest_deadline < now) |
1164 | *timeout = 0; | 1167 | *timeout = 0; |
1165 | else | 1168 | else |
1166 | *timeout = (earliest_deadline - now); | 1169 | *timeout = 1000 * (1 + earliest_deadline - now); |
1167 | return MHD_YES; | 1170 | return MHD_YES; |
1168 | } | 1171 | } |
1169 | 1172 | ||
@@ -1185,6 +1188,7 @@ MHD_select (struct MHD_Daemon *daemon, int may_block) | |||
1185 | fd_set es; | 1188 | fd_set es; |
1186 | int max; | 1189 | int max; |
1187 | struct timeval timeout; | 1190 | struct timeval timeout; |
1191 | struct timeval *tv; | ||
1188 | unsigned MHD_LONG_LONG ltimeout; | 1192 | unsigned MHD_LONG_LONG ltimeout; |
1189 | int ds; | 1193 | int ds; |
1190 | 1194 | ||
@@ -1195,8 +1199,13 @@ MHD_select (struct MHD_Daemon *daemon, int may_block) | |||
1195 | FD_ZERO (&rs); | 1199 | FD_ZERO (&rs); |
1196 | FD_ZERO (&ws); | 1200 | FD_ZERO (&ws); |
1197 | FD_ZERO (&es); | 1201 | FD_ZERO (&es); |
1198 | max = 0; | 1202 | if (-1 != daemon->wpipe[0]) |
1199 | 1203 | { | |
1204 | max = daemon->wpipe[0]; | ||
1205 | FD_SET (daemon->wpipe[0], &rs); | ||
1206 | } | ||
1207 | else | ||
1208 | max = 0; | ||
1200 | if (0 == (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) | 1209 | if (0 == (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) |
1201 | { | 1210 | { |
1202 | /* single-threaded, go over everything */ | 1211 | /* single-threaded, go over everything */ |
@@ -1217,26 +1226,21 @@ MHD_select (struct MHD_Daemon *daemon, int may_block) | |||
1217 | FD_SET (max, &rs); | 1226 | FD_SET (max, &rs); |
1218 | } | 1227 | } |
1219 | 1228 | ||
1220 | /* in case we are missing the SIGALRM, keep going after | 1229 | tv = NULL; |
1221 | at most 1s; see http://lists.gnu.org/archive/html/libmicrohttpd/2009-10/msg00013.html */ | ||
1222 | timeout.tv_usec = 0; | ||
1223 | timeout.tv_sec = 1; | ||
1224 | if (may_block == MHD_NO) | 1230 | if (may_block == MHD_NO) |
1225 | { | 1231 | { |
1226 | timeout.tv_usec = 0; | 1232 | timeout.tv_usec = 0; |
1227 | timeout.tv_sec = 0; | 1233 | timeout.tv_sec = 0; |
1234 | tv = &timeout; | ||
1228 | } | 1235 | } |
1229 | else | 1236 | else if (MHD_YES == MHD_get_timeout (daemon, <imeout)) |
1230 | { | 1237 | { |
1231 | /* ltimeout is in ms */ | 1238 | /* ltimeout is in ms */ |
1232 | if ( (MHD_YES == MHD_get_timeout (daemon, <imeout)) && | 1239 | timeout.tv_usec = (ltimeout % 1000) * 1000; |
1233 | (ltimeout < 1000) ) | 1240 | timeout.tv_sec = ltimeout / 1000; |
1234 | { | 1241 | tv = &timeout; |
1235 | timeout.tv_usec = ltimeout * 1000; | ||
1236 | timeout.tv_sec = 0; | ||
1237 | } | ||
1238 | } | 1242 | } |
1239 | num_ready = SELECT (max + 1, &rs, &ws, &es, &timeout); | 1243 | num_ready = SELECT (max + 1, &rs, &ws, &es, tv); |
1240 | 1244 | ||
1241 | if (daemon->shutdown == MHD_YES) | 1245 | if (daemon->shutdown == MHD_YES) |
1242 | return MHD_NO; | 1246 | return MHD_NO; |
@@ -1279,38 +1283,93 @@ MHD_select (struct MHD_Daemon *daemon, int may_block) | |||
1279 | return MHD_YES; | 1283 | return MHD_YES; |
1280 | } | 1284 | } |
1281 | 1285 | ||
1286 | |||
1282 | /** | 1287 | /** |
1283 | * Poll for new connection. Used only with THREAD_PER_CONNECTION | 1288 | * Poll for new connection. |
1284 | * | 1289 | * |
1285 | * @param daemon daemon to run poll loop for | 1290 | * @param daemon daemon to run poll loop for |
1291 | * @param may_block YES if blocking, NO if non-blocking | ||
1292 | * @return MHD_NO on serious errors, MHD_YES on success | ||
1286 | */ | 1293 | */ |
1287 | static int | 1294 | static int |
1288 | MHD_poll (struct MHD_Daemon *daemon) | 1295 | MHD_poll (struct MHD_Daemon *daemon, |
1296 | int may_block) | ||
1289 | { | 1297 | { |
1290 | #ifdef HAVE_POLL_H | 1298 | #ifdef HAVE_POLL_H |
1291 | struct pollfd p; | 1299 | unsigned int num_connections; |
1292 | 1300 | struct MHD_Connection *pos; | |
1293 | if (0 == (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) | ||
1294 | return MHD_NO; | ||
1295 | p.fd = daemon->socket_fd; | ||
1296 | p.events = POLLIN; | ||
1297 | p.revents = 0; | ||
1298 | 1301 | ||
1299 | if (poll(&p, 1, 1000) < 0) { | 1302 | num_connections = 0; |
1300 | if (errno == EINTR) | 1303 | pos = daemon->connections; |
1301 | return MHD_YES; | 1304 | while (pos != NULL) |
1305 | { | ||
1306 | num_connections++; | ||
1307 | pos = pos->next; | ||
1308 | } | ||
1309 | { | ||
1310 | struct pollfd p[2 + num_connections]; | ||
1311 | struct MHD_Pollfd mp; | ||
1312 | unsigned MHD_LONG_LONG ltimeout; | ||
1313 | unsigned int i; | ||
1314 | int timeout; | ||
1315 | |||
1316 | p[0].fd = daemon->socket_fd; | ||
1317 | p[0].events = POLLIN; | ||
1318 | p[0].revents = 0; | ||
1319 | p[1].fd = daemon->wpipe[0]; | ||
1320 | p[1].events = POLLIN; | ||
1321 | p[1].revents = 0; | ||
1322 | if (may_block == MHD_NO) | ||
1323 | timeout = 0; | ||
1324 | else if (MHD_YES != MHD_get_timeout (daemon, <imeout)) | ||
1325 | timeout = -1; | ||
1326 | else | ||
1327 | timeout = (ltimeout > INT_MAX) ? INT_MAX : (int) ltimeout; | ||
1328 | |||
1329 | i = 0; | ||
1330 | pos = daemon->connections; | ||
1331 | while (pos != NULL) | ||
1332 | { | ||
1333 | memset(&mp, 0, sizeof (struct MHD_Pollfd)); | ||
1334 | MHD_connection_get_pollfd (pos, &mp); | ||
1335 | memset(&p, 0, sizeof (p)); | ||
1336 | p[2+i].fd = mp.fd; | ||
1337 | if (mp.events & MHD_POLL_ACTION_IN) | ||
1338 | p[2+i].events |= POLLIN; | ||
1339 | if (mp.events & MHD_POLL_ACTION_OUT) | ||
1340 | p[2+i].events |= POLLOUT; | ||
1341 | i++; | ||
1342 | pos = pos->next; | ||
1343 | } | ||
1344 | if (poll (p, 2 + num_connections, timeout) < 0) { | ||
1345 | if (errno == EINTR) | ||
1346 | return MHD_YES; | ||
1302 | #if HAVE_MESSAGES | 1347 | #if HAVE_MESSAGES |
1303 | MHD_DLOG (daemon, "poll failed: %s\n", STRERROR (errno)); | 1348 | MHD_DLOG (daemon, "poll failed: %s\n", STRERROR (errno)); |
1304 | #endif | 1349 | #endif |
1305 | return MHD_NO; | 1350 | return MHD_NO; |
1351 | } | ||
1352 | /* handle shutdown cases */ | ||
1353 | if (daemon->shutdown == MHD_YES) | ||
1354 | return MHD_NO; | ||
1355 | if (daemon->socket_fd < 0) | ||
1356 | return MHD_YES; | ||
1357 | if (0 != (p[0].revents & POLLIN)) | ||
1358 | MHD_accept_connection (daemon); | ||
1359 | i = 0; | ||
1360 | pos = daemon->connections; | ||
1361 | while (pos != NULL) | ||
1362 | { | ||
1363 | if (0 != (p[2+i].revents & POLLIN)) | ||
1364 | pos->read_handler (pos); | ||
1365 | if (0 != (p[2+i].revents & POLLOUT)) | ||
1366 | pos->write_handler (pos); | ||
1367 | if (pos->socket_fd != -1) | ||
1368 | pos->idle_handler (pos); | ||
1369 | i++; | ||
1370 | pos = pos->next; | ||
1371 | } | ||
1306 | } | 1372 | } |
1307 | /* handle shutdown cases */ | ||
1308 | if (daemon->shutdown == MHD_YES) | ||
1309 | return MHD_NO; | ||
1310 | if (daemon->socket_fd < 0) | ||
1311 | return MHD_YES; | ||
1312 | if (0 != (p.revents & POLLIN)) | ||
1313 | MHD_accept_connection (daemon); | ||
1314 | return MHD_YES; | 1373 | return MHD_YES; |
1315 | #else | 1374 | #else |
1316 | return MHD_NO; | 1375 | return MHD_NO; |
@@ -1335,7 +1394,10 @@ MHD_run (struct MHD_Daemon *daemon) | |||
1335 | & MHD_USE_THREAD_PER_CONNECTION)) | 1394 | & MHD_USE_THREAD_PER_CONNECTION)) |
1336 | || (0 != (daemon->options & MHD_USE_SELECT_INTERNALLY))) | 1395 | || (0 != (daemon->options & MHD_USE_SELECT_INTERNALLY))) |
1337 | return MHD_NO; | 1396 | return MHD_NO; |
1338 | MHD_select (daemon, MHD_NO); | 1397 | if ((daemon->options & MHD_USE_POLL) == 0) |
1398 | MHD_select (daemon, MHD_NO); | ||
1399 | else | ||
1400 | MHD_poll (daemon, MHD_NO); | ||
1339 | MHD_cleanup_connections (daemon); | 1401 | MHD_cleanup_connections (daemon); |
1340 | return MHD_YES; | 1402 | return MHD_YES; |
1341 | } | 1403 | } |
@@ -1357,7 +1419,7 @@ MHD_select_thread (void *cls) | |||
1357 | if ((daemon->options & MHD_USE_POLL) == 0) | 1419 | if ((daemon->options & MHD_USE_POLL) == 0) |
1358 | MHD_select (daemon, MHD_YES); | 1420 | MHD_select (daemon, MHD_YES); |
1359 | else | 1421 | else |
1360 | MHD_poll(daemon); | 1422 | MHD_poll (daemon, MHD_YES); |
1361 | MHD_cleanup_connections (daemon); | 1423 | MHD_cleanup_connections (daemon); |
1362 | } | 1424 | } |
1363 | return NULL; | 1425 | return NULL; |
@@ -1725,7 +1787,7 @@ MHD_start_daemon_va (unsigned int options, | |||
1725 | } | 1787 | } |
1726 | #endif | 1788 | #endif |
1727 | retVal->socket_fd = -1; | 1789 | retVal->socket_fd = -1; |
1728 | retVal->options = (enum MHD_OPTION)options; | 1790 | retVal->options = (enum MHD_OPTION) options; |
1729 | retVal->port = port; | 1791 | retVal->port = port; |
1730 | retVal->apc = apc; | 1792 | retVal->apc = apc; |
1731 | retVal->apc_cls = apc_cls; | 1793 | retVal->apc_cls = apc_cls; |
@@ -1735,6 +1797,37 @@ MHD_start_daemon_va (unsigned int options, | |||
1735 | retVal->pool_size = MHD_POOL_SIZE_DEFAULT; | 1797 | retVal->pool_size = MHD_POOL_SIZE_DEFAULT; |
1736 | retVal->unescape_callback = &MHD_http_unescape; | 1798 | retVal->unescape_callback = &MHD_http_unescape; |
1737 | retVal->connection_timeout = 0; /* no timeout */ | 1799 | retVal->connection_timeout = 0; /* no timeout */ |
1800 | retVal->wpipe[0] = -1; | ||
1801 | retVal->wpipe[1] = -1; | ||
1802 | if ( (0 != (options & MHD_USE_THREAD_PER_CONNECTION)) || | ||
1803 | (0 != (options & MHD_USE_SELECT_INTERNALLY)) ) | ||
1804 | { | ||
1805 | if (0 != pipe (retVal->wpipe)) | ||
1806 | { | ||
1807 | #if HAVE_MESSAGES | ||
1808 | FPRINTF(stderr, | ||
1809 | "Failed to create control pipe: %s\n", | ||
1810 | STRERROR (errno)); | ||
1811 | #endif | ||
1812 | free (retVal); | ||
1813 | return NULL; | ||
1814 | } | ||
1815 | #ifndef WINDOWS | ||
1816 | if ( (0 == (options & MHD_USE_POLL)) && | ||
1817 | (retVal->wpipe[0] >= FD_SETSIZE) ) | ||
1818 | { | ||
1819 | #if HAVE_MESSAGES | ||
1820 | FPRINTF(stderr, | ||
1821 | "file descriptor for control pipe exceeds maximum value\n"); | ||
1822 | #endif | ||
1823 | close (retVal->wpipe[0]); | ||
1824 | close (retVal->wpipe[1]); | ||
1825 | free (retVal); | ||
1826 | return NULL; | ||
1827 | } | ||
1828 | #endif | ||
1829 | } | ||
1830 | |||
1738 | #ifdef DAUTH_SUPPORT | 1831 | #ifdef DAUTH_SUPPORT |
1739 | retVal->digest_auth_rand_size = 0; | 1832 | retVal->digest_auth_rand_size = 0; |
1740 | retVal->digest_auth_random = NULL; | 1833 | retVal->digest_auth_random = NULL; |
@@ -1809,22 +1902,6 @@ MHD_start_daemon_va (unsigned int options, | |||
1809 | } | 1902 | } |
1810 | #endif | 1903 | #endif |
1811 | 1904 | ||
1812 | /* poll support currently only works with MHD_USE_THREAD_PER_CONNECTION */ | ||
1813 | if ( (0 != (options & MHD_USE_POLL)) && | ||
1814 | (0 == (options & MHD_USE_THREAD_PER_CONNECTION)) ) | ||
1815 | { | ||
1816 | #if HAVE_MESSAGES | ||
1817 | MHD_DLOG (retVal, | ||
1818 | "MHD poll support only works with MHD_USE_THREAD_PER_CONNECTION\n"); | ||
1819 | #endif | ||
1820 | #if DAUTH_SUPPORT | ||
1821 | free (retVal->nnc); | ||
1822 | pthread_mutex_destroy (&retVal->nnc_lock); | ||
1823 | #endif | ||
1824 | free (retVal); | ||
1825 | return NULL; | ||
1826 | } | ||
1827 | |||
1828 | /* Thread pooling currently works only with internal select thread model */ | 1905 | /* Thread pooling currently works only with internal select thread model */ |
1829 | if ( (0 == (options & MHD_USE_SELECT_INTERNALLY)) && | 1906 | if ( (0 == (options & MHD_USE_SELECT_INTERNALLY)) && |
1830 | (retVal->worker_pool_size > 0) ) | 1907 | (retVal->worker_pool_size > 0) ) |
@@ -2172,12 +2249,15 @@ MHD_stop_daemon (struct MHD_Daemon *daemon) | |||
2172 | int fd; | 2249 | int fd; |
2173 | unsigned int i; | 2250 | unsigned int i; |
2174 | int rc; | 2251 | int rc; |
2252 | char c; | ||
2175 | 2253 | ||
2176 | if (daemon == NULL) | 2254 | if (daemon == NULL) |
2177 | return; | 2255 | return; |
2178 | daemon->shutdown = MHD_YES; | 2256 | daemon->shutdown = MHD_YES; |
2179 | fd = daemon->socket_fd; | 2257 | fd = daemon->socket_fd; |
2180 | daemon->socket_fd = -1; | 2258 | daemon->socket_fd = -1; |
2259 | if (daemon->wpipe[1] != -1) | ||
2260 | write (daemon->wpipe[1], "e", 1); | ||
2181 | 2261 | ||
2182 | /* Prepare workers for shutdown */ | 2262 | /* Prepare workers for shutdown */ |
2183 | for (i = 0; i < daemon->worker_pool_size; ++i) | 2263 | for (i = 0; i < daemon->worker_pool_size; ++i) |
@@ -2202,8 +2282,6 @@ MHD_stop_daemon (struct MHD_Daemon *daemon) | |||
2202 | 2282 | ||
2203 | /* Signal workers to stop and clean them up */ | 2283 | /* Signal workers to stop and clean them up */ |
2204 | for (i = 0; i < daemon->worker_pool_size; ++i) | 2284 | for (i = 0; i < daemon->worker_pool_size; ++i) |
2205 | pthread_kill (daemon->worker_pool[i].pid, SIGALRM); | ||
2206 | for (i = 0; i < daemon->worker_pool_size; ++i) | ||
2207 | { | 2285 | { |
2208 | if (0 != (rc = pthread_join (daemon->worker_pool[i].pid, &unused))) | 2286 | if (0 != (rc = pthread_join (daemon->worker_pool[i].pid, &unused))) |
2209 | { | 2287 | { |
@@ -2221,7 +2299,6 @@ MHD_stop_daemon (struct MHD_Daemon *daemon) | |||
2221 | ((0 != (daemon->options & MHD_USE_SELECT_INTERNALLY)) | 2299 | ((0 != (daemon->options & MHD_USE_SELECT_INTERNALLY)) |
2222 | && (0 == daemon->worker_pool_size))) | 2300 | && (0 == daemon->worker_pool_size))) |
2223 | { | 2301 | { |
2224 | pthread_kill (daemon->pid, SIGALRM); | ||
2225 | if (0 != (rc = pthread_join (daemon->pid, &unused))) | 2302 | if (0 != (rc = pthread_join (daemon->pid, &unused))) |
2226 | { | 2303 | { |
2227 | #if HAVE_MESSAGES | 2304 | #if HAVE_MESSAGES |
@@ -2272,6 +2349,15 @@ MHD_stop_daemon (struct MHD_Daemon *daemon) | |||
2272 | pthread_mutex_destroy (&daemon->nnc_lock); | 2349 | pthread_mutex_destroy (&daemon->nnc_lock); |
2273 | #endif | 2350 | #endif |
2274 | pthread_mutex_destroy (&daemon->per_ip_connection_mutex); | 2351 | pthread_mutex_destroy (&daemon->per_ip_connection_mutex); |
2352 | |||
2353 | if (daemon->wpipe[1] != -1) | ||
2354 | { | ||
2355 | /* just to be sure, remove the one char we | ||
2356 | wrote into the pipe */ | ||
2357 | (void) read (daemon->wpipe[0], &c, 1); | ||
2358 | close (daemon->wpipe[0]); | ||
2359 | close (daemon->wpipe[1]); | ||
2360 | } | ||
2275 | free (daemon); | 2361 | free (daemon); |
2276 | } | 2362 | } |
2277 | 2363 | ||
@@ -2330,18 +2416,6 @@ MHD_get_version (void) | |||
2330 | return PACKAGE_VERSION; | 2416 | return PACKAGE_VERSION; |
2331 | } | 2417 | } |
2332 | 2418 | ||
2333 | #ifndef WINDOWS | ||
2334 | |||
2335 | static struct sigaction sig; | ||
2336 | |||
2337 | static struct sigaction old; | ||
2338 | |||
2339 | static void | ||
2340 | sigalrmHandler (int sig) | ||
2341 | { | ||
2342 | } | ||
2343 | #endif | ||
2344 | |||
2345 | #ifdef __GNUC__ | 2419 | #ifdef __GNUC__ |
2346 | #define ATTRIBUTE_CONSTRUCTOR __attribute__ ((constructor)) | 2420 | #define ATTRIBUTE_CONSTRUCTOR __attribute__ ((constructor)) |
2347 | #define ATTRIBUTE_DESTRUCTOR __attribute__ ((destructor)) | 2421 | #define ATTRIBUTE_DESTRUCTOR __attribute__ ((destructor)) |
@@ -2355,22 +2429,14 @@ GCRY_THREAD_OPTION_PTHREAD_IMPL; | |||
2355 | #endif | 2429 | #endif |
2356 | 2430 | ||
2357 | /** | 2431 | /** |
2358 | * Initialize the signal handler for SIGALRM | 2432 | * Initialize do setup work. |
2359 | * and do other setup work. | ||
2360 | */ | 2433 | */ |
2361 | void ATTRIBUTE_CONSTRUCTOR MHD_init () | 2434 | void ATTRIBUTE_CONSTRUCTOR MHD_init () |
2362 | { | 2435 | { |
2363 | mhd_panic = &mhd_panic_std; | 2436 | mhd_panic = &mhd_panic_std; |
2364 | mhd_panic_cls = NULL; | 2437 | mhd_panic_cls = NULL; |
2365 | 2438 | ||
2366 | #ifndef WINDOWS | 2439 | #ifdef WINDOWS |
2367 | /* make sure SIGALRM does not kill us */ | ||
2368 | memset (&sig, 0, sizeof (struct sigaction)); | ||
2369 | memset (&old, 0, sizeof (struct sigaction)); | ||
2370 | sig.sa_flags = SA_NODEFER; | ||
2371 | sig.sa_handler = &sigalrmHandler; | ||
2372 | sigaction (SIGALRM, &sig, &old); | ||
2373 | #else | ||
2374 | plibc_init ("GNU", "libmicrohttpd"); | 2440 | plibc_init ("GNU", "libmicrohttpd"); |
2375 | #endif | 2441 | #endif |
2376 | #if HTTPS_SUPPORT | 2442 | #if HTTPS_SUPPORT |
@@ -2388,9 +2454,7 @@ void ATTRIBUTE_DESTRUCTOR MHD_fini () | |||
2388 | if (0 != pthread_mutex_destroy(&MHD_gnutls_init_mutex)) | 2454 | if (0 != pthread_mutex_destroy(&MHD_gnutls_init_mutex)) |
2389 | mhd_panic (mhd_panic_cls, __FILE__, __LINE__, NULL); | 2455 | mhd_panic (mhd_panic_cls, __FILE__, __LINE__, NULL); |
2390 | #endif | 2456 | #endif |
2391 | #ifndef WINDOWS | 2457 | #ifdef WINDOWS |
2392 | sigaction (SIGALRM, &old, &sig); | ||
2393 | #else | ||
2394 | plibc_shutdown (); | 2458 | plibc_shutdown (); |
2395 | #endif | 2459 | #endif |
2396 | } | 2460 | } |
diff --git a/src/daemon/internal.h b/src/daemon/internal.h index 9a3eb8cb..ee499cef 100644 --- a/src/daemon/internal.h +++ b/src/daemon/internal.h | |||
@@ -857,6 +857,11 @@ struct MHD_Daemon | |||
857 | int socket_fd; | 857 | int socket_fd; |
858 | 858 | ||
859 | /** | 859 | /** |
860 | * Pipe we use to signal shutdown. | ||
861 | */ | ||
862 | int wpipe[2]; | ||
863 | |||
864 | /** | ||
860 | * Are we shutting down? | 865 | * Are we shutting down? |
861 | */ | 866 | */ |
862 | int shutdown; | 867 | int shutdown; |
diff --git a/src/examples/minimal_example.c b/src/examples/minimal_example.c index 9293242b..8c7d17d9 100644 --- a/src/examples/minimal_example.c +++ b/src/examples/minimal_example.c | |||
@@ -67,7 +67,10 @@ main (int argc, char *const *argv) | |||
67 | printf ("%s PORT\n", argv[0]); | 67 | printf ("%s PORT\n", argv[0]); |
68 | return 1; | 68 | return 1; |
69 | } | 69 | } |
70 | d = MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION | MHD_USE_DEBUG, | 70 | d = MHD_start_daemon (MHD_USE_SELECT_INTERNALLY | MHD_USE_DEBUG | MHD_USE_POLL, |
71 | // MHD_USE_SELECT_INTERNALLY | MHD_USE_DEBUG, | ||
72 | // MHD_USE_THREAD_PER_CONNECTION | MHD_USE_DEBUG | MHD_USE_POLL, | ||
73 | // MHD_USE_THREAD_PER_CONNECTION | MHD_USE_DEBUG, | ||
71 | atoi (argv[1]), | 74 | atoi (argv[1]), |
72 | NULL, NULL, &ahc_echo, PAGE, | 75 | NULL, NULL, &ahc_echo, PAGE, |
73 | MHD_OPTION_CONNECTION_TIMEOUT, (unsigned int) 5, | 76 | MHD_OPTION_CONNECTION_TIMEOUT, (unsigned int) 5, |
diff --git a/src/include/microhttpd.h b/src/include/microhttpd.h index 881ff312..3f3b61de 100644 --- a/src/include/microhttpd.h +++ b/src/include/microhttpd.h | |||
@@ -106,7 +106,7 @@ extern "C" | |||
106 | /** | 106 | /** |
107 | * Current version of the library. | 107 | * Current version of the library. |
108 | */ | 108 | */ |
109 | #define MHD_VERSION 0x00090702 | 109 | #define MHD_VERSION 0x00090703 |
110 | 110 | ||
111 | /** | 111 | /** |
112 | * MHD-internal return code for "YES". | 112 | * MHD-internal return code for "YES". |