int fd;
uint32_t events;
uint64_t data;
+ uint32_t last_revents;
};
struct epoll_instance {
ep->items[ep->count].fd = fd;
ep->items[ep->count].events = ev.events;
ep->items[ep->count].data = ev.data;
+ ep->items[ep->count].last_revents = 0;
ep->count++;
return 0;
}
if (copy_from_user(&ev, user_event, sizeof(ev)) < 0) return -EFAULT;
ep->items[idx].events = ev.events;
ep->items[idx].data = ev.data;
+ ep->items[idx].last_revents = 0;
return 0;
}
if (vfs_rev & VFS_POLL_HUP) revents |= EPOLLHUP;
if (revents) {
- out[ready].events = revents;
- out[ready].data = ep->items[i].data;
- ready++;
+ int report = 1;
+ if (ep->items[i].events & EPOLLET) {
+ uint32_t new_bits = revents & ~ep->items[i].last_revents;
+ if (!new_bits) report = 0;
+ }
+ ep->items[i].last_revents = revents;
+ if (report) {
+ out[ready].events = revents;
+ out[ready].data = ep->items[i].data;
+ ready++;
+ }
+ } else {
+ ep->items[i].last_revents = 0;
}
}
};
enum {
- POLLIN = 0x0001,
+ POLLIN = 0x0001,
POLLOUT = 0x0004,
+ EPOLLET = (1U << 31),
};
enum {
sys_write(1, "[init] epoll OK\n", (uint32_t)(sizeof("[init] epoll OK\n") - 1));
}
+ // C22b: EPOLLET edge-triggered mode
+ {
+ int epfd = sys_epoll_create(1);
+ if (epfd < 0) {
+ sys_write(1, "[init] epollet create failed\n", (uint32_t)(sizeof("[init] epollet create failed\n") - 1));
+ sys_exit(1);
+ }
+
+ int fds[2];
+ if (sys_pipe(fds) < 0) {
+ sys_write(1, "[init] epollet pipe failed\n", (uint32_t)(sizeof("[init] epollet pipe failed\n") - 1));
+ sys_exit(1);
+ }
+
+ struct { uint32_t events; uint32_t data; } ev;
+ ev.events = POLLIN | EPOLLET;
+ ev.data = 42;
+ if (sys_epoll_ctl(epfd, 1, fds[0], &ev) < 0) {
+ sys_write(1, "[init] epollet ctl failed\n", (uint32_t)(sizeof("[init] epollet ctl failed\n") - 1));
+ sys_exit(1);
+ }
+
+ (void)sys_write(fds[1], "X", 1);
+
+ struct { uint32_t events; uint32_t data; } out;
+ int n = sys_epoll_wait(epfd, &out, 1, 0);
+ if (n != 1 || !(out.events & POLLIN)) {
+ sys_write(1, "[init] epollet first wait failed\n", (uint32_t)(sizeof("[init] epollet first wait failed\n") - 1));
+ sys_exit(1);
+ }
+
+ n = sys_epoll_wait(epfd, &out, 1, 0);
+ if (n != 0) {
+ sys_write(1, "[init] epollet second wait should be 0\n", (uint32_t)(sizeof("[init] epollet second wait should be 0\n") - 1));
+ sys_exit(1);
+ }
+
+ char tmp;
+ (void)sys_read(fds[0], &tmp, 1);
+
+ n = sys_epoll_wait(epfd, &out, 1, 0);
+ if (n != 0) {
+ sys_write(1, "[init] epollet post-drain should be 0\n", (uint32_t)(sizeof("[init] epollet post-drain should be 0\n") - 1));
+ sys_exit(1);
+ }
+
+ (void)sys_write(fds[1], "Y", 1);
+
+ n = sys_epoll_wait(epfd, &out, 1, 0);
+ if (n != 1 || !(out.events & POLLIN)) {
+ sys_write(1, "[init] epollet re-arm failed\n", (uint32_t)(sizeof("[init] epollet re-arm failed\n") - 1));
+ sys_exit(1);
+ }
+
+ (void)sys_close(fds[0]);
+ (void)sys_close(fds[1]);
+ (void)sys_close(epfd);
+ sys_write(1, "[init] epollet OK\n", (uint32_t)(sizeof("[init] epollet OK\n") - 1));
+ }
+
// C23: inotify_init/add_watch/rm_watch smoke
{
int ifd = sys_inotify_init();