#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); } }