Answers/Solutions to Exercises in Chapter 11, Exercise 4
E4: Repeat exercise 2 with a change that each child process will open its own and different log after the fork(). Compare the logs.
S4: The same program as in Exercise 2. Note that right after the fork, we create a new log. So each process has its own separate log. Compare the entries.
#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) { parent=0; // remember, that you are not parent // create your own log sprintf(logfile+strlen(logfile),"_%d",i); create_log(logfile); Msg("I am a child process pid=%d\n",getpid()); 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
Outuput in 4 different logs.
log of the parent process:
message number = 0, process id = 28127, time and date = 23:17:36 05/07/04 registered atexit FinalAtexit() message number = 1, process id = 28127, time and date = 23:17:36 05/07/04 registered atexit RemoveShmAtexit() message number = 2, process id = 28127, time and date = 23:17:36 05/07/04 registered atexit RemoveSemAtexit() message number = 3, process id = 28127, time and date = 23:17:36 05/07/04 created shm1 with id 4001 of size 4 message number = 4, process id = 28127, time and date = 23:17:36 05/07/04 attached shm1 with id 4001 at address ff2e0000 message number = 5, process id = 28127, time and date = 23:17:36 05/07/04 created shm2 with id 2302 of size 9 message number = 6, process id = 28127, time and date = 23:17:36 05/07/04 attached shm2 with id 2302 at address ff1f0000 message number = 7, process id = 28127, time and date = 23:17:36 05/07/04 created semaphore semid=1703936 message number = 8, process id = 28127, time and date = 23:17:36 05/07/04 locked semaphore semid=1703936 message number = 9, process id = 28127, time and date = 23:17:36 05/07/04 shm2 content 1:28127 message number = 10, process id = 28127, time and date = 23:17:36 05/07/04 detached from shm2 message number = 11, process id = 28127, time and date = 23:17:36 05/07/04 Unlocked semaphore semid=1703936 message number = 12, process id = 28127, time and date = 23:17:36 05/07/04 I, parent, forked process pid=28128 message number = 13, process id = 28127, time and date = 23:17:36 05/07/04 I, parent, forked process pid=28129 message number = 14, process id = 28127, time and date = 23:17:36 05/07/04 I, parent, forked process pid=28130 message number = 15, process id = 28127, time and date = 23:17:36 05/07/04 received notification of child process 28128 terminated message number = 16, process id = 28127, time and date = 23:17:36 05/07/04 locked semaphore semid=0 message number = 17, process id = 28127, time and date = 23:17:36 05/07/04 attached shared memory segment with id 603 at address ff1f0000 message number = 18, process id = 28127, time and date = 23:17:36 05/07/04 shm2 content 4:28127,28128,28129,28130 message number = 19, process id = 28127, time and date = 23:17:36 05/07/04 detached from shm2 message number = 20, process id = 28127, time and date = 23:17:36 05/07/04 Unlocked semaphore semid=1703936 message number = 21, process id = 28127, time and date = 23:17:36 05/07/04 received notification of child process 28130 terminated message number = 22, process id = 28127, time and date = 23:17:36 05/07/04 locked semaphore semid=0 message number = 23, process id = 28127, time and date = 23:17:36 05/07/04 attached shared memory segment with id 603 at address ff1f0000 message number = 24, process id = 28127, time and date = 23:17:36 05/07/04 shm2 content 4:28127,28128,28129,28130 message number = 25, process id = 28127, time and date = 23:17:36 05/07/04 detached from shm2 message number = 26, process id = 28127, time and date = 23:17:36 05/07/04 Unlocked semaphore semid=1703936 message number = 27, process id = 28127, time and date = 23:17:36 05/07/04 received notification of child process 28129 terminated message number = 28, process id = 28127, time and date = 23:17:36 05/07/04 locked semaphore semid=0 message number = 29, process id = 28127, time and date = 23:17:36 05/07/04 attached shared memory segment with id 603 at address ff1f0000 message number = 30, process id = 28127, time and date = 23:17:36 05/07/04 shm2 content 4:28127,28128,28129,28130 message number = 31, process id = 28127, time and date = 23:17:36 05/07/04 detached from shm2 message number = 32, process id = 28127, time and date = 23:17:36 05/07/04 Unlocked semaphore semid=1703936 message number = 33, process id = 28127, time and date = 23:17:36 05/07/04 Removed semaphore semid=1703936 message number = 34, process id = 28127, time and date = 23:17:36 05/07/04 going to remove shared memory with id = 4001 message number = 35, process id = 28127, time and date = 23:17:36 05/07/04 removed shared memory with id = 4001 message number = 36, process id = 28127, time and date = 23:17:36 05/07/04 going to remove shared memory id = 603 message number = 37, process id = 28127, time and date = 23:17:36 05/07/04 removed shared memory with id = 603 message number = 38, process id = 28127, time and date = 23:17:36 05/07/04 the program is finished
log of the 1st child process:
message number = 12, process id = 28128, time and date = 23:17:36 05/07/04 I am a child process pid=28128 message number = 13, process id = 28128, time and date = 23:17:36 05/07/04 locked semaphore semid=0 message number = 14, process id = 28128, time and date = 23:17:36 05/07/04 attached shared memory segment with id 2302 at address ff1f0000 message number = 15, process id = 28128, time and date = 23:17:36 05/07/04 shm2 content 1:28127 message number = 16, process id = 28128, time and date = 23:17:36 05/07/04 created new shm2 with id 503 of size 12 message number = 17, process id = 28128, time and date = 23:17:36 05/07/04 attached new shm2 with id 503 at address ff1e0000 message number = 18, process id = 28128, time and date = 23:17:36 05/07/04 removed shared memory with id = 2302 message number = 19, process id = 28128, time and date = 23:17:36 05/07/04 shm2 content 2:28127,28128 message number = 20, process id = 28128, time and date = 23:17:36 05/07/04 detached from shm2 message number = 21, process id = 28128, time and date = 23:17:36 05/07/04 child process pid=28128 terminates
log of the 2nd child process:
message number = 13, process id = 28129, time and date = 23:17:36 05/07/04 I am a child process pid=28129 message number = 14, process id = 28129, time and date = 23:17:36 05/07/04 locked semaphore semid=0 message number = 15, process id = 28129, time and date = 23:17:36 05/07/04 attached shared memory segment with id 503 at address ff1f0000 message number = 16, process id = 28129, time and date = 23:17:36 05/07/04 shm2 content 2:28127,28128 message number = 17, process id = 28129, time and date = 23:17:36 05/07/04 created new shm2 with id 2402 of size 16 message number = 18, process id = 28129, time and date = 23:17:36 05/07/04 attached new shm2 with id 2402 at address ff1e0000 message number = 19, process id = 28129, time and date = 23:17:36 05/07/04 removed shared memory with id = 503 message number = 20, process id = 28129, time and date = 23:17:36 05/07/04 shm2 content 3:28127,28128,28129 message number = 21, process id = 28129, time and date = 23:17:36 05/07/04 detached from shm2 message number = 22, process id = 28129, time and date = 23:17:36 05/07/04 child process pid=28129 terminates
log of the 3rd child process:
message number = 14, process id = 28130, time and date = 23:17:36 05/07/04 I am a child process pid=28130 message number = 15, process id = 28130, time and date = 23:17:36 05/07/04 locked semaphore semid=0 message number = 16, process id = 28130, time and date = 23:17:36 05/07/04 attached shared memory segment with id 2402 at address ff1f0000 message number = 17, process id = 28130, time and date = 23:17:36 05/07/04 shm2 content 3:28127,28128,28129 message number = 18, process id = 28130, time and date = 23:17:36 05/07/04 created new shm2 with id 603 of size 20 message number = 19, process id = 28130, time and date = 23:17:36 05/07/04 attached new shm2 with id 603 at address ff1e0000 message number = 20, process id = 28130, time and date = 23:17:36 05/07/04 removed shared memory with id = 2402 message number = 21, process id = 28130, time and date = 23:17:36 05/07/04 shm2 content 4:28127,28128,28129,28130 message number = 22, process id = 28130, time and date = 23:17:36 05/07/04 detached from shm2 message number = 23, process id = 28130, time and date = 23:17:36 05/07/04 child process pid=28130 terminates
Back to Answers/Solutions Index Back to Answers/Solutions for Chapter 11 Index