xref: /spdk/lib/util/pipe.c (revision 60982c759db49b4f4579f16e3b24df0725ba4b94)
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 
9 struct spdk_pipe {
10 	uint8_t	*buf;
11 	uint32_t sz;
12 
13 	uint32_t write;
14 	uint32_t read;
15 	bool full;
16 };
17 
18 struct spdk_pipe *
19 spdk_pipe_create(void *buf, uint32_t sz)
20 {
21 	struct spdk_pipe *pipe;
22 
23 	pipe = calloc(1, sizeof(*pipe));
24 	if (pipe == NULL) {
25 		return NULL;
26 	}
27 
28 	pipe->buf = buf;
29 	pipe->sz = sz;
30 
31 	return pipe;
32 }
33 
34 void
35 spdk_pipe_destroy(struct spdk_pipe *pipe)
36 {
37 	free(pipe);
38 }
39 
40 int
41 spdk_pipe_writer_get_buffer(struct spdk_pipe *pipe, uint32_t requested_sz, struct iovec *iovs)
42 {
43 	uint32_t sz;
44 	uint32_t read;
45 	uint32_t write;
46 
47 	read = pipe->read;
48 	write = pipe->write;
49 
50 	if (pipe->full || requested_sz == 0) {
51 		iovs[0].iov_base = NULL;
52 		iovs[0].iov_len = 0;
53 		return 0;
54 	}
55 
56 	if (read <= write) {
57 		sz = spdk_min(requested_sz, pipe->sz - write);
58 
59 		iovs[0].iov_base = pipe->buf + write;
60 		iovs[0].iov_len = sz;
61 
62 		requested_sz -= sz;
63 
64 		if (requested_sz > 0) {
65 			sz = spdk_min(requested_sz, read);
66 
67 			iovs[1].iov_base = (sz == 0) ? NULL : pipe->buf;
68 			iovs[1].iov_len = sz;
69 		} else {
70 			iovs[1].iov_base = NULL;
71 			iovs[1].iov_len = 0;
72 		}
73 	} else {
74 		sz = spdk_min(requested_sz, read - write);
75 
76 		iovs[0].iov_base = pipe->buf + write;
77 		iovs[0].iov_len = sz;
78 		iovs[1].iov_base = NULL;
79 		iovs[1].iov_len = 0;
80 	}
81 
82 	return iovs[0].iov_len + iovs[1].iov_len;
83 }
84 
85 int
86 spdk_pipe_writer_advance(struct spdk_pipe *pipe, uint32_t requested_sz)
87 {
88 	uint32_t sz;
89 	uint32_t read;
90 	uint32_t write;
91 
92 	read = pipe->read;
93 	write = pipe->write;
94 
95 	if (requested_sz > pipe->sz || pipe->full) {
96 		return -EINVAL;
97 	}
98 
99 	if (read <= write) {
100 		if (requested_sz > (pipe->sz - write) + read) {
101 			return -EINVAL;
102 		}
103 
104 		sz = spdk_min(requested_sz, pipe->sz - write);
105 
106 		write += sz;
107 		if (write == pipe->sz) {
108 			write = 0;
109 		}
110 		requested_sz -= sz;
111 
112 		if (requested_sz > 0) {
113 			write = requested_sz;
114 		}
115 	} else {
116 		if (requested_sz > (read - write)) {
117 			return -EINVAL;
118 		}
119 
120 		write += requested_sz;
121 	}
122 
123 	if (read == write) {
124 		pipe->full = true;
125 	}
126 	pipe->write = write;
127 
128 	return 0;
129 }
130 
131 uint32_t
132 spdk_pipe_reader_bytes_available(struct spdk_pipe *pipe)
133 {
134 	uint32_t read;
135 	uint32_t write;
136 
137 	read = pipe->read;
138 	write = pipe->write;
139 
140 	if (read == write && !pipe->full) {
141 		return 0;
142 	} else if (read < write) {
143 		return write - read;
144 	} else {
145 		return (pipe->sz - read) + write;
146 	}
147 }
148 
149 int
150 spdk_pipe_reader_get_buffer(struct spdk_pipe *pipe, uint32_t requested_sz, struct iovec *iovs)
151 {
152 	uint32_t sz;
153 	uint32_t read;
154 	uint32_t write;
155 
156 	read = pipe->read;
157 	write = pipe->write;
158 
159 	if ((read == write && !pipe->full) || requested_sz == 0) {
160 		iovs[0].iov_base = NULL;
161 		iovs[0].iov_len = 0;
162 		iovs[1].iov_base = NULL;
163 		iovs[1].iov_len = 0;
164 	} else if (read < write) {
165 		sz = spdk_min(requested_sz, write - read);
166 
167 		iovs[0].iov_base = pipe->buf + read;
168 		iovs[0].iov_len = sz;
169 		iovs[1].iov_base = NULL;
170 		iovs[1].iov_len = 0;
171 	} else {
172 		sz = spdk_min(requested_sz, pipe->sz - read);
173 
174 		iovs[0].iov_base = pipe->buf + read;
175 		iovs[0].iov_len = sz;
176 
177 		requested_sz -= sz;
178 
179 		if (requested_sz > 0) {
180 			sz = spdk_min(requested_sz, write);
181 			iovs[1].iov_base = (sz == 0) ? NULL : pipe->buf;
182 			iovs[1].iov_len = sz;
183 		} else {
184 			iovs[1].iov_base = NULL;
185 			iovs[1].iov_len = 0;
186 		}
187 	}
188 
189 	return iovs[0].iov_len + iovs[1].iov_len;
190 }
191 
192 int
193 spdk_pipe_reader_advance(struct spdk_pipe *pipe, uint32_t requested_sz)
194 {
195 	uint32_t sz;
196 	uint32_t read;
197 	uint32_t write;
198 
199 	read = pipe->read;
200 	write = pipe->write;
201 
202 	if (requested_sz == 0) {
203 		return 0;
204 	}
205 
206 	if (read < write) {
207 		if (requested_sz > (write - read)) {
208 			return -EINVAL;
209 		}
210 
211 		read += requested_sz;
212 	} else {
213 		sz = spdk_min(requested_sz, pipe->sz - read);
214 
215 		read += sz;
216 		if (read == pipe->sz) {
217 			read = 0;
218 		}
219 		requested_sz -= sz;
220 
221 		if (requested_sz > 0) {
222 			if (requested_sz > write) {
223 				return -EINVAL;
224 			}
225 
226 			read = requested_sz;
227 		}
228 	}
229 
230 	/* We know we advanced at least one byte, so the pipe isn't full. */
231 	pipe->full = false;
232 	pipe->read = read;
233 
234 	return 0;
235 }
236