#include #include #include #include #include /* * mirror.c - copy standard input to two output files at once * usage: simulcp outfile1 outfile2 * - three processes run in parallel sharing memory * - reader process fills a buffer , flags it as ready * two readers wait for ready flag, each write to output * then raise another semaphore when done */ #define BUFFERSIZE BUFSIZ #define MEMKEY 4444 #define SEMKEY 4445 struct databuf { char buf[BUFFERSIZE]; int amt ; }; typedef struct databuf BUFFER; #define oops(m,x) {perror(m); cleanup(0); exit(x);} int segid; /* shared segment here */ int semid; /* three semaphores, two ready's one done */ void cleanup(int); main(int ac, char *av[]) { struct databuf *buffer; /* a pointer to the buffer */ int pid; if ( ac != 3 ){ fprintf(stderr,"usage: mirror outfile1 outfile2\n"); exit(1); } /** get a buffer for shared memory **/ segid = shmget(MEMKEY,sizeof(BUFFER),0666|IPC_CREAT); if ( segid == -1 ) oops("shmget",1); buffer = shmat(segid,NULL,0); if ( buffer == (void *) -1 ) oops("shmat",2); /** get two semaphores, [ok2read,ok2fill] **/ semid = semget(SEMKEY, 3, 0666|IPC_CREAT|IPC_EXCL); if ( semid == -1 ) oops("semget",4); set_sem_value(semid,0,2); /* number of writers done */ set_sem_value(semid,1,0); /* writer 1 waits for this */ set_sem_value(semid,2,0); /* writer 2 waits for this */ signal(SIGINT,cleanup); /* remove ipc objects */ /** get two writing children **/ if ( ( pid = fork() ) == -1 ) oops("fork one",20); if ( pid == 0 ) writer(1,av[1], buffer, semid); else { if ( ( pid = fork() ) == -1 ) oops("fork two", 20); if ( pid == 0 ) writer(2,av[2], buffer, semid); else { reader(buffer, semid); printf("Waiting for children\n"); while( wait(NULL) != -1 ) ; cleanup(0); } } } void cleanup(int s) { shmctl(segid, IPC_RMID, NULL); /* delete shmem */ semctl(semid, 0, IPC_RMID, NULL); /* delete sem's */ } set_sem_value(int semid, int semnum, int val) { union semun {int val; struct semid_ds *buf; unsigned short *array;}; union semun initval; /* initializer for sem's */ initval.val = val; if ( semctl(semid, semnum, SETVAL, initval) == -1 ) oops("semctl",4); } /* * read from standard input to buffer, then set FULL semaphore */ reader(BUFFER *buffer, int semid) { int bnum = 1; do { semaphore_operation(0,semid,0,-2); printf("reading chunk %d\n", bnum++); buffer->amt = read(0,buffer->buf,BUFFERSIZE); semaphore_operation(0,semid,1, 1); semaphore_operation(0,semid,2, 1); } while( buffer->amt > 0 ); printf("reader done\n"); } /* * pours contents of buckets into filename */ writer(int semnum, char *filename, BUFFER *buffer, int semid) { int fd = open(filename, O_WRONLY|O_CREAT, 0644); tabs(semnum); printf("writer %d to %s pid %d\n", semnum, filename, getpid()); while(1){ semaphore_operation(semnum,semid,semnum,-1); /* wait for flag */ tabs(semnum); printf("writing to %s\n", filename); if ( buffer->amt <= 0 || write(fd,buffer->buf,buffer->amt) == -1) break; semaphore_operation(semnum,semid,0,+1); /* I am done */ } close(fd); printf("closed %s\n", filename); } semaphore_operation(int indent, int semid, int semnum, int operation) { struct sembuf action; action.sem_op = operation; action.sem_num = semnum; action.sem_flg = 0; tabs(indent); printf("[sem %d operation %d]\n", semnum, operation); if ( semop(semid, &action, 1) == -1 ) oops("semop", 2); } tabs(int n) { while(n--) printf("\t\t"); }