How to make a file descriptor blocking? - c

Given an arbitrary file descriptor, can I make it blocking if it is non-blocking? If so, how?

Its been a while since I played with C, but you could use the fcntl() function to change the flags of a file descriptor:
#include <unistd.h>
#include <fcntl.h>
// Save the existing flags
saved_flags = fcntl(fd, F_GETFL);
// Set the new flags with O_NONBLOCK masked out
fcntl(fd, F_SETFL, saved_flags & ~O_NONBLOCK);

I would expect simply non-setting the O_NONBLOCK flag should revert the file descriptor to the default mode, which is blocking:
/* Makes the given file descriptor non-blocking.
* Returns 1 on success, 0 on failure.
*/
int make_blocking(int fd)
{
int flags;
flags = fcntl(fd, F_GETFL, 0);
if(flags == -1) /* Failed? */
return 0;
/* Clear the blocking flag. */
flags &= ~O_NONBLOCK;
return fcntl(fd, F_SETFL, flags) != -1;
}

Related

Why my fcntl function doesn't set the flag?

my program](https://i.stack.imgur.com/nvyaw.png)
After running my program waiting till there will be a symbol to read, but I want to end the program when the read function cannot read anything
Id tried to set the flag inside the open function and it worked, but my exercise is to set the flag by the fcntl func
First, you should read the current flags and update it like:
int flags = fcntl (a, F_GETFL, 0);
if (flags == -1) {
// handle error
}
flags |= O_NONBLOCK;
fcntl (a, F_SETFL, flags);

POSIX flags - how to set all of them / individual ones

I have this peice of code that should read from a pseudo terminal and print to another pseudo terminal (stdin):
// Declare & define a file descriptor.
int fd;
int status;
char string[] = "XXXX";
char buffer[8];
// Establish connection between a file and the file descriptor.
fd = open("/dev/pts/4", O_RDWR);
// Check if connection was established.
if(fd == -1){
printf("Assigning failed: %s\n", strerror(errno));
}
else{
fputs("Assigning successful!\n", stdout);
// Set some flags for the connection.
fcntl(fd, F_SETFL, 0);
}
// Read from the connection.
status = read(fd, buffer, 8);
if (status == -1){
printf("Read failed: %s\n", strerror(errno));
}
else{
printf("I read this: %s\n", buffer);
}
return 0;
I don't know exactly what fcntl(fd, F_SETFL, 0); does, but untill I used it I wasn't able to read from the /dev/pts/4. After I used it for the first time I could read normaly, even if I commented out this line of code.
I tried to explain it to myself reading POSIX...
F_SETFL flag is defined in the POSIX as:
Set the file status flags, defined in <fcntl.h>, for the file
description associated with fildes from the corresponding bits in the
third argument, arg, taken as type int. Bits corresponding to the file
access mode and the file creation flags, as defined in <fcntl.h>, that
are set in arg shall be ignored. If any bits in arg other than those
mentioned here are changed by the application, the result is
unspecified. If fildes does not support non-blocking operations, it is
unspecified whether the O_NONBLOCK flag will be ignored.
So it sets file status flags asociated with the 1st argument (file descriptor) of fnctl() to 0? I found an explanation about the status flags in the POSIX:
The <fcntl.h> header shall define the following symbolic constants for
use as file status flags for open(), openat(), and fcntl(). The values
shall be suitable for use in #if preprocessing directives.
O_APPEND Set append mode. O_DSYNC Write according
to synchronized I/O data integrity completion. O_NONBLOCK
Non-blocking mode. O_RSYNC Synchronized read I/O
operations. O_SYNC Write according to synchronized I/O
file integrity completion.
So does fcntl(fd, F_SETFL, 0); set all those to 0? Are all of those flags a single bit? How do I only set one of them to 1 or 0? And how do I know which bit is assigned to which flag?
It's a bitmask. Each flag is a bit (or several bits) in the integer you pass to fcntl. Each symbolic constant expands to a number in which only the corresponding bit(s) is set, and so you can set several flags by ORing them together. For instance, if bit 2 is the append flag, then O_APPEND would be 0b100 == 4; if bit 3 is the nonblock flag, then O_NONBLOCK would be 0b1000 == 8, and so on. But by using the symbolic constants, you don't need to know which bits they actually are, which is good since they may vary between OSes.
In fcntl(fd, F_SETFL, 0), the number 0 has no bits set, so all the flags are cleared. To set append and clear the rest, you could do fcntl(fd, F_SETFL, O_APPEND);. To set both append and nonblock, OR their constants together: fcntl(fd, F_SETFL, O_APPEND | O_NONBLOCK);
With similar bit operations, you can operate on the flags returned by fl = fcntl(fd, F_GETFL):
int fl = fcntl(fd, F_GETFL);
if (fl & O_APPEND) { ... } // test if in append mode
fcntl(fd, F_SETFL, fl | O_NONBLOCK); // turn on nonblock and keep everything else the same
fcntl(fd, F_SETFL, fl & ~O_DSYNC); // turn off dsync and keep everything else the same
There's some more examples here.

Why fcntl(fd, F_SETFL, 0) use in serial port programming

I am starting serial port programming in Linux. After reading several examples on the web, I don't understand exact effect of fcntl(fd, F_SETFL, 0)? It is clearing bits, but what flags does it affect? What does it set and or clear?
Take one by one
1) Function call used
fcntl() - It perform the operation on file descriptor passed in argument.
2) 2nd argument in call
F_SETFL (int)
Set the file status flags to the value specified by arg. File access
mode (O_RDONLY, O_WRONLY, O_RDWR) and file creation flags (i.e.,
O_CREAT, O_EXCL, O_NOCTTY, O_TRUNC) in arg are ignored. On Linux this
command can change only the O_APPEND, O_ASYNC, O_DIRECT, O_NOATIME,
and O_NONBLOCK flags.
3) 3rd argument in call
It is 0 means, It set file status flag to zero.
As Jean-Baptiste Yunès said in comment.
file access mode and file creation flags are ignored. This command
reset every other flags: no append, no async, no direct, no atime, and
no nonblocking
So finally
fcntl(fd, F_SETFL, 0)
This call will set opened file desciptor's file status flag to value 0.
But idealy this way we should not change file status flag.
Best way is to first get the current file status flag using F_GETFL and then just change required bit in that.
See example:
If you want to modify the file status flags, you should get the current flags with F_GETFL and modify the value. Don’t assume that the flags listed here are the only ones that are implemented; your program may be run years from now and more flags may exist then. For example, here is a function to set or clear the flag O_NONBLOCK without altering any other flags:
/* Set the O_NONBLOCK flag of desc if value is nonzero,
or clear the flag if value is 0.
Return 0 on success, or -1 on error with errno set. */
int
set_nonblock_flag (int desc, int value)
{
int oldflags = fcntl (desc, F_GETFL, 0);
/* If reading the flags failed, return error indication now. */
if (oldflags == -1)
return -1;
/* Set just the flag we want to set. */
if (value != 0)
oldflags |= O_NONBLOCK;
else
oldflags &= ~O_NONBLOCK;
/* Store modified flag word in the descriptor. */
return fcntl (desc, F_SETFL, oldflags);
}
per the man page for fcntl()
F_SETFL (int)
Set the file status flags to the value specified by arg. File
access mode (O_RDONLY, O_WRONLY, O_RDWR) and file creation
flags (i.e., O_CREAT, O_EXCL, O_NOCTTY, O_TRUNC) in arg are
ignored. On Linux this command can change only the O_APPEND,
O_ASYNC, O_DIRECT, O_NOATIME, and O_NONBLOCK flags. It is not
possible to change the O_DSYNC and O_SYNC flags; see BUGS,
below.
This is from the man page.

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:
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.
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:
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.

Linux C, Why fcntl act on STDIN will also affect on STDOUT and STDERR?

I have met a problem when acting function fcntl on stdin, when I set the stdin FD status flag to O_NONBLOCK, It works well but within a side effect. The status flag of stdout and stderr has also changed to O_NONBLOCK.
I investigated the source code of function fcntl, SYSCALL_DEFINE3 and do_fcntl, but got nothing helps. Also stackoverflow or google. I consider that it may related to kernel or glibc implementation.
My computer is Ubuntu 12.04 on x86_64, within gcc 4.6.3 installed.
int flag = 0;
int value = O_NONBLOCK;
int fd = open("./tmp", O_RDONLY);
if(-1 == (flag = fcntl(fd, F_GETFL)))
fprintf(stdout, "%d:%s\n", errno, strerror(errno));
flag = fcntl(stdin->_fileno, F_GETFL);
flag = fcntl(stderr->_fileno, F_GETFL);
if(-1 == (flag = fcntl(stdout->_fileno, F_GETFL)))
fprintf(stdout, "%d:%s\n", errno, strerror(errno));
flag = fcntl(stdout->_fileno, F_SETFL, flag | O_NONBLOCK);
flag = fcntl(fd, F_GETFL);
flag = fcntl(stdin->_fileno, F_GETFL);
flag = fcntl(stdout->_fileno, F_GETFL);
flag = fcntl(stderr->_fileno, F_GETFL);
flag = fcntl(stdin->_fileno, F_SETFL, flag | O_APPEND);
flag = fcntl(fd, F_GETFL);
flag = fcntl(stdin->_fileno, F_GETFL);
flag = fcntl(stdout->_fileno, F_GETFL);
flag = fcntl(stderr->_fileno, F_GETFL);
close(fd);
This is my code for this problem.
One of the 'tricks' traditionally used by the login process (or terminal opening process) is to open the terminal in read-write mode for file descriptor 0 (standard input), and then duplicate that for file descriptors 1 and 2 (standard output and standard error). This means that:
All three standard file descriptors share the same open file description.
You can write to standard input and read from standard output or standard error.
Changing the file description information for one changes it for the others.
The F_GETFL and F_SETFL options to fcntl() are related to the open file description.
The F_GETFD and F_SETFD options to fcntl() are related to the file descriptor.
A given open file description may have several file descriptors associated with, either within a single process (after dup() or dup2()) or across processes (because of fork()).
Following from Jonathan's answer, here's some saner code:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
void show_nonblock_status(void) {
char streams[3][7] = {"stdin", "stdout", "stderr"};
for ( int i = 0; i < 3; ++i ) {
int flag = fcntl(i, F_GETFL);
if ( flag == -1 ) {
perror("error getting flags");
exit(EXIT_FAILURE);
}
if ( flag & O_NONBLOCK ) {
printf("O_NONBLOCK is set for %s\n", streams[i]);
} else {
printf("O_NONBLOCK is not set for %s\n", streams[i]);
}
}
}
int main(void) {
show_nonblock_status();
int flag = fcntl(1, F_GETFL);
if ( flag == -1 ) {
perror("error getting flags");
exit(EXIT_FAILURE);
}
flag = fcntl(1, F_SETFL, flag | O_NONBLOCK);
if ( flag == -1 ) {
perror("error getting flags");
exit(EXIT_FAILURE);
}
show_nonblock_status();
return 0;
}
which gives the following output under various uses:
paul#local:~/src/c/scratch$ ./fct
O_NONBLOCK is not set for stdin
O_NONBLOCK is not set for stdout
O_NONBLOCK is not set for stderr
O_NONBLOCK is set for stdin
O_NONBLOCK is set for stdout
O_NONBLOCK is set for stderr
paul#local:~/src/c/scratch$ cat testfile | ./fct
O_NONBLOCK is not set for stdin
O_NONBLOCK is not set for stdout
O_NONBLOCK is not set for stderr
O_NONBLOCK is not set for stdin
O_NONBLOCK is set for stdout
O_NONBLOCK is set for stderr
paul#local:~/src/c/scratch$ cat testfile | ./fct 2>/dev/null
O_NONBLOCK is not set for stdin
O_NONBLOCK is not set for stdout
O_NONBLOCK is not set for stderr
O_NONBLOCK is not set for stdin
O_NONBLOCK is set for stdout
O_NONBLOCK is not set for stderr
paul#local:~/src/c/scratch$
In the first case, the file description is the same, so O_NONBLOCK is set for all three.
In the second case, a file is piped to stdin, so that has a different file description to stdout and stderr, both of which have O_NONBLOCK set.
In the third case, a file is piped to stdin, and stderr is redirected to /dev/null, so all 3 file descriptions are different, and O_NONBLOCK is only set for stdout.

Resources