LCOV - code coverage report
Current view: top level - lib/util - pipe.c (source / functions) Hit Total Coverage
Test: ut_cov_unit.info Lines: 124 165 75.2 %
Date: 2024-12-14 20:56:31 Functions: 9 12 75.0 %

          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             : #include "spdk/queue.h"
       9             : #include "spdk/log.h"
      10             : 
      11             : struct spdk_pipe_buf {
      12             :         SLIST_ENTRY(spdk_pipe_buf)      link;
      13             :         uint32_t                        sz;
      14             : };
      15             : 
      16             : struct spdk_pipe_group {
      17             :         SLIST_HEAD(, spdk_pipe_buf) bufs;
      18             : };
      19             : 
      20             : struct spdk_pipe {
      21             :         uint8_t *buf;
      22             :         uint32_t sz;
      23             : 
      24             :         uint32_t write;
      25             :         uint32_t read;
      26             :         bool full;
      27             : 
      28             :         struct spdk_pipe_group *group;
      29             : };
      30             : 
      31             : struct spdk_pipe *
      32           7 : spdk_pipe_create(void *buf, uint32_t sz)
      33             : {
      34             :         struct spdk_pipe *pipe;
      35             : 
      36           7 :         pipe = calloc(1, sizeof(*pipe));
      37           7 :         if (pipe == NULL) {
      38           0 :                 return NULL;
      39             :         }
      40             : 
      41           7 :         pipe->buf = buf;
      42           7 :         pipe->sz = sz;
      43             : 
      44           7 :         return pipe;
      45             : }
      46             : 
      47             : void *
      48          30 : spdk_pipe_destroy(struct spdk_pipe *pipe)
      49             : {
      50             :         void *buf;
      51             : 
      52          30 :         if (pipe == NULL) {
      53          23 :                 return NULL;
      54             :         }
      55             : 
      56           7 :         if (pipe->group) {
      57           0 :                 spdk_pipe_group_remove(pipe->group, pipe);
      58             :         }
      59             : 
      60           7 :         buf = pipe->buf;
      61           7 :         free(pipe);
      62           7 :         return buf;
      63             : }
      64             : 
      65             : static void
      66           0 : pipe_alloc_buf_from_group(struct spdk_pipe *pipe)
      67             : {
      68             :         struct spdk_pipe_buf *buf;
      69             :         struct spdk_pipe_group *group;
      70             : 
      71           0 :         assert(pipe->group != NULL);
      72           0 :         group = pipe->group;
      73             : 
      74             :         /* We have to pick a buffer that's the correct size. It's almost always
      75             :          * the first one. */
      76           0 :         buf = SLIST_FIRST(&group->bufs);
      77           0 :         while (buf != NULL) {
      78           0 :                 if (buf->sz == pipe->sz) {
      79             :                         /* TODO: Could track the previous and do an SLIST_REMOVE_AFTER */
      80           0 :                         SLIST_REMOVE(&pipe->group->bufs, buf, spdk_pipe_buf, link);
      81           0 :                         pipe->buf = (void *)buf;
      82           0 :                         return;
      83             :                 }
      84           0 :                 buf = SLIST_NEXT(buf, link);
      85             :         }
      86             :         /* Should never get here. */
      87           0 :         assert(false);
      88             : }
      89             : 
      90             : int
      91          13 : spdk_pipe_writer_get_buffer(struct spdk_pipe *pipe, uint32_t requested_sz, struct iovec *iovs)
      92             : {
      93             :         uint32_t sz;
      94             :         uint32_t read;
      95             :         uint32_t write;
      96             : 
      97          13 :         read = pipe->read;
      98          13 :         write = pipe->write;
      99             : 
     100          13 :         if (pipe->full || requested_sz == 0) {
     101           2 :                 iovs[0].iov_base = NULL;
     102           2 :                 iovs[0].iov_len = 0;
     103           2 :                 return 0;
     104             :         }
     105             : 
     106          11 :         if (pipe->buf == NULL) {
     107           0 :                 pipe_alloc_buf_from_group(pipe);
     108             :         }
     109             : 
     110          11 :         if (read <= write) {
     111           9 :                 sz = spdk_min(requested_sz, pipe->sz - write);
     112             : 
     113           9 :                 iovs[0].iov_base = pipe->buf + write;
     114           9 :                 iovs[0].iov_len = sz;
     115             : 
     116           9 :                 requested_sz -= sz;
     117             : 
     118           9 :                 if (requested_sz > 0) {
     119           3 :                         sz = spdk_min(requested_sz, read);
     120             : 
     121           3 :                         iovs[1].iov_base = (sz == 0) ? NULL : pipe->buf;
     122           3 :                         iovs[1].iov_len = sz;
     123             :                 } else {
     124           6 :                         iovs[1].iov_base = NULL;
     125           6 :                         iovs[1].iov_len = 0;
     126             :                 }
     127             :         } else {
     128           2 :                 sz = spdk_min(requested_sz, read - write);
     129             : 
     130           2 :                 iovs[0].iov_base = pipe->buf + write;
     131           2 :                 iovs[0].iov_len = sz;
     132           2 :                 iovs[1].iov_base = NULL;
     133           2 :                 iovs[1].iov_len = 0;
     134             :         }
     135             : 
     136          11 :         return iovs[0].iov_len + iovs[1].iov_len;
     137             : }
     138             : 
     139             : int
     140          11 : spdk_pipe_writer_advance(struct spdk_pipe *pipe, uint32_t requested_sz)
     141             : {
     142             :         uint32_t sz;
     143             :         uint32_t read;
     144             :         uint32_t write;
     145             : 
     146          11 :         read = pipe->read;
     147          11 :         write = pipe->write;
     148             : 
     149          11 :         if (requested_sz > pipe->sz || pipe->full) {
     150           1 :                 return -EINVAL;
     151             :         }
     152             : 
     153          10 :         if (read <= write) {
     154           7 :                 if (requested_sz > (pipe->sz - write) + read) {
     155           1 :                         return -EINVAL;
     156             :                 }
     157             : 
     158           6 :                 sz = spdk_min(requested_sz, pipe->sz - write);
     159             : 
     160           6 :                 write += sz;
     161           6 :                 if (write == pipe->sz) {
     162           3 :                         write = 0;
     163             :                 }
     164           6 :                 requested_sz -= sz;
     165             : 
     166           6 :                 if (requested_sz > 0) {
     167           1 :                         write = requested_sz;
     168             :                 }
     169             :         } else {
     170           3 :                 if (requested_sz > (read - write)) {
     171           2 :                         return -EINVAL;
     172             :                 }
     173             : 
     174           1 :                 write += requested_sz;
     175             :         }
     176             : 
     177           7 :         if (read == write) {
     178           3 :                 pipe->full = true;
     179             :         }
     180           7 :         pipe->write = write;
     181             : 
     182           7 :         return 0;
     183             : }
     184             : 
     185             : uint32_t
     186           3 : spdk_pipe_reader_bytes_available(struct spdk_pipe *pipe)
     187             : {
     188             :         uint32_t read;
     189             :         uint32_t write;
     190             : 
     191           3 :         read = pipe->read;
     192           3 :         write = pipe->write;
     193             : 
     194           3 :         if (read == write && !pipe->full) {
     195           0 :                 return 0;
     196           3 :         } else if (read < write) {
     197           2 :                 return write - read;
     198             :         } else {
     199           1 :                 return (pipe->sz - read) + write;
     200             :         }
     201             : }
     202             : 
     203             : int
     204          12 : spdk_pipe_reader_get_buffer(struct spdk_pipe *pipe, uint32_t requested_sz, struct iovec *iovs)
     205             : {
     206             :         uint32_t sz;
     207             :         uint32_t read;
     208             :         uint32_t write;
     209             : 
     210          12 :         read = pipe->read;
     211          12 :         write = pipe->write;
     212             : 
     213          12 :         if ((read == write && !pipe->full) || requested_sz == 0) {
     214           2 :                 iovs[0].iov_base = NULL;
     215           2 :                 iovs[0].iov_len = 0;
     216           2 :                 iovs[1].iov_base = NULL;
     217           2 :                 iovs[1].iov_len = 0;
     218          10 :         } else if (read < write) {
     219           5 :                 sz = spdk_min(requested_sz, write - read);
     220             : 
     221           5 :                 iovs[0].iov_base = pipe->buf + read;
     222           5 :                 iovs[0].iov_len = sz;
     223           5 :                 iovs[1].iov_base = NULL;
     224           5 :                 iovs[1].iov_len = 0;
     225             :         } else {
     226           5 :                 sz = spdk_min(requested_sz, pipe->sz - read);
     227             : 
     228           5 :                 iovs[0].iov_base = pipe->buf + read;
     229           5 :                 iovs[0].iov_len = sz;
     230             : 
     231           5 :                 requested_sz -= sz;
     232             : 
     233           5 :                 if (requested_sz > 0) {
     234           3 :                         sz = spdk_min(requested_sz, write);
     235           3 :                         iovs[1].iov_base = (sz == 0) ? NULL : pipe->buf;
     236           3 :                         iovs[1].iov_len = sz;
     237             :                 } else {
     238           2 :                         iovs[1].iov_base = NULL;
     239           2 :                         iovs[1].iov_len = 0;
     240             :                 }
     241             :         }
     242             : 
     243          12 :         return iovs[0].iov_len + iovs[1].iov_len;
     244             : }
     245             : 
     246             : int
     247           9 : spdk_pipe_reader_advance(struct spdk_pipe *pipe, uint32_t requested_sz)
     248             : {
     249             :         uint32_t sz;
     250             :         uint32_t read;
     251             :         uint32_t write;
     252             : 
     253           9 :         read = pipe->read;
     254           9 :         write = pipe->write;
     255             : 
     256           9 :         if (requested_sz == 0) {
     257           0 :                 return 0;
     258             :         }
     259             : 
     260           9 :         if (read < write) {
     261           7 :                 if (requested_sz > (write - read)) {
     262           2 :                         return -EINVAL;
     263             :                 }
     264             : 
     265           5 :                 read += requested_sz;
     266             :         } else {
     267           2 :                 sz = spdk_min(requested_sz, pipe->sz - read);
     268             : 
     269           2 :                 read += sz;
     270           2 :                 if (read == pipe->sz) {
     271           2 :                         read = 0;
     272             :                 }
     273           2 :                 requested_sz -= sz;
     274             : 
     275           2 :                 if (requested_sz > 0) {
     276           1 :                         if (requested_sz > write) {
     277           0 :                                 return -EINVAL;
     278             :                         }
     279             : 
     280           1 :                         read = requested_sz;
     281             :                 }
     282             :         }
     283             : 
     284             :         /* We know we advanced at least one byte, so the pipe isn't full. */
     285           7 :         pipe->full = false;
     286             : 
     287           7 :         if (read == write) {
     288             :                 /* The pipe is empty. To re-use the same memory more frequently, jump
     289             :                  * both pointers back to the beginning of the pipe. */
     290           5 :                 read = 0;
     291           5 :                 pipe->write = 0;
     292             : 
     293             :                 /* Additionally, release the buffer to the shared pool */
     294           5 :                 if (pipe->group) {
     295           0 :                         struct spdk_pipe_buf *buf = (struct spdk_pipe_buf *)pipe->buf;
     296           0 :                         buf->sz = pipe->sz;
     297           0 :                         SLIST_INSERT_HEAD(&pipe->group->bufs, buf, link);
     298           0 :                         pipe->buf = NULL;
     299             :                 }
     300             :         }
     301             : 
     302           7 :         pipe->read = read;
     303             : 
     304           7 :         return 0;
     305             : }
     306             : 
     307             : struct spdk_pipe_group *
     308          12 : spdk_pipe_group_create(void)
     309             : {
     310             :         struct spdk_pipe_group *group;
     311             : 
     312          12 :         group = calloc(1, sizeof(*group));
     313          12 :         if (!group) {
     314           0 :                 return NULL;
     315             :         }
     316             : 
     317          12 :         SLIST_INIT(&group->bufs);
     318             : 
     319          12 :         return group;
     320             : }
     321             : 
     322             : void
     323          12 : spdk_pipe_group_destroy(struct spdk_pipe_group *group)
     324             : {
     325          12 :         if (!SLIST_EMPTY(&group->bufs)) {
     326           0 :                 SPDK_ERRLOG("Destroying a pipe group that still has buffers!\n");
     327           0 :                 assert(false);
     328             :         }
     329             : 
     330          12 :         free(group);
     331          12 : }
     332             : 
     333             : int
     334           0 : spdk_pipe_group_add(struct spdk_pipe_group *group, struct spdk_pipe *pipe)
     335             : {
     336             :         struct spdk_pipe_buf *buf;
     337             : 
     338           0 :         assert(pipe->group == NULL);
     339             : 
     340           0 :         pipe->group = group;
     341           0 :         if (pipe->read != pipe->write || pipe->full) {
     342             :                 /* Pipe currently has valid data, so keep the buffer attached
     343             :                  * to the pipe for now.  We can move it to the group's SLIST
     344             :                  * later when it gets emptied.
     345             :                  */
     346           0 :                 return 0;
     347             :         }
     348             : 
     349           0 :         buf = (struct spdk_pipe_buf *)pipe->buf;
     350           0 :         buf->sz = pipe->sz;
     351           0 :         SLIST_INSERT_HEAD(&group->bufs, buf, link);
     352           0 :         pipe->buf = NULL;
     353           0 :         return 0;
     354             : }
     355             : 
     356             : int
     357           0 : spdk_pipe_group_remove(struct spdk_pipe_group *group, struct spdk_pipe *pipe)
     358             : {
     359           0 :         assert(pipe->group == group);
     360             : 
     361           0 :         if (pipe->buf == NULL) {
     362             :                 /* Associate a buffer with the pipe before returning. */
     363           0 :                 pipe_alloc_buf_from_group(pipe);
     364           0 :                 assert(pipe->buf != NULL);
     365             :         }
     366             : 
     367           0 :         pipe->group = NULL;
     368           0 :         return 0;
     369             : }

Generated by: LCOV version 1.15