diff options
Diffstat (limited to 'src/daemon/daemon.c')
-rw-r--r-- | src/daemon/daemon.c | 131 |
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 | |||
1326 | thread_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); |