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 <info@bnoordhuis.nl>
Reviewed-By: Richard Lau <riclau@uk.ibm.com>
This commit is contained in:
Irek Fakhrutdinov 2020-03-15 11:12:42 +01:00 committed by Ben Noordhuis
parent 742e0ba7df
commit f06734057b
3 changed files with 7 additions and 1 deletions

View File

@ -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))

View File

@ -40,6 +40,7 @@
struct epoll_event {
int events;
int fd;
int is_msg;
};
typedef struct {

View File

@ -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;
}