cannot switch to blocking mode using fcntl in linux
Asked Answered
W

3

6

I have a sample program:

int main()
{
   const char* fn = "/tmp/tmpfifo";
   int i = mkfifo(fn, 0666);
   int fd = open(fn, O_RDONLY | O_NONBLOCK);
   int flags = fcntl(fd, F_GETFL);
   flags &= ~O_NONBLOCK;
   fcntl(fd, F_SETFL, flags);

   char buf[1024];
   int rd= read(fd, buf, 100);
   cout << rd << endl;
   remove(fn);
   return 0;
}

It seems that after removing the non-blocking flag from the file descriptor, the read call should block until something is written into the FIFO, but my program always runs without blocking and rd=0 result. Can you please explain this behaviour? Thanks!

Windblown answered 12/4, 2015 at 7:59 Comment(9)
looks like C++ and not C. See #2785000Merna
is c++, c difference important here?Windblown
When you read from fifo with rd = 0 as result, is there any change in errno value?Ballplayer
cout << rd << endl; is pure C++ but everything is explain in the previous link #2785000Merna
Yes, that can easily be replaced with a printf and is not relevant to the discussion.Paunchy
Have you examined flags before/after flags &= ~O_NONBLOCK; to insure the bitwise negation is accomplishing what you need? Why not set O_RDONLY instead flags with your 2nd call to fcntl as a test.?Paunchy
The writer should create the fifo firstMerna
@AntoJurković errno doesn't change.Windblown
@DavidC.Rankin I tried setting `fcntl(fd, F_SETFL, O_RDONLY) that didn't change anythingWindblown
R
4

The behavior you are seeing is expected. You've done the following:

  1. Opened the read end of the FIFO using O_NONBLOCK, so that a writer need not be present on the FIFO. This guarantees that the open() will immediately succeed.
  2. Disabled O_NONBLOCK before subsequent reads. You've now taken yourself back to a position that is equivalent to the standard (blocking) case where a FIFO had a reader and writer, but the writer closed the FIFO. At that point, the reader should see end-of-file, which is what you are seeing.
Ridings answered 13/4, 2015 at 20:20 Comment(0)
B
1

I looked at your code and at first glance it seems like it should work. There are no errors returned, you don't seem to be breaking any rules, but it's just not blocking.

So I went ahead and traced the read call to see what it was doing:

ftrace

And it goes all the way to the pipe_read function without any attempt to block. Once it's there it realizes there's nobody on the other side of the pipe and returns EOF.

So this is apparently by design, but with a pipe only the open call will try to block if there's no writer, once open returns it's just assumed that there must be a writer at the other end of that pipe or that you're nonblocking and ready to handle that. And it sort of makes sense. If you're trying to read from a pipe but the writer is gone (or was never there in the first place), you don't want to keep waiting there forever.

If you want to wait until a writer opens the pipe, don't use O_NONBLOCK in the open call. If you do use O_NONBLOCK in open, then there might not be anyone at the other end of the pipe and the read calls may just return EOF without blocking.

So in short make sure there's someone at the other end of the pipe when you're reading from it.

Brooks answered 12/4, 2015 at 9:41 Comment(0)
W
0

It's strange! I tried a code which opens the file without O_NONBLOCK and then procedes in 3 stages. The 3rd stage doesn'act correctly althoug the O_NONBLOCK flag results reset!

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>

int main()
{
   char buf[1024];
   int rd;
   const char* fn = "prova.txt";
   int i = mkfifo(fn, 0666);
   int fd = open(fn, O_RDONLY); // | O_NONBLOCK);
   int flags = fcntl(fd, F_GETFL);
   //flags &= ~O_NONBLOCK;
   printf("1) Waits!\t\tflags=0%08o\n",flags);

   rd= read(fd, buf, 100);
   printf("%d %o\n",rd,flags);

   flags |= O_NONBLOCK;
   printf("2) Doesn't wait!\tflags=0%08o\n",flags);
   fcntl(fd, F_SETFL, flags);
   rd= read(fd, buf, 100);
   printf("%d %o\n",rd,flags);  

   //This doen't act the flag ????
   flags &= ~O_NONBLOCK;
   fcntl(fd, F_SETFL, flags);
   flags=fcntl(fd, F_GETFL);
   printf("3) Waits!\t\tflags=0%08o\n",flags);
   rd= read(fd, buf, 100);
   printf("%d %o\n",rd,flags);

   puts("End!");
   return 0;
}

Here is the command sequence and the output:

sergio@zarathustra:~$ ./a.out &
[2] 6555
sergio@zarathustra:~$ echo xxx >> prova.txt
1) Waits!       flags=000100000
4 100000
2) Doesn't wait!    flags=000104000
0 104000
3) Waits!       flags=000100000
0 100000
End!
sergio@zarathustra:~$ 
Warmongering answered 12/4, 2015 at 9:35 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.