172 lines
4.3 KiB
C
172 lines
4.3 KiB
C
#include <pthread.h>
|
|
#include <stdio.h>
|
|
#include <errno.h>
|
|
#include <unistd.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <signal.h>
|
|
|
|
/**************************************************************************
|
|
* Authors: Gary Fleming, Amber McCloughan
|
|
* Class: CIS452 - Operating Systems Concepts
|
|
* Professor: Dr. Greg Wolffe
|
|
* Date: 2/14/2019
|
|
*
|
|
* Program that starts out with a dispatcher thread. This thread
|
|
* waits on user input. When it receives a filename string from
|
|
* the user, it spawns a worker thread that goes out to
|
|
* "retrieve" the filename from the "file server". On an exit,
|
|
* the program prints statistics about files serviced.
|
|
*
|
|
* To end the program, do a Ctrl + C.
|
|
***************************************************************************/
|
|
|
|
// Input limit.
|
|
#define CHAR_LIMIT 1024
|
|
|
|
// See function implementations for information.
|
|
void *file_request(void *arg);
|
|
void sigHandler(int);
|
|
|
|
// File counter.
|
|
int counter;
|
|
|
|
// File access time counter.
|
|
int timeCounter;
|
|
|
|
// Mutex.
|
|
pthread_mutex_t lock;
|
|
|
|
// Input buffer.
|
|
char *input;
|
|
|
|
/**
|
|
* The main function for driving the program.
|
|
*/
|
|
int main()
|
|
{
|
|
// Seeding randomness.
|
|
srand(time(NULL));
|
|
|
|
/*
|
|
* Initializing the mutex.
|
|
* I figured out how to do this using the following article:
|
|
* https://www.geeksforgeeks.org/mutex-lock-for-linux-thread-synchronization/
|
|
*/
|
|
pthread_mutex_init(&lock, NULL);
|
|
|
|
// Thread ID holder.
|
|
pthread_t thread1;
|
|
|
|
// Status variable for checking if pthread_create failed.
|
|
int status;
|
|
|
|
// Initializing file counter.
|
|
counter = 0;
|
|
|
|
// Allocating memory for input buffer.
|
|
input = malloc(CHAR_LIMIT * sizeof(char));
|
|
|
|
// Binding signal handler for keyboard interrupt.
|
|
signal(SIGINT, sigHandler);
|
|
|
|
// The dispatching loop.
|
|
while (1)
|
|
{
|
|
// User input for filename.
|
|
fprintf(stderr, "Enter file name: ");
|
|
input = fgets(input, CHAR_LIMIT, stdin);
|
|
|
|
// Removing newline character from input.
|
|
strtok(input, "\n");
|
|
|
|
// Spawning a thread to deal with the "file" requested.
|
|
if ((status = pthread_create(&thread1, NULL, file_request, strdup(input))) != 0)
|
|
{
|
|
fprintf(stderr, "Thread creation error %d: %s.\n", status, strerror(status));
|
|
exit(1);
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* Function executed by worked threads. Randomly decides
|
|
* whether the "file" can be accessed from the disk cache
|
|
* (80% chance) or if it has to be fetched from the hard
|
|
* drive (20% chance). If the "file" is accessed from cache,
|
|
* the thread sleeps for a second. If the "file" is accessed
|
|
* from the hard drive, the thread sleeps for 7-10 seconds.
|
|
* A mutex is used to ensure mutual exclusion for writes.
|
|
*
|
|
* @param arg, the name of the "file" to be handled by the
|
|
* worker thread.
|
|
*/
|
|
void *file_request(void *arg)
|
|
{
|
|
// Probability roll for HDD or cache.
|
|
int val = (rand() % 5) + 1;
|
|
|
|
// Variable used for sleep time.
|
|
int val2;
|
|
|
|
// File accessed from disk.
|
|
if (val == 5)
|
|
{
|
|
// 7-10 seconds.
|
|
val2 = (rand() % 4) + 7;
|
|
}
|
|
// File accessed from cache.
|
|
else
|
|
{
|
|
// 1 second.
|
|
val2 = 1;
|
|
}
|
|
|
|
// Sleep for seconds decided on above.
|
|
sleep(val2);
|
|
|
|
// Serving the file.
|
|
fprintf(stderr, "\nServing file \"%s\" after %i seconds.\n", (char *)arg, val2);
|
|
|
|
// Writing to global variables. Mutex lock!
|
|
pthread_mutex_lock(&lock);
|
|
counter++;
|
|
timeCounter += val2;
|
|
pthread_mutex_unlock(&lock);
|
|
|
|
// Freeing allocated memory.
|
|
free(arg);
|
|
|
|
// Goodbye (no need to return anything).
|
|
return NULL;
|
|
}
|
|
|
|
/**
|
|
* Handler for signals. Bound for the one signal handled
|
|
* in this application: SIGINT (program interrupt signal ^C).
|
|
*
|
|
* @param sigNum, the identifying number of the signal
|
|
* sent and now being handled. According to the
|
|
* man page for signal, SIGINT = 2.
|
|
*/
|
|
void sigHandler(int sigNum)
|
|
{
|
|
if (sigNum == SIGINT)
|
|
{
|
|
// Exit message.
|
|
printf(" received. That's it, I'm shutting you down...\n");
|
|
printf("Files serviced: %i.\n", counter);
|
|
printf("Avg. file access time: %lf seconds.\n", (double)timeCounter / (double)counter);
|
|
|
|
// Destroying mutex.
|
|
pthread_mutex_destroy(&lock);
|
|
|
|
// Freeing user input pointer.
|
|
free(input);
|
|
|
|
// Exiting program.
|
|
exit(0);
|
|
}
|
|
} |