Using Standard I/O Library to read and write the file. Rather than using signal function, I used sigaction. Thus don’t need to call TELL_WAIT in the for body.
/**
* apue-chap10: exercise10-6c.c
*
* Description: Standard I/O Library + sigaction
*
* Created On: Feb 16, 2012
*
* @author: Huang Zhu
*
* @email: zhuhuang.zp@gmail.com
*/
#include <apueerr.h>
#include <signal.h>
#include <stdio.h>
#include <fcntl.h>
#define __USE_POSIX199309 1
static volatile sig_atomic_t sigflag;
static sigset_t newmask, oldmask, zeromask;
struct sigaction act, oact1, oact2;
static void sig_usr(int signo)
{
sigflag = 1;
}
void TELL_WAIT(void)
{
act.sa_handler = sig_usr;
sigemptyset(&act.sa_mask);
act.sa_flags = 0;
if(sigaction(SIGUSR1, &act, &oact1) < 0)
err_sys("sigaction SIGUSR1 error");
if(sigaction(SIGUSR2, &act, &oact2) < 0)
err_sys("sigaction SIGUSR2 error");
sigemptyset(&zeromask);
sigemptyset(&newmask);
sigaddset(&newmask, SIGUSR1);
sigaddset(&newmask, SIGUSR2);
//block SIGUSR1 and SIGUSR2, and save current signal mask
if(sigprocmask(SIG_BLOCK, &newmask, &oldmask) < 0)
perror("SIG_BLOCK error");
}
void TELL_PARENT(pid_t pid)
{
kill(pid, SIGUSR2);
}
void TELL_CHILD(pid_t pid)
{
kill(pid, SIGUSR1);
}
void WAIT_PARENT(void)
{
while(sigflag == 0)
sigsuspend(&zeromask); //set mask and sleep and wait
sigflag = 0;
if(sigprocmask(SIG_SETMASK, &oldmask, NULL) < 0)
perror("SIG_SETMASK error");
}
void WAIT_CHILD(void)
{
while(sigflag == 0)
sigsuspend(&zeromask); //set mask and sleep and wait
sigflag = 0;
if(sigprocmask(SIG_SETMASK, &oldmask, NULL) < 0)
perror("SIG_SETMASK error");
}
int main(void)
{
int fd, pid, ppid, counter, round = 5;
FILE* fp;
char *filename = "counter.file";
int i, j;
if((fd = open(filename, O_RDWR | O_CREAT | O_TRUNC | O_SYNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) < 0)
err_sys("open error");
if((fp = fdopen(fd, "r+")) == NULL )
err_sys("fdopen error");
if(fputc(0, fp) != EOF){
printf("Writing initial value of the counter: 0\n");
fflush(fp); //if fflush is not used, the change of counter cannot be seen instantly by other readers.
}
if(ferror(fp))
err_sys("fputc error");
TELL_WAIT();
if((pid = fork()) < 0){
err_sys("fork error");
}else if(pid == 0){ //child
ppid = getppid();
for(i = 0; i < round; i++){
printf("\nChild: round %d\n", i+1);
counter = -1;
rewind(fp);
counter = fgetc(fp);
printf("Child: read counter from the file: %d\n", counter);
counter++;
printf("Child: increase counter to: %d\n", counter);
rewind(fp);
if(fputc(counter, fp) != EOF){
printf("Child: Write counter to the file: %d\n", counter);
fflush(fp);
}
if(ferror(fp))
err_sys("Child: fputc error");
TELL_PARENT(ppid);
WAIT_PARENT();
}
counter = -1;
rewind(fp);
counter = fgetc(fp);
printf("\nChild: read counter from the file: %d\n", counter);
exit(0);
}else{ //parent
for(j = 0; j < round; j++){
WAIT_CHILD();
printf("\nParent: round %d\n", j+1);
counter = -1;
rewind(fp);
counter = fgetc(fp);
printf("Parent: read counter from the file: %d\n", counter);
counter++;
printf("Parent: increase counter to: %d\n", counter);
rewind(fp);
if(fputc(counter, fp) != EOF){
printf("Parent: Write counter to the file: %d\n", counter);
fflush(fp);
}
if(ferror(fp))
err_sys("Parent: fputc error");
TELL_CHILD(pid);
}
}
fclose(fp);
close(fd);
return 0;
}