commit 56a368dbd14db50c5f11ae3b8c1a172df438fa0c Author: Amber Date: Sun Feb 21 21:22:21 2021 -0500 Initial commit. diff --git a/reader.c b/reader.c new file mode 100644 index 0000000..c0f2275 --- /dev/null +++ b/reader.c @@ -0,0 +1,244 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/************************************************************************** + * Authors: Gary Fleming, Amber McCloughan + * Class: CIS452 - Operating Systems Concepts + * Professor: Dr. Greg Wolffe + * Date: 2/20/2019 + * + * Program that reads to a shared memory segment. A reader process can have + * an ID of either 0 or 1. This is determined through program arguments. The + * readers wait for a writer to write something, print it, and then allow + * the writer to write again. + * + * The reader relies on the writer to create the shared memory segments. + * If the reader goes to get a shared memory segment and it hasn't been + * created, the program will end, asking the user to run the writer first. + * + * We keep track of which reader IDs are actually active using a flag + * array called "counter". If counter[0] is 0, no reader with ID 0 is up. + * Therefore, the writer process does not have to wait on that reader. + * + * The flag array "flag" determines synchronization. The writer + * must go, and then the readers. The writer cannot write to the shared + * memory segment if the readers are still reading. If flag[0] is 1, then + * the reader with ID 0 is still reading. The writer waits for both reader + * processes to set their flag element to 0 before it writes anything. + * + * To end the program, do a Ctrl + C. + ***************************************************************************/ + +// Max number of characters to read. +#define MAX_CHARS 1024 + +// See function implementation for more details. +void sigHandler(int); + +// The ID of this reader. Either 0 or 1, depending on argv. +int myId; + +// IDs for shared memory. +int bufId, flagId, counterId; + +// Shared memory buffer. +char *bufPtr; + +// Shared memory flags. +int *flagPtr; + +// Shared memory for reader IDs. +int *counterPtr; + +// Local buffer. +char *localBuf; + +/** + * Main function of the reader program. Takes in + * an argument, which is the ID of the reader. + * This can be either 0 or 1. + * + * @param argc, number of arguments. + * @param argv, the actual arguments. + */ +int main(int argc, char *argv[]) +{ + // Ensuring ID argument exists. + if (argc < 2) + { + printf("Please provide either a 0 or 1 as an argument for ID.\n"); + return 1; + } + + // Binding signal handler for keyboard interrupt. + signal(SIGINT, sigHandler); + + // Initializing the local buffer. + localBuf = malloc(sizeof(char) * MAX_CHARS); + + // Determining shared memory keys. + key_t bufKey = ftok("Writer.c", 10); + key_t flagKey = ftok("Writer.c", 20); + key_t counterKey = ftok("Writer.c", 30); + + // Getting shared memory. + if ((bufId = shmget(bufKey, sizeof(char) * MAX_CHARS, S_IRUSR | S_IWUSR)) < 0) + { + perror("Shared memory get failed for buffer... Did the writer create it?\n"); + exit(1); + } + if ((flagId = shmget(flagKey, sizeof(int) * 2, S_IRUSR | S_IWUSR)) < 0) + { + perror("Shared memory get failed for flag... Did the writer create it?\n"); + exit(1); + } + if ((counterId = shmget(counterKey, sizeof(int) * 2, S_IRUSR | S_IWUSR)) < 0) + { + perror("Shared memory get failed for the counter... Did the writer create it?\n"); + exit(1); + } + + // Attaching shared memory. + if ((bufPtr = shmat(bufId, 0, 0)) == (void *)-1) + { + perror("Couldn't attach buffer pointer...\n"); + exit(1); + } + if ((flagPtr = shmat(flagId, 0, 0)) == (void *)-1) + { + perror("Couldn't attach flag pointer...\n"); + exit(1); + } + if ((counterPtr = shmat(counterId, 0, 0)) == (void *)-1) + { + perror("Couldn't attach counter pointer...\n"); + exit(1); + } + + // Determining ID based on arguments. + if (atoi(argv[1]) == 0) + { + if (counterPtr[0] == 1) + { + printf("Reader with ID 0 already exists. Please use the other ID.\n"); + + // Detaching shared memory segments. + if (shmdt(bufPtr) < 0) + { + perror("Couldn't detach buffer memory.\n"); + exit(1); + } + if (shmdt(flagPtr) < 0) + { + perror("Couldn't detach flag memory.\n"); + exit(1); + } + if (shmdt(counterPtr) < 0) + { + perror("Couldn't detach counter memory.\n"); + exit(1); + } + exit(1); + } + myId = 0; + counterPtr[0] = 1; + } + else + { + if (counterPtr[1] == 1) + { + printf("Reader with ID 1 already exists. Please use the other ID.\n"); + + // Detaching shared memory segments. + if (shmdt(bufPtr) < 0) + { + perror("Couldn't detach buffer memory.\n"); + exit(1); + } + if (shmdt(flagPtr) < 0) + { + perror("Couldn't detach flag memory.\n"); + exit(1); + } + if (shmdt(counterPtr) < 0) + { + perror("Couldn't detach counter memory.\n"); + exit(1); + } + exit(1); + } + myId = 1; + counterPtr[1] = 1; + } + + // Reading loop. + while (1) + { + // Wait until writer writes something. + while (flagPtr[myId] != 1) + ; + + // Reading from buffer. + strcpy(localBuf, bufPtr); + + // I'm done with my critical section. + flagPtr[myId] = 0; + + // Print out what the writer wrote. + printf("%s\n", localBuf); + } + + // Exit. + return 0; +} + +/** + * 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"); + + // Turning off different flags. + counterPtr[myId] = 0; + flagPtr[myId] = 0; + + // Freeing local buffer. + free(localBuf); + + // Detaching shared memory segments. + if (shmdt(bufPtr) < 0) + { + perror("Couldn't detach buffer memory.\n"); + exit(1); + } + if (shmdt(flagPtr) < 0) + { + perror("Couldn't detach flag memory.\n"); + exit(1); + } + if (shmdt(counterPtr) < 0) + { + perror("Couldn't detach counter memory.\n"); + exit(1); + } + + // Exiting program. + exit(0); + } +} \ No newline at end of file diff --git a/writer.c b/writer.c new file mode 100644 index 0000000..997002b --- /dev/null +++ b/writer.c @@ -0,0 +1,188 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/************************************************************************** + * Authors: Gary Fleming, Amber McCloughan + * Class: CIS452 - Operating Systems Concepts + * Professor: Dr. Greg Wolffe + * Date: 2/21/2019 + * + * Program that writes to a shared memory segment. In charge of creating + * the segments and reading user input into them. Can only write if both + * readers are not reading (lockstep synchronization). + * + * We keep track of which reader IDs are actually active using a flag + * array called "counter". If counter[0] is 0, no reader with ID 0 is up. + * Therefore, the writer process does not have to wait on that reader. + * + * The flag array "flag" determines synchronization. The writer + * must go, and then the readers. The writer cannot write to the shared + * memory segment if the readers are still reading. If flag[0] is 1, then + * the reader with ID 0 is still reading. The writer waits for both reader + * processes to set their flag element to 0 before it writes anything. + * + * To end the program, do a Ctrl + C. + ***************************************************************************/ + +// Max number of characters to be read. +#define MAX_CHARS 1024 + +// See function implementation for details. +void sigHandler(int); + +// Shared memory IDs. +int bufId, flagId, counterId; + +// Shared memory segment for buffer. +char *bufPtr; + +// Shared memory segment for flags. +int *flagPtr; + +// Shared memory segment for reader IDs. +int *counterPtr; + +// Local buffer for user input. +char *localBuf; + +int main() +{ + // Binding signal handler for keyboard interrupt. + signal(SIGINT, sigHandler); + + // Initializing local buffer. + localBuf = malloc(sizeof(char) * MAX_CHARS); + + // Determining shared memory keys. + key_t bufKey = ftok("Writer.c", 10); + key_t flagKey = ftok("Writer.c", 20); + key_t counterKey = ftok("Writer.c", 30); + + // Creating shared memory segments. + if ((bufId = shmget(bufKey, sizeof(char) * MAX_CHARS, IPC_CREAT | IPC_EXCL | S_IRUSR | S_IWUSR)) < 0) + { + perror("Shared memory get failed... Are processes from a previous session still running?\n"); + exit(1); + } + if ((flagId = shmget(flagKey, sizeof(int) * 2, IPC_CREAT | IPC_EXCL | S_IRUSR | S_IWUSR)) < 0) + { + perror("Shared memory get failed... Are processes from a previous session still running?\n"); + exit(1); + } + if ((counterId = shmget(counterKey, sizeof(int) * 2, IPC_CREAT | IPC_EXCL | S_IRUSR | S_IWUSR)) < 0) + { + perror("Shared memory get failed... Are processes from a previous session still running?\n"); + exit(1); + } + + // Attaching shared memory segments. + if ((bufPtr = shmat(bufId, 0, 0)) == (void *)-1) + { + perror("can't attach\n"); + exit(1); + } + if ((flagPtr = shmat(flagId, 0, 0)) == (void *)-1) + { + perror("can't attach\n"); + exit(1); + } + if ((counterPtr = shmat(counterId, 0, 0)) == (void *)-1) + { + perror("can't attach\n"); + exit(1); + } + + // Writing loop. + while (1) + { + // Reading from user input. + fgets(localBuf, MAX_CHARS, stdin); + + // Removing newline character from input. + strtok(localBuf, "\n"); + + // Waiting on any readers to finish up before writing. + while (flagPtr[0] != 0 || flagPtr[1] != 0) + ; + + // Writing local buffer into shared memory. + strcpy(bufPtr, localBuf); + + /* + * Readers, you may read now. If a reader at a given ID + * does not exist, we don't set their flag to 1. This + * is why we used counterPtr, which keeps track of if + * a reader is active at a given ID. This allows for 1 + * writer and 1 reader if you desire. + */ + flagPtr[0] = counterPtr[0]; + flagPtr[1] = counterPtr[1]; + } + + // Exit. + return 0; +} + +/** + * 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"); + + // Freeing local buffer. + free(localBuf); + + // Flagging shared memory segments for deletion. + if (shmctl(bufId, IPC_RMID, 0) < 0) + { + perror("can't deallocate #1\n"); + exit(1); + } + if (shmctl(flagId, IPC_RMID, 0) < 0) + { + perror("can't deallocate #2\n"); + exit(1); + } + if (shmctl(counterId, IPC_RMID, 0) < 0) + { + perror("can't deallocate #3\n"); + exit(1); + } + + // Detaching shared memory segments. + if (shmdt(bufPtr) < 0) + { + perror("just can't let go #1\n"); + exit(1); + } + if (shmdt(flagPtr) < 0) + { + perror("just can't let go #2\n"); + exit(1); + } + if (shmdt(counterPtr) < 0) + { + perror("just can't let go #3\n"); + exit(1); + } + + // Exiting program. + exit(0); + } +} \ No newline at end of file