forked from xxyzz/ostep-hw
-
Notifications
You must be signed in to change notification settings - Fork 0
/
server_io_uring.c
146 lines (131 loc) · 4.25 KB
/
server_io_uring.c
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
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
#include "connection.h"
#include <liburing.h>
#include <stdio.h>
#include <time.h> // clock_gettime
#include <unistd.h> // close
// man io_uring
// https://kernel.dk/io_uring.pdf
// https://github.com/axboe/liburing
// https://github.com/torvalds/linux/blob/master/fs/io_uring.c
// https://github.com/torvalds/linux/blob/master/include/uapi/linux/io_uring.h
// https://lwn.net/Kernel/Index/#io_uring
struct user_data {
char buf[BUFSIZ];
int socket_fd;
int file_fd;
int index;
int io_op;
};
struct user_data data_arr[LISTEN_BACKLOG];
int numAccepts = 0, numReqs = 0;
void prep_accept(struct io_uring *ring, int sfd) {
struct io_uring_sqe *sqe = io_uring_get_sqe(ring);
if (sqe == NULL)
handle_error("io_uring_get_sqe");
io_uring_prep_accept(sqe, sfd, NULL, NULL, 0);
// https://github.com/axboe/liburing/commit/8ecd3fd959634df81d66af8b3a69c16202a014e8
data_arr[--numAccepts].io_op = IORING_OP_ACCEPT;
data_arr[numAccepts].index = numAccepts;
io_uring_sqe_set_data(sqe, &data_arr[numAccepts]);
if (io_uring_submit(ring) < 0)
handle_error("io_uring_submit");
}
void prep_recv(struct io_uring *ring, int sfd, int cfd, int index) {
struct io_uring_sqe *sqe = io_uring_get_sqe(ring);
if (sqe == NULL)
handle_error("io_uring_get_sqe");
data_arr[index].io_op = IORING_OP_RECV;
data_arr[index].socket_fd = cfd;
memset(data_arr[index].buf, 0, BUFSIZ);
io_uring_prep_recv(sqe, cfd, data_arr[index].buf, BUFSIZ, 0);
io_uring_sqe_set_data(sqe, &data_arr[index]);
if (numAccepts > 0)
prep_accept(ring, sfd);
else if (io_uring_submit(ring) < 0)
handle_error("io_uring_submit");
}
void prep_read(struct io_uring *ring, int index) {
struct io_uring_sqe *sqe = io_uring_get_sqe(ring);
if (sqe == NULL)
handle_error("io_uring_get_sqe");
int file_fd = open(data_arr[index].buf, O_RDONLY);
if (file_fd == -1) {
fprintf(stderr, "buf: %s\n", data_arr[index].buf);
handle_error("open");
}
data_arr[index].io_op = IORING_OP_READ;
data_arr[index].file_fd = file_fd;
memset(data_arr[index].buf, 0, BUFSIZ);
io_uring_prep_read(sqe, file_fd, data_arr[index].buf, BUFSIZ, 0);
io_uring_sqe_set_data(sqe, &data_arr[index]);
if (io_uring_submit(ring) < 0)
handle_error("io_uring_submit");
}
void prep_send(struct io_uring *ring, int index) {
struct io_uring_sqe *sqe = io_uring_get_sqe(ring);
if (sqe == NULL)
handle_error("io_uring_get_sqe");
close(data_arr[index].file_fd);
data_arr[index].io_op = IORING_OP_SEND;
io_uring_prep_send(sqe, data_arr[index].socket_fd, data_arr[index].buf,
BUFSIZ, 0);
io_uring_sqe_set_data(sqe, &data_arr[index]);
if (io_uring_submit(ring) < 0)
handle_error("io_uring_submit");
}
int main(int argc, char *argv[]) {
if (argc != 2) {
fprintf(stderr, "Usage: %s numReqs\n", argv[0]);
exit(EXIT_FAILURE);
}
struct timespec start, end;
if (clock_gettime(CLOCK_MONOTONIC, &start) == -1)
handle_error("clock_gettime");
numReqs = atoi(argv[1]);
if (numReqs <= 0) {
fprintf(stderr, "Get out\n");
exit(EXIT_FAILURE);
}
numAccepts = numReqs;
int sfd = init_socket(1, 0);
struct io_uring ring;
if (io_uring_queue_init(LISTEN_BACKLOG, &ring, IORING_SETUP_SQPOLL))
handle_error("io_uring_queue_init");
prep_accept(&ring, sfd);
while (numReqs > 0) {
struct io_uring_cqe *cqe;
if (io_uring_wait_cqe(&ring, &cqe))
handle_error("io_uring_wait_cqe");
if (cqe->res < 0) {
fprintf(stderr, "I/O error: %s\n", strerror(-cqe->res));
exit(EXIT_FAILURE);
}
struct user_data *data = io_uring_cqe_get_data(cqe);
switch (data->io_op) {
case IORING_OP_ACCEPT:
prep_recv(&ring, sfd, cqe->res, data->index);
break;
case IORING_OP_RECV:
prep_read(&ring, data->index);
break;
case IORING_OP_READ:
prep_send(&ring, data->index);
break;
case IORING_OP_SEND:
close(data_arr[data->index].socket_fd);
numReqs--;
break;
default:
handle_error("Unknown I/O");
}
io_uring_cqe_seen(&ring, cqe);
}
io_uring_queue_exit(&ring);
close(sfd);
if (clock_gettime(CLOCK_MONOTONIC, &end) == -1)
handle_error("clock_gettime");
// nanoseconds
printf("%f\n",
((end.tv_sec - start.tv_sec) * 1E9 + end.tv_nsec - start.tv_nsec));
return 0;
}