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