Linux Files and the Event Poll Interface - Controlling Epoll (
Page 2 of 4 )
The epoll_ctl() system call can be used to add file descriptors to and remove file descriptors from a given epoll context:
#include <sys/epoll.h>
int epoll_ctl (int epfd,
int op,
int fd,
struct epoll_event *event);
The header <sys/epoll.h> defines the
epoll_event
structure as:
struct epoll_event {
__u32 events; /* events */
union {
void *ptr;
int fd;
__u32 u32;
__u64 u64;
} data;
};
A successful call to
epoll_ctl()
controls the epoll instance associated with the file descriptor
epfd
. The parameter
op
specifies the operation to be taken against the file associated with
fd
. The
event
parameter further describes the behavior of the operation.
Here are valid values for the
op
parameter:
EPOLL_CTL_ADD
Add a monitor on the file associated with the file
descriptor
fd
to the
epoll instance associated with epfd
, per the events defined in
event
.
EPOLL_CTL_DEL
Remove a monitor on the file associated with the file descriptor
fd
from the epoll instance associated with
epfd
.
EPOLL_CTL_MOD
Modify an existing monitor of
fd
with the updated events specified by
event
.
The
events
field in the
epoll_event
structure lists which events to monitor on the given file descriptor. Multiple events can be bitwise-ORed together. Here are valid values:
EPOLLERR
An error condition occurred on the file. This event is always monitored, even if it’s not specified.
EPOLLET
Enables edge-triggered behavior for the monitor of the file (see the upcoming section “Edge- Versus Level-Triggered Events”). The default behavior is level- triggered.
EPOLLHUP
A hangup occurred on the file. This event is always monitored, even if it’s not specified.
EPOLLIN
The file is available to be read from without blocking.
EPOLLONESHOT
After an event is generated and read, the file is automatically no longer monitored. A new event mask must be specified via
EPOLL_CTL_MOD
to reenable the watch.
EPOLLOUT
The file is available to be written to without blocking.
EPOLLPRI
There is urgent out-of-band data available to read.
The
data
field inside the
event_poll
structure is for the user’s private use. The contents are returned to the user upon receipt of the requested event. The common practice is to set
event.data.fd
to
fd
, which makes it easy to look up which file descriptor caused the event.
Upon success,
epoll_ctl()
returns
0
. On failure, the call returns
-1
, and sets
errno
to one of the following values:
EBADF
epfd
is not a valid epoll instance, or
fd
is not a valid file descriptor.
EEXIST
op
was
EPOLL_CTL_ADD
, but
fd
is already associated with
epfd
.
EINVAL
epfd
is not an epoll instance,
epfd
is the same as
fd
, or
op
is invalid.
ENOENT
op
was
EPOLL_CTL_MOD
, or
EPOLL_CTL_DEL
, but
fd
is not associated with
epfd
.
ENOMEM
There was insufficient memory to process the request.
EPERM
fd
does not support epoll.
As an example, to add a new watch on the file associated with
fd
to the epoll instance
epfd
, you would write:
struct epoll_event event;
int ret;
event.data.fd = fd; /* return the fd to us later */
event.events = EPOLLIN | EPOLLOUT;
ret = epoll_ctl (epfd, EPOLL_CTL_ADD, fd, &event);
if (ret)
perror ("epoll_ctl");
To modify an existing event on the file associated with
fd
on the epoll instance
epfd
, you would write:
struct epoll_event event;
int ret;
event.data.fd = fd; /* return the fd to us later */
event.events = EPOLLIN;
ret = epoll_ctl (epfd, EPOLL_CTL_MOD, fd, &event);
if (ret)
perror ("epoll_ctl");
Conversely, to remove an existing event on the file associated with
fd
from the epoll instance
epfd
, you would write:
struct epoll_event event;
int ret;
ret = epoll_ctl (epfd, EPOLL_CTL_DEL, fd, &event);
if (ret)
perror ("epoll_ctl");
Note that the
event
parameter can be
NULL
when
op
is
EPOLL_CTL_DEL
, as there is no event mask to provide. Kernel versions before 2.6.9, however, erroneously check for this parameter to be non-
NULL
. For portability to these older kernels, you should pass in a valid non-
NULL
pointer; it will not be touched. Kernel 2.6.9 fixed this bug.