简体   繁体   中英

cannot switch to blocking mode using fcntl in linux

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!

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.

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:~$ 

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM