What's the difference between async and nonblocking in unix socket? - c

I'm seeing such code in nginx:
if(fcntl(ngx_processes[s].channel[0], F_SETFL, fcntl(s, F_GETFL) | O_NONBLOCK) == -1) {
...
if (ioctl(ngx_processes[s].channel[0], FIOASYNC, &on) == -1) {
...
Anyone can tell me what's the difference between fcntl(s, F_SETFL, fcntl(s, F_GETFL) | O_NONBLOCK) and ioctl(s, FIOASYNC, &on) ,aren't async and nonblocking the same thing??

FIOASYNC toggles the O_ASYNC flag (which is usually set in open(2) or fcntl(2)) for a file descriptor, which will ask the kernel to send SIGIO or SIGPOLL to the process when the file descriptor is ready for IO.
O_ASYNC is not used often:
it is extremely difficult to properly handle IO in signal handlers; they are best left as tiny as possible
because signals interrupt the control flow of the program, they 'cost more' to run than standard system calls, such as select(2) or poll(2)
signals provide less information than other calls: they only report one fd ready vs many fds that might be ready.
The O_NONBLOCK doesn't provide any notification to the user process that a fd is ready for read(2) or write(2) -- instead, it changes the behavior of read(2) and write(2) and similar calls to return immediately if the file descriptor isn't ready for reading or writing. O_NONBLOCK is typically used in conjunction with select(2) or poll(2) or similar calls to guarantee that the main loop of a client or server won't block on one specific peer, and thus starve all its peers.

Related

File Descriptor flags and functions

I would like to know what happens with the O_NONBLOCK flag when I use the given file_des in a function. Does it keep the set flag, or not?
If not, should I reset it inside function? Is there any other way?
main()
{
int file_des;
fcntl(file_des, F_SETFD, O_NONBLOCK);
function(file_des);
}
function(int file_des)
{
//do something with file_des
//What happens with the O_NONBLOCK flag?
}
File descriptors are process-wide. When used in a function, or a thread, they always work the same way. That way is controlled by status flags. In Linux, there are five status flags:
O_APPEND: Causes all writes to occur at the end of the file, ignoring file position.
O_ASYNC: A signal is generated when read or write is possible; only available for terminals, pseudoterminals, sockets, pipes, and FIFOs. (I do seem to recall it is available also for some character devices, but I have not verified which ones, if any; the man pages do not say.)
O_DIRECT: Skip page cache for I/O. Complicated, with many constraints; do not use except in very limited special circumstances.
O_NOATIME: Do not update last access time.
O_NONBLOCK: Non-blocking I/O. Instead of waiting (blocking) when data is not immediately available, or cannot be immediately sent, return a short count. If nothing can be sent or received, read()/write() etc. return -1 with errno == EWOULDBLOCK.
O_NONBLOCK has no effect on normal files or block devices.
You modify these by setting the new set of status flags using fcntl(fd, F_SETFL, flags), with zero or more flags OR'ed together. (To disable all, use zero.)
The fcntl(fd, F_SETFD, dflags) sets the set of file descriptor flags. Currently, there is only one such flag, O_CLOEXEC, which causes the descriptor to be automatically closed when an execve() or other exec family of functions succeeds (including popen() and all others that fork and execute a new process). O_CLOEXEC is normally used as a flag for the open() call, though, to avoid the race window against another thread doing a fork() in between.
When you use open(filename, flags) or open(filename, flags, mode), the flags argument is a combination of access mode (O_RDONLY, O_WRONLY, or O_RDWR; exactly one must be used), file creation flags (including file descriptor flags), and file status flags, OR'ed together. (Except for O_ASYNC, which cannot be specified at open() time, and must be set afterwards using fcntl(fd, F_SETFL, flags | O_ASYNC).)

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.

Errno 35 (EAGAIN) returned on recv call

I have a socket which waits for recv and then after receiving data, sends data forward for processing. However, then it again goes for recv, and this time it receives nothing returns -1 and when printed the errno it prints 35 (which is EAGAIN).
This happens only on MAC OS Lion operating system, for other OS this runs perfectly fine
do{
rc = recv(i, buffer, sizeof(buffer), 0);
if (rc < 0){
printf("err code %d", errno);
}
if(rc == 0){
//Code for processing the data in buffer
break;
}
....
}while(1);
EDIT: Corrected indentation and errno
You either set the socket to non-blocking mode or enabled the receive timeout. Here's from recv(2) on a mac:
The calls fail if:
[EAGAIN] The socket is marked non-blocking, and the receive operation would block, or a receive timeout had been set, and the timeout expired before data were received.
Edit 0:
Hmm, apologies for quoting again. This time from intro(2):
11 EDEADLK Resource deadlock avoided. An attempt was made to
lock a system resource that would have resulted in a deadlock
situation.
...
35 EAGAIN Resource temporarily
unavailable. This is a temporary condition and later calls to the
same routine may complete normally.
Just use strerror(3) to figure out the actual issue.
Your socket is in non-blocking mode. EAGAIN is the normal return from recv() (and other system calls) when there is no data available to read. In that sense it's not really an error.
If you meant for your socket to be nonblocking then you need to monitor it to find out when it has data available and only call recv() when there is data available. Use poll() (or kqueue, which is specific to FreeBSD and MacOS) to monitor is. Usually this is done in your application's main event loop.
If you did not mean for your socket to be nonblocking, then you should set it to blocking more with fcntl():
flags = fcntl(i, F_GETFL, 0); /* add error checking here, please */
flags &= ~O_NONBLOCK;
fcntl(i, F_SETFL, flags); /* add more error checking here! */
But you should be aware that the default blocking state of sockets (and all file descriptors) is blocking, so if your socket is in nonblocking mode then that means someone or something has manually made it nonblocking.
In blocking mode, the recv call will block and wait for more data instead of returning EAGAIN (or EWOULDBLOCK which is the same thing as EAGAIN).

Triggering Signal Handler For I/O

Using C on Linux, how would I go about triggering a signal handler every time I write data to a buffer using the write() function. The handler will be reading all data written to the buffer at the time of execution.
Sockets support this by enabling async mode on the socket file descriptor. On Linux this is done using fcntl calls:
/* set socket owner (the process that will receive signals) */
fcntl(fd, F_SETOWN, getpid());
/* optional if you want to receive a real-time signal instead of SIGIO */
fnctl(fd, F_SETSIG, signum);
/* turn on async mode -- this is the important part which enables signal delivery */
fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) | O_ASYNC);
Use pipe() with O_ASYNC and you'll recieve a SIGIO on the read end of the pipe whenever there's new data on the pipe.
I don't 100% understand what you are trying to do, BUT
select might be what you need. waiting for data to be written to a file/pipe. You can use it to do/simulate asynchronous I/O.
If the file descriptor being used with write() is not for a FIFO, pipe (as suggested by Ken Bloom), asynchronous socket (as suggested by mark4o), and does not otherwise cause a signal (i.e. SIGIO), I suppose you could use raise() to send a signal to the current process after writing data to the buffer. Depending on what you are actually trying to achieve, this may not be the best solution.
Update
If I understand you correctly, you want to write to a file, have a SIGIO signal generated on completion of the write, and then read the data back from within the signal handler. It seems you want to use asynchronous I/O for a file.
In Asynchronous I/O on linux or: Welcome to hell, the author describes various asynchronous I/O techniques on Linux, including using the SIGIO signal. The SIGIO signal technique cannot be used with regular files.
Even though the author of the previously mentioned article doesn't think highly of the POSIX AIO API provided in the 2.6 kernel, you may want to look into it anyway as it can be used to provide notification of asychronous read/write completion to a regular file through signals and function callbacks.
In Boost application performance using asynchronous I/O, the author provides an overview of basic Linux I/O models before introducing the AIO API.

Check Socket File Descriptor is Available?

If I got a file descriptor (socket fd), how to check this fd is avaiable for read/write?
In my situation, the client has connected to server and we know the fd.
However, the server will disconnect the socket, are there any clues to check it ?
You want fcntl() to check for read/write settings on the fd:
#include <unistd.h>
#include <fcntl.h>
int r;
r = fcntl(fd, F_GETFL);
if (r == -1)
/* Error */
if (r & O_RDONLY)
/* Read Only */
else if (r & O_WRONLY)
/* Write Only */
else if (r & O_RDWR)
/* Read/Write */
But this is a separate issue from when the socket is no longer connected. If you are already using select() or poll() then you're almost there. poll() will return status nicely if you specify POLLERR in events and check for it in revents.
If you're doing normal blocking I/O then just handle the read/write errors as they come in and recover gracefully.
You can use select() or poll() for this.
In C#, this question is answered here
In general, socket disconnect is asynchronous and needs to be polled for in some manner. An async read on the socket will typically return if it's closed as well, giving you a chance to pick up on the status change quicker. Winsock (Windows) has the ability to register to receive notification of a disconnect (but again, this may not happen for a long time after the other side "goes away", unless you use some type of 'keepalive' (SO_KEEPALIVE, which by default may not notice for hours, or an application-level heartbeat).
I found the recv can check. when socket fd is bad, some errno is set.
ret = recv(socket_fd, buffer, bufferSize, MSG_PEEK);
if(EPIPE == errno){
// something wrong
}
Well, you could call select(). If the server has disconnected, I believe you'll eventually get an error code returned... If not, you can use select() to tell whether you're network stack is ready to send more data (or receive it).

Resources