cannot switch to blocking mode using fcntl in linux - c

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.

Related

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.

Fread: ferror on pty without data?

I have two processes communicating via a pty, nonblocking. Problem is that the fread() on the master fails when there is no data available to process.
How can I ignore the "no reader/data present" case when reading from the unconnected file descriptor on the master side? I suspect there is some flag for open() or fcntl() which I skipped during reading?
// initialization:
int pty_fd = posix_openpt(O_RDWR | O_NOCTTY);
int rc = grantpt(pty_fd);
rc = unlockpt(pty_fd);
fcntl(pty_fd, F_SETFL, O_NONBLOCK);
fd_read = fdopen(pty_fd, "r");
// now, trying to read will fail if no data is present:
char buf[100];
int count = sizeof(buf);
size_t bytesRead = fread(buf, sizeof(char), count, fd_read);
if ((bytesRead == 0) && (ferror(fd_read)) {
printf("fail...\n");
}
Sure, I can ignore the return value of ferror(), but I suppose this is not the right way to use this function.
Ah, one thing: I found the POLLHUP trick on stackoverflowz. It works but is racy and hence not suitable for my case...
Greetings

why non-blocking write to disk doesn't return EAGAIN or EWOULDBLOCK?

I modified a program from APUE, the program first open a file, then mark the fd as non-blocking, then continue write to the fd until write return -1.
I think since disk I/O is slow, when write buffers in OS is nearly full, the write system call will return -1, and the errno should be EAGAIN or EWOULDBLOCK.
But I ran the program for about several minutes and I repeated running the program serveral times, the write system call didn't returned -1 even once! Why?
Here's the code:
#include "apue.h"
#include <errno.h>
#include <fcntl.h>
char buf[4096];
int
main(void)
{
int nwrite;
int fd = open("a.txt", O_RDWR);
if(fd<0){
printf("fd<0\n");
return 0;
}
int i;
for(i = 0; i<sizeof(buf); i++)
buf[i] = i*2;
set_fl(fd, O_NONBLOCK); /* set nonblocking */
while (1) {
nwrite = write(fd, buf, sizeof(buf));
if (nwrite < 0) {
printf("write returned:%d, errno=%d\n", nwrite, errno);
return 0;
}
}
clr_fl(STDOUT_FILENO, O_NONBLOCK); /* clear nonblocking */
exit(0);
}
The O_NONBLOCK flag is primarily meaningful for file descriptors representing streams (e.g, pipes, sockets, and character devices), where it prevents read and write operations from blocking when there is no data waiting to read, or buffers are too full to write anything more at the moment. It has no effect on file descriptors opened to regular files; disk I/O delays are essentially ignored by the system.
If you want to do asynchronous I/O to files, you may want to take a look at the POSIX AIO interface. Be warned that it's rather hairy and infrequently used, though.

Read and Write operations get bad fd and no such file

I have this C program.
I have two processes, father and son, and use semaphores to make them synchronize one at time.
The father has to write (n) numbers, ten in this case, always in the first byte of the opened file and the son has to read it.
The problem is that when I print the results, I get bad file descriptor for the write (father) and no such file for the read(the son).
Can you help me, please?? Thank you
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <pthread.h>
#include <semaphore.h>
#define FILENAME "test.txt"
#define MUTEX "/mutex"
#define READ "/read"
#define WRITE "/write"
int main(int argc, char *argv[]){
int i, pid, n=10, fd, x;
int nread, nwrite;
char c = 'a';
sem_t *mutex, *reader, *writer;
//fd = open(FILENAME, O_CREAT | O_TRUNC, 0666);
mutex = sem_open(MUTEX, O_CREAT, 0666, 1);
reader = sem_open(READ, O_CREAT, 0666, 0);
writer = sem_open(WRITE, O_CREAT, 0666, 1);
pid = fork();
fd = open(FILENAME, O_CREAT | O_TRUNC, 0777);
if(fd < 0){
perror("Open FILE error");
exit(-1);}
if(pid == 0){ // son
do{
sem_wait(reader); // si può leggere???
sem_wait(mutex);
lseek(fd, 0, SEEK_SET);
nread = read(fd, &x, sizeof(int));
if(nread <=0)
perror("Read error");
printf("Son has read (%d byte) = %d\n", nread, x);
fflush(NULL);
sem_post(mutex);
sem_post(writer);
}
while(x != (n-1));
exit(0);
}
else{
for(i=0; i<n; i++){
sem_wait(writer); // can I write??
sem_wait(mutex);
lseek(fd, 0, SEEK_SET);
nwrite = write(fd, &c, sizeof(char));
if(nwrite <= 0)
perror("nwrite error");
printf("Father has written (%d byte) %d\n", nwrite, i);
fflush(NULL);
sem_post(mutex);
sem_post(reader); // it's possible to read
}
//wait(NULL);
}
sem_unlink(MUTEX);
sem_unlink(READ);
sem_unlink(WRITE);
//remove(FILENAME);
exit(0);
}
First, you opened the file without specifying an o_flag. That's actually undefined behavior ("Applications shall specify exactly one of .... O_RDONLY .... O_WRONLY .... O_RDWR"), but for practical purposes means the file was opened read only.
Thus the parent's write operation fails with EBADF. Can't write to a read only file!
Second, the child's error checking is incorrect. read() may return zero on success, in which case errno, consulted by perror(), is not guaranteed to be meaningful. You mean to check for a return value of less than zero, not of less than or equal to zero.
Your open() call is opening the file for read only. You have:
fd = open(FILENAME, O_CREAT | O_TRUNC, 0777);
Because you don't explicitly say O_WRONLY or O_RDWR, and because the traditional value for O_RDONLY is 0, you are effectively opening the file read-only.
The 0777 permissions are suspect too. You are not creating an executable; you should not be giving the file executable permissions. In my book, you probably shouldn't be giving others write permission on the file. In fact, I'd probably go with 0600 permissions.
Your program is a bit strange.
First off, you are asking for trouble by having parent and child processes race to be the one to create the target file. It would be better for the parent to create and open the file before forking, and for (only) the child to open it after. Be aware that in that case the child should first close (its copy of) the file descriptor opened by the parent. Alternatively, the way you're doing things, if the parent opened the file then it would probably be sufficient for the child to just use the file descriptor it inherits, without opening the file itself at all.
With that said, it would be more usual for parent and child processes to communicate via a pipe than via a physical file. That has the particular advantage that you do not need to synchronize access via a semaphore; ordinary blocking I/O does the job.
Additionally, I don't see what your mutex semaphore is doing for you. Even with a design that requires you to manually synchronize writing and reading, it looks like your reader and writer semaphores will serve that purpose without help.
Importantly, your parent process is writing in sizeof(char)-byte uints, whereas your child process is trying to read in sizeof(int)-byte units. This is unlikely to have the result you want.
Furthermore, the read() and write() functions may return successfully without having transferred the full number of bytes requested (unless that number is 1 and the file is open in blocking mode). You need to account for that by being prepared to use multiple I/O operations to transfer multi-byte data, if necessary.
Finally, it would be best for just one process to unlink your semaphores. It is ok for that to happen while the other process is still running.

FIFO pipe is always readable in select()

In C pseudo-code:
while (1) {
fifo = open("fifo", O_RDONLY | O_NONBLOCK);
fd_set read;
FD_SET(fifo, &read);
select(nfds, &read, NULL, NULL, NULL);
}
The process sleeps as triggered by select() until another process writes into fifo. Afterwards it will always find fifo as a readable file descriptor.
How to avoid this behavior (that is, after fifo has been read once, how to make it be found as unreadable until it gets another write?)
You opened that FIFO as read only (O_RDONLY), whenever there is no writer to the FIFO, the read end will receive an EOF.
Select system call will return on EOF and for every EOF you handle there will be a new EOF. This is the reason for the observed behavior.
To avoid this open that FIFO for both reading and writing (O_RDWR). This ensures that you have at least one writer on the FIFO thus there wont be an EOF and as a result select won't return unless someone writes to that FIFO.
The simple answer is to read until read() returns EWOULDBLOCK (or EAGAIN), or craps out with an error.
What you are saying simply cannot be happening unless the operating system (or runtime) that you are using is buggy. Otherwise you must be doing something wrong. For example, select() is using level-triggered I/O. I'd think that, most likely, you are not draining the socket completely, and so select() always indicates that you have something left in there (this does not happen with edge-triggered event notifications).
Below is a simple example that shows how one should read until the read() returns EWOULDBLOCK in order to avoid leaving descriptor in readable state (I've compiled and tested this on OS X, and there is also mostly no error checking, but you should get the idea):
/*
* FIFO example using select.
*
* $ mkfifo /tmp/fifo
* $ clang -Wall -o test ./test.c
* $ ./test &
* $ echo 'hello' > /tmp/fifo
* $ echo 'hello world' > /tmp/fifo
* $ killall test
*/
#include <sys/types.h>
#include <sys/select.h>
#include <errno.h>
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
int main()
{
int fd;
int n;
fd_set set;
ssize_t bytes;
size_t total_bytes;
char buf[1024];
fd = open("/tmp/fifo", O_RDWR | O_NONBLOCK);
if (fd == -1) {
perror("open");
return EXIT_FAILURE;
}
FD_ZERO(&set);
FD_SET(fd, &set);
for (;;) {
n = select(fd+1, &set, NULL, NULL, NULL);
if (!n)
continue;
if (n == -1) {
perror("select");
return EXIT_FAILURE;
}
if (FD_ISSET(fd, &set)) {
printf("Descriptor %d is ready.\n", fd);
total_bytes = 0;
for (;;) {
bytes = read(fd, buf, sizeof(buf));
if (bytes > 0) {
total_bytes += (size_t)bytes;
} else {
if (errno == EWOULDBLOCK) {
/* Done reading */
printf("done reading (%lu bytes)\n", total_bytes);
break;
} else {
perror("read");
return EXIT_FAILURE;
}
}
}
}
}
return EXIT_SUCCESS;
}
Basically, level-triggered I/O means that you get notified all the time if there is something to read, even though you might have been notified of this before. On a contrary, edge-triggered I/O means that you are getting notified only once every time new data arrives and it doesn't matter whether you read it or not. select() is a level-triggered I/O interface.
Hope it helps. Good Luck!

Resources