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

           Branch data     Line data    Source code
       1                 :            : /*
       2                 :            :  * Copyright (c) 2021 Intel Corporation
       3                 :            :  *
       4                 :            :  * SPDX-License-Identifier: Apache-2.0
       5                 :            :  */
       6                 :            : 
       7                 :            : #include <errno.h>
       8                 :            : #include <stddef.h>
       9                 :            : #include <stdbool.h>
      10                 :            : #include <stdio.h>
      11                 :            : #include <zephyr/sys/bitarray.h>
      12                 :            : #include <zephyr/sys/check.h>
      13                 :            : #include <zephyr/sys/sys_io.h>
      14                 :            : 
      15                 :            : /* Number of bits represented by one bundle */
      16                 :            : #define bundle_bitness(ba)      (sizeof((ba)->bundles[0]) * 8)
      17                 :            : 
      18                 :            : struct bundle_data {
      19                 :            :          /* Start and end index of bundles */
      20                 :            :         size_t sidx, eidx;
      21                 :            : 
      22                 :            :          /* Offset inside start and end bundles */
      23                 :            :         size_t soff, eoff;
      24                 :            : 
      25                 :            :          /* Masks for start/end bundles */
      26                 :            :         uint32_t smask, emask;
      27                 :            : };
      28                 :            : 
      29                 :          0 : static void setup_bundle_data(sys_bitarray_t *bitarray,
      30                 :            :                               struct bundle_data *bd,
      31                 :            :                               size_t offset, size_t num_bits)
      32                 :            : {
      33                 :          0 :         bd->sidx = offset / bundle_bitness(bitarray);
      34                 :          0 :         bd->soff = offset % bundle_bitness(bitarray);
      35                 :            : 
      36                 :          0 :         bd->eidx = (offset + num_bits - 1) / bundle_bitness(bitarray);
      37                 :          0 :         bd->eoff = (offset + num_bits - 1) % bundle_bitness(bitarray);
      38                 :            : 
      39                 :          0 :         bd->smask = ~(BIT(bd->soff) - 1);
      40                 :          0 :         bd->emask = (BIT(bd->eoff) - 1) | BIT(bd->eoff);
      41                 :            : 
      42         [ #  # ]:          0 :         if (bd->sidx == bd->eidx) {
      43                 :            :                 /* The region lies within the same bundle. So combine the masks. */
      44                 :          0 :                 bd->smask &= bd->emask;
      45                 :            :         }
      46                 :          0 : }
      47                 :            : 
      48                 :            : /*
      49                 :            :  * Find out if the bits in a region is all set or all clear.
      50                 :            :  *
      51                 :            :  * @param[in]  bitarray  Bitarray struct
      52                 :            :  * @param[in]  offset    Starting bit location
      53                 :            :  * @param[in]  num_bits  Number of bits in the region
      54                 :            :  * @param[in]  match_set True if matching all set bits,
      55                 :            :  *                       False if matching all cleared bits
      56                 :            :  * @param[out] bd        Data related to matching which can be
      57                 :            :  *                       used later to find out where the region
      58                 :            :  *                       lies in the bitarray bundles.
      59                 :            :  * @param[out] mismatch  Offset to the mismatched bit.
      60                 :            :  *                       Can be NULL.
      61                 :            :  *
      62                 :            :  * @retval     true      If all bits are set or cleared
      63                 :            :  * @retval     false     Not all bits are set or cleared
      64                 :            :  */
      65                 :          0 : static bool match_region(sys_bitarray_t *bitarray, size_t offset,
      66                 :            :                          size_t num_bits, bool match_set,
      67                 :            :                          struct bundle_data *bd,
      68                 :            :                          size_t *mismatch)
      69                 :            : {
      70                 :          0 :         size_t idx;
      71                 :          0 :         uint32_t bundle;
      72                 :          0 :         uint32_t mismatch_bundle;
      73                 :          0 :         size_t mismatch_bundle_idx;
      74                 :          0 :         size_t mismatch_bit_off;
      75                 :            : 
      76                 :          0 :         setup_bundle_data(bitarray, bd, offset, num_bits);
      77                 :            : 
      78         [ #  # ]:          0 :         if (bd->sidx == bd->eidx) {
      79                 :          0 :                 bundle = bitarray->bundles[bd->sidx];
      80         [ #  # ]:          0 :                 if (!match_set) {
      81                 :          0 :                         bundle = ~bundle;
      82                 :            :                 }
      83                 :            : 
      84         [ #  # ]:          0 :                 if ((bundle & bd->smask) != bd->smask) {
      85                 :            :                         /* Not matching to mask. */
      86                 :          0 :                         mismatch_bundle = ~bundle & bd->smask;
      87                 :          0 :                         mismatch_bundle_idx = bd->sidx;
      88                 :          0 :                         goto mismatch;
      89                 :            :                 } else {
      90                 :            :                         /* Matching to mask. */
      91                 :          0 :                         goto out;
      92                 :            :                 }
      93                 :            :         }
      94                 :            : 
      95                 :            :         /* Region lies in a number of bundles. Need to loop through them. */
      96                 :            : 
      97                 :            :         /* Start of bundles */
      98                 :          0 :         bundle = bitarray->bundles[bd->sidx];
      99         [ #  # ]:          0 :         if (!match_set) {
     100                 :          0 :                 bundle = ~bundle;
     101                 :            :         }
     102                 :            : 
     103         [ #  # ]:          0 :         if ((bundle & bd->smask) != bd->smask) {
     104                 :            :                 /* Start bundle not matching to mask. */
     105                 :          0 :                 mismatch_bundle = ~bundle & bd->smask;
     106                 :          0 :                 mismatch_bundle_idx = bd->sidx;
     107                 :          0 :                 goto mismatch;
     108                 :            :         }
     109                 :            : 
     110                 :            :         /* End of bundles */
     111                 :          0 :         bundle = bitarray->bundles[bd->eidx];
     112         [ #  # ]:          0 :         if (!match_set) {
     113                 :          0 :                 bundle = ~bundle;
     114                 :            :         }
     115                 :            : 
     116         [ #  # ]:          0 :         if ((bundle & bd->emask) != bd->emask) {
     117                 :            :                 /* End bundle not matching to mask. */
     118                 :          0 :                 mismatch_bundle = ~bundle & bd->emask;
     119                 :          0 :                 mismatch_bundle_idx = bd->eidx;
     120                 :          0 :                 goto mismatch;
     121                 :            :         }
     122                 :            : 
     123                 :            :         /* In-between bundles */
     124         [ #  # ]:          0 :         for (idx = bd->sidx + 1; idx < bd->eidx; idx++) {
     125                 :            :                 /* Note that this is opposite from above so that
     126                 :            :                  * we are simply checking if bundle == 0.
     127                 :            :                  */
     128                 :          0 :                 bundle = bitarray->bundles[idx];
     129         [ #  # ]:          0 :                 if (match_set) {
     130                 :          0 :                         bundle = ~bundle;
     131                 :            :                 }
     132                 :            : 
     133         [ #  # ]:          0 :                 if (bundle != 0U) {
     134                 :            :                         /* Bits in "between bundles" do not match */
     135                 :          0 :                         mismatch_bundle = bundle;
     136                 :          0 :                         mismatch_bundle_idx = idx;
     137                 :          0 :                         goto mismatch;
     138                 :            :                 }
     139                 :            :         }
     140                 :            : 
     141                 :          0 : out:
     142                 :            :         /* All bits in region matched. */
     143                 :            :         return true;
     144                 :            : 
     145                 :          0 : mismatch:
     146         [ #  # ]:          0 :         if (mismatch != NULL) {
     147                 :            :                 /* Must have at least 1 bit set to indicate
     148                 :            :                  * where the mismatch is.
     149                 :            :                  */
     150         [ #  # ]:          0 :                 __ASSERT_NO_MSG(mismatch_bundle != 0);
     151                 :            : 
     152                 :          0 :                 mismatch_bit_off = find_lsb_set(mismatch_bundle) - 1;
     153                 :          0 :                 mismatch_bit_off += mismatch_bundle_idx *
     154                 :            :                                     bundle_bitness(bitarray);
     155                 :          0 :                 *mismatch = (uint32_t)mismatch_bit_off;
     156                 :            :         }
     157                 :            :         return false;
     158                 :            : }
     159                 :            : 
     160                 :            : /*
     161                 :            :  * Set or clear a region of bits.
     162                 :            :  *
     163                 :            :  * @param bitarray Bitarray struct
     164                 :            :  * @param offset   Starting bit location
     165                 :            :  * @param num_bits Number of bits in the region
     166                 :            :  * @param to_set   True if to set all bits.
     167                 :            :  *                 False if to clear all bits.
     168                 :            :  * @param bd       Bundle data. Can reuse the output from
     169                 :            :  *                 match_region(). NULL if there is no
     170                 :            :  *                 prior call to match_region().
     171                 :            :  */
     172                 :          0 : static void set_region(sys_bitarray_t *bitarray, size_t offset,
     173                 :            :                        size_t num_bits, bool to_set,
     174                 :            :                        struct bundle_data *bd)
     175                 :            : {
     176                 :          0 :         size_t idx;
     177                 :          0 :         struct bundle_data bdata;
     178                 :            : 
     179         [ #  # ]:          0 :         if (bd == NULL) {
     180                 :          0 :                 bd = &bdata;
     181                 :          0 :                 setup_bundle_data(bitarray, bd, offset, num_bits);
     182                 :            :         }
     183                 :            : 
     184         [ #  # ]:          0 :         if (bd->sidx == bd->eidx) {
     185                 :            :                 /* Start/end at same bundle */
     186         [ #  # ]:          0 :                 if (to_set) {
     187                 :          0 :                         bitarray->bundles[bd->sidx] |= bd->smask;
     188                 :            :                 } else {
     189                 :          0 :                         bitarray->bundles[bd->sidx] &= ~bd->smask;
     190                 :            :                 }
     191                 :            :         } else {
     192                 :            :                 /* Start/end at different bundle.
     193                 :            :                  * So set/clear the bits in start and end bundles
     194                 :            :                  * separately. For in-between bundles,
     195                 :            :                  * set/clear all bits.
     196                 :            :                  */
     197         [ #  # ]:          0 :                 if (to_set) {
     198                 :          0 :                         bitarray->bundles[bd->sidx] |= bd->smask;
     199                 :          0 :                         bitarray->bundles[bd->eidx] |= bd->emask;
     200         [ #  # ]:          0 :                         for (idx = bd->sidx + 1; idx < bd->eidx; idx++) {
     201                 :          0 :                                 bitarray->bundles[idx] = ~0U;
     202                 :            :                         }
     203                 :            :                 } else {
     204                 :          0 :                         bitarray->bundles[bd->sidx] &= ~bd->smask;
     205                 :          0 :                         bitarray->bundles[bd->eidx] &= ~bd->emask;
     206         [ #  # ]:          0 :                         for (idx = bd->sidx + 1; idx < bd->eidx; idx++) {
     207                 :          0 :                                 bitarray->bundles[idx] = 0U;
     208                 :            :                         }
     209                 :            :                 }
     210                 :            :         }
     211                 :          0 : }
     212                 :            : 
     213                 :          0 : int sys_bitarray_popcount_region(sys_bitarray_t *bitarray, size_t num_bits, size_t offset,
     214                 :            :                                  size_t *count)
     215                 :            : {
     216                 :          0 :         k_spinlock_key_t key;
     217                 :          0 :         size_t idx;
     218                 :          0 :         struct bundle_data bd;
     219                 :          0 :         int ret;
     220                 :            : 
     221         [ #  # ]:          0 :         __ASSERT_NO_MSG(bitarray != NULL);
     222         [ #  # ]:          0 :         __ASSERT_NO_MSG(bitarray->num_bits > 0);
     223                 :            : 
     224                 :          0 :         key = k_spin_lock(&bitarray->lock);
     225                 :            : 
     226   [ #  #  #  # ]:          0 :         if (num_bits == 0 || offset + num_bits > bitarray->num_bits) {
     227                 :          0 :                 ret = -EINVAL;
     228                 :          0 :                 goto out;
     229                 :            :         }
     230                 :            : 
     231         [ #  # ]:          0 :         CHECKIF(count == NULL) {
     232                 :          0 :                 ret = -EINVAL;
     233                 :          0 :                 goto out;
     234                 :            :         }
     235                 :            : 
     236                 :          0 :         setup_bundle_data(bitarray, &bd, offset, num_bits);
     237                 :            : 
     238         [ #  # ]:          0 :         if (bd.sidx == bd.eidx) {
     239                 :            :                 /* Start/end at same bundle */
     240                 :          0 :                 *count = POPCOUNT(bitarray->bundles[bd.sidx] & bd.smask);
     241                 :            :         } else {
     242                 :            :                 /* Start/end at different bundle.
     243                 :            :                  * So count the bits in start and end bundles
     244                 :            :                  * separately with correct mask applied. For in-between bundles,
     245                 :            :                  * count all bits.
     246                 :            :                  */
     247                 :          0 :                 *count = 0;
     248                 :          0 :                 *count += POPCOUNT(bitarray->bundles[bd.sidx] & bd.smask);
     249                 :          0 :                 *count += POPCOUNT(bitarray->bundles[bd.eidx] & bd.emask);
     250         [ #  # ]:          0 :                 for (idx = bd.sidx + 1; idx < bd.eidx; idx++) {
     251                 :          0 :                         *count += POPCOUNT(bitarray->bundles[idx]);
     252                 :            :                 }
     253                 :            :         }
     254                 :            : 
     255                 :            :         ret = 0;
     256                 :            : 
     257                 :          0 : out:
     258                 :          0 :         k_spin_unlock(&bitarray->lock, key);
     259                 :          0 :         return ret;
     260                 :            : }
     261                 :            : 
     262                 :          0 : int sys_bitarray_xor(sys_bitarray_t *dst, sys_bitarray_t *other, size_t num_bits, size_t offset)
     263                 :            : {
     264                 :          0 :         k_spinlock_key_t key_dst, key_other;
     265                 :          0 :         int ret;
     266                 :          0 :         size_t idx;
     267                 :          0 :         struct bundle_data bd;
     268                 :            : 
     269         [ #  # ]:          0 :         __ASSERT_NO_MSG(dst != NULL);
     270         [ #  # ]:          0 :         __ASSERT_NO_MSG(dst->num_bits > 0);
     271         [ #  # ]:          0 :         __ASSERT_NO_MSG(other != NULL);
     272         [ #  # ]:          0 :         __ASSERT_NO_MSG(other->num_bits > 0);
     273                 :            : 
     274                 :          0 :         key_dst = k_spin_lock(&dst->lock);
     275                 :          0 :         key_other = k_spin_lock(&other->lock);
     276                 :            : 
     277                 :            : 
     278         [ #  # ]:          0 :         if (dst->num_bits != other->num_bits) {
     279                 :          0 :                 ret = -EINVAL;
     280                 :          0 :                 goto out;
     281                 :            :         }
     282                 :            : 
     283   [ #  #  #  # ]:          0 :         if (num_bits == 0 || offset + num_bits > dst->num_bits) {
     284                 :          0 :                 ret = -EINVAL;
     285                 :          0 :                 goto out;
     286                 :            :         }
     287                 :            : 
     288                 :          0 :         setup_bundle_data(other, &bd, offset, num_bits);
     289                 :            : 
     290         [ #  # ]:          0 :         if (bd.sidx == bd.eidx) {
     291                 :            :                 /* Start/end at same bundle */
     292                 :          0 :                 dst->bundles[bd.sidx] =
     293                 :          0 :                         ((other->bundles[bd.sidx] ^ dst->bundles[bd.sidx]) & bd.smask) |
     294                 :          0 :                         (dst->bundles[bd.sidx] & ~bd.smask);
     295                 :            :         } else {
     296                 :            :                 /* Start/end at different bundle.
     297                 :            :                  * So xor the bits in start and end bundles according to their bitmasks
     298                 :            :                  * separately. For in-between bundles,
     299                 :            :                  * xor all bits.
     300                 :            :                  */
     301                 :          0 :                 dst->bundles[bd.sidx] =
     302                 :          0 :                         ((other->bundles[bd.sidx] ^ dst->bundles[bd.sidx]) & bd.smask) |
     303                 :          0 :                         (dst->bundles[bd.sidx] & ~bd.smask);
     304                 :          0 :                 dst->bundles[bd.eidx] =
     305                 :          0 :                         ((other->bundles[bd.eidx] ^ dst->bundles[bd.eidx]) & bd.emask) |
     306                 :          0 :                         (dst->bundles[bd.eidx] & ~bd.emask);
     307         [ #  # ]:          0 :                 for (idx = bd.sidx + 1; idx < bd.eidx; idx++) {
     308                 :          0 :                         dst->bundles[idx] ^= other->bundles[idx];
     309                 :            :                 }
     310                 :            :         }
     311                 :            : 
     312                 :            :         ret = 0;
     313                 :            : 
     314                 :          0 : out:
     315                 :          0 :         k_spin_unlock(&other->lock, key_other);
     316                 :          0 :         k_spin_unlock(&dst->lock, key_dst);
     317                 :          0 :         return ret;
     318                 :            : }
     319                 :            : 
     320                 :          0 : int sys_bitarray_set_bit(sys_bitarray_t *bitarray, size_t bit)
     321                 :            : {
     322                 :          0 :         k_spinlock_key_t key;
     323                 :          0 :         int ret;
     324                 :          0 :         size_t idx, off;
     325                 :            : 
     326         [ #  # ]:          0 :         __ASSERT_NO_MSG(bitarray != NULL);
     327         [ #  # ]:          0 :         __ASSERT_NO_MSG(bitarray->num_bits > 0);
     328                 :            : 
     329                 :          0 :         key = k_spin_lock(&bitarray->lock);
     330                 :            : 
     331         [ #  # ]:          0 :         if (bit >= bitarray->num_bits) {
     332                 :          0 :                 ret = -EINVAL;
     333                 :          0 :                 goto out;
     334                 :            :         }
     335                 :            : 
     336                 :          0 :         idx = bit / bundle_bitness(bitarray);
     337                 :          0 :         off = bit % bundle_bitness(bitarray);
     338                 :            : 
     339                 :          0 :         bitarray->bundles[idx] |= BIT(off);
     340                 :            : 
     341                 :          0 :         ret = 0;
     342                 :            : 
     343                 :          0 : out:
     344                 :          0 :         k_spin_unlock(&bitarray->lock, key);
     345                 :          0 :         return ret;
     346                 :            : }
     347                 :            : 
     348                 :          0 : int sys_bitarray_clear_bit(sys_bitarray_t *bitarray, size_t bit)
     349                 :            : {
     350                 :          0 :         k_spinlock_key_t key;
     351                 :          0 :         int ret;
     352                 :          0 :         size_t idx, off;
     353                 :            : 
     354         [ #  # ]:          0 :         __ASSERT_NO_MSG(bitarray != NULL);
     355         [ #  # ]:          0 :         __ASSERT_NO_MSG(bitarray->num_bits > 0);
     356                 :            : 
     357                 :          0 :         key = k_spin_lock(&bitarray->lock);
     358                 :            : 
     359         [ #  # ]:          0 :         if (bit >= bitarray->num_bits) {
     360                 :          0 :                 ret = -EINVAL;
     361                 :          0 :                 goto out;
     362                 :            :         }
     363                 :            : 
     364                 :          0 :         idx = bit / bundle_bitness(bitarray);
     365                 :          0 :         off = bit % bundle_bitness(bitarray);
     366                 :            : 
     367                 :          0 :         bitarray->bundles[idx] &= ~BIT(off);
     368                 :            : 
     369                 :          0 :         ret = 0;
     370                 :            : 
     371                 :          0 : out:
     372                 :          0 :         k_spin_unlock(&bitarray->lock, key);
     373                 :          0 :         return ret;
     374                 :            : }
     375                 :            : 
     376                 :          0 : int sys_bitarray_test_bit(sys_bitarray_t *bitarray, size_t bit, int *val)
     377                 :            : {
     378                 :          0 :         k_spinlock_key_t key;
     379                 :          0 :         int ret;
     380                 :          0 :         size_t idx, off;
     381                 :            : 
     382         [ #  # ]:          0 :         __ASSERT_NO_MSG(bitarray != NULL);
     383         [ #  # ]:          0 :         __ASSERT_NO_MSG(bitarray->num_bits > 0);
     384                 :            : 
     385                 :          0 :         key = k_spin_lock(&bitarray->lock);
     386                 :            : 
     387         [ #  # ]:          0 :         CHECKIF(val == NULL) {
     388                 :          0 :                 ret = -EINVAL;
     389                 :          0 :                 goto out;
     390                 :            :         }
     391                 :            : 
     392         [ #  # ]:          0 :         if (bit >= bitarray->num_bits) {
     393                 :          0 :                 ret = -EINVAL;
     394                 :          0 :                 goto out;
     395                 :            :         }
     396                 :            : 
     397                 :          0 :         idx = bit / bundle_bitness(bitarray);
     398                 :          0 :         off = bit % bundle_bitness(bitarray);
     399                 :            : 
     400         [ #  # ]:          0 :         if ((bitarray->bundles[idx] & BIT(off)) != 0) {
     401                 :          0 :                 *val = 1;
     402                 :            :         } else {
     403                 :          0 :                 *val = 0;
     404                 :            :         }
     405                 :            : 
     406                 :            :         ret = 0;
     407                 :            : 
     408                 :          0 : out:
     409                 :          0 :         k_spin_unlock(&bitarray->lock, key);
     410                 :          0 :         return ret;
     411                 :            : }
     412                 :            : 
     413                 :          0 : int sys_bitarray_test_and_set_bit(sys_bitarray_t *bitarray, size_t bit, int *prev_val)
     414                 :            : {
     415                 :          0 :         k_spinlock_key_t key;
     416                 :          0 :         int ret;
     417                 :          0 :         size_t idx, off;
     418                 :            : 
     419         [ #  # ]:          0 :         __ASSERT_NO_MSG(bitarray != NULL);
     420         [ #  # ]:          0 :         __ASSERT_NO_MSG(bitarray->num_bits > 0);
     421                 :            : 
     422                 :          0 :         key = k_spin_lock(&bitarray->lock);
     423                 :            : 
     424         [ #  # ]:          0 :         CHECKIF(prev_val == NULL) {
     425                 :          0 :                 ret = -EINVAL;
     426                 :          0 :                 goto out;
     427                 :            :         }
     428                 :            : 
     429         [ #  # ]:          0 :         if (bit >= bitarray->num_bits) {
     430                 :          0 :                 ret = -EINVAL;
     431                 :          0 :                 goto out;
     432                 :            :         }
     433                 :            : 
     434                 :          0 :         idx = bit / bundle_bitness(bitarray);
     435                 :          0 :         off = bit % bundle_bitness(bitarray);
     436                 :            : 
     437         [ #  # ]:          0 :         if ((bitarray->bundles[idx] & BIT(off)) != 0) {
     438                 :          0 :                 *prev_val = 1;
     439                 :            :         } else {
     440                 :          0 :                 *prev_val = 0;
     441                 :            :         }
     442                 :            : 
     443                 :          0 :         bitarray->bundles[idx] |= BIT(off);
     444                 :            : 
     445                 :          0 :         ret = 0;
     446                 :            : 
     447                 :          0 : out:
     448                 :          0 :         k_spin_unlock(&bitarray->lock, key);
     449                 :          0 :         return ret;
     450                 :            : }
     451                 :            : 
     452                 :          0 : int sys_bitarray_test_and_clear_bit(sys_bitarray_t *bitarray, size_t bit, int *prev_val)
     453                 :            : {
     454                 :          0 :         k_spinlock_key_t key;
     455                 :          0 :         int ret;
     456                 :          0 :         size_t idx, off;
     457                 :            : 
     458         [ #  # ]:          0 :         __ASSERT_NO_MSG(bitarray != NULL);
     459         [ #  # ]:          0 :         __ASSERT_NO_MSG(bitarray->num_bits > 0);
     460                 :            : 
     461                 :          0 :         key = k_spin_lock(&bitarray->lock);
     462                 :            : 
     463         [ #  # ]:          0 :         CHECKIF(prev_val == NULL) {
     464                 :          0 :                 ret = -EINVAL;
     465                 :          0 :                 goto out;
     466                 :            :         }
     467                 :            : 
     468         [ #  # ]:          0 :         if (bit >= bitarray->num_bits) {
     469                 :          0 :                 ret = -EINVAL;
     470                 :          0 :                 goto out;
     471                 :            :         }
     472                 :            : 
     473                 :          0 :         idx = bit / bundle_bitness(bitarray);
     474                 :          0 :         off = bit % bundle_bitness(bitarray);
     475                 :            : 
     476         [ #  # ]:          0 :         if ((bitarray->bundles[idx] & BIT(off)) != 0) {
     477                 :          0 :                 *prev_val = 1;
     478                 :            :         } else {
     479                 :          0 :                 *prev_val = 0;
     480                 :            :         }
     481                 :            : 
     482                 :          0 :         bitarray->bundles[idx] &= ~BIT(off);
     483                 :            : 
     484                 :          0 :         ret = 0;
     485                 :            : 
     486                 :          0 : out:
     487                 :          0 :         k_spin_unlock(&bitarray->lock, key);
     488                 :          0 :         return ret;
     489                 :            : }
     490                 :            : 
     491                 :          0 : int sys_bitarray_alloc(sys_bitarray_t *bitarray, size_t num_bits,
     492                 :            :                        size_t *offset)
     493                 :            : {
     494                 :          0 :         k_spinlock_key_t key;
     495                 :          0 :         uint32_t bit_idx;
     496                 :          0 :         int ret;
     497                 :          0 :         struct bundle_data bd;
     498                 :          0 :         size_t off_start, off_end;
     499                 :          0 :         size_t mismatch;
     500                 :            : 
     501         [ #  # ]:          0 :         __ASSERT_NO_MSG(bitarray != NULL);
     502         [ #  # ]:          0 :         __ASSERT_NO_MSG(bitarray->num_bits > 0);
     503                 :            : 
     504                 :          0 :         key = k_spin_lock(&bitarray->lock);
     505                 :            : 
     506         [ #  # ]:          0 :         CHECKIF(offset == NULL) {
     507                 :          0 :                 ret = -EINVAL;
     508                 :          0 :                 goto out;
     509                 :            :         }
     510                 :            : 
     511   [ #  #  #  # ]:          0 :         if ((num_bits == 0) || (num_bits > bitarray->num_bits)) {
     512                 :          0 :                 ret = -EINVAL;
     513                 :          0 :                 goto out;
     514                 :            :         }
     515                 :            : 
     516                 :            :         bit_idx = 0;
     517                 :            : 
     518                 :            :         /* Find the first non-allocated bit by looking at bundles
     519                 :            :          * instead of individual bits.
     520                 :            :          *
     521                 :            :          * On RISC-V 64-bit, it complains about undefined reference to `ffs`.
     522                 :            :          * So don't use this on RISCV64.
     523                 :            :          */
     524         [ #  # ]:          0 :         for (size_t idx = 0; idx < bitarray->num_bundles; idx++) {
     525         [ #  # ]:          0 :                 if (~bitarray->bundles[idx] == 0U) {
     526                 :            :                         /* bundle is all 1s => all allocated, skip */
     527                 :          0 :                         bit_idx += bundle_bitness(bitarray);
     528                 :          0 :                         continue;
     529                 :            :                 }
     530                 :            : 
     531         [ #  # ]:          0 :                 if (bitarray->bundles[idx] != 0U) {
     532                 :            :                         /* Find the first free bit in bundle if not all free */
     533                 :          0 :                         off_start = find_lsb_set(~bitarray->bundles[idx]) - 1;
     534                 :          0 :                         bit_idx += off_start;
     535                 :            :                 }
     536                 :            : 
     537                 :            :                 break;
     538                 :            :         }
     539                 :            : 
     540                 :          0 :         off_end = bitarray->num_bits - num_bits;
     541                 :          0 :         ret = -ENOSPC;
     542         [ #  # ]:          0 :         while (bit_idx <= off_end) {
     543         [ #  # ]:          0 :                 if (match_region(bitarray, bit_idx, num_bits, false,
     544                 :            :                                  &bd, &mismatch)) {
     545                 :          0 :                         set_region(bitarray, bit_idx, num_bits, true, &bd);
     546                 :            : 
     547                 :          0 :                         *offset = bit_idx;
     548                 :          0 :                         ret = 0;
     549                 :          0 :                         break;
     550                 :            :                 }
     551                 :            : 
     552                 :            :                 /* Fast-forward to the bit just after
     553                 :            :                  * the mismatched bit.
     554                 :            :                  */
     555                 :          0 :                 bit_idx = mismatch + 1;
     556                 :            :         }
     557                 :            : 
     558                 :          0 : out:
     559                 :          0 :         k_spin_unlock(&bitarray->lock, key);
     560                 :          0 :         return ret;
     561                 :            : }
     562                 :            : 
     563                 :          0 : int sys_bitarray_find_nth_set(sys_bitarray_t *bitarray, size_t n, size_t num_bits, size_t offset,
     564                 :            :                               size_t *found_at)
     565                 :            : {
     566                 :          0 :         k_spinlock_key_t key;
     567                 :          0 :         size_t count, idx;
     568                 :          0 :         uint32_t mask;
     569                 :          0 :         struct bundle_data bd;
     570                 :          0 :         int ret;
     571                 :            : 
     572         [ #  # ]:          0 :         __ASSERT_NO_MSG(bitarray != NULL);
     573         [ #  # ]:          0 :         __ASSERT_NO_MSG(bitarray->num_bits > 0);
     574                 :            : 
     575                 :          0 :         key = k_spin_lock(&bitarray->lock);
     576                 :            : 
     577   [ #  #  #  # ]:          0 :         if (n == 0 || num_bits == 0 || offset + num_bits > bitarray->num_bits) {
     578                 :          0 :                 ret = -EINVAL;
     579                 :          0 :                 goto out;
     580                 :            :         }
     581                 :            : 
     582                 :          0 :         ret = 1;
     583                 :          0 :         mask = 0;
     584                 :          0 :         setup_bundle_data(bitarray, &bd, offset, num_bits);
     585                 :            : 
     586                 :          0 :         count = POPCOUNT(bitarray->bundles[bd.sidx] & bd.smask);
     587                 :            :         /* If we already found more bits set than n, we found the target bundle */
     588         [ #  # ]:          0 :         if (count >= n) {
     589                 :          0 :                 idx = bd.sidx;
     590                 :          0 :                 mask = bd.smask;
     591                 :          0 :                 goto found;
     592                 :            :         }
     593                 :            :         /* Keep looking if there are more bundles */
     594         [ #  # ]:          0 :         if (bd.sidx != bd.eidx) {
     595                 :            :                 /* We are now only looking for the remaining bits */
     596                 :          0 :                 n -= count;
     597                 :            :                 /* First bundle was already checked, keep looking in middle (complete)
     598                 :            :                  * bundles.
     599                 :            :                  */
     600         [ #  # ]:          0 :                 for (idx = bd.sidx + 1; idx < bd.eidx; idx++) {
     601                 :          0 :                         count = POPCOUNT(bitarray->bundles[idx]);
     602         [ #  # ]:          0 :                         if (count >= n) {
     603                 :          0 :                                 mask = ~(mask & 0);
     604                 :          0 :                                 goto found;
     605                 :            :                         }
     606                 :          0 :                         n -= count;
     607                 :            :                 }
     608                 :            :                 /* Continue searching in last bundle */
     609                 :          0 :                 count = POPCOUNT(bitarray->bundles[bd.eidx] & bd.emask);
     610         [ #  # ]:          0 :                 if (count >= n) {
     611                 :          0 :                         idx = bd.eidx;
     612                 :          0 :                         mask = bd.emask;
     613                 :          0 :                         goto found;
     614                 :            :                 }
     615                 :            :         }
     616                 :            : 
     617                 :          0 :         goto out;
     618                 :            : 
     619                 :          0 : found:
     620                 :            :         /* The bit we are looking for must be in the current bundle idx.
     621                 :            :          * Find out the exact index of the bit.
     622                 :            :          */
     623         [ #  # ]:          0 :         for (int j = 0; j <= bundle_bitness(bitarray) - 1; j++) {
     624         [ #  # ]:          0 :                 if (bitarray->bundles[idx] & mask & BIT(j)) {
     625         [ #  # ]:          0 :                         if (--n <= 0) {
     626                 :          0 :                                 *found_at = idx * bundle_bitness(bitarray) + j;
     627                 :          0 :                                 ret = 0;
     628                 :          0 :                                 break;
     629                 :            :                         }
     630                 :            :                 }
     631                 :            :         }
     632                 :            : 
     633                 :          0 : out:
     634                 :          0 :         k_spin_unlock(&bitarray->lock, key);
     635                 :          0 :         return ret;
     636                 :            : }
     637                 :            : 
     638                 :          0 : int sys_bitarray_free(sys_bitarray_t *bitarray, size_t num_bits,
     639                 :            :                       size_t offset)
     640                 :            : {
     641                 :          0 :         k_spinlock_key_t key;
     642                 :          0 :         int ret;
     643                 :          0 :         size_t off_end = offset + num_bits - 1;
     644                 :          0 :         struct bundle_data bd;
     645                 :            : 
     646         [ #  # ]:          0 :         __ASSERT_NO_MSG(bitarray != NULL);
     647         [ #  # ]:          0 :         __ASSERT_NO_MSG(bitarray->num_bits > 0);
     648                 :            : 
     649                 :          0 :         key = k_spin_lock(&bitarray->lock);
     650                 :            : 
     651         [ #  # ]:          0 :         if ((num_bits == 0)
     652         [ #  # ]:          0 :             || (num_bits > bitarray->num_bits)
     653         [ #  # ]:          0 :             || (offset >= bitarray->num_bits)
     654         [ #  # ]:          0 :             || (off_end >= bitarray->num_bits)) {
     655                 :          0 :                 ret = -EINVAL;
     656                 :          0 :                 goto out;
     657                 :            :         }
     658                 :            : 
     659                 :            :         /* Note that we need to make sure the bits in specified region
     660                 :            :          * (offset to offset + num_bits) are all allocated before we clear
     661                 :            :          * them.
     662                 :            :          */
     663         [ #  # ]:          0 :         if (match_region(bitarray, offset, num_bits, true, &bd, NULL)) {
     664                 :          0 :                 set_region(bitarray, offset, num_bits, false, &bd);
     665                 :          0 :                 ret = 0;
     666                 :            :         } else {
     667                 :            :                 ret = -EFAULT;
     668                 :            :         }
     669                 :            : 
     670                 :          0 : out:
     671                 :          0 :         k_spin_unlock(&bitarray->lock, key);
     672                 :          0 :         return ret;
     673                 :            : }
     674                 :            : 
     675                 :          0 : static bool is_region_set_clear(sys_bitarray_t *bitarray, size_t num_bits,
     676                 :            :                                 size_t offset, bool to_set)
     677                 :            : {
     678                 :          0 :         bool ret;
     679                 :          0 :         struct bundle_data bd;
     680                 :          0 :         size_t off_end = offset + num_bits - 1;
     681                 :          0 :         k_spinlock_key_t key = k_spin_lock(&bitarray->lock);
     682                 :            : 
     683         [ #  # ]:          0 :         __ASSERT_NO_MSG(bitarray != NULL);
     684         [ #  # ]:          0 :         __ASSERT_NO_MSG(bitarray->num_bits > 0);
     685                 :            : 
     686         [ #  # ]:          0 :         if ((num_bits == 0)
     687         [ #  # ]:          0 :             || (num_bits > bitarray->num_bits)
     688         [ #  # ]:          0 :             || (offset >= bitarray->num_bits)
     689         [ #  # ]:          0 :             || (off_end >= bitarray->num_bits)) {
     690                 :          0 :                 ret = false;
     691                 :          0 :                 goto out;
     692                 :            :         }
     693                 :            : 
     694                 :          0 :         ret = match_region(bitarray, offset, num_bits, to_set, &bd, NULL);
     695                 :            : 
     696                 :          0 : out:
     697                 :          0 :         k_spin_unlock(&bitarray->lock, key);
     698                 :          0 :         return ret;
     699                 :            : }
     700                 :            : 
     701                 :          0 : bool sys_bitarray_is_region_set(sys_bitarray_t *bitarray, size_t num_bits,
     702                 :            :                                 size_t offset)
     703                 :            : {
     704                 :          0 :         return is_region_set_clear(bitarray, num_bits, offset, true);
     705                 :            : }
     706                 :            : 
     707                 :          0 : bool sys_bitarray_is_region_cleared(sys_bitarray_t *bitarray, size_t num_bits,
     708                 :            :                                     size_t offset)
     709                 :            : {
     710                 :          0 :         return is_region_set_clear(bitarray, num_bits, offset, false);
     711                 :            : }
     712                 :            : 
     713                 :          0 : static int set_clear_region(sys_bitarray_t *bitarray, size_t num_bits,
     714                 :            :                             size_t offset, bool to_set)
     715                 :            : {
     716                 :          0 :         int ret;
     717                 :          0 :         size_t off_end = offset + num_bits - 1;
     718                 :          0 :         k_spinlock_key_t key = k_spin_lock(&bitarray->lock);
     719                 :            : 
     720         [ #  # ]:          0 :         __ASSERT_NO_MSG(bitarray != NULL);
     721         [ #  # ]:          0 :         __ASSERT_NO_MSG(bitarray->num_bits > 0);
     722                 :            : 
     723         [ #  # ]:          0 :         if ((num_bits == 0)
     724         [ #  # ]:          0 :             || (num_bits > bitarray->num_bits)
     725         [ #  # ]:          0 :             || (offset >= bitarray->num_bits)
     726         [ #  # ]:          0 :             || (off_end >= bitarray->num_bits)) {
     727                 :          0 :                 ret = -EINVAL;
     728                 :          0 :                 goto out;
     729                 :            :         }
     730                 :            : 
     731                 :          0 :         set_region(bitarray, offset, num_bits, to_set, NULL);
     732                 :          0 :         ret = 0;
     733                 :            : 
     734                 :          0 : out:
     735                 :          0 :         k_spin_unlock(&bitarray->lock, key);
     736                 :          0 :         return ret;
     737                 :            : }
     738                 :            : 
     739                 :          0 : int sys_bitarray_test_and_set_region(sys_bitarray_t *bitarray, size_t num_bits,
     740                 :            :                                      size_t offset, bool to_set)
     741                 :            : {
     742                 :          0 :         int ret;
     743                 :          0 :         bool region_clear;
     744                 :          0 :         struct bundle_data bd;
     745                 :            : 
     746         [ #  # ]:          0 :         __ASSERT_NO_MSG(bitarray != NULL);
     747         [ #  # ]:          0 :         __ASSERT_NO_MSG(bitarray->num_bits > 0);
     748                 :            : 
     749                 :          0 :         size_t off_end = offset + num_bits - 1;
     750                 :          0 :         k_spinlock_key_t key = k_spin_lock(&bitarray->lock);
     751                 :            : 
     752                 :            : 
     753         [ #  # ]:          0 :         if ((num_bits == 0)
     754         [ #  # ]:          0 :             || (num_bits > bitarray->num_bits)
     755         [ #  # ]:          0 :             || (offset >= bitarray->num_bits)
     756         [ #  # ]:          0 :             || (off_end >= bitarray->num_bits)) {
     757                 :          0 :                 ret = -EINVAL;
     758                 :          0 :                 goto out;
     759                 :            :         }
     760                 :            : 
     761                 :          0 :         region_clear = match_region(bitarray, offset, num_bits, !to_set, &bd, NULL);
     762         [ #  # ]:          0 :         if (region_clear) {
     763                 :          0 :                 set_region(bitarray, offset, num_bits, to_set, &bd);
     764                 :          0 :                 ret = 0;
     765                 :            :         } else {
     766                 :            :                 ret = -EEXIST;
     767                 :            :         }
     768                 :            : 
     769                 :          0 : out:
     770                 :          0 :         k_spin_unlock(&bitarray->lock, key);
     771                 :          0 :         return ret;
     772                 :            : }
     773                 :            : 
     774                 :          0 : int sys_bitarray_set_region(sys_bitarray_t *bitarray, size_t num_bits,
     775                 :            :                             size_t offset)
     776                 :            : {
     777                 :          0 :         return set_clear_region(bitarray, num_bits, offset, true);
     778                 :            : }
     779                 :            : 
     780                 :          0 : int sys_bitarray_clear_region(sys_bitarray_t *bitarray, size_t num_bits,
     781                 :            :                               size_t offset)
     782                 :            : {
     783                 :          0 :         return set_clear_region(bitarray, num_bits, offset, false);
     784                 :            : }

Generated by: LCOV version 1.14