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