CDS LAB 9 2007 - SIGNALS AND SEMAPHORES When the signal handler completes, where does the code continue executing? ============================================================================= It continues from the place where it was `interrupted'. This will be the place where the process's execution thread entered the kernel (either through a voluntary system call, most likely in this case caused by executing sleep(1), or when this occurs through a timer interrupt (which will occur at the end of the process' timeslice). You can always insert an exit statement in the handler to terminate the process. Good/Bad Software Engineering Student ===================================== Assume the program which sometimes gets into an infinite loop is called " "randinfloop". The main() program and the handler is shown here. int main(void) { int status, fork_pid; if ((fork_pid=fork())) { // Parent signal(SIGCHLD, handler1); // handler1() will be called if child exits sleep(5); signal(SIGCHLD, SIG_IGN); // if the child terminates now, do nothing printf("Bad student - must be a software engineer!\n"); kill(fork_pid, SIGKILL); // terminate the child now } else { // Child status = execl("./randinfloop", "randinfloop", (char *) NULL); if (status != 0) perror("execl error:"); } return 0; } void handler1(int sig) { printf("Good student - must be a scientist!\n"); exit(0); return; } Why semaphores persist ====================== Because they can be used to provide a synchronization construct between multiple processes, and these processes do not have to have a common ancestry. Alternating Printout ==================== Solution 1: use sem1 as a `turn' variable; if its even, parent can enter, (else child the enter) the critical section. In order to use gettimeofday(), add at the top of the program: #include struct timeval mytime; Setup the P&V() operators for semaphore 1 (before loop): sem1_P.sem_num = 1; sem1_P.sem_op = -1; sem1_P.sem_flg = 0; sem1_V.sem_num = 1; sem1_V.sem_op = +1; sem1_V.sem_flg = 0; At the top of the body of the `for (irpt...)' loop, add: // while semaphore is odd (even), the parent (child) waits here while ((semctl(semid, 1, GETVAL) % 2) == (fork_pid!=0)); and modify the print statement to include the times: gettimeofday(&mytime, NULL); printf("%s %d \t@ time %d.%d\n", fork_pid? "Parent": "Child", irpt, (int) mytime.tv_sec, (int) mytime.tv_usec); and at the bottom of the loop, add: semop(semid, &sem1_V, 1); // (atomic) increment of semaphore 1 by 1 Solution 2: parent process does a P() on semaphore 0 and a V() on semaphore 1, with the child doing the converse. This means that each allows only the other to enter the critical region next. Note that semaphore 1 is initially 0; this ensures the parent gets the first turn. Use the timer code and P&V operator setup code as above, but add: int mysem; // current process uses P(mysem) and V(1-mysem) initialize this between the fork() and the for loop: mysem = (fork_pid==0); // 0 on parent, 1 on child Now replace the code performing the P() operation from: semop(semid, sem0_P, 1) to: semop(semid, mysem==0? &sem0_P: &sem1_P, 1) and that performing the V() operation from: semop(semid, &sem0_V, 1) to: semop(semid, mysem==0? &sem1_V: &sem0_V, 1)