From f06734057b81eaffb35ebe25d5740e3942daf129 Mon Sep 17 00:00:00 2001 From: Irek Fakhrutdinov Date: Sun, 15 Mar 2020 11:12:42 +0100 Subject: [PATCH] zos: explicitly mark message queue events The os390 epoll_wait implementation uses poll() to detect events in both file descriptors and the message queue used for file system events. The only message queue ID is always placed at the end of the array passed to the poll() call. When the poll() call returns all FDs and the message queue are checked for events by iterating through that array. In order to distinguish the message queue from the FDs its ID value is compared with the only message queue ID we have and if it matches the message queue handler function is called. When the message queue ID is relatively small, it may have the same value as the value of one of the file descriptors. If this happens, the message queue handler is called for the matching file descriptor, and this call fails. The file descriptor ends up being unhandled and this makes the next poll() call to return immediately. Eventually this will happen again and again, leading to an infinite busy loop and high CPU usage. To prevent the incorrect interpretation of file descriptors as the message queue, a new field has been added to the epoll event struct. This field is checked instead of the ID value and the message queue handler function is never called for file descriptors. PR-URL: https://github.com/libuv/libuv/pull/2013 Reviewed-By: Ben Noordhuis Reviewed-By: Richard Lau --- src/unix/os390-syscalls.c | 5 +++++ src/unix/os390-syscalls.h | 1 + src/unix/os390.c | 2 +- 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/unix/os390-syscalls.c b/src/unix/os390-syscalls.c index 4a926c76..e8fe7c2e 100644 --- a/src/unix/os390-syscalls.c +++ b/src/unix/os390-syscalls.c @@ -308,6 +308,11 @@ int epoll_wait(uv__os390_epoll* lst, struct epoll_event* events, ev.fd = pfd->fd; ev.events = pfd->revents; + if (i == lst->size - 1) + ev.is_msg = 1; + else + ev.is_msg = 0; + if (pfd->revents & POLLIN && pfd->revents & POLLOUT) reventcount += 2; else if (pfd->revents & (POLLIN | POLLOUT)) diff --git a/src/unix/os390-syscalls.h b/src/unix/os390-syscalls.h index ea599107..5130457c 100644 --- a/src/unix/os390-syscalls.h +++ b/src/unix/os390-syscalls.h @@ -40,6 +40,7 @@ struct epoll_event { int events; int fd; + int is_msg; }; typedef struct { diff --git a/src/unix/os390.c b/src/unix/os390.c index a7305006..dce169b9 100644 --- a/src/unix/os390.c +++ b/src/unix/os390.c @@ -923,7 +923,7 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { continue; ep = loop->ep; - if (fd == ep->msg_queue) { + if (pe->is_msg) { os390_message_queue_handler(ep); continue; }