diff --git a/src/connections.c b/src/connections.c index efc3b1c..8319023 100644 --- a/src/connections.c +++ b/src/connections.c @@ -32,36 +32,28 @@ #include #include -Connection *newConnection(int fd) { - Connection *ret = malloc(sizeof(Connection)); - if (ret == NULL) - return NULL; +int newConnection(int fd, Connection *ret) { ret->fd = fd; ret->progress = RECEIVE_REQUEST; ret->currLineAlloc = 30; ret->currLineLen = 0; ret->currLine = malloc(ret->currLineAlloc); - if (ret->currLine == NULL) { - free(ret); - return NULL; - } + if (ret->currLine == NULL) + return 1; ret->allocatedFields = 10; ret->fields = malloc(sizeof(Field) * ret->allocatedFields); if (ret->fields == NULL) { free(ret->currLine); - free(ret); - return NULL; + return 1; } ret->path = NULL; ret->body = NULL; //pointers to things that are allocated within functions should be //initialized to NULL so that free() doens't fail. - - ret->next = NULL; - return ret; + return 0; } void resetConnection(Connection *conn) { @@ -79,7 +71,6 @@ void freeConnection(Connection *conn) { free(conn->path); free(conn->fields); free(conn->body); - free(conn); } static int processRequest(Connection *conn) { diff --git a/src/include/connections.h b/src/include/connections.h index 4e057b1..afac43e 100644 --- a/src/include/connections.h +++ b/src/include/connections.h @@ -50,8 +50,6 @@ typedef struct Connection { size_t bodylen; size_t receivedBody; - struct Connection *next; - char *currLine; //persistent size_t currLineAlloc; @@ -62,7 +60,7 @@ typedef struct Connection { //Ephemeral fields: Things which are freed and reallocated after each new //request, path, body -Connection *newConnection(int fd); +int newConnection(int fd, Connection *ret); //returns non-zero on error. creates a new connection bound to fd void resetConnection(Connection *conn); void freeConnection(Connection *conn); diff --git a/src/include/runner.h b/src/include/runner.h index 00ff176..9fa20e9 100644 --- a/src/include/runner.h +++ b/src/include/runner.h @@ -27,11 +27,10 @@ typedef struct { int *pending; //pending[thread id] = the number of connections being handled by that // thread - int *schedule; + int notify; /* - * schedule[0] = the thread that should take the next connection (-1 if - * there is no connection). - * schedule[1] = the fd of the connection to be accepted + * When this runner should accept a connection, notify will contain an + * int ready to be read. */ int id; } RunnerArgs; diff --git a/src/main.c b/src/main.c index fed8ae5..064414e 100644 --- a/src/main.c +++ b/src/main.c @@ -103,21 +103,20 @@ int main(int argc, char **argv) { } int *pending = calloc(processes - 1, sizeof(int)); - int *schedule = malloc(2 * sizeof(int)); - if (schedule == NULL) - exit(EXIT_FAILURE); - schedule[0] = -1; + int (*notify)[2] = malloc(sizeof(int[2]) * (processes - 1)); pthread_t *threads = malloc(sizeof(pthread_t) * (processes - 1)); if (threads == NULL) exit(EXIT_FAILURE); for (int i = 0; i < processes - 1; i++) { + if (pipe(notify[i])) + exit(EXIT_FAILURE); RunnerArgs *args = malloc(sizeof(RunnerArgs)); if (args == NULL) exit(EXIT_FAILURE); args->site = site; args->pending = pending; - args->schedule = schedule; + args->notify = notify[i][0]; args->id = i; pthread_create(threads + i, NULL, (void*(*)(void*)) runServer, args); @@ -126,24 +125,23 @@ int main(int argc, char **argv) { for (;;) { fsync(fd); //TODO: Find out why this works - if (schedule[0] == -1) { - int newfd = accept(fd, (struct sockaddr *) &addr, - &addrlen); - if (newfd < 0) - exit(EXIT_FAILURE); - int flags = fcntl(newfd, F_GETFL); - if (fcntl(newfd, F_SETFL, flags | O_NONBLOCK)) - exit(EXIT_FAILURE); - int lowestThread = 0; - int lowestCount = pending[0]; - for (int i = 1; i < processes - 1; i++) { - if (pending[i] < lowestCount) { - lowestThread = i; - lowestCount = pending[i]; - } + int newfd = accept(fd, (struct sockaddr *) &addr, + &addrlen); + if (newfd < 0) + exit(EXIT_FAILURE); + int flags = fcntl(newfd, F_GETFL); + if (fcntl(newfd, F_SETFL, flags | O_NONBLOCK)) + exit(EXIT_FAILURE); + int lowestThread = 0; + int lowestCount = pending[0]; + for (int i = 1; i < processes - 1; i++) { + if (pending[i] < lowestCount) { + lowestThread = i; + lowestCount = pending[i]; } - schedule[1] = newfd; - schedule[0] = lowestThread; } + if (write(notify[lowestThread][1], &newfd, sizeof(newfd)) + < sizeof(newfd)) + exit(EXIT_FAILURE); } } diff --git a/src/runner.c b/src/runner.c index da07454..aff7d21 100644 --- a/src/runner.c +++ b/src/runner.c @@ -22,6 +22,7 @@ #include #include +#include #include #include #include @@ -33,49 +34,56 @@ void *runServer(RunnerArgs *args) { Sitefile *site = args->site; int *pending = args->pending; - int *schedule = args->schedule; + int notify = args->notify; int id = args->id; - Connection *connections = NULL; - Connection *last = NULL; - //Connections are processed in a queue, which is really just a linked - //list where we add to the end and read from the beginning. + int allocConns = 100; + struct pollfd *fds = malloc(sizeof(struct pollfd) * allocConns); + Connection *connections = malloc(sizeof(Connection) * allocConns); + assert(fds != NULL); + assert(connections != NULL); + fds[0].fd = notify; + fds[0].events = POLLIN; + int connCount = 1; + //connections are 1 indexed, this is because fds[0] is the notify fd. + for (;;) { - if (schedule[0] == id) { - Connection *newconn = newConnection(schedule[1]); - assert(newconn != NULL); + poll(fds, connCount, -1); - if (last == NULL) - connections = newconn; - else - last->next = newconn; - last = newconn; - pending[id]++; - schedule[0] = -1; - } - - Connection *prev = NULL; - Connection *iter = connections; - //I know of the Linus Thorvalds good taste code thing, it just - //gets very confusing very fast to think about pointers to - //pointers which have pointers. - while (iter != NULL) { - if (updateConnection(iter, site)) { - if (iter == last) - last = prev; - Connection *old = iter; - iter = iter->next; - freeConnection(old); - if (prev == NULL) - connections = iter; - else - prev->next = iter; + for (int i = 1; i < connCount; i++) { + if (updateConnection(connections + i, site)) { + connCount--; + memcpy(fds + i, fds + connCount, + sizeof(struct pollfd)); pending[id]--; } - else { - prev = iter; - iter = iter->next; + } + + if (fds[0].revents == POLLIN) { + if (connCount >= allocConns) { + allocConns *= 2; + struct pollfd *newfds = realloc(fds, + sizeof(struct pollfd) * allocConns); + if (newfds == NULL) + exit(EXIT_FAILURE); + fds = newfds; + + Connection *newconns = realloc(connections, + sizeof(Connection) * allocConns); + if (newconns == NULL) + exit(EXIT_FAILURE); + connections = newconns; } + int newfd; + if (read(notify, &newfd, sizeof(newfd)) < sizeof(newfd)) + exit(EXIT_FAILURE); + fds[connCount].fd = newfd; + fds[connCount].events = POLLIN; + + if (newConnection(newfd, connections + connCount)) + exit(EXIT_FAILURE); + connCount++; + pending[id]++; } } return NULL;