Mike
Mike

Reputation: 49403

failure to understand select() system call

I'm running an test with a FIFO and a select() system command. The idea is:

  1. Process one should sleep waiting for messages from the FIFO with a select() command
  2. If no messages come in, process one should wake every 5 seconds and say "nothing yet"
  3. If a message comes in, it should wake up, print the message, then terminate

So here's the code NOTE I'm taking out the error checking to save space:

//process 1's code
int main()
{
  int fd, ret;
  fd_set rfds;
  char buffer[100] = {0}; 
  char * myfifo = "/tmp/myfifo";
  struct timeval tv;

  tv.tv_sec = 5;  // 5 second sleep
  tv.tv_usec = 0;

  mkfifo(myfifo, 0666); //Make the fifo

  fd = open(myfifo, O_RDONLY);
  FD_ZERO(&rfds);    // clear the flags
  FD_SET(fd, &rfds); // set "read" on fd

  while((ret = select(fd+1, &rfds, NULL, NULL, &tv)) <= 0) //should be 1 when we're ready to read
  {
     FD_ZERO(&rfds);     //I believe we should clear/reset these every time?
     FD_SET(fd, &rfds);
     printf("Nothing yet...%d\n",ret);
     fflush(stdout);
  }
  n = read(fd, buffer, 100);
  printf("I got a read of %d bytes\nIt was %s\n",n, buffer);

  unlink(myfifo);

  return 0;
}

Once I have process 1 up and running, I wait a good 10s then I kick off process two:

//Process 2's code
int main()
{
  int fd, n, ret;
  fd_set rfds;
  char buffer[100] = {0};
  char * myfifo = "/tmp/myfifo";
  fd = open(myfifo, O_WRONLY);

  printf("What would you like to send?\n");
  fgets(buffer, 100, stdin);
  write(fd, buffer, strlen(buffer));

  close(fd);
  return 0;
}

I'm expecting to see something like:

Nothing yet...0
Nothing yet...0
I got a read of X bytes
It was <some string>

Instead I see nothing, until I type in something and hit enter for process two, process one returns the string correctly... but why isn't the loop printing the message?

Upvotes: 3

Views: 2313

Answers (2)

alk
alk

Reputation: 70941

As you are on Linux you might like to add O_NONBLOCK to the open() call on the reader side. For details please see man 7 fifo.

Upvotes: 3

Serge
Serge

Reputation: 6095

man select:

On Linux, select() modifies timeout to reflect the amount of time not slept; most other implementations do not do this. (POSIX.1-2001 permits either behavior.)

Thus you should reinitialize tv inside the loop. But this is not a cause of your problem. The cause is:

man mkfifo:

Opening a FIFO for reading normally blocks until some other process opens the same FIFO for writing, and vice versa.

Upvotes: 6

Related Questions