aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/libs/liburing/test/fdinfo-sqpoll.c
blob: 1328497d3608db992121e463529fbe6c09306d15 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
#include "../config-host.h"
/* SPDX-License-Identifier: MIT */
/*
 * Description: Race fdinfo reading with SQPOLL thread exiting
 */
#include <errno.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <sys/types.h>
#include <pthread.h>

#include "helpers.h"
#include "liburing.h"

struct data {
	struct io_uring ring;
	pthread_t thread;
	pthread_barrier_t barrier;
	volatile int done;
};

static int rand_between(int a, int b)
{
	return a + rand() % (b - a + 1);
}

static void *fdinfo_read(void *__data)
{
	struct data *d = __data;
	char fd_name[128];
	char *buf;
	int fd;

	buf = malloc(4096);

	sprintf(fd_name, "/proc/self/fdinfo/%d", d->ring.ring_fd);
	fd = open(fd_name, O_RDONLY);
	if (fd < 0) {
		perror("open");
		return NULL;
	}

	pthread_barrier_wait(&d->barrier);

	do {
		int ret = read(fd, buf, 4096);

		if (ret < 0) {
			perror("fdinfo read");
			break;
		}
	} while (!d->done);

	close(fd);
	free(buf);
	return NULL;
}

static int __test(void)
{
	struct data d = { };
	void *tret;
	int ret;

	ret = t_create_ring(8, &d.ring, IORING_SETUP_SQPOLL);
	if (ret == T_SETUP_SKIP)
		exit(T_EXIT_SKIP);
	else if (ret < 0)
		exit(T_EXIT_FAIL);
	pthread_barrier_init(&d.barrier, NULL, 2);
	pthread_create(&d.thread, NULL, fdinfo_read, &d);
	pthread_barrier_wait(&d.barrier);
	usleep(rand_between(1000, 100000));
	d.done = 1;
	pthread_join(d.thread, &tret);
	exit(T_EXIT_PASS);
}

static int test(void)
{
	pid_t pid;

	pid = fork();
	if (pid) {
		int wstatus;

		usleep(rand_between(10, 2000));
		kill(pid, SIGINT);
		waitpid(pid, &wstatus, 0);
	} else {
		return __test();
	}

	return T_EXIT_PASS;
}

int main(int argc, char *argv[])
{
	int i, ret;

	if (argc > 1)
		return T_EXIT_SKIP;

	for (i = 0; i < 1000; i++) {
		ret = test();
		if (ret == T_EXIT_SKIP) {
			return T_EXIT_SKIP;
		} else if (ret) {
			fprintf(stderr, "test failed\n");
			return T_EXIT_FAIL;
		}
	}

	return T_EXIT_PASS;
}