/** * Author: Eric Bergstrom * Title: stattest.c * Description: This program records the order that the NUM processes * finishes in an array. This is repeated SAMPLE times and averaged. * The output of the program shows each process along with the a value * representing its average order. The lower the number, the higher * the priority. Since we are testing a probabilistic scheduling * algorithm, the answers will vary each time it is run. * Lottery tickets are assigned at the command line. * * USAGE: stats [ticket1] [ticket2] ... * if no ticket is specified for a process, it defaults to 1. * * Issues: This program is a little buggy, containing some * deadlock issues requiring a restart when it locks up. * A watchdog timer fixes some of the deadlock, so for the * most part it functions correctly. */ #define _POSIX_SOURCE 1 #include #include #include #include #include #include #include "setlottery.h" #define NUM 4 /* number of processes to test */ #define SAMPLE 35 /* sample size */ #define MSGSIZE 16 #define DEBUG 0 /* 1 for debug messages, 0 for none */ #define SHOW_CYCLE 0 /* 1 to show current cycle number, 0 for no messages */ #define ALARM_SC 75 #define WORK_ITER 100000 int created = 0; /* number of child finshed being created */ int c[NUM]; /* child pid array */ int P[NUM]; /* lottery ticket value for process P[i] */ int alarm_flag = 0; int deadlocks = 0; /* parent_code - invoked when parent gets SIGUSR1 signal * Advances number of child processes that have been * created and are ready to run */ void parent_code(int sig) { /* update number of children that have contacted me*/ #if DEBUG == 1 printf("PARENT: updating created: %d\n", created + 1 ); #endif created++; } /* work - invoked when child gets SIGUSR1 signal * Just does some trivial task and returns */ void work(int sig) { int i = 0; /* do some work */ for ( i = 0; i < WORK_ITER; ++i ); } /* watchdog - invoked when parent times out, sets an alarm variable. */ void watchdog(int sig) { alarm_flag = 1; } void child(int pd[2], int index ); void parent( int p[2], int ans[NUM] ); /* * main() - parent process forks children process to compete * for resources */ int main (int argc, char **argv) { int pid, sid, i = 0, j = 0, repeat = 0; int ans[NUM]; float successful = 0; static struct sigaction pwork; int p[2]; /* initialize histogram and default lottery ticket */ for( i = 0; i < NUM; ++i ) { ans[i] = 0; P[i] = 1; } if ( argc == 1 ) printf("all processes given 1 ticket\n"); /* set lottery tickets passed from user */ /* not much error checking here ... */ if( argc > 1 ) { for ( i = 1; i <= NUM; ++i ) { sscanf(argv[i], "%d", &P[i-1]); printf("process(%d) will be assigned %d tickets\n", i-1, P[i-1]); } } /* set action for parent code */ pwork.sa_handler = parent_code; sigaction(SIGUSR1, &pwork, NULL ); /* change session id so that kill doesn't kill the shell */ sid = setsid(); /* get parent name */ pid = getpid(); while( repeat++ < SAMPLE ) { #if SHOW_CYCLE == 1 printf("starting cycle %d\n", repeat ); #endif /* initialize process storage */ for ( i = 0; i < NUM; ++i ) c[i] = 0; /* reset created global */ created = 0; /* create pipe to communicate with child */ if ( pipe(p) == -1 ) { printf("ERROR creating pipe\n"); exit(1); } /* create NUM processes */ for( i = 0; i < NUM; i++ ) { if ( (c[i] = fork()) == -1 ) { break; } if ( c[i] == 0 ) { child( p, i ); } #if DEBUG == 1 printf("%d: created %d\n", getpid(), c[i] ); #endif } parent( p, ans ); successful += 1.0; close(p[0]); close(p[1]); } /* report results */ printf("lower score reflects higher priority\n"); for( j = 0; j < NUM; j++ ) { printf("[%d] = %2.2f\n", j, ans[j] / successful ); } if ( deadlocks > 0 ) printf("%d deadlock(s) were detected\n", deadlocks); return 0; } /* * child - sets up function to call when SIGUSR1 is sent. * Sets the priorities for lottery tickets. * Waits for a signal from the parent letting it know that * all the other children are ready to go. Notifies parent * when done. */ void child( int pd[2], int index ) { static struct sigaction cwork; int i, cpid, ppid, status, res, assigned; char msg[MSGSIZE]; cpid = getpid(); ppid = getppid(); /* set action for cwork */ cwork.sa_handler = work; sigaction(SIGUSR1, &cwork, NULL ); /* close off in port */ close(pd[0]); /* set up lottery tickets */ assigned = setLotteryTickets(cpid, P[index]); #if DEBUG == 1 printf("%d(%d) has %d tickets ...\n", cpid, index, assigned ); #endif /* notify parent that child has finished */ kill( ppid, SIGUSR1 ); alarm(ALARM_SC * 2); pause(); /* notify parent of completion */ sprintf(msg, "%d", cpid ); #if DEBUG == 1 printf("CHILD: sending message: %s\n", msg); #endif res = write( pd[1], msg, MSGSIZE ); /* close up pipe */ close(pd[1]); /* end child process */ exit(0); } /* * parent - waits for all the children processes to be created * and initialized. Once the children are set, the parent waits * for responses from the children. The order that the children * finishes is placed within an array, creating a histogram. */ void parent( int p[2], int ans[NUM] ) { int cpid, i, j, cnt = 0, status, ex_status, val, wd = 0, cmpt; char buf[MSGSIZE], ch; static struct sigaction alrm; /* set up alarm code */ alrm.sa_handler = watchdog; sigaction(SIGALRM, &alrm, NULL); /* close unneeded write fd */ close(p[1]); /* wait for all the processes to be created and have their lottery tickets set */ while( created < NUM ) { alarm(ALARM_SC); #if DEBUG == 1 printf("Parent pausing for signal %d\n", created); #endif pause(); if ( alarm_flag ) { alarm_flag = 0; wd = 1; break; } } if ( wd == 1 ) { #if DEBUG == 1 printf("watchdog activated\n"); #endif deadlocks++; cmpt = created - 1; } else cmpt = NUM; /* signal everyone to do their work (parent also gets notified) */ ex_status = kill(0, SIGUSR1 ); #if DEBUG == 1 printf("PARENT: kill signal returned with %d\n", ex_status ); #endif /* wait for all the processes to finish */ for( i = 0; i < NUM; ++i ) { #if DEBUG == 1 printf("PARENT: waiting for message %d\n", i); #endif /* read in messages from the child processes */ /* make read non-blocking */ read(p[0], buf, MSGSIZE ); sscanf(buf, "%d", &val ); #if DEBUG == 1 printf("PARENT: received message from %d\n", val ); #endif /* determine order and update histogram */ cnt++; for( j = 0; j < NUM; ++j ) { if ( c[j] == val ) break; } /* if timed out, assume finished last */ if ( cnt == 0 ) cnt = 4; ans[j] += cnt; } /* reclaim resources */ for ( i = 0; i < NUM; ++i ) { cpid = waitpid(-1, &status, 0); ex_status = WEXITSTATUS(status); #if DEBUG == 1 printf("Exit status from %d was %d\n", cpid, ex_status ); #endif } }