866 lines
23 KiB
HTML
866 lines
23 KiB
HTML
|
|
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
|
<HTML><HEAD><TITLE>Man page of EPOLL</TITLE>
|
|
</HEAD><BODY>
|
|
<H1>EPOLL</H1>
|
|
Section: Linux Programmer's Manual (7)<BR>Updated: 2019-03-06<BR><A HREF="#index">Index</A>
|
|
<A HREF="/cgi-bin/man/man2html">Return to Main Contents</A><HR>
|
|
|
|
<A NAME="lbAB"> </A>
|
|
<H2>NAME</H2>
|
|
|
|
epoll - I/O event notification facility
|
|
<A NAME="lbAC"> </A>
|
|
<H2>SYNOPSIS</H2>
|
|
|
|
<B>#include <<A HREF="file:///usr/include/sys/epoll.h">sys/epoll.h</A>></B>
|
|
|
|
<A NAME="lbAD"> </A>
|
|
<H2>DESCRIPTION</H2>
|
|
|
|
The
|
|
<B>epoll</B>
|
|
|
|
API performs a similar task to
|
|
<B><A HREF="/cgi-bin/man/man2html?2+poll">poll</A></B>(2):
|
|
|
|
monitoring multiple file descriptors to see if I/O is possible on any of them.
|
|
The
|
|
<B>epoll</B>
|
|
|
|
API can be used either as an edge-triggered or a level-triggered
|
|
interface and scales well to large numbers of watched file descriptors.
|
|
<P>
|
|
|
|
The central concept of the
|
|
<B>epoll</B>
|
|
|
|
API is the
|
|
<B>epoll</B>
|
|
|
|
<I>instance</I>,
|
|
|
|
an in-kernel data structure which, from a user-space perspective,
|
|
can be considered as a container for two lists:
|
|
<DL COMPACT>
|
|
<DT id="1">*<DD>
|
|
The
|
|
<I>interest</I>
|
|
|
|
list (sometimes also called the
|
|
<B>epoll</B>
|
|
|
|
set): the set of file descriptors that the process has registered
|
|
an interest in monitoring.
|
|
<DT id="2">*<DD>
|
|
The
|
|
<I>ready</I>
|
|
|
|
list: the set of file descriptors that are "ready" for I/O.
|
|
The ready list is a subset of
|
|
(or, more precisely, a set of references to)
|
|
the file descriptors in the interest list that is dynamically populated
|
|
by the kernel as a result of I/O activity on those file descriptors.
|
|
</DL>
|
|
<P>
|
|
|
|
The following system calls are provided to
|
|
create and manage an
|
|
<B>epoll</B>
|
|
|
|
instance:
|
|
<DL COMPACT>
|
|
<DT id="3">*<DD>
|
|
<B><A HREF="/cgi-bin/man/man2html?2+epoll_create">epoll_create</A></B>(2)
|
|
|
|
creates a new
|
|
<B>epoll</B>
|
|
|
|
instance and returns a file descriptor referring to that instance.
|
|
(The more recent
|
|
<B><A HREF="/cgi-bin/man/man2html?2+epoll_create1">epoll_create1</A></B>(2)
|
|
|
|
extends the functionality of
|
|
<B><A HREF="/cgi-bin/man/man2html?2+epoll_create">epoll_create</A></B>(2).)
|
|
|
|
<DT id="4">*<DD>
|
|
Interest in particular file descriptors is then registered via
|
|
<B><A HREF="/cgi-bin/man/man2html?2+epoll_ctl">epoll_ctl</A></B>(2),
|
|
|
|
which adds items to the interest list of the
|
|
<B>epoll</B>
|
|
|
|
instance.
|
|
<DT id="5">*<DD>
|
|
<B><A HREF="/cgi-bin/man/man2html?2+epoll_wait">epoll_wait</A></B>(2)
|
|
|
|
waits for I/O events,
|
|
blocking the calling thread if no events are currently available.
|
|
(This system call can be thought of as fetching items from
|
|
the ready list of the
|
|
<B>epoll</B>
|
|
|
|
instance.)
|
|
|
|
</DL>
|
|
<A NAME="lbAE"> </A>
|
|
<H3>Level-triggered and edge-triggered</H3>
|
|
|
|
The
|
|
<B>epoll</B>
|
|
|
|
event distribution interface is able to behave both as edge-triggered
|
|
(ET) and as level-triggered (LT).
|
|
The difference between the two mechanisms
|
|
can be described as follows.
|
|
Suppose that
|
|
this scenario happens:
|
|
<DL COMPACT>
|
|
<DT id="6">1.<DD>
|
|
The file descriptor that represents the read side of a pipe
|
|
(<I>rfd</I>)
|
|
|
|
is registered on the
|
|
<B>epoll</B>
|
|
|
|
instance.
|
|
<DT id="7">2.<DD>
|
|
A pipe writer writes 2 kB of data on the write side of the pipe.
|
|
<DT id="8">3.<DD>
|
|
A call to
|
|
<B><A HREF="/cgi-bin/man/man2html?2+epoll_wait">epoll_wait</A></B>(2)
|
|
|
|
is done that will return
|
|
<I>rfd</I>
|
|
|
|
as a ready file descriptor.
|
|
<DT id="9">4.<DD>
|
|
The pipe reader reads 1 kB of data from
|
|
<I>rfd</I>.
|
|
|
|
<DT id="10">5.<DD>
|
|
A call to
|
|
<B><A HREF="/cgi-bin/man/man2html?2+epoll_wait">epoll_wait</A></B>(2)
|
|
|
|
is done.
|
|
</DL>
|
|
<P>
|
|
|
|
If the
|
|
<I>rfd</I>
|
|
|
|
file descriptor has been added to the
|
|
<B>epoll</B>
|
|
|
|
interface using the
|
|
<B>EPOLLET</B>
|
|
|
|
(edge-triggered)
|
|
flag, the call to
|
|
<B><A HREF="/cgi-bin/man/man2html?2+epoll_wait">epoll_wait</A></B>(2)
|
|
|
|
done in step
|
|
<B>5</B>
|
|
|
|
will probably hang despite the available data still present in the file
|
|
input buffer;
|
|
meanwhile the remote peer might be expecting a response based on the
|
|
data it already sent.
|
|
The reason for this is that edge-triggered mode
|
|
delivers events only when changes occur on the monitored file descriptor.
|
|
So, in step
|
|
<B>5</B>
|
|
|
|
the caller might end up waiting for some data that is already present inside
|
|
the input buffer.
|
|
In the above example, an event on
|
|
<I>rfd</I>
|
|
|
|
will be generated because of the write done in
|
|
<B>2</B>
|
|
|
|
and the event is consumed in
|
|
<B>3</B>.
|
|
|
|
Since the read operation done in
|
|
<B>4</B>
|
|
|
|
does not consume the whole buffer data, the call to
|
|
<B><A HREF="/cgi-bin/man/man2html?2+epoll_wait">epoll_wait</A></B>(2)
|
|
|
|
done in step
|
|
<B>5</B>
|
|
|
|
might block indefinitely.
|
|
<P>
|
|
|
|
An application that employs the
|
|
<B>EPOLLET</B>
|
|
|
|
flag should use nonblocking file descriptors to avoid having a blocking
|
|
read or write starve a task that is handling multiple file descriptors.
|
|
The suggested way to use
|
|
<B>epoll</B>
|
|
|
|
as an edge-triggered
|
|
(<B>EPOLLET</B>)
|
|
|
|
interface is as follows:
|
|
<DL COMPACT><DT id="11"><DD>
|
|
<DL COMPACT>
|
|
<DT id="12"><B>i</B>
|
|
|
|
<DD>
|
|
with nonblocking file descriptors; and
|
|
<DT id="13"><B>ii</B>
|
|
|
|
<DD>
|
|
by waiting for an event only after
|
|
<B><A HREF="/cgi-bin/man/man2html?2+read">read</A></B>(2)
|
|
|
|
or
|
|
<B><A HREF="/cgi-bin/man/man2html?2+write">write</A></B>(2)
|
|
|
|
return
|
|
<B>EAGAIN</B>.
|
|
|
|
</DL>
|
|
</DL>
|
|
|
|
<P>
|
|
|
|
By contrast, when used as a level-triggered interface
|
|
(the default, when
|
|
<B>EPOLLET</B>
|
|
|
|
is not specified),
|
|
<B>epoll</B>
|
|
|
|
is simply a faster
|
|
<B><A HREF="/cgi-bin/man/man2html?2+poll">poll</A></B>(2),
|
|
|
|
and can be used wherever the latter is used since it shares the
|
|
same semantics.
|
|
<P>
|
|
|
|
Since even with edge-triggered
|
|
<B>epoll</B>,
|
|
|
|
multiple events can be generated upon receipt of multiple chunks of data,
|
|
the caller has the option to specify the
|
|
<B>EPOLLONESHOT</B>
|
|
|
|
flag, to tell
|
|
<B>epoll</B>
|
|
|
|
to disable the associated file descriptor after the receipt of an event with
|
|
<B><A HREF="/cgi-bin/man/man2html?2+epoll_wait">epoll_wait</A></B>(2).
|
|
|
|
When the
|
|
<B>EPOLLONESHOT</B>
|
|
|
|
flag is specified,
|
|
it is the caller's responsibility to rearm the file descriptor using
|
|
<B><A HREF="/cgi-bin/man/man2html?2+epoll_ctl">epoll_ctl</A></B>(2)
|
|
|
|
with
|
|
<B>EPOLL_CTL_MOD</B>.
|
|
|
|
<P>
|
|
|
|
If multiple threads
|
|
(or processes, if child processes have inherited the
|
|
<B>epoll</B>
|
|
|
|
file descriptor across
|
|
<B><A HREF="/cgi-bin/man/man2html?2+fork">fork</A></B>(2))
|
|
|
|
are blocked in
|
|
<B><A HREF="/cgi-bin/man/man2html?2+epoll_wait">epoll_wait</A></B>(2)
|
|
|
|
waiting on the same epoll file descriptor and a file descriptor
|
|
in the interest list that is marked for edge-triggered
|
|
(<B>EPOLLET</B>)
|
|
|
|
notification becomes ready,
|
|
just one of the threads (or processes) is awoken from
|
|
<B><A HREF="/cgi-bin/man/man2html?2+epoll_wait">epoll_wait</A></B>(2).
|
|
|
|
This provides a useful optimization for avoiding "thundering herd" wake-ups
|
|
in some scenarios.
|
|
|
|
<A NAME="lbAF"> </A>
|
|
<H3>Interaction with autosleep</H3>
|
|
|
|
If the system is in
|
|
<B>autosleep</B>
|
|
|
|
mode via
|
|
<I>/sys/power/autosleep</I>
|
|
|
|
and an event happens which wakes the device from sleep, the device
|
|
driver will keep the device awake only until that event is queued.
|
|
To keep the device awake until the event has been processed,
|
|
it is necessary to use the
|
|
<B><A HREF="/cgi-bin/man/man2html?2+epoll_ctl">epoll_ctl</A></B>(2)
|
|
|
|
<B>EPOLLWAKEUP</B>
|
|
|
|
flag.
|
|
<P>
|
|
|
|
When the
|
|
<B>EPOLLWAKEUP</B>
|
|
|
|
flag is set in the
|
|
<B>events</B>
|
|
|
|
field for a
|
|
<I>struct epoll_event</I>,
|
|
|
|
the system will be kept awake from the moment the event is queued,
|
|
through the
|
|
<B><A HREF="/cgi-bin/man/man2html?2+epoll_wait">epoll_wait</A></B>(2)
|
|
|
|
call which returns the event until the subsequent
|
|
<B><A HREF="/cgi-bin/man/man2html?2+epoll_wait">epoll_wait</A></B>(2)
|
|
|
|
call.
|
|
If the event should keep the system awake beyond that time,
|
|
then a separate
|
|
<I>wake_lock</I>
|
|
|
|
should be taken before the second
|
|
<B><A HREF="/cgi-bin/man/man2html?2+epoll_wait">epoll_wait</A></B>(2)
|
|
|
|
call.
|
|
<A NAME="lbAG"> </A>
|
|
<H3>/proc interfaces</H3>
|
|
|
|
The following interfaces can be used to limit the amount of
|
|
kernel memory consumed by epoll:
|
|
|
|
|
|
|
|
|
|
|
|
<DL COMPACT>
|
|
<DT id="14"><I>/proc/sys/fs/epoll/max_user_watches</I> (since Linux 2.6.28)
|
|
|
|
<DD>
|
|
This specifies a limit on the total number of
|
|
file descriptors that a user can register across
|
|
all epoll instances on the system.
|
|
The limit is per real user ID.
|
|
Each registered file descriptor costs roughly 90 bytes on a 32-bit kernel,
|
|
and roughly 160 bytes on a 64-bit kernel.
|
|
Currently,
|
|
|
|
the default value for
|
|
<I>max_user_watches</I>
|
|
|
|
is 1/25 (4%) of the available low memory,
|
|
divided by the registration cost in bytes.
|
|
</DL>
|
|
<A NAME="lbAH"> </A>
|
|
<H3>Example for suggested usage</H3>
|
|
|
|
While the usage of
|
|
<B>epoll</B>
|
|
|
|
when employed as a level-triggered interface does have the same
|
|
semantics as
|
|
<B><A HREF="/cgi-bin/man/man2html?2+poll">poll</A></B>(2),
|
|
|
|
the edge-triggered usage requires more clarification to avoid stalls
|
|
in the application event loop.
|
|
In this example, listener is a
|
|
nonblocking socket on which
|
|
<B><A HREF="/cgi-bin/man/man2html?2+listen">listen</A></B>(2)
|
|
|
|
has been called.
|
|
The function
|
|
<I>do_use_fd()</I>
|
|
|
|
uses the new ready file descriptor until
|
|
<B>EAGAIN</B>
|
|
|
|
is returned by either
|
|
<B><A HREF="/cgi-bin/man/man2html?2+read">read</A></B>(2)
|
|
|
|
or
|
|
<B><A HREF="/cgi-bin/man/man2html?2+write">write</A></B>(2).
|
|
|
|
An event-driven state machine application should, after having received
|
|
<B>EAGAIN</B>,
|
|
|
|
record its current state so that at the next call to
|
|
<I>do_use_fd()</I>
|
|
|
|
it will continue to
|
|
<B><A HREF="/cgi-bin/man/man2html?2+read">read</A></B>(2)
|
|
|
|
or
|
|
<B><A HREF="/cgi-bin/man/man2html?2+write">write</A></B>(2)
|
|
|
|
from where it stopped before.
|
|
<P>
|
|
|
|
|
|
|
|
#define MAX_EVENTS 10
|
|
struct epoll_event ev, events[MAX_EVENTS];
|
|
int listen_sock, conn_sock, nfds, epollfd;
|
|
<P>
|
|
/* Code to set up listening socket, 'listen_sock',
|
|
<BR> (socket(), bind(), listen()) omitted */
|
|
<P>
|
|
epollfd = epoll_create1(0);
|
|
if (epollfd == -1) {
|
|
<BR> perror("epoll_create1");
|
|
<BR> exit(EXIT_FAILURE);
|
|
}
|
|
<P>
|
|
ev.events = EPOLLIN;
|
|
ev.data.fd = listen_sock;
|
|
if (epoll_ctl(epollfd, EPOLL_CTL_ADD, listen_sock, &ev) == -1) {
|
|
<BR> perror("epoll_ctl: listen_sock");
|
|
<BR> exit(EXIT_FAILURE);
|
|
}
|
|
<P>
|
|
for (;;) {
|
|
<BR> nfds = epoll_wait(epollfd, events, MAX_EVENTS, -1);
|
|
<BR> if (nfds == -1) {
|
|
<BR> perror("epoll_wait");
|
|
<BR> exit(EXIT_FAILURE);
|
|
<BR> }
|
|
<P>
|
|
<BR> for (n = 0; n < nfds; ++n) {
|
|
<BR> if (events[n].data.fd == listen_sock) {
|
|
<BR> conn_sock = accept(listen_sock,
|
|
<BR> (struct sockaddr *) &addr, &addrlen);
|
|
<BR> if (conn_sock == -1) {
|
|
<BR> perror("accept");
|
|
<BR> exit(EXIT_FAILURE);
|
|
<BR> }
|
|
<BR> setnonblocking(conn_sock);
|
|
<BR> ev.events = EPOLLIN | EPOLLET;
|
|
<BR> ev.data.fd = conn_sock;
|
|
<BR> if (epoll_ctl(epollfd, EPOLL_CTL_ADD, conn_sock,
|
|
<BR> &ev) == -1) {
|
|
<BR> perror("epoll_ctl: conn_sock");
|
|
<BR> exit(EXIT_FAILURE);
|
|
<BR> }
|
|
<BR> } else {
|
|
<BR> do_use_fd(events[n].data.fd);
|
|
<BR> }
|
|
<BR> }
|
|
}
|
|
|
|
|
|
<P>
|
|
|
|
When used as an edge-triggered interface, for performance reasons, it is
|
|
possible to add the file descriptor inside the
|
|
<B>epoll</B>
|
|
|
|
interface
|
|
(<B>EPOLL_CTL_ADD</B>)
|
|
|
|
once by specifying
|
|
(<B>EPOLLIN</B>|<B>EPOLLOUT</B>).
|
|
|
|
This allows you to avoid
|
|
continuously switching between
|
|
<B>EPOLLIN</B>
|
|
|
|
and
|
|
<B>EPOLLOUT</B>
|
|
|
|
calling
|
|
<B><A HREF="/cgi-bin/man/man2html?2+epoll_ctl">epoll_ctl</A></B>(2)
|
|
|
|
with
|
|
<B>EPOLL_CTL_MOD</B>.
|
|
|
|
<A NAME="lbAI"> </A>
|
|
<H3>Questions and answers</H3>
|
|
|
|
<DL COMPACT>
|
|
<DT id="15">0.<DD>
|
|
What is the key used to distinguish the file descriptors registered in an
|
|
interest list?
|
|
<DT id="16"><DD>
|
|
The key is the combination of the file descriptor number and
|
|
the open file description
|
|
(also known as an "open file handle",
|
|
the kernel's internal representation of an open file).
|
|
<DT id="17">1.<DD>
|
|
What happens if you register the same file descriptor on an
|
|
<B>epoll</B>
|
|
|
|
instance twice?
|
|
<DT id="18"><DD>
|
|
You will probably get
|
|
<B>EEXIST</B>.
|
|
|
|
However, it is possible to add a duplicate
|
|
(<B><A HREF="/cgi-bin/man/man2html?2+dup">dup</A></B>(2),
|
|
|
|
<B><A HREF="/cgi-bin/man/man2html?2+dup2">dup2</A></B>(2),
|
|
|
|
<B><A HREF="/cgi-bin/man/man2html?2+fcntl">fcntl</A></B>(2)
|
|
|
|
<B>F_DUPFD</B>)
|
|
|
|
file descriptor to the same
|
|
<B>epoll</B>
|
|
|
|
instance.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
This can be a useful technique for filtering events,
|
|
if the duplicate file descriptors are registered with different
|
|
<I>events</I>
|
|
|
|
masks.
|
|
<DT id="19">2.<DD>
|
|
Can two
|
|
<B>epoll</B>
|
|
|
|
instances wait for the same file descriptor?
|
|
If so, are events reported to both
|
|
<B>epoll</B>
|
|
|
|
file descriptors?
|
|
<DT id="20"><DD>
|
|
Yes, and events would be reported to both.
|
|
However, careful programming may be needed to do this correctly.
|
|
<DT id="21">3.<DD>
|
|
Is the
|
|
<B>epoll</B>
|
|
|
|
file descriptor itself poll/epoll/selectable?
|
|
<DT id="22"><DD>
|
|
Yes.
|
|
If an
|
|
<B>epoll</B>
|
|
|
|
file descriptor has events waiting, then it will
|
|
indicate as being readable.
|
|
<DT id="23">4.<DD>
|
|
What happens if one attempts to put an
|
|
<B>epoll</B>
|
|
|
|
file descriptor into its own file descriptor set?
|
|
<DT id="24"><DD>
|
|
The
|
|
<B><A HREF="/cgi-bin/man/man2html?2+epoll_ctl">epoll_ctl</A></B>(2)
|
|
|
|
call fails
|
|
(<B>EINVAL</B>).
|
|
|
|
However, you can add an
|
|
<B>epoll</B>
|
|
|
|
file descriptor inside another
|
|
<B>epoll</B>
|
|
|
|
file descriptor set.
|
|
<DT id="25">5.<DD>
|
|
Can I send an
|
|
<B>epoll</B>
|
|
|
|
file descriptor over a UNIX domain socket to another process?
|
|
<DT id="26"><DD>
|
|
Yes, but it does not make sense to do this, since the receiving process
|
|
would not have copies of the file descriptors in the interest list.
|
|
<DT id="27">6.<DD>
|
|
Will closing a file descriptor cause it to be removed from all
|
|
<B>epoll</B>
|
|
|
|
interest lists?
|
|
<DT id="28"><DD>
|
|
Yes, but be aware of the following point.
|
|
A file descriptor is a reference to an open file description (see
|
|
<B><A HREF="/cgi-bin/man/man2html?2+open">open</A></B>(2)).
|
|
|
|
Whenever a file descriptor is duplicated via
|
|
<B><A HREF="/cgi-bin/man/man2html?2+dup">dup</A></B>(2),
|
|
|
|
<B><A HREF="/cgi-bin/man/man2html?2+dup2">dup2</A></B>(2),
|
|
|
|
<B><A HREF="/cgi-bin/man/man2html?2+fcntl">fcntl</A></B>(2)
|
|
|
|
<B>F_DUPFD</B>,
|
|
|
|
or
|
|
<B><A HREF="/cgi-bin/man/man2html?2+fork">fork</A></B>(2),
|
|
|
|
a new file descriptor referring to the same open file description is
|
|
created.
|
|
An open file description continues to exist until all
|
|
file descriptors referring to it have been closed.
|
|
<DT id="29"><DD>
|
|
A file descriptor is removed from an
|
|
interest list only after all the file descriptors referring to the underlying
|
|
open file description have been closed.
|
|
This means that even after a file descriptor that is part of an
|
|
interest list has been closed,
|
|
events may be reported for that file descriptor if other file
|
|
descriptors referring to the same underlying file description remain open.
|
|
To prevent this happening,
|
|
the file descriptor must be explicitly removed from the interest list (using
|
|
<B><A HREF="/cgi-bin/man/man2html?2+epoll_ctl">epoll_ctl</A></B>(2)
|
|
|
|
<B>EPOLL_CTL_DEL</B>)
|
|
|
|
before it is duplicated.
|
|
Alternatively,
|
|
the application must ensure that all file descriptors are closed
|
|
(which may be difficult if file descriptors were duplicated
|
|
behind the scenes by library functions that used
|
|
<B><A HREF="/cgi-bin/man/man2html?2+dup">dup</A></B>(2)
|
|
|
|
or
|
|
<B><A HREF="/cgi-bin/man/man2html?2+fork">fork</A></B>(2)).
|
|
|
|
<DT id="30">7.<DD>
|
|
If more than one event occurs between
|
|
<B><A HREF="/cgi-bin/man/man2html?2+epoll_wait">epoll_wait</A></B>(2)
|
|
|
|
calls, are they combined or reported separately?
|
|
<DT id="31"><DD>
|
|
They will be combined.
|
|
<DT id="32">8.<DD>
|
|
Does an operation on a file descriptor affect the
|
|
already collected but not yet reported events?
|
|
<DT id="33"><DD>
|
|
You can do two operations on an existing file descriptor.
|
|
Remove would be meaningless for
|
|
this case.
|
|
Modify will reread available I/O.
|
|
<DT id="34">9.<DD>
|
|
Do I need to continuously read/write a file descriptor
|
|
until
|
|
<B>EAGAIN</B>
|
|
|
|
when using the
|
|
<B>EPOLLET</B>
|
|
|
|
flag (edge-triggered behavior)?
|
|
<DT id="35"><DD>
|
|
Receiving an event from
|
|
<B><A HREF="/cgi-bin/man/man2html?2+epoll_wait">epoll_wait</A></B>(2)
|
|
|
|
should suggest to you that such
|
|
file descriptor is ready for the requested I/O operation.
|
|
You must consider it ready until the next (nonblocking)
|
|
read/write yields
|
|
<B>EAGAIN</B>.
|
|
|
|
When and how you will use the file descriptor is entirely up to you.
|
|
<DT id="36"><DD>
|
|
For packet/token-oriented files (e.g., datagram socket,
|
|
terminal in canonical mode),
|
|
the only way to detect the end of the read/write I/O space
|
|
is to continue to read/write until
|
|
<B>EAGAIN</B>.
|
|
|
|
<DT id="37"><DD>
|
|
For stream-oriented files (e.g., pipe, FIFO, stream socket), the
|
|
condition that the read/write I/O space is exhausted can also be detected by
|
|
checking the amount of data read from / written to the target file
|
|
descriptor.
|
|
For example, if you call
|
|
<B><A HREF="/cgi-bin/man/man2html?2+read">read</A></B>(2)
|
|
|
|
by asking to read a certain amount of data and
|
|
<B><A HREF="/cgi-bin/man/man2html?2+read">read</A></B>(2)
|
|
|
|
returns a lower number of bytes, you
|
|
can be sure of having exhausted the read I/O space for the file
|
|
descriptor.
|
|
The same is true when writing using
|
|
<B><A HREF="/cgi-bin/man/man2html?2+write">write</A></B>(2).
|
|
|
|
(Avoid this latter technique if you cannot guarantee that
|
|
the monitored file descriptor always refers to a stream-oriented file.)
|
|
</DL>
|
|
<A NAME="lbAJ"> </A>
|
|
<H3>Possible pitfalls and ways to avoid them</H3>
|
|
|
|
<DL COMPACT>
|
|
<DT id="38"><B>o Starvation (edge-triggered)</B>
|
|
|
|
<DD>
|
|
</DL>
|
|
<P>
|
|
|
|
If there is a large amount of I/O space,
|
|
it is possible that by trying to drain
|
|
it the other files will not get processed causing starvation.
|
|
(This problem is not specific to
|
|
<B>epoll</B>.)
|
|
|
|
<P>
|
|
|
|
The solution is to maintain a ready list
|
|
and mark the file descriptor as ready
|
|
in its associated data structure, thereby allowing the application to
|
|
remember which files need to be processed but still round robin amongst
|
|
all the ready files.
|
|
This also supports ignoring subsequent events you
|
|
receive for file descriptors that are already ready.
|
|
<DL COMPACT>
|
|
<DT id="39"><B>o If using an event cache...</B>
|
|
|
|
<DD>
|
|
</DL>
|
|
<P>
|
|
|
|
If you use an event cache or store all the file descriptors returned from
|
|
<B><A HREF="/cgi-bin/man/man2html?2+epoll_wait">epoll_wait</A></B>(2),
|
|
|
|
then make sure to provide a way to mark
|
|
its closure dynamically (i.e., caused by
|
|
a previous event's processing).
|
|
Suppose you receive 100 events from
|
|
<B><A HREF="/cgi-bin/man/man2html?2+epoll_wait">epoll_wait</A></B>(2),
|
|
|
|
and in event #47 a condition causes event #13 to be closed.
|
|
If you remove the structure and
|
|
<B><A HREF="/cgi-bin/man/man2html?2+close">close</A></B>(2)
|
|
|
|
the file descriptor for event #13, then your
|
|
event cache might still say there are events waiting for that
|
|
file descriptor causing confusion.
|
|
<P>
|
|
|
|
One solution for this is to call, during the processing of event 47,
|
|
<B>epoll_ctl</B>(<B>EPOLL_CTL_DEL</B>)
|
|
|
|
to delete file descriptor 13 and
|
|
<B><A HREF="/cgi-bin/man/man2html?2+close">close</A></B>(2),
|
|
|
|
then mark its associated
|
|
data structure as removed and link it to a cleanup list.
|
|
If you find another
|
|
event for file descriptor 13 in your batch processing,
|
|
you will discover the file descriptor had been
|
|
previously removed and there will be no confusion.
|
|
<A NAME="lbAK"> </A>
|
|
<H2>VERSIONS</H2>
|
|
|
|
The
|
|
<B>epoll</B>
|
|
|
|
API was introduced in Linux kernel 2.5.44.
|
|
|
|
Support was added to glibc in version 2.3.2.
|
|
<A NAME="lbAL"> </A>
|
|
<H2>CONFORMING TO</H2>
|
|
|
|
The
|
|
<B>epoll</B>
|
|
|
|
API is Linux-specific.
|
|
Some other systems provide similar
|
|
mechanisms, for example, FreeBSD has
|
|
<I>kqueue</I>,
|
|
|
|
and Solaris has
|
|
<I>/dev/poll</I>.
|
|
|
|
<A NAME="lbAM"> </A>
|
|
<H2>NOTES</H2>
|
|
|
|
The set of file descriptors that is being monitored via
|
|
an epoll file descriptor can be viewed via the entry for
|
|
the epoll file descriptor in the process's
|
|
<I>/proc/[pid]/fdinfo</I>
|
|
|
|
directory.
|
|
See
|
|
<B><A HREF="/cgi-bin/man/man2html?5+proc">proc</A></B>(5)
|
|
|
|
for further details.
|
|
<P>
|
|
|
|
The
|
|
<B><A HREF="/cgi-bin/man/man2html?2+kcmp">kcmp</A></B>(2)
|
|
|
|
<B>KCMP_EPOLL_TFD</B>
|
|
|
|
operation can be used to test whether a file descriptor
|
|
is present in an epoll instance.
|
|
<A NAME="lbAN"> </A>
|
|
<H2>SEE ALSO</H2>
|
|
|
|
<B><A HREF="/cgi-bin/man/man2html?2+epoll_create">epoll_create</A></B>(2),
|
|
|
|
<B><A HREF="/cgi-bin/man/man2html?2+epoll_create1">epoll_create1</A></B>(2),
|
|
|
|
<B><A HREF="/cgi-bin/man/man2html?2+epoll_ctl">epoll_ctl</A></B>(2),
|
|
|
|
<B><A HREF="/cgi-bin/man/man2html?2+epoll_wait">epoll_wait</A></B>(2),
|
|
|
|
<B><A HREF="/cgi-bin/man/man2html?2+poll">poll</A></B>(2),
|
|
|
|
<B><A HREF="/cgi-bin/man/man2html?2+select">select</A></B>(2)
|
|
|
|
<A NAME="lbAO"> </A>
|
|
<H2>COLOPHON</H2>
|
|
|
|
This page is part of release 5.05 of the Linux
|
|
<I>man-pages</I>
|
|
|
|
project.
|
|
A description of the project,
|
|
information about reporting bugs,
|
|
and the latest version of this page,
|
|
can be found at
|
|
<A HREF="https://www.kernel.org/doc/man-pages/.">https://www.kernel.org/doc/man-pages/.</A>
|
|
<P>
|
|
|
|
<HR>
|
|
<A NAME="index"> </A><H2>Index</H2>
|
|
<DL>
|
|
<DT id="40"><A HREF="#lbAB">NAME</A><DD>
|
|
<DT id="41"><A HREF="#lbAC">SYNOPSIS</A><DD>
|
|
<DT id="42"><A HREF="#lbAD">DESCRIPTION</A><DD>
|
|
<DL>
|
|
<DT id="43"><A HREF="#lbAE">Level-triggered and edge-triggered</A><DD>
|
|
<DT id="44"><A HREF="#lbAF">Interaction with autosleep</A><DD>
|
|
<DT id="45"><A HREF="#lbAG">/proc interfaces</A><DD>
|
|
<DT id="46"><A HREF="#lbAH">Example for suggested usage</A><DD>
|
|
<DT id="47"><A HREF="#lbAI">Questions and answers</A><DD>
|
|
<DT id="48"><A HREF="#lbAJ">Possible pitfalls and ways to avoid them</A><DD>
|
|
</DL>
|
|
<DT id="49"><A HREF="#lbAK">VERSIONS</A><DD>
|
|
<DT id="50"><A HREF="#lbAL">CONFORMING TO</A><DD>
|
|
<DT id="51"><A HREF="#lbAM">NOTES</A><DD>
|
|
<DT id="52"><A HREF="#lbAN">SEE ALSO</A><DD>
|
|
<DT id="53"><A HREF="#lbAO">COLOPHON</A><DD>
|
|
</DL>
|
|
<HR>
|
|
This document was created by
|
|
<A HREF="/cgi-bin/man/man2html">man2html</A>,
|
|
using the manual pages.<BR>
|
|
Time: 00:06:08 GMT, March 31, 2021
|
|
</BODY>
|
|
</HTML>
|