Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

When to use the POLLOUT event of the poll C function?

Tags:

c

posix

tcp

polling

I wrote a small TCP servers with socket() + POLLIN poll() + recv() + send(), but I don't know when to use POLLOUT poll or select writefds to poll on writable event.

Can anyone give me an example of the real usage of POLLOUT?

like image 313
xiaochen Avatar asked Aug 29 '12 02:08

xiaochen


People also ask

What does poll () do in C?

The poll() function shall identify those file descriptors on which an application can read or write data, or on which certain events have occurred. Data other than high-priority data may be read without blocking. For STREAMS, this flag is set in revents even if the message is of zero length.

What is the use of poll function?

The poll() function is used to enable an application to multiplex I/O over a set of descriptors. For each member of the array pointed to by fds, poll() will examine the given descriptor for the event(s) specified. nfds is the number of pollfd structures in the fds array.

What is Pollout?

From Linux documentation, POLLOUT means Normal data may be written without blocking.

What is Linux poll?

poll is a POSIX system call to wait for one or more file descriptors to become ready for use. On *BSD and macOS, it has been largely superseded by kqueue in high performance applications. On Linux, it has been superseded by ppoll and epoll.


2 Answers

From nginx source, I found that:

If there is some data to send out, nginx tries to send it with a syscall (maybe writev). However, if nginx can not send total data at one time, it will set POLLOUT on pollfd, if using poll event, to wait for a writable event. When getting a writable event, nginx will send the left data.

It is easy to reproduce this case when nginx tries to response large static file

like image 179
xiaochen Avatar answered Oct 20 '22 04:10

xiaochen


The usual pattern is to use non-blocking file descriptors with poll() like this:

  • When getting ready to poll(),
    • Always set POLLIN because you are always interested in reading what the other end of the socket has send you.
      • Except if you have a large backlog of incoming data and you intentionally want to make the other end wait before sending more.
    • Set POLLOUT only if you have outstanding data to send to the other end.
  • Upon return from poll(), if it indicates that data is available to read,
    • read it and do something with it
  • Upon return from poll(), if it indicates that the socket is writable,
    • Try sending your outstanding data.
      • If you managed to write all of it, you're not going to set POLLOUT next time through the loop
      • If you only managed to send some of it (or none of it) then keep the rest for later. You will set POLLOUT the next time through the loop.
  • When you have new data to send (either in response to data you read or in response to some external event), you have two choices:
    • Eagerly try to send some of it right away. You may successfully send none, some, or all of it. Just like with the previous case, keep the portion of the data that wasn't written for next time and plan to set POLLOUT the next time through the loop only if there was some data left.
    • Just keep a hold on the data and plan to set POLLOUT the next time through the loop. (This choice is often easier to program because you only need to handle writing data in one place in your loop but on the other hand it delays writing the data until the next time through the loop.)
like image 27
Celada Avatar answered Oct 20 '22 06:10

Celada