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