experchange > linux.development.system

chenstrace (06-15-18, 08:10 AM)
As my expection, the following test code should only return from epoll_wait once, just like man page of epoll said:

"edge-triggered mode delivers events only when changes occur on the monitored file descriptor"

But in fact, the epoll_wait returned more than once, why?

#include <stdio.h>
#include <sys/epoll.h>
#include <string.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <limits.h>
#define MAX_EVENTS 512

static char* get_epoll_events_str(uint32_t event);

int main(int argc, char *argv[]) {
int i,nfds;
struct epoll_event event;
struct epoll_event events[MAX_EVENTS];
int fd = STDIN_FILENO;
int epfd = epoll_create1(0);
if (epfd == -1) {
perror("epoll_create1");
exit(EXIT_FAILURE);
}

event.events = EPOLLOUT | EPOLLET;
event.data.u64 = 123;
int ret = epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &event);
if (ret == -1) {
perror("epoll_ctl");
exit(EXIT_FAILURE);
}
while (1) {
nfds = epoll_wait(epfd, events, MAX_EVENTS, -1);
if (nfds == -1) {
perror("epoll_wait");
exit(EXIT_FAILURE);
}
printf("epoll_wait return %d\n", nfds);

for (i = 0; i < nfds; i++) {
char* str = get_epoll_events_str(events[i].events);
printf("%dth fd's data.u64=%lu,event is %s\n",i,events[i].data.u64,str);
free(str);
}
sleep(1);
}
return 0;
}

static char* get_epoll_events_str(uint32_t event) {
char str[4096] = {0};

if(event == 0)
{
return NULL;
}

if (event & EPOLLIN) strcat(str, "EPOLLIN,");
if (event & EPOLLPRI) strcat(str, "EPOLLPRI,");
if (event & EPOLLOUT) strcat(str, "EPOLLOUT,");
if (event & EPOLLRDNORM) strcat(str, "EPOLLRDNORM,");
if (event & EPOLLRDBAND) strcat(str, "EPOLLRDBAND,");
if (event & EPOLLWRNORM) strcat(str, "EPOLLWRNORM,");
if (event & EPOLLWRBAND) strcat(str, "EPOLLWRBAND,");
if (event & EPOLLMSG) strcat(str, "EPOLLMSG,");
if (event & EPOLLERR) strcat(str, "EPOLLERR,");
if (event & EPOLLHUP) strcat(str, "EPOLLHUP,");
if (event & EPOLLRDHUP) strcat(str, "EPOLLRDHUP,");
if (event & EPOLLWAKEUP) strcat(str, "EPOLLWAKEUP,");
if (event & EPOLLONESHOT) strcat(str, "EPOLLONESHOT,");
if (event & EPOLLET) strcat(str, "EPOLLET,");

if(strlen(str) == 0)
{
return NULL;
}

return strdup(str);
}
Rainer Weikusat (06-15-18, 02:15 PM)
chenstrace <k54765254> writes:
> As my expection, the following test code should only return from epoll_wait once, just like man page of epoll said:
> "edge-triggered mode delivers events only when changes occur on the monitored file descriptor"
> But in fact, the epoll_wait returned more than once, why?


[please see original for code]

It shouldn't return at all weren't it for the fact that stdin and stdout
refer to the same terminal device: You'll get a notification whenever
an output operation completes and since you keep printing message to
same (virtual) device, the program feeds itself with events.

It's possible to demonstrate this by opening three shell windows and
determining the terminal device used for each. If there are only these
three, they should usually be /dev/pts/0, /dev/pts/1 and /dev/pts/2[*].

The program can be started with stdin connect to the second pty via

../a.out <>/dev/pts/1

If you now go to the third terminal and print to the pty of the second
terminal session, eg, via

echo dumdideldu >/dev/pts/1

you'll get an epoll notification in the program which gets printed to
/dev/pts/0 without causing another epoll notification.
[*] Unless Fedora meanwhile 'fixed' that to make them /rest/4lIE1XES/ved,
/jump/ved/Pa8Z and /michel/aus/loenneberga for some reason with a very
elaborate justification which keeps changing in line with what will
most likely 'sell' to the current target audience.