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