LCOV - code coverage report
Current view: top level - include/spdk - util.h (source / functions) Hit Total Coverage
Test: ut_cov_unit.info Lines: 28 32 87.5 %
Date: 2024-07-13 00:15:50 Functions: 9 9 100.0 %

          Line data    Source code
       1             : /*   SPDX-License-Identifier: BSD-3-Clause
       2             :  *   Copyright (C) 2017 Intel Corporation. All rights reserved.
       3             :  *   Copyright (c) 2019 Mellanox Technologies LTD. All rights reserved.
       4             :  */
       5             : 
       6             : /** \file
       7             :  * General utility functions
       8             :  */
       9             : 
      10             : #ifndef SPDK_UTIL_H
      11             : #define SPDK_UTIL_H
      12             : 
      13             : /* memset_s is only available if __STDC_WANT_LIB_EXT1__ is set to 1 before including \<string.h\> */
      14             : #define __STDC_WANT_LIB_EXT1__ 1
      15             : 
      16             : #include "spdk/stdinc.h"
      17             : 
      18             : #ifdef __cplusplus
      19             : extern "C" {
      20             : #endif
      21             : 
      22             : #define SPDK_CACHE_LINE_SIZE 64
      23             : 
      24             : #define spdk_min(a,b) (((a)<(b))?(a):(b))
      25             : #define spdk_max(a,b) (((a)>(b))?(a):(b))
      26             : 
      27             : #define SPDK_COUNTOF(arr) (sizeof(arr) / sizeof((arr)[0]))
      28             : 
      29             : #define SPDK_CONTAINEROF(ptr, type, member) ((type *)((uintptr_t)ptr - offsetof(type, member)))
      30             : 
      31             : /** Returns size of an object pointer by ptr up to and including member */
      32             : #define SPDK_SIZEOF(ptr, member) (offsetof(__typeof__(*(ptr)), member) + sizeof((ptr)->member))
      33             : 
      34             : /**
      35             :  * Get the size of a member of a struct.
      36             :  */
      37             : #define SPDK_SIZEOF_MEMBER(type, member) (sizeof(((type *)0)->member))
      38             : 
      39             : #define SPDK_SEC_TO_USEC 1000000ULL
      40             : #define SPDK_SEC_TO_NSEC 1000000000ULL
      41             : 
      42             : /* Ceiling division of unsigned integers */
      43             : #define SPDK_CEIL_DIV(x,y) (((x)+(y)-1)/(y))
      44             : 
      45             : /**
      46             :  * Macro to align a value to a given power-of-two. The resultant value
      47             :  * will be of the same type as the first parameter, and will be no
      48             :  * bigger than the first parameter. Second parameter must be a
      49             :  * power-of-two value.
      50             :  */
      51             : #define SPDK_ALIGN_FLOOR(val, align) \
      52             :         (__typeof__(val))((val) & (~((__typeof__(val))((align) - 1))))
      53             : /**
      54             :  * Macro to align a value to a given power-of-two. The resultant value
      55             :  * will be of the same type as the first parameter, and will be no lower
      56             :  * than the first parameter. Second parameter must be a power-of-two
      57             :  * value.
      58             :  */
      59             : #define SPDK_ALIGN_CEIL(val, align) \
      60             :         SPDK_ALIGN_FLOOR(((val) + ((__typeof__(val)) (align) - 1)), align)
      61             : 
      62             : uint32_t spdk_u32log2(uint32_t x);
      63             : 
      64             : static inline uint32_t
      65      209702 : spdk_align32pow2(uint32_t x)
      66             : {
      67      209702 :         return 1u << (1 + spdk_u32log2(x - 1));
      68             : }
      69             : 
      70             : uint64_t spdk_u64log2(uint64_t x);
      71             : 
      72             : static inline uint64_t
      73       34374 : spdk_align64pow2(uint64_t x)
      74             : {
      75       34374 :         return 1ULL << (1 + spdk_u64log2(x - 1));
      76             : }
      77             : 
      78             : /**
      79             :  * Check if a uint32_t is a power of 2.
      80             :  */
      81             : static inline bool
      82        1274 : spdk_u32_is_pow2(uint32_t x)
      83             : {
      84        1274 :         if (x == 0) {
      85           0 :                 return false;
      86             :         }
      87             : 
      88        1274 :         return (x & (x - 1)) == 0;
      89             : }
      90             : 
      91             : /**
      92             :  * Check if a uint64_t is a power of 2.
      93             :  */
      94             : static inline bool
      95           3 : spdk_u64_is_pow2(uint64_t x)
      96             : {
      97           3 :         if (x == 0) {
      98           0 :                 return false;
      99             :         }
     100             : 
     101           3 :         return (x & (x - 1)) == 0;
     102             : }
     103             : 
     104             : static inline uint64_t
     105        7669 : spdk_divide_round_up(uint64_t num, uint64_t divisor)
     106             : {
     107        7669 :         return (num + divisor - 1) / divisor;
     108             : }
     109             : 
     110             : struct spdk_single_ioviter {
     111             :         struct iovec    *iov;
     112             :         size_t          iovcnt;
     113             :         size_t          idx;
     114             :         size_t          iov_len;
     115             :         uint8_t         *iov_base;
     116             : };
     117             : 
     118             : /**
     119             :  * An N-way iovec iterator. Calculate the size, given N, using
     120             :  * SPDK_IOVITER_SIZE. For backward compatibility, the structure
     121             :  * has a default size of 2 iovecs.
     122             :  */
     123             : struct spdk_ioviter {
     124             :         uint32_t        count;
     125             : 
     126             :         union {
     127             :                 struct spdk_single_ioviter iters_compat[2];
     128             :                 struct spdk_single_ioviter iters[0];
     129             :         };
     130             : };
     131             : 
     132             : /* count must be greater than or equal to 2 */
     133             : #define SPDK_IOVITER_SIZE(count) (sizeof(struct spdk_single_ioviter) * (count - 2) + sizeof(struct spdk_ioviter))
     134             : 
     135             : /**
     136             :  * Initialize and move to the first common segment of the two given
     137             :  * iovecs. See spdk_ioviter_next().
     138             :  */
     139             : size_t spdk_ioviter_first(struct spdk_ioviter *iter,
     140             :                           struct iovec *siov, size_t siovcnt,
     141             :                           struct iovec *diov, size_t diovcnt,
     142             :                           void **src, void **dst);
     143             : 
     144             : /**
     145             :  * Initialize and move to the first common segment of the N given
     146             :  * iovecs. See spdk_ioviter_nextv().
     147             :  */
     148             : size_t spdk_ioviter_firstv(struct spdk_ioviter *iter,
     149             :                            uint32_t count,
     150             :                            struct iovec **iov,
     151             :                            size_t *iovcnt,
     152             :                            void **out);
     153             : 
     154             : /**
     155             :  * Move to the next segment in the iterator.
     156             :  *
     157             :  * This will iterate through the segments of the source and destination
     158             :  * and return the individual segments, one by one. For example, if the
     159             :  * source consists of one element of length 4k and the destination
     160             :  * consists of 4 elements each of length 1k, this function will return
     161             :  * 4 1k src+dst pairs of buffers, and then return 0 bytes to indicate
     162             :  * the iteration is complete on the fifth call.
     163             :  */
     164             : size_t spdk_ioviter_next(struct spdk_ioviter *iter, void **src, void **dst);
     165             : 
     166             : /**
     167             :  * Move to the next segment in the iterator.
     168             :  *
     169             :  * This will iterate through the segments of the iovecs in the iterator
     170             :  * and return the individual segments, one by one. For example, if the
     171             :  * set consists one iovec of one element of length 4k and another iovec
     172             :  * of 4 elements each of length 1k, this function will return
     173             :  * 4 1k pairs of buffers, and then return 0 bytes to indicate
     174             :  * the iteration is complete on the fifth call.
     175             :  */
     176             : size_t spdk_ioviter_nextv(struct spdk_ioviter *iter, void **out);
     177             : 
     178             : /**
     179             :  * Operate like memset across an iovec.
     180             :  */
     181             : void
     182             : spdk_iov_memset(struct iovec *iovs, int iovcnt, int c);
     183             : 
     184             : /**
     185             :  * Initialize an iovec with just the single given buffer.
     186             :  */
     187             : void
     188             : spdk_iov_one(struct iovec *iov, int *iovcnt, void *buf, size_t buflen);
     189             : 
     190             : #define SPDK_IOV_ONE(piov, piovcnt, buf, buflen) do {   \
     191             :         (piov)->iov_base = (buf);                    \
     192             :         (piov)->iov_len = (buflen);                  \
     193             :         *(piovcnt) = 1;                                 \
     194             : } while (0)
     195             : 
     196             : /**
     197             :  * Copy the data described by the source iovec to the destination iovec.
     198             :  *
     199             :  * \return The number of bytes copied.
     200             :  */
     201             : size_t spdk_iovcpy(struct iovec *siov, size_t siovcnt, struct iovec *diov, size_t diovcnt);
     202             : 
     203             : /**
     204             :  * Same as spdk_iovcpy(), but the src/dst buffers might overlap.
     205             :  *
     206             :  * \return The number of bytes copied.
     207             :  */
     208             : size_t spdk_iovmove(struct iovec *siov, size_t siovcnt, struct iovec *diov, size_t diovcnt);
     209             : 
     210             : /**
     211             :  * Transfer state for iterative copying in or out of an iovec.
     212             :  */
     213             : struct spdk_iov_xfer {
     214             :         struct iovec *iovs;
     215             :         int iovcnt;
     216             :         int cur_iov_idx;
     217             :         size_t cur_iov_offset;
     218             : };
     219             : 
     220             : /**
     221             :  * Initialize a transfer context to point to the given iovec.
     222             :  */
     223             : void
     224             : spdk_iov_xfer_init(struct spdk_iov_xfer *ix, struct iovec *iovs, int iovcnt);
     225             : 
     226             : /**
     227             :  * Copy from the given buf up to buf_len bytes, into the given ix iovec
     228             :  * iterator, advancing the iterator as needed.. Returns the number of bytes
     229             :  * copied.
     230             :  */
     231             : size_t
     232             : spdk_iov_xfer_from_buf(struct spdk_iov_xfer *ix, const void *buf, size_t buf_len);
     233             : 
     234             : /**
     235             :  * Copy from the given ix iovec iterator into the given buf up to buf_len
     236             :  * bytes, advancing the iterator as needed. Returns the number of bytes copied.
     237             :  */
     238             : size_t
     239             : spdk_iov_xfer_to_buf(struct spdk_iov_xfer *ix, const void *buf, size_t buf_len);
     240             : 
     241             : /**
     242             :  * Copy iovs contents to buf through memcpy.
     243             :  */
     244             : void spdk_copy_iovs_to_buf(void *buf, size_t buf_len, struct iovec *iovs,
     245             :                            int iovcnt);
     246             : 
     247             : /**
     248             :  * Copy buf contents to iovs through memcpy.
     249             :  */
     250             : void spdk_copy_buf_to_iovs(struct iovec *iovs, int iovcnt, void *buf,
     251             :                            size_t buf_len);
     252             : 
     253             : /**
     254             :  * Scan build is really pessimistic and assumes that mempool functions can
     255             :  * dequeue NULL buffers even if they return success. This is obviously a false
     256             :  * positive, but the mempool dequeue can be done in a DPDK inline function that
     257             :  * we can't decorate with usual assert(buf != NULL). Instead, we'll
     258             :  * preinitialize the dequeued buffer array with some dummy objects.
     259             :  */
     260             : #define SPDK_CLANG_ANALYZER_PREINIT_PTR_ARRAY(arr, arr_size, buf_size) \
     261             :         do { \
     262             :                 static char dummy_buf[buf_size]; \
     263             :                 int i; \
     264             :                 for (i = 0; i < arr_size; i++) { \
     265             :                         arr[i] = (void *)dummy_buf; \
     266             :                 } \
     267             :         } while (0)
     268             : 
     269             : /**
     270             :  * Add two sequence numbers s1 and s2
     271             :  *
     272             :  * \param s1 First sequence number
     273             :  * \param s2 Second sequence number
     274             :  *
     275             :  * \return Sum of s1 and s2 based on serial number arithmetic.
     276             :  */
     277             : static inline uint32_t
     278           5 : spdk_sn32_add(uint32_t s1, uint32_t s2)
     279             : {
     280           5 :         return (uint32_t)(s1 + s2);
     281             : }
     282             : 
     283             : #define SPDK_SN32_CMPMAX        (1U << (32 - 1))
     284             : 
     285             : /**
     286             :  * Compare if sequence number s1 is less than s2.
     287             :  *
     288             :  * \param s1 First sequence number
     289             :  * \param s2 Second sequence number
     290             :  *
     291             :  * \return true if s1 is less than s2, or false otherwise.
     292             :  */
     293             : static inline bool
     294          31 : spdk_sn32_lt(uint32_t s1, uint32_t s2)
     295             : {
     296          55 :         return (s1 != s2) &&
     297          24 :                ((s1 < s2 && s2 - s1 < SPDK_SN32_CMPMAX) ||
     298           9 :                 (s1 > s2 && s1 - s2 > SPDK_SN32_CMPMAX));
     299             : }
     300             : 
     301             : /**
     302             :  * Compare if sequence number s1 is greater than s2.
     303             :  *
     304             :  * \param s1 First sequence number
     305             :  * \param s2 Second sequence number
     306             :  *
     307             :  * \return true if s1 is greater than s2, or false otherwise.
     308             :  */
     309             : static inline bool
     310          26 : spdk_sn32_gt(uint32_t s1, uint32_t s2)
     311             : {
     312          33 :         return (s1 != s2) &&
     313           7 :                ((s1 < s2 && s2 - s1 > SPDK_SN32_CMPMAX) ||
     314           3 :                 (s1 > s2 && s1 - s2 < SPDK_SN32_CMPMAX));
     315             : }
     316             : 
     317             : /**
     318             :  * Copies the value (unsigned char)ch into each of the first \b count characters of the object pointed to by \b data
     319             :  * \b data_size is used to check that filling \b count bytes won't lead to buffer overflow
     320             :  *
     321             :  * \param data Buffer to fill
     322             :  * \param data_size Size of the buffer
     323             :  * \param ch Fill byte
     324             :  * \param count Number of bytes to fill
     325             :  */
     326             : static inline void
     327           6 : spdk_memset_s(void *data, size_t data_size, int ch, size_t count)
     328             : {
     329             : #ifdef __STDC_LIB_EXT1__
     330             :         /* memset_s was introduced as an optional feature in C11 */
     331             :         memset_s(data, data_size, ch, count);
     332             : #else
     333             :         size_t i;
     334           6 :         volatile unsigned char *buf = (volatile unsigned char *)data;
     335             : 
     336           6 :         if (!buf) {
     337           0 :                 return;
     338             :         }
     339           6 :         if (count > data_size) {
     340           0 :                 count = data_size;
     341             :         }
     342             : 
     343         632 :         for (i = 0; i < count; i++) {
     344         626 :                 buf[i] = (unsigned char)ch;
     345             :         }
     346             : #endif
     347             : }
     348             : 
     349             : #ifdef __cplusplus
     350             : }
     351             : #endif
     352             : 
     353             : #endif

Generated by: LCOV version 1.15