coord.c - The parent program
Code
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <unistd.h>
#include <wait.h>
#include <string.h>
#include <time.h>
#include <signal.h>
#include "helper.h"
//GLOBALLY DEFINED VARIABLES (explained in README)
int *A_SHARE;
int *B_SHARE;
int *C_SHARE;
struct shminfo *info;
pid_t *pids;
int INFO_ID, n;
int matSize(FILE *file, struct shminfo *info, int flag);
int getShm(int size);
void processLimit(int *p, FILE *f);
void handler(int sig);
void cleanUp(int *A_SHARE, int *B_SHARE, int *C_SHARE, int *flags, int INFO_ID, struct shminfo *info, pid_t *pids);
int main(int argc, char *argv[]) {
int k, j, size, opt, compTime, c_id = 0, totalProcess = 0;
char arg1[10];
char arg2[10];
char arg3[10];
char arg4[10];
FILE *f, *p;
//Catch signals INT and ALRM for handling
signal(SIGALRM, handler);
signal(SIGINT, handler);
signal(SIGQUIT, SIG_IGN);
signal(SIGTSTP, SIG_IGN);
signal(SIGABRT, SIG_IGN);
//Seed the random num generator (for use later when trying to seed sleep() inside of worker processes.
srand(time(NULL));
//Set default computation time
compTime = 100;
while ((opt = getopt (argc, argv, "ht:")) != -1) {
switch(opt) {
case 'h':
printf("Proper usage: coord [-t:] [Matrix A] [Matrix B] [Matrix C]\n");
printf("Please use the format for matricies A and B specified in the README\n");
exit(0);
case 't':
compTime = atoi(optarg);
break;
default:
break;
}
}
//Create various shared memory segments for the matricies, attach them and store their IDs
INFO_ID = shmget( IPC_PRIVATE, sizeof(struct shminfo), IPC_CREAT | IPC_EXCL | 0777);
if ( INFO_ID == -1 ) {
perror("coord: Error");
exit(1);
}
//Attach ID for our information struct
info = (struct shminfo *)shmat(INFO_ID, 0, 0);
f = fopen(argv[optind], "r");
size = matSize(f, info, 0);
info->A_ID = getShm(size);
A_SHARE = (int *)shmat(info->A_ID, 0, 0);
for (k = 0; k < size; k++) {
fscanf(f, "%d", &A_SHARE[k]);
}
f = fopen(argv[optind + 1], "r");
size = matSize(f, info, 1);
info->B_ID = getShm(size);
B_SHARE = (int *)shmat(info->B_ID, 0, 0);
for (k = 0; k < size; k++) {
fscanf(f, "%d", &B_SHARE[k]);
}
info->FLAGS_ID = shmget( IPC_PRIVATE, info->A_COLS * info->B_ROWS * sizeof(int), IPC_CREAT | IPC_EXCL | 0777);
if ( info->FLAGS_ID == -1 ) {
perror("coord: Error");
exit(1);
}
n = info->A_ROWS * info-> B_COLS;
//Set up our final (result) matrix: Set up shared mem, attach and open the file argument
info->C_ID = getShm(n);
C_SHARE = (int *)shmat(info->C_ID, 0, 0);
info->C_ROWS = info->A_ROWS;
info->C_COLS = info->B_COLS;
flags = (int *)shmat(info->FLAGS_ID, 0, 0);
f = fopen(argv[optind + 2], "w");
sprintf(arg1, "%d", INFO_ID);
pids = (pid_t *)malloc(n * sizeof(pid_t));
//Open (possibly create) Log file for recording
p = fopen("Log", "w+");
//Set our computation time alarm
alarm(compTime);
//Nested loop structure to produce children
for (k = 0; k < info->A_ROWS; k++) {
for (j = 0; j < info->B_COLS; j++) {
//Convert various integer args to strings for the sake of passing in EXECL
sprintf(arg2, "%d", k);
sprintf(arg3, "%d", j);
sprintf(arg4, "%d", c_id);
++totalProcess;
if ((pids[c_id] = fork() ) < 0) {
perror("coord: Error");
return 1;
}
//If process is child, exec it into the worker program
if (pids[c_id] == 0) {
// Try to get a better random seed from time() in worker processes
usleep(5 * (rand() % 3)); //
execl("worker", "worker", arg1, arg2, arg3, arg4, (char *)(NULL));
}
++c_id;
if (totalProcess >= 20) {
processLimit(&totalProcess, p);
}
}
}
//The loop above works in blocks of 20; check to see if any processes are still finishing
if (totalProcess > 0) {
processLimit(&totalProcess, p);
}
//Write our result matrix C to the file specified in argv
for (k = 0; k < n; k++) {
if (k % info->C_COLS == 0 && k != 0) {
fprintf(f, "\n");
}
fprintf(f, "%d ", C_SHARE[k]);
}
//Clean up any shared memory and other things left lying around
cleanUp(A_SHARE, B_SHARE, C_SHARE, flags, INFO_ID, info, pids);
return 0;
}
//Function for handling interrupts
void handler(int sig) {
if (sig == SIGINT) {
printf("\nSIGINT recieved: cleaning up and terminating child processes...\n");
}
if (sig == SIGALRM) {
printf("\nComputation has gone over alotted time limit: cleaning up and terminating child processes...\n");
}
int k;
for (k = 0; k < n; k++) {
if (pids[k] > 0) {
kill(pids[k], SIGTERM);
}
}
cleanUp(A_SHARE, B_SHARE, C_SHARE, flags, INFO_ID, info, pids);
exit(1);
}
//Function for cleaning up memory
void cleanUp(int *A_SHARE, int *B_SHARE, int *C_SHARE, int *flags, int INFO_ID, struct shminfo *info, pid_t *pids) {
shmdt( (void *) A_SHARE );
shmdt( (void *) B_SHARE );
shmdt( (void *) C_SHARE );
shmdt( (void *) flags );
shmctl(info->A_ID, IPC_RMID, 0);
shmctl(info->B_ID, IPC_RMID, 0);
shmctl(info->C_ID, IPC_RMID, 0);
shmctl(info->FLAGS_ID, IPC_RMID, 0);
shmdt( (void *) info );
shmctl(INFO_ID, IPC_RMID, 0);
free(pids);
}
//Function to wait for children to finish & write their results to the log file
void processLimit(int *p, FILE *f) {
int k = *p;
int status;
pid_t pid;
while (k > 0) {
pid = wait (&status);
f=fopen("Log", "ab+");
fprintf(f, "coord: Child %ld returned result %d\n", (long)pid, WEXITSTATUS(status));
--k;
--*p;
}
}
//Function to get the total size n of a matrix, where n = rows * columns
int matSize(FILE *file, struct shminfo *info, int flag) {
int rows = 0;
int cols = 0;
int prod = 0;
fscanf(file, "%d", &rows);
fscanf(file, "%d", &cols);
if (flag == 0) {
info->A_ROWS = rows;
info->A_COLS = cols;
} else {
info->B_ROWS = rows;
info->B_COLS = cols;
}
prod = rows * cols;
return prod;
}
// Function to get shared memory IDs
int getShm(int size) {
int memId;
memId = shmget( IPC_PRIVATE, size*sizeof(int), IPC_CREAT | IPC_EXCL | 0777);
if ( memId == -1 ) {
perror("coord: Error");
exit(1);
}
return memId;;
}
worker.c - The Child program
Code
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include "helper.h"
void process(const int i, int n, int *flag, struct shminfo *info);
void critical(long times, int id);
int ele;
int main(int argc, char *argv[]) {
int *A_MAT, *B_MAT, *C_MAT;
int i, row, col, num, processID;
int element = 0;
int infoID;
int *flag;
struct shminfo *info;
infoID = atoi(argv[1]);
row = atoi(argv[2]);
col = atoi(argv[3]);
processID = atoi(argv[4]);
info = (struct shminfo *)shmat(infoID, 0, 0);
A_MAT = (int *)shmat(info->A_ID, 0, 0);
B_MAT = (int *)shmat(info->B_ID, 0, 0);
C_MAT = (int *)shmat(info->C_ID, 0, 0);
flag = (int *)shmat(info->FLAGS_ID, 0, 0);
num = info->A_ROWS * info->B_COLS;
//TODO: Fix larger x smaller matrix
for (i = 0; i < info->A_COLS; i++) {
element += A_MAT[(row * info->A_COLS) + i] * B_MAT[(i * info->A_ROWS) + col];
}
ele = element;
C_MAT[(info->C_ROWS * row) + col] = element;
printf("Worker ID %d (PID: %d) produced result %d from operands %d and %d\n", processID, (int)getpid(), element, row, col);
process(processID, num, flag, info);
return element;
}
void process(const int i, int n, int *flag, struct shminfo *info) {
int j;
long times = 0;
do {
flag[i] = want_in;
j = info->turn;
while(j != i) {
j = (flag[j] != idle) ? info->turn : (j + 1) % n;
}
flag[i] = in_cs;
for (j = 0; j < n; j++) {
if ((j != i) && (flag[j] == in_cs)) {
break;
}
}
times++;
} while ((j < n) || (info->turn != i && flag[info->turn] != idle));
info->turn = i;
critical(times, i);
j = (info->turn + 1) % n;
while (flag[j] == idle) {
j = (j + 1) % n;
}
info->turn = j;
flag[i] = idle;
}
void critical(long times, int id) {
time_t currentTime;
int cid;
cid = getpid();
srand(time(NULL));
sleep(rand() % 3 + 1);
FILE *f;
f = fopen("Log", "a+");
time(¤tTime);
fprintf(f, "Child %d attempted to enter critical section %ld times\n", cid, times);
fprintf(f, "Child %d wrote value %d to the matrix\n", cid, ele);
fprintf(f, "Child %d exited critical section at %s\n", cid, ctime(¤tTime));
}