xref: /spdk/lib/util/pipe.c (revision 0ed85362c8132a2d1927757fbcade66b6660d26a)
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 		iovs[0].iov_base = (sz == 0) ? NULL : (pipe->buf + write);
83 		iovs[0].iov_len = sz;
84 
85 		requested_sz -= sz;
86 
87 		if (requested_sz > 0) {
88 			sz = spdk_min(requested_sz, read);
89 
90 			iovs[1].iov_base = (sz == 0) ? NULL : pipe->buf;
91 			iovs[1].iov_len = sz;
92 		} else {
93 			iovs[1].iov_base = NULL;
94 			iovs[1].iov_len = 0;
95 		}
96 	} else {
97 		sz = spdk_min(requested_sz, read - write - 1);
98 
99 		iovs[0].iov_base = (sz == 0) ? NULL : (pipe->buf + write);
100 		iovs[0].iov_len = sz;
101 		iovs[1].iov_base = NULL;
102 		iovs[1].iov_len = 0;
103 	}
104 
105 	return iovs[0].iov_len + iovs[1].iov_len;
106 }
107 
108 int
109 spdk_pipe_writer_advance(struct spdk_pipe *pipe, uint32_t requested_sz)
110 {
111 	uint32_t sz;
112 	uint32_t read;
113 	uint32_t write;
114 
115 	read = pipe->read;
116 	write = pipe->write;
117 
118 	if (requested_sz > pipe->sz - 1) {
119 		return -EINVAL;
120 	}
121 
122 	if (read <= write) {
123 		if (requested_sz > (read + pipe->sz) - write) {
124 			return -EINVAL;
125 		}
126 
127 		sz = spdk_min(requested_sz, pipe->sz - write);
128 
129 		write += sz;
130 		if (write > pipe->sz - 1) {
131 			write = 0;
132 		}
133 		requested_sz -= sz;
134 
135 		if (requested_sz > 0) {
136 			if (requested_sz >= read) {
137 				return -EINVAL;
138 			}
139 
140 			write = requested_sz;
141 		}
142 	} else {
143 		if (requested_sz > (read - write - 1)) {
144 			return -EINVAL;
145 		}
146 
147 		write += requested_sz;
148 	}
149 
150 	pipe->write = write;
151 
152 	return 0;
153 }
154 
155 uint32_t
156 spdk_pipe_reader_bytes_available(struct spdk_pipe *pipe)
157 {
158 	uint32_t read;
159 	uint32_t write;
160 
161 	read = pipe->read;
162 	write = pipe->write;
163 
164 	if (read <= write) {
165 		return write - read;
166 	}
167 
168 	return (write + pipe->sz) - read;
169 }
170 
171 int
172 spdk_pipe_reader_get_buffer(struct spdk_pipe *pipe, uint32_t requested_sz, struct iovec *iovs)
173 {
174 	uint32_t sz;
175 	uint32_t read;
176 	uint32_t write;
177 
178 	read = pipe->read;
179 	write = pipe->write;
180 
181 	if (read <= write) {
182 		sz = spdk_min(requested_sz, write - read);
183 
184 		iovs[0].iov_base = (sz == 0) ? NULL : (pipe->buf + read);
185 		iovs[0].iov_len = sz;
186 		iovs[1].iov_base = NULL;
187 		iovs[1].iov_len = 0;
188 	} else {
189 		sz = spdk_min(requested_sz, pipe->sz - read);
190 
191 		iovs[0].iov_base = (sz == 0) ? NULL : (pipe->buf + read);
192 		iovs[0].iov_len = sz;
193 
194 		requested_sz -= sz;
195 
196 		if (requested_sz > 0) {
197 			sz = spdk_min(requested_sz, write);
198 			iovs[1].iov_base = (sz == 0) ? NULL : pipe->buf;
199 			iovs[1].iov_len = sz;
200 		} else {
201 			iovs[1].iov_base = NULL;
202 			iovs[1].iov_len = 0;
203 		}
204 	}
205 
206 	return iovs[0].iov_len + iovs[1].iov_len;
207 }
208 
209 int
210 spdk_pipe_reader_advance(struct spdk_pipe *pipe, uint32_t requested_sz)
211 {
212 	uint32_t sz;
213 	uint32_t read;
214 	uint32_t write;
215 
216 	read = pipe->read;
217 	write = pipe->write;
218 
219 	if (read <= write) {
220 		if (requested_sz > (write - read)) {
221 			return -EINVAL;
222 		}
223 
224 		read += requested_sz;
225 	} else {
226 		sz = spdk_min(requested_sz, pipe->sz - read);
227 
228 		read += sz;
229 		if (read > pipe->sz - 1) {
230 			read = 0;
231 		}
232 		requested_sz -= sz;
233 
234 		if (requested_sz > 0) {
235 			if (requested_sz > write) {
236 				return -EINVAL;
237 			}
238 
239 			read = requested_sz;
240 		}
241 	}
242 
243 	pipe->read = read;
244 
245 	return 0;
246 }
247