`poll()` returns -1 but errno is 0
Nahor via Cygwin <[email protected]> Thu, 16 Apr 2026 15:37:45 -0700
| Newsgroups | gmane.os.cygwin |
|---|---|
| Message-ID | <CA+1R0Vh-hygR06K4MUbvou8JQwGP4B5YvMCc0rJiQUYzp2kAGg@mail.gmail.com> |
Hi, In some cases, `poll()` return -1 but errno is still 0. Attached is a way to reproduce it. On my system, it fails immediately (from a wall clock point of view, there are quite a few iterations with the app). This was first reported against the fish shell and then against MSYS2 (https://github.com/msys2/msys2-runtime/issues/308). The MSYS2 issue also has a reproducible sample. It's not as quick to fail, but it's less artificial (more similar to how fish works). Potentially related: Sometimes `poll()` fails with a EFAULT errno. I haven't found a way to reproduce that outside the fish test suite. And there, it's fairly rare (maybe 5% of the time for the full test suite, which has ~150 tests, some of which spawn lots of processes) Regards, Nahor -- Problem reports: https://cygwin.com/problems.html FAQ: https://cygwin.com/faq/ Documentation: https://cygwin.com/docs.html Unsubscribe info: https://cygwin.com/ml/#unsubscribe-simple
main.c
(text/plain, 2.2 KB)
#include <assert.h>
#include <errno.h>
#include <fcntl.h>
#include <poll.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#define FD_MAX_COUNT 100
static pthread_mutex_t monitor_mutex = PTHREAD_MUTEX_INITIALIZER;
static int pending_fds[FD_MAX_COUNT];
int make_nonblock(int fd) {
int flags = fcntl(fd, F_GETFL, 0);
assert(flags >= 0);
if ((flags & O_NONBLOCK) != 0) {
assert(fcntl(fd, F_SETFL, flags | O_NONBLOCK) == 0);
}
}
void make_pipe(int fds[2]) {
assert(pipe(fds) == 0);
make_nonblock(fds[0]);
make_nonblock(fds[1]);
}
void* monitor_thread(void *) {
while (1) {
struct pollfd pfds[FD_MAX_COUNT];
int pfds_count = 0;
pthread_mutex_lock(&monitor_mutex);
for (int i = 0; i < FD_MAX_COUNT; ++i) {
if (pending_fds[i] >= 0) {
pfds[pfds_count].fd = pending_fds[i];
pfds[pfds_count].events = POLLIN;
pfds[pfds_count].revents = 0;
pfds_count++;
}
}
pthread_mutex_unlock(&monitor_mutex);
int res = poll(pfds, pfds_count, 0);
if (res < 0) {
if (errno != EBADF) {
perror("poll");
exit(1);
}
}
}
return NULL;
}
void* client_thread(void *_idx) {
size_t idx = (size_t)_idx;
while (1) {
// sleep
int duration = rand() % 100;
usleep(duration * 1000);
// create fd
int fds[2];
make_pipe(fds);
// store fd for poll
pthread_mutex_lock(&monitor_mutex);
pending_fds[idx] = fds[0];
pthread_mutex_unlock(&monitor_mutex);
// sleep
duration = rand() % 100;
usleep(duration * 1000);
// remove fd from poll and close
pthread_mutex_lock(&monitor_mutex);
pending_fds[idx] = -1;
pthread_mutex_unlock(&monitor_mutex);
close(fds[0]);
close(fds[1]);
}
return NULL;
}
int main() {
for (int i = 0; i < FD_MAX_COUNT; ++i) {
pending_fds[i] = -1;
}
pthread_t threads[FD_MAX_COUNT];
for (size_t i = 0; i < FD_MAX_COUNT; ++i) {
pthread_create(&threads[i], NULL, client_thread, (void*)i);
}
pthread_t monitor_th;
pthread_create(&monitor_th, NULL, monitor_thread, NULL);
// not actually returning
pthread_join(monitor_th, NULL);
for (size_t i = 0; i < FD_MAX_COUNT; ++i) {
pthread_join(threads[i], NULL);
}
}