diff --git a/Main.c b/Main.c index bb8bd9f71e0789b8c1443522ce69a682a80ee52e..889467b456a7fd6094fdf04b1478e1de212d8095 100644 --- a/Main.c +++ b/Main.c @@ -27,18 +27,27 @@ #include <stdlib.h> #include <sys/types.h> #include <sys/socket.h> +#include <unistd.h> #include "apue.h" +#include "HelperHeader.h" // Define Vars. #define BUFFER_SIZE 4096 +#define THREAD_MAX 50 // Variables. +// pthread_cond_t thread_finished; +int threads_finished; +int thread_free[THREAD_MAX]; +int thread_joinable[THREAD_MAX]; +pthread_t* thread_array; // Method Declaration. -void* serve_request(); +void* serve_request(); // Handles processing of a request from a new thread. +void join_threads(); // Attempts to join all finished child threads. /** @@ -46,14 +55,15 @@ void* serve_request(); * Initializes and runs program. */ int main(int argc, char* argv[]) { + int index; int return_int; int listen_fd; int con_fd; + int thread_created; unsigned short port_number; char* media_path; struct sockaddr_in server_address; socklen_t address_len; - pthread_t* thread_array; pthread_attr_t attr; size_t stacksize; @@ -99,7 +109,7 @@ int main(int argc, char* argv[]) { err_sys("Failed to bind to socket."); } - // Actually listen for connections. + // Actually listen for connections. Holds a buffer of 10 connections, if they back up. return_int = listen(listen_fd, 10); if (return_int < 0) { err_sys("Error on listen attempt."); @@ -108,31 +118,104 @@ int main(int argc, char* argv[]) { printf("Successfully built socket. Setting up threading...\n"); // Setup threading. - thread_array = calloc(100, sizeof(pthread_t)); + thread_array = calloc(THREAD_MAX, sizeof(pthread_t)); pthread_attr_init(&attr); pthread_attr_getstacksize(&attr, &stacksize); if (stacksize < 8388608) { stacksize = 8388608; } pthread_attr_setstacksize(&attr, (stacksize * 2)); + // pthread_cond_init(&thread_finished, 0); + threads_finished = 0; + + for (index = 0; index < THREAD_MAX; index++) { + thread_free[index] = 1; + thread_joinable[index] = 0; + } printf("Threading established. Awaiting connection...\n"); // Run indefinitely, accepting new connections and creating new threads for each. while (1) { + // Check for successful connection. if ((con_fd = accept(listen_fd, (struct sockaddr*) &server_address, (socklen_t*) &address_len)) >= 0) { printf("Recieving request...\n"); + // Loop until new thread is created. + thread_created = 0; + while (thread_created == 0) { + // Search for first available thread. + index = 0; + while ((thread_created == 0) && (index < THREAD_MAX)) { + if (thread_free[index] == 1) { + // Found available thread. Changing thread status and exiting loop. + thread_free[index] = 0; + thread_created = 1; + printf("Thread found. Starting thread #%d\n", index); + } else { + // Thread not available. Check next. + index++; + } + } + + // Iterated through all possible threads. Check that an open one was found. + if (thread_created == 0) { + // No open thread found. + printf("No open threads found. Waiting 1 second and trying again...\n"); + sleep(1); + + // Check if any threads have finished. If so, join. + if (threads_finished == 1) { + join_threads(); + } + } + } + // A connection has been established. Open new thread. - pthread_create(&thread_array[0], &attr, serve_request, (void*) NULL); + pthread_create(&thread_array[0], &attr, serve_request, (void*) copy_int(&index)); + } + + // Check if any threads have finished. If so, join. + if (threads_finished == 1) { + join_threads(); } } } -void* serve_request() { - printf("Request recieved and thread created!\n"); - printf("Not doing anything about it though. Terminating thread.\n"); +/** + * Handles processing of a request from a new thread. + */ +void* serve_request(int* index) { + printf("\nRequest recieved and thread #%d created!\n", *index); + printf("Not doing anything about it though. Terminating thread.\n\n"); + + // Set values so that main can figure out what child threads are done executing. + threads_finished = 1; + thread_joinable[*index] = 1; + free(index); + + // Exit thread. pthread_exit((void*) NULL); } + + +/** + * Attempts to join all finished child threads. + */ +void join_threads() { + int index; + + printf("\nAttempting to join threads...\n"); + + for (index = 0; index < THREAD_MAX; index++) { + if (thread_joinable[index] == 1) { + pthread_join(thread_array[index], (void*) NULL); + thread_free[index] = 1; + thread_joinable[index] = 0; + printf("Joining thread #%d\n", index); + } + } + threads_finished = 0; +}