
/* timedselect.c - It reads from two pipes with timeout. It uses the
   select function
*/


#include <sys/types.h>
#include <sys/time.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#define MAXLINE 20

void child(int fd[2], int seed, int who);

int main(void)
{
  int     m, n, rc; 
  int fd1[2];     /* pipe for communications from child1 to parent */
  int fd2[2];     /* pipe for communications from child2 to parent */
  pid_t   pid;
  char    line[MAXLINE];
  fd_set   readset;
  static struct timeval timeout;
  static struct timeval tspecb, tspeca;
  char line1[60];
  
  /* child1 */
  if (pipe(fd1) < 0) {
    perror("pipe1");
    exit(1);}
  if ( (pid = fork()) < 0) {
    perror("fork1");
    exit(1);}
  else if (pid == 0) {  /*We are in child 1*/
    child(fd1, 17, 1);}
  
  /* child2 */
  if (pipe(fd2) < 0) {
    perror("pipe2");
    exit(1);}
  if ( (pid = fork()) < 0) {
    perror("fork2");
    exit(1);}
  else if (pid == 0) {  /*We are in child 2*/
    child(fd2, 19, 2);}
  
  /* parent */
  
  close(fd1[1]);
  close(fd2[1]);
  m = 1 + ((fd1[0] < fd2[0])?fd2[0]:fd1[0]); /*Max # of objs to wait for*/
  /*Setting a timeout for 1.1 seconds*/
  timeout.tv_sec = 1;
  timeout.tv_usec = 100000;
  while (1) {
    gettimeofday(&tspecb, NULL);
    /*
    if (clock_gettime(CLOCK_REALTIME, &tspecb) < 0) {
      perror("clock_gettime");
      exit(1);
    }
    */
    sprintf(line1, "Time before select: sec: %ld  sec: %ld nsec\n",
	    tspecb.tv_sec, tspecb.tv_usec);
    write(STDOUT_FILENO, line1, strlen(line1));
    FD_ZERO(&readset);
    FD_SET(fd1[0], &readset);
    FD_SET(fd2[0], &readset);
    if ((rc = select(m,&readset, NULL, NULL, &timeout)) < 0) {
      perror("select");
      exit(1);}
    if (rc == 0) { /*No read operation has completed*/
      write(STDOUT_FILENO, "\nTimeout: \n", 11);
    } else { /*Some read operation has completed*/
      if (FD_ISSET(fd1[0], &readset)) {
	bzero(line1,60);
	n = read(fd1[0], line, MAXLINE);
	gettimeofday(&tspeca, NULL);
	sprintf(line1, "No Timeout        : sec: %1ld nsec: %6ld %20s\n",
		tspeca.tv_sec, tspeca.tv_usec, line);
	write(STDOUT_FILENO, line1, strlen(line1));
      }
      if (FD_ISSET(fd2[0], &readset)) {
	bzero(line1,60);
	n = read(fd2[0], line, MAXLINE);
	gettimeofday(&tspeca, NULL);
	sprintf(line1, "No Timeout        : sec: %1ld nsec: %6ld %20s\n",
		tspeca.tv_sec, tspeca.tv_usec, line);
	write(STDOUT_FILENO, line1, strlen(line1));
      }
    }
  }
  exit(0);
}

void child (int fd[2], int seed, int who) {
  char line[MAXLINE];
  
  close(fd[0]);/*Close end of pipe we are not using*/
  srand(seed); /*Initializing the seed for the standard 
		 random number generator*/
  sprintf(line, "From child %d\n", who); /*String sent on pipe*/
  while (1) {
    write(fd[1], line, 13);
    sleep(rand() % 3 + 1);} /*we sleep 1 to 3 seconds*/
  exit(0);
}

