Line data Source code
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 7 : spdk_pipe_create(void *buf, uint32_t sz) 20 : { 21 : struct spdk_pipe *pipe; 22 : 23 7 : pipe = calloc(1, sizeof(*pipe)); 24 7 : if (pipe == NULL) { 25 0 : return NULL; 26 : } 27 : 28 7 : pipe->buf = buf; 29 7 : pipe->sz = sz; 30 : 31 7 : return pipe; 32 : } 33 : 34 : void 35 27 : spdk_pipe_destroy(struct spdk_pipe *pipe) 36 : { 37 27 : free(pipe); 38 27 : } 39 : 40 : int 41 13 : 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 13 : read = pipe->read; 48 13 : write = pipe->write; 49 : 50 13 : if (pipe->full || requested_sz == 0) { 51 2 : iovs[0].iov_base = NULL; 52 2 : iovs[0].iov_len = 0; 53 2 : return 0; 54 : } 55 : 56 11 : if (read <= write) { 57 8 : sz = spdk_min(requested_sz, pipe->sz - write); 58 : 59 8 : iovs[0].iov_base = pipe->buf + write; 60 8 : iovs[0].iov_len = sz; 61 : 62 8 : requested_sz -= sz; 63 : 64 8 : if (requested_sz > 0) { 65 3 : sz = spdk_min(requested_sz, read); 66 : 67 3 : iovs[1].iov_base = (sz == 0) ? NULL : pipe->buf; 68 3 : iovs[1].iov_len = sz; 69 : } else { 70 5 : iovs[1].iov_base = NULL; 71 5 : iovs[1].iov_len = 0; 72 : } 73 : } else { 74 3 : sz = spdk_min(requested_sz, read - write); 75 : 76 3 : iovs[0].iov_base = pipe->buf + write; 77 3 : iovs[0].iov_len = sz; 78 3 : iovs[1].iov_base = NULL; 79 3 : iovs[1].iov_len = 0; 80 : } 81 : 82 11 : return iovs[0].iov_len + iovs[1].iov_len; 83 : } 84 : 85 : int 86 11 : 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 11 : read = pipe->read; 93 11 : write = pipe->write; 94 : 95 11 : if (requested_sz > pipe->sz || pipe->full) { 96 1 : return -EINVAL; 97 : } 98 : 99 10 : if (read <= write) { 100 6 : if (requested_sz > (pipe->sz - write) + read) { 101 1 : return -EINVAL; 102 : } 103 : 104 5 : sz = spdk_min(requested_sz, pipe->sz - write); 105 : 106 5 : write += sz; 107 5 : if (write == pipe->sz) { 108 3 : write = 0; 109 : } 110 5 : requested_sz -= sz; 111 : 112 5 : if (requested_sz > 0) { 113 1 : write = requested_sz; 114 : } 115 : } else { 116 4 : if (requested_sz > (read - write)) { 117 2 : return -EINVAL; 118 : } 119 : 120 2 : write += requested_sz; 121 : } 122 : 123 7 : if (read == write) { 124 3 : pipe->full = true; 125 : } 126 7 : pipe->write = write; 127 : 128 7 : return 0; 129 : } 130 : 131 : uint32_t 132 3 : spdk_pipe_reader_bytes_available(struct spdk_pipe *pipe) 133 : { 134 : uint32_t read; 135 : uint32_t write; 136 : 137 3 : read = pipe->read; 138 3 : write = pipe->write; 139 : 140 3 : if (read == write && !pipe->full) { 141 0 : return 0; 142 3 : } else if (read < write) { 143 1 : return write - read; 144 : } else { 145 2 : return (pipe->sz - read) + write; 146 : } 147 : } 148 : 149 : int 150 12 : 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 12 : read = pipe->read; 157 12 : write = pipe->write; 158 : 159 12 : if ((read == write && !pipe->full) || requested_sz == 0) { 160 2 : iovs[0].iov_base = NULL; 161 2 : iovs[0].iov_len = 0; 162 2 : iovs[1].iov_base = NULL; 163 2 : iovs[1].iov_len = 0; 164 10 : } else if (read < write) { 165 4 : sz = spdk_min(requested_sz, write - read); 166 : 167 4 : iovs[0].iov_base = pipe->buf + read; 168 4 : iovs[0].iov_len = sz; 169 4 : iovs[1].iov_base = NULL; 170 4 : iovs[1].iov_len = 0; 171 : } else { 172 6 : sz = spdk_min(requested_sz, pipe->sz - read); 173 : 174 6 : iovs[0].iov_base = pipe->buf + read; 175 6 : iovs[0].iov_len = sz; 176 : 177 6 : requested_sz -= sz; 178 : 179 6 : if (requested_sz > 0) { 180 4 : sz = spdk_min(requested_sz, write); 181 4 : iovs[1].iov_base = (sz == 0) ? NULL : pipe->buf; 182 4 : iovs[1].iov_len = sz; 183 : } else { 184 2 : iovs[1].iov_base = NULL; 185 2 : iovs[1].iov_len = 0; 186 : } 187 : } 188 : 189 12 : return iovs[0].iov_len + iovs[1].iov_len; 190 : } 191 : 192 : int 193 9 : 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 9 : read = pipe->read; 200 9 : write = pipe->write; 201 : 202 9 : if (requested_sz == 0) { 203 0 : return 0; 204 : } 205 : 206 9 : if (read < write) { 207 6 : if (requested_sz > (write - read)) { 208 2 : return -EINVAL; 209 : } 210 : 211 4 : read += requested_sz; 212 : } else { 213 3 : sz = spdk_min(requested_sz, pipe->sz - read); 214 : 215 3 : read += sz; 216 3 : if (read == pipe->sz) { 217 2 : read = 0; 218 : } 219 3 : requested_sz -= sz; 220 : 221 3 : if (requested_sz > 0) { 222 2 : if (requested_sz > write) { 223 0 : return -EINVAL; 224 : } 225 : 226 2 : read = requested_sz; 227 : } 228 : } 229 : 230 : /* We know we advanced at least one byte, so the pipe isn't full. */ 231 7 : pipe->full = false; 232 7 : pipe->read = read; 233 : 234 7 : return 0; 235 : }