cis-452-lab-5/writer.c

188 lines
5.3 KiB
C

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
/**************************************************************************
* 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);
}
}