Is the write() function in C blocking or non-blocking? - c

I looked on the Linux man pages for the answer but can't seem to find it. I know that read() is blocking but I'm still not sure about write().
Can anyone point me to any documentation for clarification?

Read POSIX on read() and
write(). See also functions such as open() and pipe().
It depends on the attributes of the file descriptor you're reading from or writing to (think O_NONBLOCK, for example), and on the underlying file type (disk file vs pipe vs FIFO vs socket vs character or block special), and so on.
Succinctly, both read() and write() can be blocking or non-blocking, depending on circumstances.

Related

Should fsync() be called before or after write() call?

I understand the working of write() call wherein it writes the data only to kernel's buffers which is later written to disk by kernel after sorting the data optimally.
Calling fsync() on file descriptor makes sure that data is written to disk as soon as it's posted in the kernel's buffer.
My question is, whether fsync() should be called before write() or after write() call. I've read couple of books on the topic, looked on the internal as well but couldn't find a satisfactory answer.
fsync should be called after the write system call. It flushes the file data buffers and the metadata to the physical device.
Alternatively, you can use the O_SYNC flag in the open system call for the file and get the same result for each subsequent write call.
your understanding of write is kinda wrong. after calling the write system call, it queues the data into kernel's buffer then it flushes out the data into the opened file descriptor whether it is an opened file or a socket.

Fifos in Linux in packet mode

I have read the Linux manpage of pipe2, that states that you can use the O_DIRECT flag to create a pipe that performs I/O in packet mode.
I haven't found anything similar for fifos (named pipes) although I have heard that pipes and fifos share a lot of code in Linux, and it could be useful to me in a project (we already pass messages in fifos, but we have to seek for an especial terminator, reading one byte at a time).
Is there anything equivalent to perform fifo I/O in packet mode?
The O_* flags on a file descriptor can usually be changed by fcntl(fd, F_SETFL, ...) but in this case I don't think it will work, because of this:
https://lkml.org/lkml/2015/12/15/480
It's a patch that was submitted just 2 weeks ago to support exactly this use case, and the only replies to it have been a couple of build failures from an automated tester.
So you can try fixing that patch and applying it (should be easy - looks like a typo, the f should be filp)...
or (this is the option I'd prefer) see if your needs can be met by an AF_UNIX, SOCK_SEQPACKET socket instead of a pipe with this new flag. They're more powerful and more portable.
(I assume you already tried passing the O_DIRECT to open when you open the named pipe, since that's the most obvious thing.)
Both pipe & fifo are byte stream, it open a file descriptor, then use read() and write() to do communication.
If u want a packet (I am not sure what u mean, I assume you want to read a block of data without determine the boundary by yourself), POSIX - message queue might be a good choice. It send / receive data in unit of a message instead of byte by byte.
And you can also set priority on the messages which change the order of receiving, if all messages have the same priority (e.g 0), then the send & receive order is the same as FIFO.
If that's what u want, then check man mq_overview for details.
I'm not able to switch to a socket or message queue, and am stuck with using pipe. But good news, the patch refereed to in user2404501's answer eventually got accepted and is in linux v4.5 and newer. So using fnctl() to set O_DIRECT on a named pipe is valid.
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=0dbf5f20652108106cb822ad7662c786baaa03ff

How to implement a timeout in open/write function

I want to use named fifo channel and I want to implement a timeout when I write in this fifo.
fd = open(pipe, O_WRONLY);
write(fd, msg, len);
Program is blocked by function open, so using the function select will not work.
Thanks.
use select() and its timeout argument.
Read pipe(7), fifo(7), poll(2)
You might setup a timer or or alarm with a signal handler (see time(7) & signal(7)) before your call to open(2) - but I won't do that - or you could use the O_NONBLOCK flag, since fifo(7) says:
A process can open a FIFO in nonblocking mode. In this case, opening
for read-only will succeed even if no-one has opened on the write
side yet, opening for write-only will fail with ENXIO (no such device
or address) unless the other end has already been opened.
However, you need something (some other process reading) on the other side of the FIFO or pipe.
Perhaps you should consider using unix(7) sockets, i.e. the AF_UNIX address family. It looks more relevant to your case: change your code above (trying to open for writing a FIFO) to a AF_UNIX socket on the client side (with a connect), and change the other process to become an AF_UNIX socket server.
As 5gon12eder commented, you might also look into inotify(7). Or even perhaps D-bus !
I'm guessing that FIFOs or pipes are not the right solution in your situation. You should explain more and give a broader picture of your concerns and goals.

Linux Descriptor Type

How do I get the descriptor type? I am using epoll to monitor lots of descriptors like sockets, timers, and signals. I saw it is possible using fstat, but the mode only says something about sockets and pipes. fstat manpage. Is there a special function to identity a descriptor?
I do not think there is any simple or uniform way to do what you are asking. The command lsof]1 manages to determine this information so you may want to take a look at that code to see what they are doing.
Off the top of my head to determine if a descriptor is a socket you can use getsockopt(2). If a call to getsockopt fails and errno == ENOTSOCK then your descriptor is not a socket. likewise you can use isatty(3) to determine if a descriptor belongs to a serial port or terminal.

C select() writefds

I am having trouble understanding what it means to add a descriptor to writefds set for select() in linux. I wrote some simple code that adds the descriptor for stdout to the writefds set and uses a timeout of NULL. Now, my code just infinite loops checking if this descriptor is set, and if it does, it prints "WRITING". When I run my code it just keeps printing "WRITING" to infinity. The same thing happens when I do this for stdin. Again, there is no other code in the loop. Are stdin/stdout always just ready for writing?
It means you can call write on that fd and the kernel promises to not-block and consume at least 1 byte.
More details. If your socket is not in non-blocking mode and the kernel buffers associated with the socket are full, the kernel will put your thread to sleep until it can empty some of the buffer and be able to consume part of your write.
If your socket is in non-blocking mode and the kernel buffers are full, the write will return immediately without consuming any bytes.
The answer to the question "Is stdout always ready for writing" is "It depends."
stdout can be connected to anything that can be opened as a file descriptor - like a disk file, a network socket, or a pipe. The usual case is that it's connected to a terminal device.
Most of these types of file descriptors can block on writing (which means they might not be marked writeable after select() returns), but usually only if you're just written a very large amount of data to them (and so filled some kind of buffer). "Large amount" varies between the device types - if your stdout terminal is a 9600 baud serial device, then you could fill the write buffer pretty easily; an xterm, not so much.
Some device will never block - like disk files, or /dev/null, for example. (write() to a disk file might not complete immediately, but this isn't considered "blocking" - it's a "disk wait").
Yes, a truthy return from FD_ISSET(fd, &writefds) means fd is writeable. If you call select() with that FD set in the writefds after you get EWOULDBLOCK or EAGAIN (equivalent on Linux, at least) it blocks until the FD is again writeable.
There's more to it than that. For instance, an FD is also considered writeable if you've done a non-blocking connect() on it, you got EAGAIN, and call select() to wait for the connection to be established. That establishment is signalled in the writefds.

Resources