LCOV - code coverage report
Current view: top level - home/runner/zephyrproject/zephyr/lib/heap - heap.h (source / functions) Hit Total Coverage
Test: lcov.info Lines: 0 79 0.0 %
Date: 2024-09-16 20:15:30 Functions: 0 26 0.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 0 18 0.0 %

           Branch data     Line data    Source code
       1                 :            : /*
       2                 :            :  * Copyright (c) 2019 Intel Corporation
       3                 :            :  *
       4                 :            :  * SPDX-License-Identifier: Apache-2.0
       5                 :            :  */
       6                 :            : #ifndef ZEPHYR_INCLUDE_LIB_OS_HEAP_H_
       7                 :            : #define ZEPHYR_INCLUDE_LIB_OS_HEAP_H_
       8                 :            : 
       9                 :            : /*
      10                 :            :  * Internal heap APIs
      11                 :            :  */
      12                 :            : 
      13                 :            : /* Theese validation checks are non-trivially expensive, so enable
      14                 :            :  * only when debugging the heap code.  They shouldn't be routine
      15                 :            :  * assertions.
      16                 :            :  */
      17                 :            : #ifdef CONFIG_SYS_HEAP_VALIDATE
      18                 :            : #define CHECK(x) __ASSERT(x, "")
      19                 :            : #else
      20                 :            : #define CHECK(x) /**/
      21                 :            : #endif
      22                 :            : 
      23                 :            : /* Chunks are identified by their offset in 8 byte units from the
      24                 :            :  * first address in the buffer (a zero-valued chunkid_t is used as a
      25                 :            :  * null; that chunk would always point into the metadata at the start
      26                 :            :  * of the heap and cannot be allocated).  They are prefixed by a
      27                 :            :  * variable size header that depends on the size of the heap.  Heaps
      28                 :            :  * with fewer than 2^15 units (256kb) of storage use shorts to store
      29                 :            :  * the fields, otherwise the units are 32 bit integers for a 16Gb heap
      30                 :            :  * space (larger spaces really aren't in scope for this code, but
      31                 :            :  * could be handled similarly I suppose).  Because of that design
      32                 :            :  * there's a certain amount of boilerplate API needed to expose the
      33                 :            :  * field accessors since we can't use natural syntax.
      34                 :            :  *
      35                 :            :  * The fields are:
      36                 :            :  *   LEFT_SIZE: The size of the left (next lower chunk in memory)
      37                 :            :  *              neighbor chunk.
      38                 :            :  *   SIZE_AND_USED: the total size (including header) of the chunk in
      39                 :            :  *                  8-byte units.  The bottom bit stores a "used" flag.
      40                 :            :  *   FREE_PREV: Chunk ID of the previous node in a free list.
      41                 :            :  *   FREE_NEXT: Chunk ID of the next node in a free list.
      42                 :            :  *
      43                 :            :  * The free lists are circular lists, one for each power-of-two size
      44                 :            :  * category.  The free list pointers exist only for free chunks,
      45                 :            :  * obviously.  This memory is part of the user's buffer when
      46                 :            :  * allocated.
      47                 :            :  *
      48                 :            :  * The field order is so that allocated buffers are immediately bounded
      49                 :            :  * by SIZE_AND_USED of the current chunk at the bottom, and LEFT_SIZE of
      50                 :            :  * the following chunk at the top. This ordering allows for quick buffer
      51                 :            :  * overflow detection by testing left_chunk(c + chunk_size(c)) == c.
      52                 :            :  */
      53                 :            : 
      54                 :            : enum chunk_fields { LEFT_SIZE, SIZE_AND_USED, FREE_PREV, FREE_NEXT };
      55                 :            : 
      56                 :            : #define CHUNK_UNIT 8U
      57                 :            : 
      58                 :            : typedef struct { char bytes[CHUNK_UNIT]; } chunk_unit_t;
      59                 :            : 
      60                 :            : /* big_heap needs uint32_t, small_heap needs uint16_t */
      61                 :            : typedef uint32_t chunkid_t;
      62                 :            : typedef uint32_t chunksz_t;
      63                 :            : 
      64                 :            : struct z_heap_bucket {
      65                 :            :         chunkid_t next;
      66                 :            : };
      67                 :            : 
      68                 :            : struct z_heap {
      69                 :            :         chunkid_t chunk0_hdr[2];
      70                 :            :         chunkid_t end_chunk;
      71                 :            :         uint32_t avail_buckets;
      72                 :            : #ifdef CONFIG_SYS_HEAP_RUNTIME_STATS
      73                 :            :         size_t free_bytes;
      74                 :            :         size_t allocated_bytes;
      75                 :            :         size_t max_allocated_bytes;
      76                 :            : #endif
      77                 :            :         struct z_heap_bucket buckets[0];
      78                 :            : };
      79                 :            : 
      80                 :          0 : static inline bool big_heap_chunks(chunksz_t chunks)
      81                 :            : {
      82                 :          0 :         if (IS_ENABLED(CONFIG_SYS_HEAP_SMALL_ONLY)) {
      83                 :          0 :                 return false;
      84                 :            :         }
      85                 :            :         if (IS_ENABLED(CONFIG_SYS_HEAP_BIG_ONLY) || sizeof(void *) > 4U) {
      86                 :            :                 return true;
      87                 :            :         }
      88                 :            :         return chunks > 0x7fffU;
      89                 :            : }
      90                 :            : 
      91                 :          0 : static inline bool big_heap_bytes(size_t bytes)
      92                 :            : {
      93                 :          0 :         return big_heap_chunks(bytes / CHUNK_UNIT);
      94                 :            : }
      95                 :            : 
      96                 :          0 : static inline bool big_heap(struct z_heap *h)
      97                 :            : {
      98                 :          0 :         return big_heap_chunks(h->end_chunk);
      99                 :            : }
     100                 :            : 
     101                 :          0 : static inline chunk_unit_t *chunk_buf(struct z_heap *h)
     102                 :            : {
     103                 :            :         /* the struct z_heap matches with the first chunk */
     104                 :          0 :         return (chunk_unit_t *)h;
     105                 :            : }
     106                 :            : 
     107                 :          0 : static inline chunkid_t chunk_field(struct z_heap *h, chunkid_t c,
     108                 :            :                                     enum chunk_fields f)
     109                 :            : {
     110                 :          0 :         chunk_unit_t *buf = chunk_buf(h);
     111                 :          0 :         void *cmem = &buf[c];
     112                 :            : 
     113         [ #  # ]:          0 :         if (big_heap(h)) {
     114                 :          0 :                 return ((uint32_t *)cmem)[f];
     115                 :            :         } else {
     116                 :          0 :                 return ((uint16_t *)cmem)[f];
     117                 :            :         }
     118                 :            : }
     119                 :            : 
     120                 :          0 : static inline void chunk_set(struct z_heap *h, chunkid_t c,
     121                 :            :                              enum chunk_fields f, chunkid_t val)
     122                 :            : {
     123                 :          0 :         CHECK(c <= h->end_chunk);
     124                 :            : 
     125                 :          0 :         chunk_unit_t *buf = chunk_buf(h);
     126                 :          0 :         void *cmem = &buf[c];
     127                 :            : 
     128         [ #  # ]:          0 :         if (big_heap(h)) {
     129                 :          0 :                 CHECK(val == (uint32_t)val);
     130                 :          0 :                 ((uint32_t *)cmem)[f] = val;
     131                 :            :         } else {
     132                 :          0 :                 CHECK(val == (uint16_t)val);
     133                 :          0 :                 ((uint16_t *)cmem)[f] = val;
     134                 :            :         }
     135                 :          0 : }
     136                 :            : 
     137                 :          0 : static inline bool chunk_used(struct z_heap *h, chunkid_t c)
     138                 :            : {
     139                 :          0 :         return chunk_field(h, c, SIZE_AND_USED) & 1U;
     140                 :            : }
     141                 :            : 
     142                 :          0 : static inline chunksz_t chunk_size(struct z_heap *h, chunkid_t c)
     143                 :            : {
     144                 :          0 :         return chunk_field(h, c, SIZE_AND_USED) >> 1;
     145                 :            : }
     146                 :            : 
     147                 :          0 : static inline void set_chunk_used(struct z_heap *h, chunkid_t c, bool used)
     148                 :            : {
     149                 :          0 :         chunk_unit_t *buf = chunk_buf(h);
     150                 :          0 :         void *cmem = &buf[c];
     151                 :            : 
     152         [ #  # ]:          0 :         if (big_heap(h)) {
     153         [ #  # ]:          0 :                 if (used) {
     154                 :          0 :                         ((uint32_t *)cmem)[SIZE_AND_USED] |= 1U;
     155                 :            :                 } else {
     156                 :          0 :                         ((uint32_t *)cmem)[SIZE_AND_USED] &= ~1U;
     157                 :            :                 }
     158                 :            :         } else {
     159         [ #  # ]:          0 :                 if (used) {
     160                 :          0 :                         ((uint16_t *)cmem)[SIZE_AND_USED] |= 1U;
     161                 :            :                 } else {
     162                 :          0 :                         ((uint16_t *)cmem)[SIZE_AND_USED] &= ~1U;
     163                 :            :                 }
     164                 :            :         }
     165                 :          0 : }
     166                 :            : 
     167                 :            : /*
     168                 :            :  * Note: no need to preserve the used bit here as the chunk is never in use
     169                 :            :  * when its size is modified, and potential set_chunk_used() is always
     170                 :            :  * invoked after set_chunk_size().
     171                 :            :  */
     172                 :          0 : static inline void set_chunk_size(struct z_heap *h, chunkid_t c, chunksz_t size)
     173                 :            : {
     174                 :          0 :         chunk_set(h, c, SIZE_AND_USED, size << 1);
     175                 :          0 : }
     176                 :            : 
     177                 :          0 : static inline chunkid_t prev_free_chunk(struct z_heap *h, chunkid_t c)
     178                 :            : {
     179                 :          0 :         return chunk_field(h, c, FREE_PREV);
     180                 :            : }
     181                 :            : 
     182                 :          0 : static inline chunkid_t next_free_chunk(struct z_heap *h, chunkid_t c)
     183                 :            : {
     184                 :          0 :         return chunk_field(h, c, FREE_NEXT);
     185                 :            : }
     186                 :            : 
     187                 :          0 : static inline void set_prev_free_chunk(struct z_heap *h, chunkid_t c,
     188                 :            :                                        chunkid_t prev)
     189                 :            : {
     190                 :          0 :         chunk_set(h, c, FREE_PREV, prev);
     191                 :          0 : }
     192                 :            : 
     193                 :          0 : static inline void set_next_free_chunk(struct z_heap *h, chunkid_t c,
     194                 :            :                                        chunkid_t next)
     195                 :            : {
     196                 :          0 :         chunk_set(h, c, FREE_NEXT, next);
     197                 :          0 : }
     198                 :            : 
     199                 :          0 : static inline chunkid_t left_chunk(struct z_heap *h, chunkid_t c)
     200                 :            : {
     201                 :          0 :         return c - chunk_field(h, c, LEFT_SIZE);
     202                 :            : }
     203                 :            : 
     204                 :          0 : static inline chunkid_t right_chunk(struct z_heap *h, chunkid_t c)
     205                 :            : {
     206                 :          0 :         return c + chunk_size(h, c);
     207                 :            : }
     208                 :            : 
     209                 :          0 : static inline void set_left_chunk_size(struct z_heap *h, chunkid_t c,
     210                 :            :                                        chunksz_t size)
     211                 :            : {
     212                 :          0 :         chunk_set(h, c, LEFT_SIZE, size);
     213                 :          0 : }
     214                 :            : 
     215                 :          0 : static inline bool solo_free_header(struct z_heap *h, chunkid_t c)
     216                 :            : {
     217   [ #  #  #  # ]:          0 :         return big_heap(h) && (chunk_size(h, c) == 1U);
     218                 :            : }
     219                 :            : 
     220                 :          0 : static inline size_t chunk_header_bytes(struct z_heap *h)
     221                 :            : {
     222         [ #  # ]:          0 :         return big_heap(h) ? 8 : 4;
     223                 :            : }
     224                 :            : 
     225                 :          0 : static inline size_t heap_footer_bytes(size_t size)
     226                 :            : {
     227         [ #  # ]:          0 :         return big_heap_bytes(size) ? 8 : 4;
     228                 :            : }
     229                 :            : 
     230                 :          0 : static inline chunksz_t chunksz(size_t bytes)
     231                 :            : {
     232                 :          0 :         return (bytes + CHUNK_UNIT - 1U) / CHUNK_UNIT;
     233                 :            : }
     234                 :            : 
     235                 :          0 : static inline chunksz_t bytes_to_chunksz(struct z_heap *h, size_t bytes)
     236                 :            : {
     237                 :          0 :         return chunksz(chunk_header_bytes(h) + bytes);
     238                 :            : }
     239                 :            : 
     240                 :          0 : static inline chunksz_t min_chunk_size(struct z_heap *h)
     241                 :            : {
     242                 :          0 :         return bytes_to_chunksz(h, 1);
     243                 :            : }
     244                 :            : 
     245                 :          0 : static inline size_t chunksz_to_bytes(struct z_heap *h, chunksz_t chunksz_in)
     246                 :            : {
     247                 :          0 :         return chunksz_in * CHUNK_UNIT - chunk_header_bytes(h);
     248                 :            : }
     249                 :            : 
     250                 :          0 : static inline int bucket_idx(struct z_heap *h, chunksz_t sz)
     251                 :            : {
     252                 :          0 :         unsigned int usable_sz = sz - min_chunk_size(h) + 1;
     253                 :          0 :         return 31 - __builtin_clz(usable_sz);
     254                 :            : }
     255                 :            : 
     256                 :          0 : static inline bool size_too_big(struct z_heap *h, size_t bytes)
     257                 :            : {
     258                 :            :         /*
     259                 :            :          * Quick check to bail out early if size is too big.
     260                 :            :          * Also guards against potential arithmetic overflows elsewhere.
     261                 :            :          */
     262                 :          0 :         return (bytes / CHUNK_UNIT) >= h->end_chunk;
     263                 :            : }
     264                 :            : 
     265                 :            : static inline void get_alloc_info(struct z_heap *h, size_t *alloc_bytes,
     266                 :            :                            size_t *free_bytes)
     267                 :            : {
     268                 :            :         chunkid_t c;
     269                 :            : 
     270                 :            :         *alloc_bytes = 0;
     271                 :            :         *free_bytes = 0;
     272                 :            : 
     273                 :            :         for (c = right_chunk(h, 0); c < h->end_chunk; c = right_chunk(h, c)) {
     274                 :            :                 if (chunk_used(h, c)) {
     275                 :            :                         *alloc_bytes += chunksz_to_bytes(h, chunk_size(h, c));
     276                 :            :                 } else if (!solo_free_header(h, c)) {
     277                 :            :                         *free_bytes += chunksz_to_bytes(h, chunk_size(h, c));
     278                 :            :                 }
     279                 :            :         }
     280                 :            : }
     281                 :            : 
     282                 :            : #endif /* ZEPHYR_INCLUDE_LIB_OS_HEAP_H_ */

Generated by: LCOV version 1.14