xref: /spdk/lib/util/pipe.c (revision 45a053c5777494f4e8ce4bc1191c9de3920377f7)
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