xref: /spdk/lib/util/pipe.c (revision 712a3f69d32632bf6c862f00200f7f437d3f7529)
1 /*-
2  *   BSD LICENSE
3  *
4  *   Copyright (c) Intel Corporation.
5  *   All rights reserved.
6  *
7  *   Redistribution and use in source and binary forms, with or without
8  *   modification, are permitted provided that the following conditions
9  *   are met:
10  *
11  *     * Redistributions of source code must retain the above copyright
12  *       notice, this list of conditions and the following disclaimer.
13  *     * Redistributions in binary form must reproduce the above copyright
14  *       notice, this list of conditions and the following disclaimer in
15  *       the documentation and/or other materials provided with the
16  *       distribution.
17  *     * Neither the name of Intel Corporation nor the names of its
18  *       contributors may be used to endorse or promote products derived
19  *       from this software without specific prior written permission.
20  *
21  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24  *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25  *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26  *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27  *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28  *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29  *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30  *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  */
33 
34 #include "spdk/pipe.h"
35 #include "spdk/util.h"
36 
37 struct spdk_pipe {
38 	uint8_t	*buf;
39 	uint32_t sz;
40 
41 	uint32_t write;
42 	uint32_t read;
43 };
44 
45 struct spdk_pipe *
46 spdk_pipe_create(void *buf, uint32_t sz)
47 {
48 	struct spdk_pipe *pipe;
49 
50 	pipe = calloc(1, sizeof(*pipe));
51 	if (pipe == NULL) {
52 		return NULL;
53 	}
54 
55 	pipe->buf = buf;
56 	pipe->sz = sz;
57 
58 	return pipe;
59 }
60 
61 void
62 spdk_pipe_destroy(struct spdk_pipe *pipe)
63 {
64 	free(pipe);
65 }
66 
67 int
68 spdk_pipe_writer_get_buffer(struct spdk_pipe *pipe, uint32_t requested_sz, struct iovec *iovs)
69 {
70 	uint32_t sz;
71 	uint32_t read;
72 	uint32_t write;
73 
74 	read = pipe->read;
75 	write = pipe->write;
76 
77 	if (read <= write) {
78 		requested_sz = spdk_min(requested_sz, ((read + pipe->sz) - write - 1));
79 
80 		sz = spdk_min(requested_sz, pipe->sz - write);
81 
82 		if (sz == 0) {
83 			iovs[0].iov_base = NULL;
84 		} else {
85 			iovs[0].iov_base = pipe->buf + write;
86 		}
87 		iovs[0].iov_len = sz;
88 
89 		requested_sz -= sz;
90 
91 		if (requested_sz > 0) {
92 			sz = spdk_min(requested_sz, read);
93 
94 			if (sz == 0) {
95 				iovs[1].iov_base = NULL;
96 			} else {
97 				iovs[1].iov_base = pipe->buf;
98 			}
99 			iovs[1].iov_len = sz;
100 		} else {
101 			iovs[1].iov_base = NULL;
102 			iovs[1].iov_len = 0;
103 		}
104 	} else {
105 		sz = spdk_min(requested_sz, read - write - 1);
106 
107 		if (sz == 0) {
108 			iovs[0].iov_base = NULL;
109 		} else {
110 			iovs[0].iov_base = pipe->buf + write;
111 		}
112 		iovs[0].iov_len = sz;
113 
114 		iovs[1].iov_base = NULL;
115 		iovs[1].iov_len = 0;
116 	}
117 
118 	return iovs[0].iov_len + iovs[1].iov_len;
119 }
120 
121 int
122 spdk_pipe_writer_advance(struct spdk_pipe *pipe, uint32_t requested_sz)
123 {
124 	uint32_t sz;
125 	uint32_t read;
126 	uint32_t write;
127 
128 	read = pipe->read;
129 	write = pipe->write;
130 
131 	if (requested_sz > pipe->sz - 1) {
132 		return -EINVAL;
133 	}
134 
135 	if (read <= write) {
136 		if (requested_sz > (read + pipe->sz) - write) {
137 			return -EINVAL;
138 		}
139 
140 		sz = spdk_min(requested_sz, pipe->sz - write);
141 
142 		write += sz;
143 		if (write > pipe->sz - 1) {
144 			write = 0;
145 		}
146 		requested_sz -= sz;
147 
148 		if (requested_sz > 0) {
149 			if (requested_sz >= read) {
150 				return -EINVAL;
151 			}
152 
153 			write = requested_sz;
154 		}
155 	} else {
156 		if (requested_sz > (read - write - 1)) {
157 			return -EINVAL;
158 		}
159 
160 		write += requested_sz;
161 	}
162 
163 	pipe->write = write;
164 
165 	return 0;
166 }
167 
168 uint32_t
169 spdk_pipe_reader_bytes_available(struct spdk_pipe *pipe)
170 {
171 	uint32_t read;
172 	uint32_t write;
173 
174 	read = pipe->read;
175 	write = pipe->write;
176 
177 	if (read <= write) {
178 		return write - read;
179 	}
180 
181 	return (write + pipe->sz) - read;
182 }
183 
184 int
185 spdk_pipe_reader_get_buffer(struct spdk_pipe *pipe, uint32_t requested_sz, struct iovec *iovs)
186 {
187 	uint32_t sz;
188 	uint32_t read;
189 	uint32_t write;
190 
191 	read = pipe->read;
192 	write = pipe->write;
193 
194 	if (read <= write) {
195 		sz = spdk_min(requested_sz, write - read);
196 
197 		if (sz == 0) {
198 			iovs[0].iov_base = NULL;
199 		} else {
200 			iovs[0].iov_base = pipe->buf + read;
201 		}
202 		iovs[0].iov_len = sz;
203 
204 		iovs[1].iov_base = NULL;
205 		iovs[1].iov_len = 0;
206 	} else {
207 		sz = spdk_min(requested_sz, pipe->sz - read);
208 
209 		if (sz == 0) {
210 			iovs[0].iov_base = NULL;
211 		} else {
212 			iovs[0].iov_base = pipe->buf + read;
213 		}
214 		iovs[0].iov_len = sz;
215 
216 		requested_sz -= sz;
217 
218 		if (requested_sz > 0) {
219 			sz = spdk_min(requested_sz, write);
220 
221 			if (sz == 0) {
222 				iovs[1].iov_base = NULL;
223 			} else {
224 				iovs[1].iov_base = pipe->buf;
225 			}
226 			iovs[1].iov_len = sz;
227 		} else {
228 			iovs[1].iov_base = NULL;
229 			iovs[1].iov_len = 0;
230 		}
231 	}
232 
233 	return iovs[0].iov_len + iovs[1].iov_len;
234 }
235 
236 int
237 spdk_pipe_reader_advance(struct spdk_pipe *pipe, uint32_t requested_sz)
238 {
239 	uint32_t sz;
240 	uint32_t read;
241 	uint32_t write;
242 
243 	read = pipe->read;
244 	write = pipe->write;
245 
246 	if (read <= write) {
247 		if (requested_sz > (write - read)) {
248 			return -EINVAL;
249 		}
250 
251 		read += requested_sz;
252 	} else {
253 		sz = spdk_min(requested_sz, pipe->sz - read);
254 
255 		read += sz;
256 		if (read > pipe->sz - 1) {
257 			read = 0;
258 		}
259 		requested_sz -= sz;
260 
261 		if (requested_sz > 0) {
262 			if (requested_sz > write) {
263 				return -EINVAL;
264 			}
265 
266 			read = requested_sz;
267 		}
268 	}
269 
270 	pipe->read = read;
271 
272 	return 0;
273 }
274