Odd timeout behavior

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi,

I've been looking at timeouts and found a case I can't wrap my head around.

Basically, If you submit OPs in a certain order, timeout fires before
time elapses where I wouldn't expect it to. The order is as follows:

poll(listen_socket, POLLIN) <- this never fires
nop(async)
timeout(1s, count=X)

If you set X to anything but 0xffffffff/(unsigned)-1, the timeout does
not fire (at least not immediately). This is expected apart from maybe
setting X=1 which would potentially allow the timeout to fire if nop
executes after the timeout is setup.

If you set it to 0xffffffff, it will always fire (at least on my
machine). Test program I'm using is attached.

The funny thing is that, if you remove the poll, timeout will not fire.

I'm using Linus' tree (v5.6-12604-gab6f762f0f53).

Could anybody shine a bit of light here?


Thank you,
Hrvoje

-- 
I doubt, therefore I might be.
#include <assert.h>
#include <errno.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <time.h>
#include <poll.h>
#include <sys/time.h>
#include <sys/socket.h>
#include <arpa/inet.h>

#include "liburing.h"

struct io_uring_sqe* get_sqe(struct io_uring* ring)
{
	struct io_uring_sqe* sqe = io_uring_get_sqe(ring);
	assert(sqe != NULL);
	return sqe;
}

void enqueue_nop(struct io_uring* ring)
{
	struct io_uring_sqe* sqe = get_sqe(ring);

	io_uring_prep_nop(sqe);
	io_uring_sqe_set_data(sqe, (void*)1);
	io_uring_sqe_set_flags(sqe, IOSQE_ASYNC);
}

void enqueue_timeout(struct io_uring* ring)
{
	struct io_uring_sqe* sqe = get_sqe(ring);
	static struct __kernel_timespec ts;

	ts.tv_sec = 1;
	ts.tv_nsec = 0;

	io_uring_prep_timeout(sqe, &ts, (unsigned)-1, 0);
	io_uring_sqe_set_data(sqe, (void*)2);
}

void enqueue_poll(struct io_uring* ring, int fd)
{
	struct io_uring_sqe* sqe = get_sqe(ring);

	io_uring_prep_poll_add(sqe, fd, POLLIN | POLLERR | POLLHUP);
	io_uring_sqe_set_data(sqe, (void*)3);
}

int create_socket()
{
	int s = socket(AF_INET, SOCK_STREAM | SOCK_CLOEXEC, IPPROTO_TCP);
	assert(s != -1);

	int flags = fcntl(s, F_GETFL, 0);
	assert(flags != -1);

	flags |= O_NONBLOCK;

	assert(fcntl(s, F_SETFL, flags) != -1);

	struct sockaddr_in addr;

	addr.sin_family = AF_INET;
	addr.sin_port = 0x1236;
	addr.sin_addr.s_addr = 0x0100007fU;

	assert(bind(s, (struct sockaddr*)&addr, sizeof(addr)) != -1);
	assert(listen(s, 1024) != -1);

	return s;
}

int main(int argc, char *argv[])
{
	struct io_uring ring;
	int ret;

	ret = io_uring_queue_init(4, &ring, 0);
	if (ret) {
		fprintf(stderr, "ring setup failed\n");
		return 1;
	}

	int s = create_socket();
	enqueue_poll(&ring, s);

	enqueue_nop(&ring);
	enqueue_timeout(&ring);

	ret = io_uring_submit_and_wait(&ring, 1);
	if (ret == -1) {
		fprintf(stderr, "submit failed\n");
		return 1;
	}

	struct io_uring_cqe* cqe;
	uint32_t head;
	uint32_t count = 0;

	io_uring_for_each_cqe(&ring, head, cqe) {
		if (io_uring_cqe_get_data(cqe) == (void*)2)
			fprintf(stderr, "Timeout triggered!\n");

		count++;
	}

	io_uring_cq_advance(&ring, count);

	io_uring_queue_exit(&ring);
	return 0;
}

[Index of Archives]     [Linux Samsung SoC]     [Linux Rockchip SoC]     [Linux Actions SoC]     [Linux for Synopsys ARC Processors]     [Linux NFS]     [Linux NILFS]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]


  Powered by Linux