summaryrefslogtreecommitdiffhomepage
path: root/src/child.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/child.c')
-rw-r--r--src/child.c119
1 files changed, 54 insertions, 65 deletions
diff --git a/src/child.c b/src/child.c
index 15d4fe8..985357d 100644
--- a/src/child.c
+++ b/src/child.c
@@ -33,25 +33,27 @@
#include "conf.h"
#include "sblist.h"
#include "loop.h"
+#include "conns.h"
+#include "mypoll.h"
#include <pthread.h>
-static vector_t listen_fds;
+static sblist* listen_fds;
struct client {
union sockaddr_union addr;
- int fd;
};
struct child {
pthread_t thread;
struct client client;
+ struct conn_s conn;
volatile int done;
};
static void* child_thread(void* data)
{
struct child *c = data;
- handle_connection (c->client.fd, &c->client.addr);
+ handle_connection (&c->conn, &c->client.addr);
c->done = 1;
return NULL;
}
@@ -80,19 +82,24 @@ void child_main_loop (void)
union sockaddr_union cliaddr_storage;
struct sockaddr *cliaddr = (void*) &cliaddr_storage;
socklen_t clilen = sizeof(cliaddr_storage);
- fd_set rfds;
+ int nfds = sblist_getsize(listen_fds);
+ pollfd_struct *fds = safecalloc(nfds, sizeof *fds);
ssize_t i;
- int ret, listenfd, maxfd, was_full = 0;
+ int ret, listenfd, was_full = 0;
pthread_attr_t *attrp, attr;
struct child *child;
childs = sblist_new(sizeof (struct child*), config->maxclients);
- loop_records_init();
+ for (i = 0; i < nfds; i++) {
+ int *fd = sblist_get(listen_fds, i);
+ fds[i].fd = *fd;
+ fds[i].events |= MYPOLL_READ;
+ }
/*
* We have to wait for connections on multiple fds,
- * so use select.
+ * so use select/poll/whatever.
*/
while (!config->quit) {
@@ -110,7 +117,6 @@ void child_main_loop (void)
was_full = 0;
listenfd = -1;
- maxfd = 0;
/* Handle log rotation if it was requested */
if (received_sighup) {
@@ -124,62 +130,35 @@ void child_main_loop (void)
received_sighup = FALSE;
}
+ ret = mypoll(fds, nfds, -1);
- FD_ZERO(&rfds);
-
- for (i = 0; i < vector_length(listen_fds); i++) {
- int *fd = (int *) vector_getentry(listen_fds, i, NULL);
-
- ret = socket_nonblocking(*fd);
- if (ret != 0) {
- log_message(LOG_ERR, "Failed to set the listening "
- "socket %d to non-blocking: %s",
- fd, strerror(errno));
- continue;
- }
-
- FD_SET(*fd, &rfds);
- maxfd = max(maxfd, *fd);
- }
-
- ret = select(maxfd + 1, &rfds, NULL, NULL, NULL);
if (ret == -1) {
if (errno == EINTR) {
continue;
}
- log_message (LOG_ERR, "error calling select: %s",
+ log_message (LOG_ERR, "error calling " SELECT_OR_POLL ": %s",
strerror(errno));
continue;
} else if (ret == 0) {
- log_message (LOG_WARNING, "Strange: select returned 0 "
+ log_message (LOG_WARNING, "Strange: " SELECT_OR_POLL " returned 0 "
"but we did not specify a timeout...");
continue;
}
- for (i = 0; i < vector_length(listen_fds); i++) {
- int *fd = (int *) vector_getentry(listen_fds, i, NULL);
-
- if (FD_ISSET(*fd, &rfds)) {
+ for (i = 0; i < nfds; i++) {
+ if (fds[i].revents & MYPOLL_READ) {
/*
* only accept the connection on the first
* fd that we find readable. - fair?
*/
- listenfd = *fd;
+ listenfd = fds[i].fd;
break;
}
}
if (listenfd == -1) {
log_message(LOG_WARNING, "Strange: None of our listen "
- "fds was readable after select");
- continue;
- }
-
- ret = socket_blocking(listenfd);
- if (ret != 0) {
- log_message(LOG_ERR, "Failed to set listening "
- "socket %d to blocking for accept: %s",
- listenfd, strerror(errno));
+ "fds was readable after " SELECT_OR_POLL);
continue;
}
@@ -201,7 +180,7 @@ void child_main_loop (void)
continue;
}
- child = safemalloc(sizeof(struct child));
+ child = safecalloc(1, sizeof(struct child));
if (!child) {
oom:
close(connfd);
@@ -218,7 +197,9 @@ oom:
goto oom;
}
- child->client.fd = connfd;
+ conn_struct_init(&child->conn);
+ child->conn.client_fd = connfd;
+
memcpy(&child->client.addr, &cliaddr_storage, sizeof(cliaddr_storage));
attrp = 0;
@@ -233,6 +214,7 @@ oom:
goto oom;
}
}
+ safefree(fds);
}
/*
@@ -240,40 +222,48 @@ oom:
*/
void child_kill_children (int sig)
{
- size_t i;
+ size_t i, tries = 0;
if (sig != SIGTERM) return;
+ log_message (LOG_INFO,
+ "trying to bring down %zu threads...",
+ sblist_getsize(childs)
+ );
+
+again:
for (i = 0; i < sblist_getsize(childs); i++) {
struct child *c = *((struct child**)sblist_get(childs, i));
- if (!c->done) {
- /* interrupt blocking operations.
- this should cause the threads to shutdown orderly. */
- close(c->client.fd);
- }
+ if (!c->done) pthread_kill(c->thread, SIGCHLD);
}
- usleep(16);
+ usleep(8192);
collect_threads();
if (sblist_getsize(childs) != 0)
+ if(tries++ < 8) goto again;
+ if (sblist_getsize(childs) != 0)
log_message (LOG_CRIT,
"child_kill_children: %zu threads still alive!",
sblist_getsize(childs)
);
}
+void child_free_children(void) {
+ sblist_free(childs);
+ childs = 0;
+}
/**
* Listen on the various configured interfaces
*/
-int child_listening_sockets(vector_t listen_addrs, uint16_t port)
+int child_listening_sockets(sblist *listen_addrs, uint16_t port)
{
int ret;
- ssize_t i;
+ size_t i;
assert (port > 0);
if (listen_fds == NULL) {
- listen_fds = vector_create();
+ listen_fds = sblist_new(sizeof(int), 16);
if (listen_fds == NULL) {
log_message (LOG_ERR, "Could not create the list "
"of listening fds");
@@ -281,8 +271,7 @@ int child_listening_sockets(vector_t listen_addrs, uint16_t port)
}
}
- if ((listen_addrs == NULL) ||
- (vector_length(listen_addrs) == 0))
+ if (!listen_addrs || !sblist_getsize(listen_addrs))
{
/*
* no Listen directive:
@@ -292,17 +281,17 @@ int child_listening_sockets(vector_t listen_addrs, uint16_t port)
return ret;
}
- for (i = 0; i < vector_length(listen_addrs); i++) {
- const char *addr;
+ for (i = 0; i < sblist_getsize(listen_addrs); i++) {
+ char **addr;
- addr = (char *)vector_getentry(listen_addrs, i, NULL);
- if (addr == NULL) {
+ addr = sblist_get(listen_addrs, i);
+ if (!addr || !*addr) {
log_message(LOG_WARNING,
"got NULL from listen_addrs - skipping");
continue;
}
- ret = listen_sock(addr, port, listen_fds);
+ ret = listen_sock(*addr, port, listen_fds);
if (ret != 0) {
return ret;
}
@@ -313,14 +302,14 @@ int child_listening_sockets(vector_t listen_addrs, uint16_t port)
void child_close_sock (void)
{
- ssize_t i;
+ size_t i;
- for (i = 0; i < vector_length(listen_fds); i++) {
- int *fd = (int *) vector_getentry(listen_fds, i, NULL);
+ for (i = 0; i < sblist_getsize(listen_fds); i++) {
+ int *fd = sblist_get(listen_fds, i);
close (*fd);
}
- vector_delete(listen_fds);
+ sblist_free(listen_fds);
listen_fds = NULL;
}