Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright (C) 2019 Intel Corporation.
3 : : * All rights reserved.
4 : : */
5 : :
6 : : #include "spdk/pipe.h"
7 : : #include "spdk/util.h"
8 : : #include "spdk/queue.h"
9 : : #include "spdk/log.h"
10 : :
11 : : struct spdk_pipe_buf {
12 : : SLIST_ENTRY(spdk_pipe_buf) link;
13 : : uint32_t sz;
14 : : };
15 : :
16 : : struct spdk_pipe_group {
17 : : SLIST_HEAD(, spdk_pipe_buf) bufs;
18 : : };
19 : :
20 : : struct spdk_pipe {
21 : : uint8_t *buf;
22 : : uint32_t sz;
23 : :
24 : : uint32_t write;
25 : : uint32_t read;
26 : : bool full;
27 : :
28 : : struct spdk_pipe_group *group;
29 : : };
30 : :
31 : : struct spdk_pipe *
32 : 15093 : spdk_pipe_create(void *buf, uint32_t sz)
33 : : {
34 : : struct spdk_pipe *pipe;
35 : :
36 : 15093 : pipe = calloc(1, sizeof(*pipe));
37 [ + + ]: 15093 : if (pipe == NULL) {
38 : 0 : return NULL;
39 : : }
40 : :
41 [ + - + - ]: 15093 : pipe->buf = buf;
42 [ + - + - ]: 15093 : pipe->sz = sz;
43 : :
44 : 15093 : return pipe;
45 : 3282 : }
46 : :
47 : : void *
48 : 15685 : spdk_pipe_destroy(struct spdk_pipe *pipe)
49 : : {
50 : : void *buf;
51 : :
52 [ + + ]: 15685 : if (pipe == NULL) {
53 : 592 : return NULL;
54 : : }
55 : :
56 [ + + + - : 15093 : if (pipe->group) {
- + ]
57 [ # # # # ]: 108 : spdk_pipe_group_remove(pipe->group, pipe);
58 : 0 : }
59 : :
60 [ + - + - ]: 15093 : buf = pipe->buf;
61 : 15093 : free(pipe);
62 : 15093 : return buf;
63 : 3307 : }
64 : :
65 : : static void
66 : 8712389 : pipe_alloc_buf_from_group(struct spdk_pipe *pipe)
67 : : {
68 : : struct spdk_pipe_buf *buf;
69 : : struct spdk_pipe_group *group;
70 : :
71 [ + + + - : 8712389 : assert(pipe->group != NULL);
+ - # # ]
72 [ + - + - ]: 8712389 : group = pipe->group;
73 : :
74 : : /* We have to pick a buffer that's the correct size. It's almost always
75 : : * the first one. */
76 [ + - + - : 8712389 : buf = SLIST_FIRST(&group->bufs);
+ - ]
77 [ + - ]: 8712389 : while (buf != NULL) {
78 [ + - + - : 8712389 : if (buf->sz == pipe->sz) {
+ - + - -
+ ]
79 : : /* TODO: Could track the previous and do an SLIST_REMOVE_AFTER */
80 [ + - + - : 8712389 : SLIST_REMOVE(&pipe->group->bufs, buf, spdk_pipe_buf, link);
+ - + - +
- - + + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# ]
81 [ + - + - ]: 8712389 : pipe->buf = (void *)buf;
82 : 8712389 : return;
83 : : }
84 [ # # # # : 0 : buf = SLIST_NEXT(buf, link);
# # ]
85 : : }
86 : : /* Should never get here. */
87 [ # # ]: 0 : assert(false);
88 : : }
89 : :
90 : : int
91 : 132426702 : spdk_pipe_writer_get_buffer(struct spdk_pipe *pipe, uint32_t requested_sz, struct iovec *iovs)
92 : : {
93 : : uint32_t sz;
94 : : uint32_t read;
95 : : uint32_t write;
96 : :
97 [ + - + - ]: 132426702 : read = pipe->read;
98 [ + - + - ]: 132426702 : write = pipe->write;
99 : :
100 [ + + + + : 132426702 : if (pipe->full || requested_sz == 0) {
+ + + + +
+ ]
101 [ # # # # : 102 : iovs[0].iov_base = NULL;
# # ]
102 [ # # # # : 8 : iovs[0].iov_len = 0;
# # ]
103 : 8 : return 0;
104 : : }
105 : :
106 [ + + + - : 132426600 : if (pipe->buf == NULL) {
+ + ]
107 : 8711301 : pipe_alloc_buf_from_group(pipe);
108 : 17500 : }
109 : :
110 [ + + ]: 132426600 : if (read <= write) {
111 [ + + + - : 132426592 : sz = spdk_min(requested_sz, pipe->sz - write);
+ + + - +
- ]
112 : :
113 [ + - + - : 132426592 : iovs[0].iov_base = pipe->buf + write;
+ - + - +
- + - ]
114 [ + - + - : 132426504 : iovs[0].iov_len = sz;
+ - ]
115 : :
116 : 132426504 : requested_sz -= sz;
117 : :
118 [ + + ]: 132426504 : if (requested_sz > 0) {
119 [ - + ]: 12 : sz = spdk_min(requested_sz, read);
120 : :
121 [ + + # # : 12 : iovs[1].iov_base = (sz == 0) ? NULL : pipe->buf;
# # # # #
# # # ]
122 [ # # # # : 12 : iovs[1].iov_len = sz;
# # ]
123 : 3 : } else {
124 [ + - + - : 132426492 : iovs[1].iov_base = NULL;
+ - ]
125 [ + - + - : 132426492 : iovs[1].iov_len = 0;
+ - ]
126 : : }
127 : 294105 : } else {
128 [ - + ]: 8 : sz = spdk_min(requested_sz, read - write);
129 : :
130 [ # # # # : 8 : iovs[0].iov_base = pipe->buf + write;
# # # # #
# # # ]
131 [ # # # # : 8 : iovs[0].iov_len = sz;
# # ]
132 [ # # # # : 8 : iovs[1].iov_base = NULL;
# # ]
133 [ # # # # : 8 : iovs[1].iov_len = 0;
# # ]
134 : : }
135 : :
136 [ + - + - : 132426512 : return iovs[0].iov_len + iovs[1].iov_len;
+ - + - +
- + - ]
137 : 294109 : }
138 : :
139 : : int
140 : 11166831 : spdk_pipe_writer_advance(struct spdk_pipe *pipe, uint32_t requested_sz)
141 : : {
142 : : uint32_t sz;
143 : : uint32_t read;
144 : : uint32_t write;
145 : :
146 [ + - + - ]: 11166831 : read = pipe->read;
147 [ + - + - ]: 11166831 : write = pipe->write;
148 : :
149 [ + + + + : 11166831 : if (requested_sz > pipe->sz || pipe->full) {
+ + + - +
- + - -
+ ]
150 : 4 : return -EINVAL;
151 : : }
152 : :
153 [ + + ]: 11166827 : if (read <= write) {
154 [ + + + - : 11166815 : if (requested_sz > (pipe->sz - write) + read) {
- + ]
155 : 4 : return -EINVAL;
156 : : }
157 : :
158 [ + + + - : 11166811 : sz = spdk_min(requested_sz, pipe->sz - write);
+ - # # #
# ]
159 : :
160 : 11166811 : write += sz;
161 [ + + + - : 11166811 : if (write == pipe->sz) {
+ - ]
162 : 2782190 : write = 0;
163 : 3 : }
164 : 11166811 : requested_sz -= sz;
165 : :
166 [ + + ]: 11166811 : if (requested_sz > 0) {
167 : 4 : write = requested_sz;
168 : 1 : }
169 : 35064 : } else {
170 [ + + ]: 12 : if (requested_sz > (read - write)) {
171 : 8 : return -EINVAL;
172 : : }
173 : :
174 : 4 : write += requested_sz;
175 : : }
176 : :
177 [ + + ]: 11166815 : if (read == write) {
178 [ # # # # ]: 2782190 : pipe->full = true;
179 : 3 : }
180 [ + - + - ]: 11166815 : pipe->write = write;
181 : :
182 : 11166815 : return 0;
183 : 35069 : }
184 : :
185 : : uint32_t
186 : 236484222 : spdk_pipe_reader_bytes_available(struct spdk_pipe *pipe)
187 : : {
188 : : uint32_t read;
189 : : uint32_t write;
190 : :
191 [ + - + - ]: 236484222 : read = pipe->read;
192 [ + - + - ]: 236484222 : write = pipe->write;
193 : :
194 [ + + + + : 236484222 : if (read == write && !pipe->full) {
+ - + - -
+ ]
195 : 112173075 : return 0;
196 [ + + ]: 124311147 : } else if (read < write) {
197 : 61893903 : return write - read;
198 : : } else {
199 [ # # # # ]: 62417244 : return (pipe->sz - read) + write;
200 : : }
201 : 90737 : }
202 : :
203 : : int
204 : 121222869 : spdk_pipe_reader_get_buffer(struct spdk_pipe *pipe, uint32_t requested_sz, struct iovec *iovs)
205 : : {
206 : : uint32_t sz;
207 : : uint32_t read;
208 : : uint32_t write;
209 : :
210 [ + - + - ]: 121222869 : read = pipe->read;
211 [ + - + - ]: 121222869 : write = pipe->write;
212 : :
213 [ + + + + : 121222869 : if ((read == write && !pipe->full) || requested_sz == 0) {
+ + + + +
+ ]
214 [ + - + - : 7066412 : iovs[0].iov_base = NULL;
+ - ]
215 [ + - + - : 7066412 : iovs[0].iov_len = 0;
+ - ]
216 [ + - + - : 7066412 : iovs[1].iov_base = NULL;
+ - ]
217 [ + - + - : 7066412 : iovs[1].iov_len = 0;
+ - ]
218 [ + + ]: 114173959 : } else if (read < write) {
219 [ + + ]: 63377390 : sz = spdk_min(requested_sz, write - read);
220 : :
221 [ + - + - : 63377390 : iovs[0].iov_base = pipe->buf + read;
+ - + - +
- + - ]
222 [ + - + - : 63377390 : iovs[0].iov_len = sz;
+ - ]
223 [ + - + - : 63377390 : iovs[1].iov_base = NULL;
+ - ]
224 [ + - + - : 63377390 : iovs[1].iov_len = 0;
+ - ]
225 : 90739 : } else {
226 [ - + # # : 50779067 : sz = spdk_min(requested_sz, pipe->sz - read);
# # # # #
# ]
227 : :
228 [ # # # # : 50779067 : iovs[0].iov_base = pipe->buf + read;
# # # # #
# # # ]
229 [ # # # # : 50779067 : iovs[0].iov_len = sz;
# # ]
230 : :
231 : 50779067 : requested_sz -= sz;
232 : :
233 [ + + ]: 50779067 : if (requested_sz > 0) {
234 [ - + ]: 47996881 : sz = spdk_min(requested_sz, write);
235 [ + + # # : 47996881 : iovs[1].iov_base = (sz == 0) ? NULL : pipe->buf;
# # # # #
# # # ]
236 [ # # # # : 47996881 : iovs[1].iov_len = sz;
# # ]
237 : 3 : } else {
238 [ # # # # : 2782186 : iovs[1].iov_base = NULL;
# # ]
239 [ # # # # : 2782186 : iovs[1].iov_len = 0;
# # ]
240 : : }
241 : : }
242 : :
243 [ + - + - : 121222869 : return iovs[0].iov_len + iovs[1].iov_len;
+ - + - +
- + - ]
244 : : }
245 : :
246 : : int
247 : 114156453 : spdk_pipe_reader_advance(struct spdk_pipe *pipe, uint32_t requested_sz)
248 : : {
249 : : uint32_t sz;
250 : : uint32_t read;
251 : : uint32_t write;
252 : :
253 [ + - + - ]: 114156453 : read = pipe->read;
254 [ + - + - ]: 114156453 : write = pipe->write;
255 : :
256 [ + + ]: 114156453 : if (requested_sz == 0) {
257 : 0 : return 0;
258 : : }
259 : :
260 [ + + ]: 114156453 : if (read < write) {
261 [ + + ]: 63377398 : if (requested_sz > (write - read)) {
262 : 8 : return -EINVAL;
263 : : }
264 : :
265 : 63377390 : read += requested_sz;
266 : 90739 : } else {
267 [ - + # # : 50779055 : sz = spdk_min(requested_sz, pipe->sz - read);
# # # # #
# ]
268 : :
269 : 50779055 : read += sz;
270 [ + + # # : 50779055 : if (read == pipe->sz) {
# # ]
271 : 2782178 : read = 0;
272 : 2 : }
273 : 50779055 : requested_sz -= sz;
274 : :
275 [ + + ]: 50779055 : if (requested_sz > 0) {
276 [ - + ]: 4 : if (requested_sz > write) {
277 : 0 : return -EINVAL;
278 : : }
279 : :
280 : 4 : read = requested_sz;
281 : 1 : }
282 : : }
283 : :
284 : : /* We know we advanced at least one byte, so the pipe isn't full. */
285 [ + - + - ]: 114156445 : pipe->full = false;
286 : :
287 [ + + ]: 114156445 : if (read == write) {
288 : : /* The pipe is empty. To re-use the same memory more frequently, jump
289 : : * both pointers back to the beginning of the pipe. */
290 : 11166739 : read = 0;
291 [ + - + - ]: 11166739 : pipe->write = 0;
292 : :
293 : : /* Additionally, release the buffer to the shared pool */
294 [ + + + - : 11166739 : if (pipe->group) {
+ + ]
295 [ + - + - ]: 8703053 : struct spdk_pipe_buf *buf = (struct spdk_pipe_buf *)pipe->buf;
296 [ + - + - : 8703053 : buf->sz = pipe->sz;
+ - + - ]
297 [ + - + - : 8703053 : SLIST_INSERT_HEAD(&pipe->group->bufs, buf, link);
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - ]
298 [ + - + - ]: 8703053 : pipe->buf = NULL;
299 : 15862 : }
300 : 35063 : }
301 : :
302 [ + - + - ]: 114156445 : pipe->read = read;
303 : :
304 : 114156445 : return 0;
305 : 90743 : }
306 : :
307 : : struct spdk_pipe_group *
308 : 5372 : spdk_pipe_group_create(void)
309 : : {
310 : : struct spdk_pipe_group *group;
311 : :
312 : 5372 : group = calloc(1, sizeof(*group));
313 [ + + ]: 5372 : if (!group) {
314 : 0 : return NULL;
315 : : }
316 : :
317 [ - + - + : 5372 : SLIST_INIT(&group->bufs);
- + ]
318 : :
319 : 5372 : return group;
320 : 216 : }
321 : :
322 : : void
323 : 5372 : spdk_pipe_group_destroy(struct spdk_pipe_group *group)
324 : : {
325 [ + + + - : 5372 : if (!SLIST_EMPTY(&group->bufs)) {
+ - + - ]
326 : 0 : SPDK_ERRLOG("Destroying a pipe group that still has buffers!\n");
327 [ # # ]: 0 : assert(false);
328 : : }
329 : :
330 : 5372 : free(group);
331 : 5372 : }
332 : :
333 : : int
334 : 9336 : spdk_pipe_group_add(struct spdk_pipe_group *group, struct spdk_pipe *pipe)
335 : : {
336 : : struct spdk_pipe_buf *buf;
337 : :
338 [ + + + - : 9336 : assert(pipe->group == NULL);
+ - # # ]
339 : :
340 [ + - + - ]: 9336 : pipe->group = group;
341 [ + - + + : 9336 : if (pipe->read != pipe->write || pipe->full) {
+ + + - +
- + - + -
+ - - + ]
342 : : /* Pipe currently has valid data, so keep the buffer attached
343 : : * to the pipe for now. We can move it to the group's SLIST
344 : : * later when it gets emptied.
345 : : */
346 : 0 : return 0;
347 : : }
348 : :
349 [ + - + - ]: 9336 : buf = (struct spdk_pipe_buf *)pipe->buf;
350 [ + - + - : 9336 : buf->sz = pipe->sz;
+ - + - ]
351 [ + - + - : 9336 : SLIST_INSERT_HEAD(&group->bufs, buf, link);
+ - + - +
- + - + -
+ - + - ]
352 [ + - + - ]: 9336 : pipe->buf = NULL;
353 : 9336 : return 0;
354 : 1638 : }
355 : :
356 : : int
357 : 9336 : spdk_pipe_group_remove(struct spdk_pipe_group *group, struct spdk_pipe *pipe)
358 : : {
359 [ + + + - : 9336 : assert(pipe->group == group);
+ - # # ]
360 : :
361 [ + + + - : 9336 : if (pipe->buf == NULL) {
+ - ]
362 : : /* Associate a buffer with the pipe before returning. */
363 : 1088 : pipe_alloc_buf_from_group(pipe);
364 [ - + # # : 1088 : assert(pipe->buf != NULL);
# # # # ]
365 : 0 : }
366 : :
367 [ + - + - ]: 9336 : pipe->group = NULL;
368 : 9336 : return 0;
369 : : }
|