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 : 10936 : spdk_pipe_create(void *buf, uint32_t sz)
33 : : {
34 : : struct spdk_pipe *pipe;
35 : :
36 : 10936 : pipe = calloc(1, sizeof(*pipe));
37 [ - + ]: 10936 : if (pipe == NULL) {
38 : 0 : return NULL;
39 : : }
40 : :
41 : 10936 : pipe->buf = buf;
42 : 10936 : pipe->sz = sz;
43 : :
44 : 10936 : return pipe;
45 : : }
46 : :
47 : : void *
48 : 11466 : spdk_pipe_destroy(struct spdk_pipe *pipe)
49 : : {
50 : : void *buf;
51 : :
52 [ + + ]: 11466 : if (pipe == NULL) {
53 : 530 : return NULL;
54 : : }
55 : :
56 [ + + ]: 10936 : if (pipe->group) {
57 : 36 : spdk_pipe_group_remove(pipe->group, pipe);
58 : : }
59 : :
60 : 10936 : buf = pipe->buf;
61 : 10936 : free(pipe);
62 : 10936 : return buf;
63 : : }
64 : :
65 : : static void
66 : 6313180 : pipe_alloc_buf_from_group(struct spdk_pipe *pipe)
67 : : {
68 : : struct spdk_pipe_buf *buf;
69 : : struct spdk_pipe_group *group;
70 : :
71 [ - + ]: 6313180 : assert(pipe->group != NULL);
72 : 6313180 : 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 : 6313180 : buf = SLIST_FIRST(&group->bufs);
77 [ + - ]: 6313180 : while (buf != NULL) {
78 [ + - ]: 6313180 : if (buf->sz == pipe->sz) {
79 : : /* TODO: Could track the previous and do an SLIST_REMOVE_AFTER */
80 [ + - - - ]: 6313180 : SLIST_REMOVE(&pipe->group->bufs, buf, spdk_pipe_buf, link);
81 : 6313180 : pipe->buf = (void *)buf;
82 : 6313180 : return;
83 : : }
84 : 0 : buf = SLIST_NEXT(buf, link);
85 : : }
86 : : /* Should never get here. */
87 : 0 : assert(false);
88 : : }
89 : :
90 : : int
91 : 107719733 : 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 : 107719733 : read = pipe->read;
98 : 107719733 : write = pipe->write;
99 : :
100 [ + + + + : 107719733 : if (pipe->full || requested_sz == 0) {
+ + ]
101 : 6 : iovs[0].iov_base = NULL;
102 : 6 : iovs[0].iov_len = 0;
103 : 6 : return 0;
104 : : }
105 : :
106 [ + + ]: 107719727 : if (pipe->buf == NULL) {
107 : 6312260 : pipe_alloc_buf_from_group(pipe);
108 : : }
109 : :
110 [ + + ]: 107719727 : if (read <= write) {
111 : 107719721 : sz = spdk_min(requested_sz, pipe->sz - write);
112 : :
113 : 107719721 : iovs[0].iov_base = pipe->buf + write;
114 : 107719721 : iovs[0].iov_len = sz;
115 : :
116 : 107719721 : requested_sz -= sz;
117 : :
118 [ + + ]: 107719721 : if (requested_sz > 0) {
119 : 9 : sz = spdk_min(requested_sz, read);
120 : :
121 [ + + ]: 9 : iovs[1].iov_base = (sz == 0) ? NULL : pipe->buf;
122 : 9 : iovs[1].iov_len = sz;
123 : : } else {
124 : 107719712 : iovs[1].iov_base = NULL;
125 : 107719712 : iovs[1].iov_len = 0;
126 : : }
127 : : } else {
128 : 6 : sz = spdk_min(requested_sz, read - write);
129 : :
130 : 6 : iovs[0].iov_base = pipe->buf + write;
131 : 6 : iovs[0].iov_len = sz;
132 : 6 : iovs[1].iov_base = NULL;
133 : 6 : iovs[1].iov_len = 0;
134 : : }
135 : :
136 : 107719727 : return iovs[0].iov_len + iovs[1].iov_len;
137 : : }
138 : :
139 : : int
140 : 8562812 : 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 : 8562812 : read = pipe->read;
147 : 8562812 : write = pipe->write;
148 : :
149 [ + + - + : 8562812 : if (requested_sz > pipe->sz || pipe->full) {
- + ]
150 : 3 : return -EINVAL;
151 : : }
152 : :
153 [ + + ]: 8562809 : if (read <= write) {
154 [ + + ]: 8562800 : if (requested_sz > (pipe->sz - write) + read) {
155 : 3 : return -EINVAL;
156 : : }
157 : :
158 : 8562797 : sz = spdk_min(requested_sz, pipe->sz - write);
159 : :
160 : 8562797 : write += sz;
161 [ + + ]: 8562797 : if (write == pipe->sz) {
162 : 1940869 : write = 0;
163 : : }
164 : 8562797 : requested_sz -= sz;
165 : :
166 [ + + ]: 8562797 : if (requested_sz > 0) {
167 : 3 : write = requested_sz;
168 : : }
169 : : } else {
170 [ + + ]: 9 : if (requested_sz > (read - write)) {
171 : 6 : return -EINVAL;
172 : : }
173 : :
174 : 3 : write += requested_sz;
175 : : }
176 : :
177 [ + + ]: 8562800 : if (read == write) {
178 : 1940869 : pipe->full = true;
179 : : }
180 : 8562800 : pipe->write = write;
181 : :
182 : 8562800 : return 0;
183 : : }
184 : :
185 : : uint32_t
186 : 186583309 : spdk_pipe_reader_bytes_available(struct spdk_pipe *pipe)
187 : : {
188 : : uint32_t read;
189 : : uint32_t write;
190 : :
191 : 186583309 : read = pipe->read;
192 : 186583309 : write = pipe->write;
193 : :
194 [ + + - + : 186583309 : if (read == write && !pipe->full) {
+ - ]
195 : 97283818 : return 0;
196 [ + + ]: 89299491 : } else if (read < write) {
197 : 41714936 : return write - read;
198 : : } else {
199 : 47584555 : return (pipe->sz - read) + write;
200 : : }
201 : : }
202 : :
203 : : int
204 : 82206682 : 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 : 82206682 : read = pipe->read;
211 : 82206682 : write = pipe->write;
212 : :
213 [ + + - + : 82206682 : if ((read == write && !pipe->full) || requested_sz == 0) {
+ + + + ]
214 : 5074962 : iovs[0].iov_base = NULL;
215 : 5074962 : iovs[0].iov_len = 0;
216 : 5074962 : iovs[1].iov_base = NULL;
217 : 5074962 : iovs[1].iov_len = 0;
218 [ + + ]: 77131720 : } else if (read < write) {
219 : 41196171 : sz = spdk_min(requested_sz, write - read);
220 : :
221 : 41196171 : iovs[0].iov_base = pipe->buf + read;
222 : 41196171 : iovs[0].iov_len = sz;
223 : 41196171 : iovs[1].iov_base = NULL;
224 : 41196171 : iovs[1].iov_len = 0;
225 : : } else {
226 : 35935549 : sz = spdk_min(requested_sz, pipe->sz - read);
227 : :
228 : 35935549 : iovs[0].iov_base = pipe->buf + read;
229 : 35935549 : iovs[0].iov_len = sz;
230 : :
231 : 35935549 : requested_sz -= sz;
232 : :
233 [ + + ]: 35935549 : if (requested_sz > 0) {
234 : 33994683 : sz = spdk_min(requested_sz, write);
235 [ + + ]: 33994683 : iovs[1].iov_base = (sz == 0) ? NULL : pipe->buf;
236 : 33994683 : iovs[1].iov_len = sz;
237 : : } else {
238 : 1940866 : iovs[1].iov_base = NULL;
239 : 1940866 : iovs[1].iov_len = 0;
240 : : }
241 : : }
242 : :
243 : 82206682 : return iovs[0].iov_len + iovs[1].iov_len;
244 : : }
245 : :
246 : : int
247 : 77131717 : 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 : 77131717 : read = pipe->read;
254 : 77131717 : write = pipe->write;
255 : :
256 [ - + ]: 77131717 : if (requested_sz == 0) {
257 : 0 : return 0;
258 : : }
259 : :
260 [ + + ]: 77131717 : if (read < write) {
261 [ + + ]: 41196177 : if (requested_sz > (write - read)) {
262 : 6 : return -EINVAL;
263 : : }
264 : :
265 : 41196171 : read += requested_sz;
266 : : } else {
267 : 35935540 : sz = spdk_min(requested_sz, pipe->sz - read);
268 : :
269 : 35935540 : read += sz;
270 [ + + ]: 35935540 : if (read == pipe->sz) {
271 : 1940861 : read = 0;
272 : : }
273 : 35935540 : requested_sz -= sz;
274 : :
275 [ + + ]: 35935540 : if (requested_sz > 0) {
276 [ - + ]: 3 : if (requested_sz > write) {
277 : 0 : return -EINVAL;
278 : : }
279 : :
280 : 3 : read = requested_sz;
281 : : }
282 : : }
283 : :
284 : : /* We know we advanced at least one byte, so the pipe isn't full. */
285 : 77131711 : pipe->full = false;
286 : :
287 [ + + ]: 77131711 : 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 : 8562775 : read = 0;
291 : 8562775 : pipe->write = 0;
292 : :
293 : : /* Additionally, release the buffer to the shared pool */
294 [ + + ]: 8562775 : if (pipe->group) {
295 : 6306178 : struct spdk_pipe_buf *buf = (struct spdk_pipe_buf *)pipe->buf;
296 : 6306178 : buf->sz = pipe->sz;
297 : 6306178 : SLIST_INSERT_HEAD(&pipe->group->bufs, buf, link);
298 : 6306178 : pipe->buf = NULL;
299 : : }
300 : : }
301 : :
302 : 77131711 : pipe->read = read;
303 : :
304 : 77131711 : return 0;
305 : : }
306 : :
307 : : struct spdk_pipe_group *
308 : 4160 : spdk_pipe_group_create(void)
309 : : {
310 : : struct spdk_pipe_group *group;
311 : :
312 : 4160 : group = calloc(1, sizeof(*group));
313 [ - + ]: 4160 : if (!group) {
314 : 0 : return NULL;
315 : : }
316 : :
317 : 4160 : SLIST_INIT(&group->bufs);
318 : :
319 : 4160 : return group;
320 : : }
321 : :
322 : : void
323 : 4160 : spdk_pipe_group_destroy(struct spdk_pipe_group *group)
324 : : {
325 [ - + ]: 4160 : 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 : 4160 : free(group);
331 : 4160 : }
332 : :
333 : : int
334 : 7002 : spdk_pipe_group_add(struct spdk_pipe_group *group, struct spdk_pipe *pipe)
335 : : {
336 : : struct spdk_pipe_buf *buf;
337 : :
338 [ - + ]: 7002 : assert(pipe->group == NULL);
339 : :
340 : 7002 : pipe->group = group;
341 [ + - - + : 7002 : 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 : 7002 : buf = (struct spdk_pipe_buf *)pipe->buf;
350 : 7002 : buf->sz = pipe->sz;
351 : 7002 : SLIST_INSERT_HEAD(&group->bufs, buf, link);
352 : 7002 : pipe->buf = NULL;
353 : 7002 : return 0;
354 : : }
355 : :
356 : : int
357 : 7002 : spdk_pipe_group_remove(struct spdk_pipe_group *group, struct spdk_pipe *pipe)
358 : : {
359 [ - + ]: 7002 : assert(pipe->group == group);
360 : :
361 [ + + ]: 7002 : if (pipe->buf == NULL) {
362 : : /* Associate a buffer with the pipe before returning. */
363 : 920 : pipe_alloc_buf_from_group(pipe);
364 [ - + ]: 920 : assert(pipe->buf != NULL);
365 : : }
366 : :
367 : 7002 : pipe->group = NULL;
368 : 7002 : return 0;
369 : : }
|