axboe / liburing

Library providing helpers for the Linux kernel io_uring support
MIT License
2.7k stars 393 forks source link

Unable to trigger epoll event #1145

Closed NathanFreeman closed 2 months ago

NathanFreeman commented 2 months ago

Hi.

io_uring_queue_init(entries, &ring, 0);
epoll_ctl(epfd, EPOLL_CTL_ADD, ring.fd, event);

I added ring.fd to epoll, and in liburing2.2, it was possible to trigger epoll events after file operations were completed. However, starting from liburing2.3, it will be block in epoll_wait indefinitely.

my server info

LSB Version:    core-11.1.0ubuntu4-noarch:security-11.1.0ubuntu4-noarch
Distributor ID: Ubuntu
Description:    Ubuntu 22.04.2 LTS
Release:        22.04
Codename:       jammy

Linux iZ7xv05bnlqyyku0ks7bzqZ 5.15.0-71-generic #78-Ubuntu SMP Tue Apr 18 09:00:29 UTC 2023 x86_64 x86_64 x86_64 GNU/Linux

Thanks.

axboe commented 2 months ago

The liburing version should have no relevance on that, the poll mechanism is purely on the kernel side. Do you have a basic reproducer for this?

axboe commented 2 months ago

I wrote the most basic of test cases:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/epoll.h>
#include <string.h>
#include <pthread.h>
#include <inttypes.h>
#include <liburing.h>

struct d {
    pthread_barrier_t barrier;
    int poll_fd;
};

static void *fn(void *data)
{
    struct epoll_event ev;
    struct d *d = data;
    int efd, ret;

    efd = epoll_create1(EPOLL_CLOEXEC);
    if (efd < 0) {
        perror("epoll_create");
        return NULL;
    }

    ev.events = EPOLLIN;
    ev.data.fd = d->poll_fd;
    if (epoll_ctl(efd, EPOLL_CTL_ADD, d->poll_fd, &ev) < 0) {
        perror("epoll add");
        return NULL;
    }

    pthread_barrier_wait(&d->barrier);

    memset(&ev, 0, sizeof(ev));
    ret = epoll_wait(efd, &ev, 1, -1);
    if (ret < 0) {
        perror("epolL_wait");
        return NULL;
    }

    printf("epoll got %d events\n", ret);
    return NULL;
}

int main(int argc, char *argv[])
{
    struct io_uring_sqe *sqe;
    struct io_uring ring;
    pthread_t thread;
    void *tret;
    struct d d;

    io_uring_queue_init(4, &ring, 0);

    pthread_barrier_init(&d.barrier, NULL, 2);
    d.poll_fd = ring.ring_fd;
    pthread_create(&thread, NULL, fn, &d);
    pthread_barrier_wait(&d.barrier);

    sqe = io_uring_get_sqe(&ring);
    io_uring_prep_nop(sqe);
    io_uring_submit(&ring);

    pthread_join(thread, &tret);

    return 0;
}

and it works just fine for me, using a current kernel and liburing. Both 2.2 and 2.3 are old, but should not really matter here. Your kernel is old too, could be a bug in that as Ubuntu are notoriously bad a getting fixes applied.

Try the above, see if it works for you or not.

NathanFreeman commented 2 months ago

Thank you for your reply. It could be a kernel version issue. I will try testing it on the latest Ubuntu 24.04 LTS.

NathanFreeman commented 2 months ago

It seems like the issue might be caused by having multiple versions of liburing installed on my server.

axboe commented 2 months ago

That sounds very likely indeed. You see weird things if you end up compiling against one set of headers, but linking against something else.

NathanFreeman commented 2 months ago

Thank you