/* * * main.c - By: Theo Van Dinter - 96/09/10 * * For Operating Systems I - CS3013 * * */ #include "mailbox.h" #include /* Needed for signal handling */ #include /* Needed for the atoi function */ #include /* Needed for strcasecmp() ... */ /* * Range Structure - 2 way-linked list * * next = next node in linked list * prev = prev node in linked list * N1 = first number in range * N2 = last number in range * */ struct range { struct range *next; struct range *prev; int N1; int N2; }; extern void adder(int); int delrange(int,int,struct range *); void printranges(struct range *); void diegraceful(void); /* pids[] = Array with PIDs of Children */ int pids[NUMPROC]; void main(int argc, char *argv[]) { /* temp/2/3 = Temporary range variables for the 'additional' work section */ struct range *temp=(struct range *)NULL; struct range *temp2, *temp3; /* N1/N2 = Range currently being dealt with MR = Max Range setting loo = General loop variable total = Total sum of given range AD = Additional work flag msg = Variable for message passing */ int N1=0,N2=0,MR=0,loo,total=0,AD=0; struct msg msg; if (argc!=4&&argc!=5) /* Not enough/too many parameters */ { printf("\nUsage:\n\n"); printf("%s: [number 1] [number 2] [max range] \n\n",argv[0]); printf("This program will return the sum of numbers in the range "); printf("from\n"); printf("[number 1] to [number 2], inclusive. It does this by "); printf("forking\n"); printf("a number of processes (currently set to %d), and having each\n", NUMPROC); printf("\"child\" handle a certain number of values to sum ([max "); printf("range]),\n"); printf("The use of the parameter will make the program use a "); printf("different\n"); printf("method for distributing the work. Please see the OS1 "); printf("assignment\n"); printf("for more information.\n"); printf("\n"); exit(0); } if (NUMPROC>7) /* Why get errors later on? Quit early. (with a limit of 15 semaphores, we can only have 7 mailboxes (2 sems each)) */ { printf("\nThe current setting of NUMPROC (mailbox.h) is too high. "); printf("The\n"); printf("limit due to restrictions on screate() is NUMPROC=7.\n"); printf("Please lower the value in mailbox.h, and recompile.\n\n"); exit(1); } N1=atoi(argv[1]); /* First Number */ N2=atoi(argv[2]); /* Second Number */ MR=atoi(argv[3]); /* Max Range */ if (argc==5) /* Additional Mode */ AD=!strcasecmp("add",argv[4]); if (N1>N2) /* Numbers are reversed... Swap them. (N1 must be less than or equal to N2 ...) */ { printf("Numbers are reversed, please note the usage of this program next time.\n"); loo=N2; N2=N1; N1=loo; } if (MR<1) /* Max Range doesn't exist */ { printf("The Max Range is out of range, please retry with a different "); printf("value.\n"); exit(1); } if (InitMailbox()==-1) /* Initialize Semaphores and Shared Memory */ { printf("InitMailbox() failed!\n"); if (CleanupMailbox()==-1) /* We don't know why InitMailbox failed, so attempt to clean up anything we can. */ printf("CleanupMailbox() failed too!\n"); exit(1); } for(loo=1;loonext=NULL; temp->prev=NULL; if (AD==0) /* We're in 'normal' mode */ { temp2=temp; temp3=temp; for(loo=1;loo=N1) /* Queue has not been run through */ { msg.iFrom=0; msg.wTotal=0; msg.wType=0; /* Normal Request */ msg.wVal1=N1; /* N1 is the beginning of the range. */ /* Figure out the end of the range. */ if (N2-N1+1>MR) /* There are at least maxrange digits left */ { msg.wVal2=N1+MR-1; N1+=MR; } else /* There are less than (or equal to) maxrange digits left */ { msg.wVal2=N2; N1=N2+1; } printf("Process 0 sending %d-%d to Process %d\n",msg.wVal1, msg.wVal2,loo); if (SendMsg(loo,&msg)==-1) { printf("SendMsg had an error to Proc %d.\n",loo); diegraceful(); } /* Add the newly sent range to the range list */ temp2->next=(struct range *)malloc(sizeof(struct range)); temp2=temp2->next; temp2->next=(struct range *)NULL; temp2->prev=temp3; temp2->N1=msg.wVal1; temp2->N2=msg.wVal2; temp3=temp2; } } } else /* 'Additional' mode */ { if (N2!=N1) /* Not a range of 1 number */ { /* Create the first node in the range list */ temp->next=(struct range *)malloc(sizeof(struct range)); temp->prev=NULL; temp2=temp->next; temp2->next=(struct range *)NULL; temp2->prev=temp; loo=(N2-N1+1)/3; /* How many is 1/3? */ msg.iFrom=0; msg.wTotal=MR; /* Kluge: wTotal = Max Range */ msg.wType=2; /* Additional Request */ msg.wVal1=N1; /* Range for the first 2/3 of the numbers. */ msg.wVal2=N2-loo-1; /* Send all but the last third of the range. */ N1=N2-loo; /* Parent Starting Point */ printf("Process 0 sending %d-%d to Process 1\n",msg.wVal1,msg.wVal2); temp2->N1=msg.wVal1; /* Set the range we're waiting for */ temp2->N2=msg.wVal2; if (SendMsg(1,&msg)==-1) { printf("SendMsg had an error sending to Proc 1.\n"); diegraceful(); } } total=addrange(N1,N2); /* Add the range for the parent (0 sec delay means that it would have looped without stopping (adding maxrange per loop), and therefore still returned the full sum. */ printf("Process 0 added %d-%d (%d)\n",N1,N2,total); } while(temp->next!=(struct range *)NULL) /* While there's still something out there */ { if (RecvMsg(0,&msg)==-1) /* Wait for a message to come in... */ { printf("RecvMsg had an error!\n"); diegraceful(); } printf("Process 0 receives %d-%d from Process %d (%d)\n",msg.wVal1, msg.wVal2,msg.iFrom,msg.wTotal); total+=msg.wTotal; /* Total sum += Sum from child */ /* Delete the range from the range(s) we're waiting for */ if (delrange(msg.wVal1,msg.wVal2,temp)==-1) /* Error! */ { printf("Error with delrange!\n"); diegraceful(); } if (AD==0) /* Normal Mode - Send child more work */ { if (N2>=N1) /* Queue has not been run through */ { loo=msg.iFrom; msg.iFrom=0; msg.wTotal=0; msg.wType=0; /* Normal Request */ msg.wVal1=N1; /* Set the range limit */ if (N2-N1+1>MR) /* There are at least maxrange digits left */ { msg.wVal2=N1+MR-1; N1+=MR; } else /* There are less than (or equal to) maxrange digits left */ { msg.wVal2=N2; N1=N2+1; } printf("Process 0 sending %d-%d to Process %d\n",msg.wVal1, msg.wVal2,loo); /* Since we dish out work from the start of the range, when we add to the range list, it will ALWAYS be at the end of the range. Find the end. */ temp2=temp; while(temp2->next!=(struct range *)NULL) temp2=temp2->next; /* Add the range in there. */ temp3=temp2; temp2->next=(struct range *)malloc(sizeof(struct range)); temp2=temp2->next; temp2->next=(struct range *)NULL; temp2->prev=temp3; temp2->N1=msg.wVal1; temp2->N2=msg.wVal2; if (SendMsg(loo,&msg)==-1) { printf("SendMsg failed for Proc %d.\n",loo); diegraceful(); } } } } if (AD==1) /* Process 0 wouldn't report this otherwise */ printf("Process 0 added together %d integer%s\n",N2-N1+1, (N2-N1+1)!=1?"s":""); for(loo=1;loonext; while(test2!=(struct range *)NULL) /* Loop through all the nodes of the list */ { printf("%d - %d\n",test2->N1,test2->N2); test2=test2->next; } printf("\n"); } /* * delrange - 96/09/12 * * By: Theo Van Dinter (felicity@kluge.net) * * Removes a range of numbers from the linked list set of ranges. * * Parameters: N1 = First Number in Range * N2 = Last Number in Range * root = Root of the linked list * * Returns a -1 on error, 0 if ok. * */ int delrange(int N1,int N2,struct range *root) { struct range *root2; if (root->next==NULL) /* Blank list */ return(-1); root=root->next; /* First node */ while(root!=NULL) /* Go until the last node if necessary */ { if (N1==root->N1 && N2==root->N2) /* Whole range needs to go */ { root->prev->next=root->next; if (root->next!=(struct range *)NULL) root->next->prev=root->prev; free(root); return(0); } if (N1==root->N1) /* Beginning of node's range */ { root->N1=N2+1; return(0); } else if (N2==root->N2) /* End of node's range */ { root->N2=N1-1; return(0); } else if (root->N1N2>N2) /* In between the node's range */ { root2=(struct range *)malloc(sizeof(struct range)); root2->next=root->next; root2->prev=root; if (root->next!=(struct range*)NULL) root->next->prev=root2; root->next=root2; root2->N1=N2+1; root2->N2=root->N2; root->N2=N1-1; return(0); } root=root->next; /* Skip to next node */ } return(-1); /* Return error. */ } /* * diegraceful - 96/09/15 * * By: Theo Van Dinter (felicity@kluge.net) * * Attempts to die gracefully by removing processes and cleaning up things. * * No passed parameters, no returns. * */ void diegraceful() { int loo; if (CleanupMailbox()==-1) /* Cleanup if possible */ printf("CleanupMailbox()!\n"); for(loo=1;loo<=NUMPROC;loo++) /* Kill the children! */ if (pids[loo]>0) if (kill(pids[loo],9)<0) /* Signal 9 */ printf("kill(%d) failed!\n",pids[loo]); exit(1); }