Answers/Solutions to Exercises in Chapter 11, Exercise 2
E2: Write a simple C program that forks one or more child
processes. Use the logging functions from the Appendix D. Do not create a shared memory
segment for logi. Create a single log before the very
first fork() so all the child processes will inherit it.
Check the log and the sequential numbers of messages from all the processes involved.
S2: We are using the sample solution from Exercise 1, we just "deleted" the references to logi from shm1. Note that some of the entries in the log have "duplicated" sequential numbers, as all the child processes use their "own" numbers, starting with the last message number from th eparent just prior to the fork of the child.
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sys/shm.h> #include <errno.h> #include <signal.h> #include <sys/types.h> #include <sys/wait.h> #include <sys/sem.h> #include <sys/shm.h> #include "log.h" char logfile[300]; int logindex = 0; int* logi = &logindex; // The structure of shm1, contains shmId2 // The structure of shm2 // int pid pid pid .... pid // int=number of registered processes // pid pid .... pid their pid's int shmId1 = -1; // id of shm1 int shmId2 = -1; // id of shm2 int *shmAddr1; // address of attached shm1 int *shmAddr2; // address of attached shm2 int semId = -1; // id of semaphore pid_t pids[3]={-1,-1,-1}; // array of pid's of child processes int nchildren=0; // no of live child processes int parent=1; // identification of the parent process // create and lock a semaphore array of size 1, i.e. a single // semaphore. We will use it in "binary" mode // This function is only used by the parent process // function CreateAndLockSem ---------------------------------------- int CreateAndLockSem() { int size = 1; int semid = -1; union semun { int val; struct semid_ds *buf; ushort_t *array; } semarg ; int i, xerrno; // create a semaphore array of size 'size', i.e. 1 if ((semid = semget(IPC_PRIVATE,size,IPC_CREAT|S_IRUSR|S_IWUSR)) == -1) Sys_exit("semget error errno=%d\n",errno); else Msg("created semaphore semid=%d\n",semid); // set the semaphore to its initial value 0 meaning "locked" semarg.val = 0; if (semctl(semid,0,SETVAL,semarg) == -1) { xerrno = errno; // remember errno semctl(semid,0,IPC_RMID,semarg); // remove semaphore semid=-1; errno = xerrno; // recall remembered errno Sys_exit("semctl(SETVAL) error\n"); }else Msg("locked semaphore semid=%d\n",semid); return semid; }// end CreateAndLockSem // lock semaphore of the given id. This function will be used by both, // the parent and the child processes. If it is a child process, it must // exit using _exit() rather than exit(). // function LockSem ------------------------------------------ void LockSem(int semid) { union semun { int val; struct semid_ds *buf; ushort_t *array; } semarg ; struct sembuf lockSEM[1] = {{0,-1,SEM_UNDO}}; int i; /* wait in suspension until either successfully locked or woken up by a signal, when locked, the value is decreased by 1 to 0 */ while((semid=semop(semid,lockSEM,1)) == -1) { if (errno == EINTR) // signal interrupt continue; else{ if (parent) Sys_exit("semop(lockSEM) error\n"); else Sys__exit("semop(lockSEM) error\n"); } }//endwhile Msg("locked semaphore semid=%d\n",semid); }// end LockSem // unlock semaphore of the given id. This function will be used by both, // the parent and the child processes. If it is a child process, it must // exit using _exit() rather than exit(). // function UnlockSem ---------------------------------------------- void UnlockSem(int semid) { union semun { int val; struct semid_ds *buf; ushort_t *array; } semarg ; int i; struct sembuf unlockSEM[1] = {{0,1,SEM_UNDO}}; // unlock semaphor, when unlocked, the value is increased by 1 to 1 while(semop(semid,unlockSEM,1) == -1) { if (errno == EINTR) // signal interrupt continue; else{ if (parent) Sys_exit("semop(unlocksSEM) error\n"); else Sys__exit("semop(unlocksSEM) error\n"); } }//endwhile Msg("Unlocked semaphore semid=%d\n",semid); }// end UnlockSem // this function is used only by the parent process. However, it is used // in exit(), so we cannot use exit() here. But we do not need to. // function RemoveSem ------------------------------------- void RemoveSem(int semid) { union semun { int val; struct semid_ds *buf; ushort_t *array; } semarg ; // remove semaphore if (semctl(semid,0,IPC_RMID,semarg) == -1) Sys("semctl(IPC_RMID) error\n"); else Msg("Removed semaphore semid=%d\n",semid); }// end RemoveSem // only used by the parent and only during exit() // function FinalAtexit ------------------------------------------------ void FinalAtexit() { Msg("the program is finished\n"); }// end FinalAtexit // only used by the parent, and only during exit() // function RemoveShmAtexit ------------------------------------------------ void RemoveShmAtexit() { struct shmid_ds shmbuf; if (shmId1 >= 0) { // check if installed and attached Msg("going to remove shared memory with id = %d\n",shmId1); if (shmctl(shmId1,IPC_RMID,&shmbuf) < 0) Sys("shmctl(%d,IPC_RMID) error\n",shmId1); else Msg("removed shared memory with id = %d \n",shmId1); } if (shmId2 >= 0) { // check if installed and attached Msg("going to remove shared memory id = %d\n",shmId2); if (shmctl(shmId2,IPC_RMID,&shmbuf) < 0) Sys("shmctl(%d,IPC_RMID) error\n",shmId2); else Msg("removed shared memory with id = %d \n",shmId2); } }// end RemoveShmAtexit // only used by the parent, and only during exit() // function RemoveSemAtexit ------------------------------------- void RemoveSemAtexit() { if (semId == -1) // semaphore not installed return; RemoveSem(semId); semId = -1; }// end RemoveSempahoreAtexit // only used by the parent, and only during exit(). Just a clean up, // we do not want to have orphaned processes running. // function TerminateChildrenAtexit ---------------------------------- void TernminateChildrenAtexit() { int i; for(i = 0; i < 3; i++) { if (pids[i]!=-1) { sigsend(P_PID,pids[i],SIGKILL); Msg("terminated child process pid=%d in TerminateChildrenAtexit\n", pids[i]); pids[i]=-1; } } }// end TerminateChildrenAtexit // assuming shm2 is locked for us and we have correct shmId2 // and that we are attached to shm2 // only used by the child processes, so no exit() // function SHMRealloc ----------------------------------------- void SHMRealloc(pid_t pid) { int npids, size, i; struct shmid_ds shmbuf; int shmId2_old; int* shmAddr2_old; pid_t *p1, *p2; shmId2_old=shmId2; shmAddr2_old=shmAddr2; // calc mew size npids = *shmAddr2; size=(npids+1)*sizeof(pid_t)+sizeof(int); //create new shm2 if ((shmId2 = shmget(IPC_PRIVATE,size,S_IRUSR|S_IWUSR)) < 0) Sys__exit("shmget error\n"); else Msg("created new shm2 with id %d of size %d\n",shmId2,size); // attach new shm2 if ((shmAddr2 = (int*) shmat(shmId2,0,0)) == (void*) -1) Sys__exit("shmat error (%x)\n",shmAddr2); else Msg("attached new shm2 with id %d at address %x\n",shmId2,shmAddr2); // put new data in shm1 *shmAddr1=shmId2; // copy old shm2 to new shm2 *shmAddr2=(npids+1); // new number of pids p1 = (pid_t*) (shmAddr2_old+1); // get ready for pid in old shm2 p2 = (pid_t*) (shmAddr2+1); // get ready for pid in new shm2 for(i=0; i < npids; i++) { *p2++=*p1++; // copy pid from old shm2 to new shm2 }//endfor // add new pid *p2 = pid; // remove old shm2 if (shmctl(shmId2_old,IPC_RMID,&shmbuf) < 0) Sys__exit("shmctl(%d,IPC_RMID) error\n",shmId2_old); else Msg("removed shared memory with id = %d \n",shmId2_old); }// end SHMRealloc // used by both, the child processes and the parent // assuming attached to shm2 // function SHMShow ------------------------------------------------ void SHMShow() { int i, npids; pid_t *q; char c=':'; static char line[300]; // for simplicity, we are cheating here, knowing // that the print line will not exceed 300 chars sprintf(line,"shm2 content "); npids = *shmAddr2; sprintf(line+strlen(line),"%d",npids); q = (pid_t*)(shmAddr2+1); for(i = 0; i < npids; i++) { sprintf(line+strlen(line),"%c%d",c,*q++); c=','; } Msg("%s\n",line); }// end SHMShow // do the child process stuff, so no exit() // function dochild ----------------------------------------------- void dochild() { struct shmid_ds shmbuf; // you inherited across fork meaningful semId, shmId1, shmAddr1 // shmId2, shmAddr2 may have changed LockSem(semId); // wait till you lock semaphore // get shmId2 from shm1 shmId2=*shmAddr1; // attach shm2 if ((shmAddr2 = (int*) shmat(shmId2,0,0)) == (void*) -1) Sys__exit("shmat error (%x)\n",shmAddr2); else Msg("attached shared memory segment with id %d at address %x\n", shmId2,shmAddr2); // Show shm2 SHMShow(); // now add your pid to shm2 SHMRealloc(getpid()); // Show shm2 SHMShow(); // detach from shm2 if (shmdt((char*)shmAddr2)< 0) Sys__exit("shmdt() error\n"); else Msg("detached from shm2\n"); Msg__exit("child process pid=%d terminates\n",getpid()); }//end dochild // function main ---------------------------------------------------- int main(int argc,char* argv[]) { size_t size; pid_t* ptr; char* s; int i, status; pid_t pid; if (argc!=2) { fprintf(stderr,"usage -- %s <logfile>\n",argv[0]); exit(1); } if ((s = create_log(argv[1])) != NULL) { fprintf(stderr,"create log error: %s\n",s); exit(1); } // on exit announce the end of program if (atexit(FinalAtexit) < 0) Sys_exit("can't register atexit FinalAtexit()\n"); else Msg("registered atexit FinalAtexit()\n"); // on exit remove shm1 and shm2 if (atexit(RemoveShmAtexit) < 0) Sys_exit("can't register atexit RemoveShmAtexit()\n"); else Msg("registered atexit RemoveShmAtexit()\n"); // on exit remove the semaphore if (atexit(RemoveSemAtexit) < 0) Sys_exit("can't register atexit RemoveSemAtexit()\n"); else Msg("registered atexit RemoveSemAtexit()\n"); // now we can start the actual processing // create shm1 if ((shmId1 = shmget(IPC_PRIVATE,sizeof(int),S_IRUSR|S_IWUSR)) < 0) Sys_exit("shmget error for shm1\n"); else Msg("created shm1 with id %d of size %d\n",shmId1,sizeof(int)); // attach shm1 if ((shmAddr1 = (int*) shmat(shmId1,0,0)) == (void*) -1) Sys_exit("shmat error for shm1 (%x)\n",shmAddr1); else Msg("attached shm1 with id %d at address %x\n",shmId1,shmAddr1); //create shm2 size=sizeof(int)+sizeof(pid_t)+1; if ((shmId2 = shmget(IPC_PRIVATE,size,S_IRUSR|S_IWUSR)) < 0) Sys_exit("shmget error for shm2\n"); else Msg("created shm2 with id %d of size %d\n",shmId2,size); // attach shm2 if ((shmAddr2 = (int*) shmat(shmId2,0,0)) == (void*) -1) Sys_exit("shmat error for shm2 (%x)\n",shmAddr2); else Msg("attached shm2 with id %d at address %x\n",shmId2,shmAddr2); // put data in shm1 *shmAddr1=shmId2; // put data in shm2 *shmAddr2=1; // 1 registered process ptr=(pid_t*)(shmAddr2+1); *ptr=getpid(); // and it is me // create and lock the semaphore protecting shm1 semId=CreateAndLockSem(); // show contents of shm2 SHMShow(); // detach from shm2 if (shmdt((char*)shmAddr2)< 0) Sys_exit("shmdt() error\n"); else Msg("detached from shm2\n"); // and unlock the semaphore UnlockSem(semId); // now fork three process for(i=0; i < 3; i++) { if ((pids[i]=fork()) < 0) { Sys_exit("fork error\n"); }else if (pids[i]==0) { Msg("I am a child process pid=%d\n",getpid()); parent=0; // remember, that you are not parent dochild(); // do child stuff, does not return, but exits using _exit() }else{ Msg("I, parent, forked process pid=%d\n",pids[i]); nchildren++; // update the number of live child processes } }//endfor // now wait for all child processes to terminate while(nchildren > 0) { if ((pid = wait(&status)) == (pid_t) -1) if (errno == EINTR) // interrupted system call continue; else Sys_exit("waitpid error\n"); Msg("received notification of child process %d terminated\n",pid); // we got a child terminating nchildren--; // update child counter for(i=0; i < 3; i++) { // find which one it was if (pids[i]==pid) { pids[i]=-1; break; } }//endfor // let'us see shm2 now LockSem(semId); shmId2=*shmAddr1; if ((shmAddr2 = (int*) shmat(shmId2,0,0)) == (void*) -1) Sys_exit("shmat error (%x)\n",shmAddr2); else Msg("attached shared memory segment with id %d at address %x\n", shmId2,shmAddr2); SHMShow(); // detach from shm2 if (shmdt((char*)shmAddr2)< 0) Sys_exit("shmdt() error\n"); else Msg("detached from shm2\n"); UnlockSem(semId); // and unlock semaphore }// endwhile exit(1); // will do cleanup }// end main
Output in the log:
message number = 0, process id = 25404, time and date = 22:40:15 05/07/04 registered atexit FinalAtexit() message number = 1, process id = 25404, time and date = 22:40:15 05/07/04 registered atexit RemoveShmAtexit() message number = 2, process id = 25404, time and date = 22:40:15 05/07/04 registered atexit RemoveSemAtexit() message number = 3, process id = 25404, time and date = 22:40:15 05/07/04 created shm1 with id 3801 of size 4 message number = 4, process id = 25404, time and date = 22:40:15 05/07/04 attached shm1 with id 3801 at address ff2e0000 message number = 5, process id = 25404, time and date = 22:40:15 05/07/04 created shm2 with id 1902 of size 9 message number = 6, process id = 25404, time and date = 22:40:15 05/07/04 attached shm2 with id 1902 at address ff1f0000 message number = 7, process id = 25404, time and date = 22:40:15 05/07/04 created semaphore semid=1572864 message number = 8, process id = 25404, time and date = 22:40:15 05/07/04 locked semaphore semid=1572864 message number = 9, process id = 25404, time and date = 22:40:15 05/07/04 shm2 content 1:25404 message number = 10, process id = 25404, time and date = 22:40:15 05/07/04 detached from shm2 message number = 11, process id = 25404, time and date = 22:40:15 05/07/04 Unlocked semaphore semid=1572864 message number = 12, process id = 25404, time and date = 22:40:15 05/07/04 I, parent, forked process pid=25405 message number = 12, process id = 25405, time and date = 22:40:15 05/07/04 I am a child process pid=25405 message number = 13, process id = 25404, time and date = 22:40:15 05/07/04 I, parent, forked process pid=25406 message number = 13, process id = 25406, time and date = 22:40:15 05/07/04 I am a child process pid=25406 message number = 13, process id = 25405, time and date = 22:40:15 05/07/04 locked semaphore semid=0 message number = 14, process id = 25404, time and date = 22:40:15 05/07/04 I, parent, forked process pid=25407 message number = 14, process id = 25405, time and date = 22:40:15 05/07/04 attached shared memory segment with id 1902 at address ff1f0000 message number = 14, process id = 25407, time and date = 22:40:15 05/07/04 I am a child process pid=25407 message number = 15, process id = 25405, time and date = 22:40:15 05/07/04 shm2 content 1:25404 message number = 16, process id = 25405, time and date = 22:40:15 05/07/04 created new shm2 with id 103 of size 12 message number = 17, process id = 25405, time and date = 22:40:15 05/07/04 attached new shm2 with id 103 at address ff1e0000 message number = 18, process id = 25405, time and date = 22:40:15 05/07/04 removed shared memory with id = 1902 message number = 19, process id = 25405, time and date = 22:40:15 05/07/04 shm2 content 2:25404,25405 message number = 20, process id = 25405, time and date = 22:40:15 05/07/04 detached from shm2 message number = 21, process id = 25405, time and date = 22:40:15 05/07/04 child process pid=25405 terminates message number = 14, process id = 25406, time and date = 22:40:15 05/07/04 locked semaphore semid=0 message number = 15, process id = 25406, time and date = 22:40:15 05/07/04 attached shared memory segment with id 103 at address ff1f0000 message number = 15, process id = 25404, time and date = 22:40:15 05/07/04 received notification of child process 25405 terminated message number = 16, process id = 25406, time and date = 22:40:15 05/07/04 shm2 content 2:25404,25405 message number = 17, process id = 25406, time and date = 22:40:15 05/07/04 created new shm2 with id 2002 of size 16 message number = 18, process id = 25406, time and date = 22:40:15 05/07/04 attached new shm2 with id 2002 at address ff1e0000 message number = 19, process id = 25406, time and date = 22:40:15 05/07/04 removed shared memory with id = 103 message number = 20, process id = 25406, time and date = 22:40:15 05/07/04 shm2 content 3:25404,25405,25406 message number = 21, process id = 25406, time and date = 22:40:15 05/07/04 detached from shm2 message number = 22, process id = 25406, time and date = 22:40:15 05/07/04 child process pid=25406 terminates message number = 15, process id = 25407, time and date = 22:40:15 05/07/04 locked semaphore semid=0 message number = 16, process id = 25407, time and date = 22:40:15 05/07/04 attached shared memory segment with id 2002 at address ff1f0000 message number = 17, process id = 25407, time and date = 22:40:15 05/07/04 shm2 content 3:25404,25405,25406 message number = 18, process id = 25407, time and date = 22:40:15 05/07/04 created new shm2 with id 203 of size 20 message number = 19, process id = 25407, time and date = 22:40:15 05/07/04 attached new shm2 with id 203 at address ff1e0000 message number = 20, process id = 25407, time and date = 22:40:15 05/07/04 removed shared memory with id = 2002 message number = 21, process id = 25407, time and date = 22:40:15 05/07/04 shm2 content 4:25404,25405,25406,25407 message number = 22, process id = 25407, time and date = 22:40:15 05/07/04 detached from shm2 message number = 23, process id = 25407, time and date = 22:40:15 05/07/04 child process pid=25407 terminates message number = 16, process id = 25404, time and date = 22:40:15 05/07/04 locked semaphore semid=0 message number = 17, process id = 25404, time and date = 22:40:15 05/07/04 attached shared memory segment with id 203 at address ff1f0000 message number = 18, process id = 25404, time and date = 22:40:15 05/07/04 shm2 content 4:25404,25405,25406,25407 message number = 19, process id = 25404, time and date = 22:40:15 05/07/04 detached from shm2 message number = 20, process id = 25404, time and date = 22:40:15 05/07/04 Unlocked semaphore semid=1572864 message number = 21, process id = 25404, time and date = 22:40:15 05/07/04 received notification of child process 25407 terminated message number = 22, process id = 25404, time and date = 22:40:15 05/07/04 locked semaphore semid=0 message number = 23, process id = 25404, time and date = 22:40:15 05/07/04 attached shared memory segment with id 203 at address ff1f0000 message number = 24, process id = 25404, time and date = 22:40:15 05/07/04 shm2 content 4:25404,25405,25406,25407 message number = 25, process id = 25404, time and date = 22:40:15 05/07/04 detached from shm2 message number = 26, process id = 25404, time and date = 22:40:15 05/07/04 Unlocked semaphore semid=1572864 message number = 27, process id = 25404, time and date = 22:40:15 05/07/04 received notification of child process 25406 terminated message number = 28, process id = 25404, time and date = 22:40:15 05/07/04 locked semaphore semid=0 message number = 29, process id = 25404, time and date = 22:40:15 05/07/04 attached shared memory segment with id 203 at address ff1f0000 message number = 30, process id = 25404, time and date = 22:40:15 05/07/04 shm2 content 4:25404,25405,25406,25407 message number = 31, process id = 25404, time and date = 22:40:15 05/07/04 detached from shm2 message number = 32, process id = 25404, time and date = 22:40:15 05/07/04 Unlocked semaphore semid=1572864 message number = 33, process id = 25404, time and date = 22:40:15 05/07/04 Removed semaphore semid=1572864 message number = 34, process id = 25404, time and date = 22:40:15 05/07/04 going to remove shared memory with id = 3801 message number = 35, process id = 25404, time and date = 22:40:15 05/07/04 removed shared memory with id = 3801 message number = 36, process id = 25404, time and date = 22:40:15 05/07/04 going to remove shared memory id = 203 message number = 37, process id = 25404, time and date = 22:40:15 05/07/04 removed shared memory with id = 203 message number = 38, process id = 25404, time and date = 22:40:15 05/07/04 the program is finished
Back to Answers/Solutions Index Back to Answers/Solutions for Chapter 11 Index