aboutsummaryrefslogtreecommitdiff
path: root/src/daemon/daemon.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/daemon/daemon.c')
-rw-r--r--src/daemon/daemon.c131
1 files changed, 125 insertions, 6 deletions
diff --git a/src/daemon/daemon.c b/src/daemon/daemon.c
index 3c90f5b4..18775c46 100644
--- a/src/daemon/daemon.c
+++ b/src/daemon/daemon.c
@@ -1,6 +1,6 @@
1/* 1/*
2 This file is part of libmicrohttpd 2 This file is part of libmicrohttpd
3 (C) 2007, 2008 Daniel Pittman and Christian Grothoff 3 (C) 2007, 2008, 2009 Daniel Pittman and Christian Grothoff
4 4
5 This library is free software; you can redistribute it and/or 5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public 6 modify it under the terms of the GNU Lesser General Public
@@ -187,8 +187,8 @@ MHD_ip_limit_add(struct MHD_Daemon *daemon,
187 if (daemon->per_ip_connection_limit == 0) 187 if (daemon->per_ip_connection_limit == 0)
188 return MHD_YES; 188 return MHD_YES;
189 189
190 key = (struct MHD_IPCount*) malloc (sizeof(*key)); 190 key = malloc (sizeof(*key));
191 if (!key) 191 if (NULL == key)
192 return MHD_NO; 192 return MHD_NO;
193 193
194 /* Initialize key */ 194 /* Initialize key */
@@ -625,7 +625,7 @@ MHD_accept_connection (struct MHD_Daemon *daemon)
625#endif 625#endif
626#endif 626#endif
627 connection = malloc (sizeof (struct MHD_Connection)); 627 connection = malloc (sizeof (struct MHD_Connection));
628 if (connection == NULL) 628 if (NULL == connection)
629 { 629 {
630#if HAVE_MESSAGES 630#if HAVE_MESSAGES
631 MHD_DLOG (daemon, "Error allocating memory: %s\n", STRERROR (errno)); 631 MHD_DLOG (daemon, "Error allocating memory: %s\n", STRERROR (errno));
@@ -1017,6 +1017,7 @@ MHD_start_daemon_va (unsigned int options,
1017 const struct sockaddr *servaddr = NULL; 1017 const struct sockaddr *servaddr = NULL;
1018 socklen_t addrlen; 1018 socklen_t addrlen;
1019 enum MHD_OPTION opt; 1019 enum MHD_OPTION opt;
1020 unsigned int i;
1020 1021
1021 if ((port == 0) || (dh == NULL)) 1022 if ((port == 0) || (dh == NULL))
1022 return NULL; 1023 return NULL;
@@ -1080,6 +1081,9 @@ MHD_start_daemon_va (unsigned int options,
1080 va_arg (ap, LogCallback); 1081 va_arg (ap, LogCallback);
1081 retVal->uri_log_callback_cls = va_arg (ap, void *); 1082 retVal->uri_log_callback_cls = va_arg (ap, void *);
1082 break; 1083 break;
1084 case MHD_OPTION_THREAD_POOL_SIZE:
1085 retVal->worker_pool_size = va_arg (ap, unsigned int);
1086 break;
1083#if HTTPS_SUPPORT 1087#if HTTPS_SUPPORT
1084 case MHD_OPTION_PROTOCOL_VERSION: 1088 case MHD_OPTION_PROTOCOL_VERSION:
1085 _set_priority (&retVal->priority_cache->protocol, 1089 _set_priority (&retVal->priority_cache->protocol,
@@ -1126,6 +1130,17 @@ MHD_start_daemon_va (unsigned int options,
1126 } 1130 }
1127 } 1131 }
1128 1132
1133 /* Thread pooling currently works only with internal select thread model */
1134 if ((0 == (options & MHD_USE_SELECT_INTERNALLY))
1135 && (retVal->worker_pool_size > 0))
1136 {
1137#if HAVE_MESSAGES
1138 FPRINTF (stderr,
1139 "MHD thread pooling only works with MHD_USE_SELECT_INTERNALLY\n");
1140#endif
1141 return NULL;
1142 }
1143
1129 if ((options & MHD_USE_IPv6) != 0) 1144 if ((options & MHD_USE_IPv6) != 0)
1130#if HAVE_INET6 1145#if HAVE_INET6
1131 socket_fd = SOCKET (PF_INET6, SOCK_STREAM, 0); 1146 socket_fd = SOCKET (PF_INET6, SOCK_STREAM, 0);
@@ -1235,7 +1250,8 @@ MHD_start_daemon_va (unsigned int options,
1235 } 1250 }
1236#endif 1251#endif
1237 if (((0 != (options & MHD_USE_THREAD_PER_CONNECTION)) || 1252 if (((0 != (options & MHD_USE_THREAD_PER_CONNECTION)) ||
1238 (0 != (options & MHD_USE_SELECT_INTERNALLY))) 1253 ((0 != (options & MHD_USE_SELECT_INTERNALLY))
1254 && (0 == retVal->worker_pool_size)))
1239 && (0 != 1255 && (0 !=
1240 pthread_create (&retVal->pid, NULL, &MHD_select_thread, retVal))) 1256 pthread_create (&retVal->pid, NULL, &MHD_select_thread, retVal)))
1241 { 1257 {
@@ -1248,6 +1264,87 @@ MHD_start_daemon_va (unsigned int options,
1248 CLOSE (socket_fd); 1264 CLOSE (socket_fd);
1249 return NULL; 1265 return NULL;
1250 } 1266 }
1267 else if (retVal->worker_pool_size > 0)
1268 {
1269 /* Coarse-grained count of connections per thread (note error
1270 * due to integer division). Also keep track of how many
1271 * connections are leftover after an equal split. */
1272 unsigned int conns_per_thread = retVal->max_connections
1273 / retVal->worker_pool_size;
1274 unsigned int leftover_conns = retVal->max_connections
1275 % retVal->worker_pool_size;
1276
1277 /* Allocate memory for pooled objects */
1278 retVal->worker_pool = malloc (sizeof (*retVal->worker_pool)
1279 * retVal->worker_pool_size);
1280
1281 /* Start the workers in the pool */
1282 for (i = 0; i < retVal->worker_pool_size; ++i)
1283 {
1284 /* Create copy of the Daemon object for each worker */
1285 struct MHD_Daemon *d = (struct MHD_Daemon*) malloc (sizeof (*d));
1286 if (!d)
1287 {
1288#if HAVE_MESSAGES
1289 MHD_DLOG (retVal,
1290 "Failed to copy daemon object: %d\n", STRERROR (errno));
1291#endif
1292 goto thread_failed;
1293 }
1294 memcpy (d, retVal, sizeof (*d));
1295
1296 /* Adjust pooling params for worker daemons; note that memcpy()
1297 * has already copied MHD_USE_SELECT_INTERNALLY thread model into
1298 * the worker threads. */
1299 d->master = retVal;
1300 d->worker_pool_size = 0;
1301 d->worker_pool = NULL;
1302
1303 /* Divide available connections evenly amongst the threads.
1304 * Thread indexes in [0, leftover_conns) each get one of the
1305 * leftover connections. */
1306 d->max_connections = conns_per_thread;
1307 if (i < leftover_conns)
1308 ++d->max_connections;
1309
1310 /* Spawn the worker thread */
1311 if (0 != pthread_create (&d->pid, NULL, &MHD_select_thread, d))
1312 {
1313#if HAVE_MESSAGES
1314 MHD_DLOG (retVal,
1315 "Failed to create pool thread: %d\n", STRERROR (errno));
1316#endif
1317 /* Free memory for this worker; cleanup below handles
1318 * all previously-created workers. */
1319 free (d);
1320 goto thread_failed;
1321 }
1322
1323 retVal->worker_pool[i] = d;
1324 continue;
1325
1326thread_failed:
1327 /* If no worker threads created, then shut down normally. Calling
1328 * MHD_stop_daemon (as we do below) doesn't work here since it
1329 * assumes a 0-sized thread pool means we had been in the default
1330 * MHD_USE_SELECT_INTERNALLY mode. */
1331 if (i == 0)
1332 {
1333 CLOSE (socket_fd);
1334 pthread_mutex_destroy (&retVal->per_ip_connection_mutex);
1335 free (retVal);
1336 return NULL;
1337 }
1338
1339 /* Shutdown worker threads we've already created. Pretend
1340 * as though we had fully initialized our daemon, but
1341 * with a smaller number of threads than had been
1342 * requested. */
1343 retVal->worker_pool_size = i - 1;
1344 MHD_stop_daemon (retVal);
1345 return NULL;
1346 }
1347 }
1251 return retVal; 1348 return retVal;
1252} 1349}
1253 1350
@@ -1281,20 +1378,42 @@ MHD_stop_daemon (struct MHD_Daemon *daemon)
1281{ 1378{
1282 void *unused; 1379 void *unused;
1283 int fd; 1380 int fd;
1381 unsigned int i;
1284 1382
1285 if (daemon == NULL) 1383 if (daemon == NULL)
1286 return; 1384 return;
1287 daemon->shutdown = MHD_YES; 1385 daemon->shutdown = MHD_YES;
1288 fd = daemon->socket_fd; 1386 fd = daemon->socket_fd;
1289 daemon->socket_fd = -1; 1387 daemon->socket_fd = -1;
1388
1389 /* Prepare workers for shutdown */
1390 for (i = 0; i < daemon->worker_pool_size; ++i)
1391 {
1392 daemon->worker_pool[i]->shutdown = MHD_YES;
1393 daemon->worker_pool[i]->socket_fd = -1;
1394 }
1395
1290#if DEBUG_CLOSE 1396#if DEBUG_CLOSE
1291#if HAVE_MESSAGES 1397#if HAVE_MESSAGES
1292 MHD_DLOG (daemon, "MHD shutdown, closing listen socket\n"); 1398 MHD_DLOG (daemon, "MHD shutdown, closing listen socket\n");
1293#endif 1399#endif
1294#endif 1400#endif
1295 CLOSE (fd); 1401 CLOSE (fd);
1402
1403 /* Signal workers to stop and clean them up */
1404 for (i = 0; i < daemon->worker_pool_size; ++i)
1405 pthread_kill (daemon->worker_pool[i]->pid, SIGALRM);
1406 for (i = 0; i < daemon->worker_pool_size; ++i)
1407 {
1408 pthread_join (daemon->worker_pool[i]->pid, &unused);
1409 MHD_close_connections (daemon->worker_pool[i]);
1410 free (daemon->worker_pool[i]);
1411 }
1412 free (daemon->worker_pool);
1413
1296 if ((0 != (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) || 1414 if ((0 != (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) ||
1297 (0 != (daemon->options & MHD_USE_SELECT_INTERNALLY))) 1415 ((0 != (daemon->options & MHD_USE_SELECT_INTERNALLY))
1416 && (0 == daemon->worker_pool_size)))
1298 { 1417 {
1299 pthread_kill (daemon->pid, SIGALRM); 1418 pthread_kill (daemon->pid, SIGALRM);
1300 pthread_join (daemon->pid, &unused); 1419 pthread_join (daemon->pid, &unused);