Linux epoll basic tutorial

  

In linux network programming, for a long time using select to do event triggering. In the new kernel of linux, there is a mechanism to replace it, which is epoll. Compared to select, the biggest benefit of epoll is that it does not reduce efficiency as the number of listening fds grows. Because in the select implementation in the kernel, it is handled by polling, the more the number of fd polled, the more time it takes. Also, the /usr/include/linux/posix_types.h header file has such a declaration: #define __FD_SETSIZE 1024 means that select can listen for up to 1024 fd at the same time. Of course, you can expand this number by modifying the header file and recompiling the kernel, but This does not seem to be a cure.

The interface of epoll is very simple. There are three functions: 1. int epoll_create(int size); Create an epoll handle, size is used to tell the kernel how many monitors there are. This parameter is different from the first parameter in select() and gives the value of fd+1 for the largest listener. It should be noted that when the epoll handle is created, it will occupy an fd value. If you view /proc/process id/fd/under linux, you can see this fd, so after using epoll, you must Call close() to close, otherwise it may cause fd to be exhausted.

2. int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event); epoll event registration function, it is different from select() which tells the kernel what type to listen to when listening for events Event, but here to register the type of event to be listened to. The first parameter is the return value of epoll_create(), the second parameter represents the action, which is represented by three macros: EPOLL_CTL_ADD: register new fd to epfd; EPOLL_CTL_MOD: modify the listening event of registered fd; EPOLL_CTL_DEL: from Epfd deletes an fd; the third parameter is the fd to be listened to, the fourth parameter tells the kernel what to listen to, struct epoll_event is structured as follows: struct epoll_event {__uint32_t events; /* Epoll events */epoll_data_t data; /* User data variable */};

events can be a collection of the following macros: EPOLLIN: indicates that the corresponding file descriptor can be read (including the peer SOCKET is normally closed); EPOLLOUT: indicates the corresponding file descriptor Can write; EPOLLPRI: indicates that the corresponding file descriptor has urgent data readable (here should indicate that there is out-of-band data coming); EPOLLERR: indicates that the corresponding file descriptor has an error; EPOLLHUP: indicates that the corresponding file descriptor is hanged ;EPOLLET: Set EPOLL to Edge Triggered mode, which is relative to Level Triggered.EPOLLONESHOT: Only listen for one event. After listening to this event, if you need to continue listening to this socket, you need to add this socket to the EPOLL queue again.

3. int epoll_wait(int epfd, struct epoll_event * events, int maxevents, int timeout); wait for events to be generated, similar to the select() call. The parameters events are used to get the collection of events from the kernel. maxevents tells the kernel how big the events are. The maxevents value cannot be larger than the size when creating epoll_create(). The timeout is the timeout (milliseconds, 0 will return immediately, -1 will Uncertain, there are also statements that are permanently blocked). This function returns the number of events that need to be processed, such as returning 0 to indicate that it has timed out.

-------------------------------------------- ------------------------------------------------

From the man page, the specific descriptions of ET and LT are as follows

The EPOLL event has two models: Edge Triggered (ET) Level Triggered (LT)

If there is such a Example: 1. We have added a file handle (RFD) to read data from the pipeline to the epoll descriptor. 2. At this point, 2KB of data is written from the other end of the pipeline. 3. Call epoll_wait(2) And it will return RFD, indicating that it is ready to read operation 4. Then we read 1KB of data 5. Call epoll_wait(2)...

Edge Triggered Work mode: If We used the EPOLLET flag when adding the RFD to the epoll descriptor in step 1. After calling epoll_wait(2) in step 5, it will probably hang because the remaining data still exists in the input buffer of the file. And the data originator is still waiting for a feedback message for the data that has been sent. The ET work mode reports events only when an event occurs on the monitored file handle. So in step 5, the caller may give up waiting for the remaining data that is still in the file input buffer. In the above example, an event will be generated on the RFD handle, because a write operation was performed in step 2, and then the event will be destroyed in step 3. Because the read operation in step 4 does not read the data in the empty file input buffer, it is unclear whether we suspend after calling epoll_wait(2) in step 5. When epoll works in ET mode, it must use a non-blocking socket to avoid starvation of the task of processing multiple file descriptors due to a blocked read/block write operation of a file handle. It is best to call the ET mode epoll interface in the following way, which will be described later to avoid possible defects. i based on non-blocking file handle ii only needs to hang when read(2) or write(2) returns EAGAIN, waiting. But this is not to say that each read() needs to be read cyclically, until it is read that an EAGAIN is generated, and the event processing is completed. When the read data length returned by read() is less than the requested data length, Make sure that there is no data in the buffer at this time, and you can think that the event has been processed.

Level Triggered works in reverse. When calling the epoll interface in LT mode, it is equivalent to a faster poll(2), and they have the same regardless of whether the data is used later. Function. Because even if you use epoll in ET mode, multiple events will still be generated when multiple chunks of data are received. The caller can set the EPOLLONESHOT flag, which is disabled from the epoll descriptor after epoll_wait(2) receives the event. Therefore, when EPOLLONESHOT is set, processing the file handle using epoll_ctl(2) with the EPOLL_CTL_MOD flag becomes something the caller must do.

Then explain ET in detail, LT:

LT (level triggered) is the default way of working, and supports both block and no-block socket. In this way, the kernel tells you A file descriptor is ready, then you can perform IO operations on this ready fd. If you don't do anything, the kernel will continue to notify you, so this mode is less likely to be programmed. The traditional select/poll is representative of this model.

ET(edge-triggered) is a high-speed mode of operation that only supports no-block sockets. In this mode, the kernel tells you via epoll when the descriptor has never been ready to become ready. Then it assumes that you know that the file descriptor is ready and will not send more ready notifications for that file descriptor until you do something that causes the file descriptor to be no longer ready (for example, you An EWOULDBLOCK error is caused when sending, receiving, or receiving a request, or sending and receiving less than a certain amount of data. However, please note that if you do not perform IO operations on this fd (which causes it to become un-ready again), the kernel will not send more notifications (only once), but in the TCP protocol, the acceleration utility of ET mode still needs to be more More benchmark confirmation (this sentence does not understand).

Copyright © Windows knowledge All Rights Reserved