util: add bit array data structure

Change-Id: Idab4473fa23486e72334ec07d0853c6325197c20
Signed-off-by: Daniel Verkamp <daniel.verkamp@intel.com>
This commit is contained in:
Daniel Verkamp 2016-09-14 17:12:15 -07:00 committed by Ben Walker
parent f5794d088e
commit 6c5f05f177
11 changed files with 768 additions and 2 deletions

View File

@ -82,6 +82,7 @@ time test/lib/jsonrpc/jsonrpc.sh
time test/lib/log/log.sh
time test/lib/scsi/scsi.sh
time test/lib/iscsi/iscsi.sh
time test/lib/util/util.sh
timing_exit lib

136
include/spdk/bit_array.h Normal file
View File

@ -0,0 +1,136 @@
/*-
* BSD LICENSE
*
* Copyright (c) Intel Corporation.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Intel Corporation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/** \file
* Bit array data structure
*/
#ifndef SPDK_BIT_ARRAY_H
#define SPDK_BIT_ARRAY_H
#ifdef __cplusplus
extern "C" {
#endif
#include <errno.h>
#include <stdbool.h>
#include <stdint.h>
/**
* Variable-length bit array.
*/
struct spdk_bit_array;
/**
* Return the number of bits a bit array is currently sized to hold.
*/
uint32_t spdk_bit_array_capacity(const struct spdk_bit_array *ba);
/**
* Create a bit array.
*/
struct spdk_bit_array *spdk_bit_array_create(uint32_t num_bits);
/**
* Free a bit array and set the pointer to NULL.
*/
void spdk_bit_array_free(struct spdk_bit_array **bap);
/**
* Create or resize a bit array.
*
* To create a new bit array, pass a pointer to a spdk_bit_array pointer that is NULL for bap.
*
* The bit array will be sized to hold at least num_bits.
*
* If num_bits is smaller than the previous size of the bit array,
* any data beyond the new num_bits size will be cleared.
*
* If num_bits is larger than the previous size of the bit array,
* any data beyond the old num_bits size will be cleared.
*/
int spdk_bit_array_resize(struct spdk_bit_array **bap, uint32_t num_bits);
/**
* Get the value of a bit from the bit array.
*
* If bit_index is beyond the end of the current size of the bit array,
* this function will return false (i.e. bits beyond the end of the array are implicitly 0).
*/
bool spdk_bit_array_get(const struct spdk_bit_array *ba, uint32_t bit_index);
/**
* Set (to 1) a bit in the bit array.
*
* If bit_index is beyond the end of the bit array, this function will return -EINVAL.
* On success, returns 0.
*/
int spdk_bit_array_set(struct spdk_bit_array *ba, uint32_t bit_index);
/**
* Clear (to 0) a bit in the bit array.
*
* If bit_index is beyond the end of the bit array, no action is taken. Bits beyond the end of the
* bit array are implicitly 0.
*/
void spdk_bit_array_clear(struct spdk_bit_array *ba, uint32_t bit_index);
/**
* Find the index of the first set bit in the array.
*
* \param ba The bit array to search.
* \param start_bit_index The bit index from which to start searching (0 to start from the beginning
* of the array).
*
* \return The index of the first set bit. If no bits are set, returns UINT32_MAX.
*/
uint32_t spdk_bit_array_find_first_set(const struct spdk_bit_array *ba, uint32_t start_bit_index);
/**
* Find the index of the first cleared bit in the array.
*
* \param ba The bit array to search.
* \param start_bit_index The bit index from which to start searching (0 to start from the beginning
* of the array)..
*
* \return The index of the first cleared bit. Bits beyond the current size of the array are
* implicitly cleared, so if all bits within the current size are set, this function will return
* the current number of bits + 1.
*/
uint32_t spdk_bit_array_find_first_clear(const struct spdk_bit_array *ba, uint32_t start_bit_index);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -35,7 +35,7 @@ SPDK_ROOT_DIR := $(abspath $(CURDIR)/../..)
include $(SPDK_ROOT_DIR)/mk/spdk.common.mk
CFLAGS += $(DPDK_INC)
C_SRCS = fd.c string.c pci.c
C_SRCS = bit_array.c fd.c string.c pci.c
LIBNAME = util
include $(SPDK_ROOT_DIR)/mk/spdk.lib.mk

274
lib/util/bit_array.c Normal file
View File

@ -0,0 +1,274 @@
/*-
* BSD LICENSE
*
* Copyright (c) Intel Corporation.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Intel Corporation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "spdk/bit_array.h"
#include <assert.h>
#include <errno.h>
#include <limits.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
typedef uint64_t spdk_bit_array_word;
#define SPDK_BIT_ARRAY_WORD_TZCNT(x) (__builtin_ctzll(x))
#define SPDK_BIT_ARRAY_WORD_C(x) ((spdk_bit_array_word)(x))
#define SPDK_BIT_ARRAY_WORD_BYTES sizeof(spdk_bit_array_word)
#define SPDK_BIT_ARRAY_WORD_BITS (SPDK_BIT_ARRAY_WORD_BYTES * 8)
#define SPDK_BIT_ARRAY_WORD_INDEX_SHIFT (31u - __builtin_clz(SPDK_BIT_ARRAY_WORD_BITS))
#define SPDK_BIT_ARRAY_WORD_INDEX_MASK ((1u << SPDK_BIT_ARRAY_WORD_INDEX_SHIFT) - 1)
struct spdk_bit_array {
uint32_t bit_count;
spdk_bit_array_word words[];
};
struct spdk_bit_array *
spdk_bit_array_create(uint32_t num_bits)
{
struct spdk_bit_array *ba = NULL;
spdk_bit_array_resize(&ba, num_bits);
return ba;
}
void
spdk_bit_array_free(struct spdk_bit_array **bap)
{
struct spdk_bit_array *ba;
if (!bap) {
return;
}
ba = *bap;
*bap = NULL;
free(ba);
}
static inline uint32_t
spdk_bit_array_word_count(uint32_t num_bits)
{
return (num_bits + SPDK_BIT_ARRAY_WORD_BITS - 1) >> SPDK_BIT_ARRAY_WORD_INDEX_SHIFT;
}
static inline spdk_bit_array_word
spdk_bit_array_word_mask(uint32_t num_bits)
{
assert(num_bits < SPDK_BIT_ARRAY_WORD_BITS);
return (SPDK_BIT_ARRAY_WORD_C(1) << num_bits) - 1;
}
int
spdk_bit_array_resize(struct spdk_bit_array **bap, uint32_t num_bits)
{
struct spdk_bit_array *new_ba;
uint32_t old_word_count, new_word_count;
size_t new_size;
if (!bap) {
return -EINVAL;
}
new_word_count = spdk_bit_array_word_count(num_bits);
new_size = offsetof(struct spdk_bit_array, words) + new_word_count * SPDK_BIT_ARRAY_WORD_BYTES;
/*
* Always keep one extra word with a 0 and a 1 past the actual required size so that the
* find_first functions can just keep going until they match.
*/
new_size += SPDK_BIT_ARRAY_WORD_BYTES;
new_ba = (struct spdk_bit_array *)realloc(*bap, new_size);
if (!new_ba) {
return -ENOMEM;
}
/*
* Set up special extra word (see above comment about find_first_clear).
*
* This is set to 0b10 so that find_first_clear will find a 0 at the very first
* bit past the end of the buffer, and find_first_set will find a 1 at the next bit
* past that.
*/
new_ba->words[new_word_count] = 0x2;
if (*bap == NULL) {
old_word_count = 0;
new_ba->bit_count = 0;
} else {
old_word_count = spdk_bit_array_word_count(new_ba->bit_count);
}
if (new_word_count > old_word_count) {
/* Zero out new entries */
memset(&new_ba->words[old_word_count], 0,
(new_word_count - old_word_count) * SPDK_BIT_ARRAY_WORD_BYTES);
} else if (new_word_count == old_word_count && num_bits < new_ba->bit_count) {
/* Make sure any existing partial last word is cleared beyond the new num_bits. */
uint32_t last_word_bits;
spdk_bit_array_word mask;
last_word_bits = num_bits & SPDK_BIT_ARRAY_WORD_INDEX_MASK;
mask = spdk_bit_array_word_mask(last_word_bits);
new_ba->words[old_word_count - 1] &= mask;
}
new_ba->bit_count = num_bits;
*bap = new_ba;
return 0;
}
uint32_t
spdk_bit_array_capacity(const struct spdk_bit_array *ba)
{
return ba->bit_count;
}
static inline int
_spdk_bit_array_get_word(const struct spdk_bit_array *ba, uint32_t bit_index,
uint32_t *word_index, uint32_t *word_bit_index)
{
if (bit_index >= ba->bit_count) {
return -EINVAL;
}
*word_index = bit_index >> SPDK_BIT_ARRAY_WORD_INDEX_SHIFT;
*word_bit_index = bit_index & SPDK_BIT_ARRAY_WORD_INDEX_MASK;
return 0;
}
bool
spdk_bit_array_get(const struct spdk_bit_array *ba, uint32_t bit_index)
{
uint32_t word_index, word_bit_index;
if (_spdk_bit_array_get_word(ba, bit_index, &word_index, &word_bit_index)) {
return false;
}
return (ba->words[word_index] >> word_bit_index) & 1U;
}
int
spdk_bit_array_set(struct spdk_bit_array *ba, uint32_t bit_index)
{
uint32_t word_index, word_bit_index;
if (_spdk_bit_array_get_word(ba, bit_index, &word_index, &word_bit_index)) {
return -EINVAL;
}
ba->words[word_index] |= (SPDK_BIT_ARRAY_WORD_C(1) << word_bit_index);
return 0;
}
void
spdk_bit_array_clear(struct spdk_bit_array *ba, uint32_t bit_index)
{
uint32_t word_index, word_bit_index;
if (_spdk_bit_array_get_word(ba, bit_index, &word_index, &word_bit_index)) {
/*
* Clearing past the end of the bit array is a no-op, since bit past the end
* are implicitly 0.
*/
return;
}
ba->words[word_index] &= ~(SPDK_BIT_ARRAY_WORD_C(1) << word_bit_index);
}
static inline uint32_t
_spdk_bit_array_find_first(const struct spdk_bit_array *ba, uint32_t start_bit_index,
spdk_bit_array_word xor_mask)
{
uint32_t word_index, first_word_bit_index;
spdk_bit_array_word word, first_word_mask;
const spdk_bit_array_word *words, *cur_word;
if (start_bit_index >= ba->bit_count) {
return ba->bit_count;
}
word_index = start_bit_index >> SPDK_BIT_ARRAY_WORD_INDEX_SHIFT;
words = ba->words;
cur_word = &words[word_index];
/*
* Special case for first word: skip start_bit_index % SPDK_BIT_ARRAY_WORD_BITS bits
* within the first word.
*/
first_word_bit_index = start_bit_index & SPDK_BIT_ARRAY_WORD_INDEX_MASK;
first_word_mask = spdk_bit_array_word_mask(first_word_bit_index);
word = (*cur_word ^ xor_mask) & ~first_word_mask;
/*
* spdk_bit_array_resize() guarantees that an extra word with a 1 and a 0 will always be
* at the end of the words[] array, so just keep going until a word matches.
*/
while (word == 0) {
word = *++cur_word ^ xor_mask;
}
return ((uintptr_t)cur_word - (uintptr_t)words) * 8 + SPDK_BIT_ARRAY_WORD_TZCNT(word);
}
uint32_t
spdk_bit_array_find_first_set(const struct spdk_bit_array *ba, uint32_t start_bit_index)
{
uint32_t bit_index;
bit_index = _spdk_bit_array_find_first(ba, start_bit_index, 0);
/*
* If we ran off the end of the array and found the 1 bit in the extra word,
* return UINT32_MAX to indicate no actual 1 bits were found.
*/
if (bit_index >= ba->bit_count) {
bit_index = UINT32_MAX;
}
return bit_index;
}
uint32_t
spdk_bit_array_find_first_clear(const struct spdk_bit_array *ba, uint32_t start_bit_index)
{
return _spdk_bit_array_find_first(ba, start_bit_index, SPDK_BIT_ARRAY_WORD_C(-1));
}

View File

@ -34,7 +34,7 @@
SPDK_ROOT_DIR := $(abspath $(CURDIR)/../..)
include $(SPDK_ROOT_DIR)/mk/spdk.common.mk
DIRS-y = bdev event log iscsi json jsonrpc nvme nvmf memory scsi ioat
DIRS-y = bdev event log iscsi json jsonrpc nvme nvmf memory scsi ioat util
.PHONY: all clean $(DIRS-y)

44
test/lib/util/Makefile Normal file
View File

@ -0,0 +1,44 @@
#
# BSD LICENSE
#
# Copyright (c) Intel Corporation.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in
# the documentation and/or other materials provided with the
# distribution.
# * Neither the name of Intel Corporation nor the names of its
# contributors may be used to endorse or promote products derived
# from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
SPDK_ROOT_DIR := $(abspath $(CURDIR)/../../..)
include $(SPDK_ROOT_DIR)/mk/spdk.common.mk
DIRS-y = bit_array
.PHONY: all clean $(DIRS-y)
all: $(DIRS-y)
clean: $(DIRS-y)
include $(SPDK_ROOT_DIR)/mk/spdk.subdirs.mk

1
test/lib/util/bit_array/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
bit_array_ut

View File

@ -0,0 +1,52 @@
#
# BSD LICENSE
#
# Copyright (c) Intel Corporation.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in
# the documentation and/or other materials provided with the
# distribution.
# * Neither the name of Intel Corporation nor the names of its
# contributors may be used to endorse or promote products derived
# from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
SPDK_ROOT_DIR := $(abspath $(CURDIR)/../../../..)
include $(SPDK_ROOT_DIR)/mk/spdk.common.mk
CFLAGS += -I$(SPDK_ROOT_DIR)/test
CFLAGS += -I$(SPDK_ROOT_DIR)/lib/util
APP = bit_array_ut
C_SRCS := bit_array_ut.c
LIBS += -lcunit
all : $(APP)
$(APP) : $(OBJS) $(SPDK_LIBS)
$(LINK_C)
clean :
$(CLEAN_C) $(APP)
include $(SPDK_ROOT_DIR)/mk/spdk.deps.mk

View File

@ -0,0 +1,241 @@
/*-
* BSD LICENSE
*
* Copyright (c) Intel Corporation.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Intel Corporation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdio.h>
#include "spdk_cunit.h"
#include "bit_array.c"
static void
test_1bit(void)
{
struct spdk_bit_array *ba;
ba = spdk_bit_array_create(1);
SPDK_CU_ASSERT_FATAL(ba != NULL);
CU_ASSERT(spdk_bit_array_get(ba, 0) == false);
CU_ASSERT(spdk_bit_array_find_first_set(ba, 0) == UINT32_MAX);
/* Set bit 0 */
CU_ASSERT(spdk_bit_array_set(ba, 0) == 0);
CU_ASSERT(spdk_bit_array_get(ba, 0) == true);
CU_ASSERT(spdk_bit_array_find_first_set(ba, 0) == 0);
/* Clear bit 0 */
spdk_bit_array_clear(ba, 0);
CU_ASSERT(spdk_bit_array_get(ba, 0) == false);
CU_ASSERT(spdk_bit_array_find_first_set(ba, 0) == UINT32_MAX);
spdk_bit_array_free(&ba);
CU_ASSERT(ba == NULL);
}
static void
test_64bit(void)
{
struct spdk_bit_array *ba;
ba = spdk_bit_array_create(64);
SPDK_CU_ASSERT_FATAL(ba != NULL);
CU_ASSERT(spdk_bit_array_get(ba, 0) == false);
CU_ASSERT(spdk_bit_array_get(ba, 63) == false);
CU_ASSERT(spdk_bit_array_get(ba, 64) == false);
CU_ASSERT(spdk_bit_array_get(ba, 1000) == false);
CU_ASSERT(spdk_bit_array_find_first_set(ba, 0) == UINT32_MAX);
/* Set bit 1 */
CU_ASSERT(spdk_bit_array_set(ba, 1) == 0);
CU_ASSERT(spdk_bit_array_get(ba, 0) == false);
CU_ASSERT(spdk_bit_array_get(ba, 1) == true);
CU_ASSERT(spdk_bit_array_find_first_set(ba, 0) == 1);
/* Set bit 63 (1 still set) */
CU_ASSERT(spdk_bit_array_set(ba, 63) == 0);
CU_ASSERT(spdk_bit_array_get(ba, 0) == false);
CU_ASSERT(spdk_bit_array_get(ba, 1) == true);
CU_ASSERT(spdk_bit_array_get(ba, 63) == true);
CU_ASSERT(spdk_bit_array_find_first_set(ba, 0) == 1);
/* Clear bit 1 (63 still set) */
spdk_bit_array_clear(ba, 1);
CU_ASSERT(spdk_bit_array_get(ba, 1) == false);
CU_ASSERT(spdk_bit_array_find_first_set(ba, 0) == 63);
/* Clear bit 63 (no bits set) */
spdk_bit_array_clear(ba, 63);
CU_ASSERT(spdk_bit_array_get(ba, 63) == false);
CU_ASSERT(spdk_bit_array_find_first_set(ba, 0) == UINT32_MAX);
spdk_bit_array_free(&ba);
}
static void
test_find(void)
{
struct spdk_bit_array *ba;
uint32_t i;
ba = spdk_bit_array_create(256);
SPDK_CU_ASSERT_FATAL(ba != NULL);
/* Set all bits */
for (i = 0; i < 256; i++) {
CU_ASSERT(spdk_bit_array_set(ba, i) == 0);
}
/* Verify that find_first_set and find_first_clear work for each starting position */
for (i = 0; i < 256; i++) {
CU_ASSERT(spdk_bit_array_find_first_set(ba, i) == i);
CU_ASSERT(spdk_bit_array_find_first_clear(ba, i) == 256);
}
CU_ASSERT(spdk_bit_array_find_first_set(ba, 256) == UINT32_MAX);
CU_ASSERT(spdk_bit_array_find_first_clear(ba, 256) == 256);
/* Clear bits 0 through 31 */
for (i = 0; i < 32; i++) {
spdk_bit_array_clear(ba, i);
}
for (i = 0; i < 32; i++) {
CU_ASSERT(spdk_bit_array_find_first_set(ba, i) == 32);
CU_ASSERT(spdk_bit_array_find_first_clear(ba, i) == i);
}
for (i = 32; i < 256; i++) {
CU_ASSERT(spdk_bit_array_find_first_set(ba, i) == i);
CU_ASSERT(spdk_bit_array_find_first_clear(ba, i) == 256);
}
/* Clear bit 255 */
spdk_bit_array_clear(ba, 255);
for (i = 0; i < 32; i++) {
CU_ASSERT(spdk_bit_array_find_first_set(ba, i) == 32);
CU_ASSERT(spdk_bit_array_find_first_clear(ba, i) == i);
}
for (i = 32; i < 255; i++) {
CU_ASSERT(spdk_bit_array_find_first_set(ba, i) == i);
CU_ASSERT(spdk_bit_array_find_first_clear(ba, i) == 255);
}
CU_ASSERT(spdk_bit_array_find_first_clear(ba, 256) == 256);
spdk_bit_array_free(&ba);
}
static void
test_resize(void)
{
struct spdk_bit_array *ba;
/* Start with a 0 bit array */
ba = spdk_bit_array_create(0);
SPDK_CU_ASSERT_FATAL(ba != NULL);
CU_ASSERT(spdk_bit_array_get(ba, 0) == false);
CU_ASSERT(spdk_bit_array_set(ba, 0) == -EINVAL);
spdk_bit_array_clear(ba, 0);
/* Increase size to 1 bit */
SPDK_CU_ASSERT_FATAL(spdk_bit_array_resize(&ba, 1) == 0);
SPDK_CU_ASSERT_FATAL(ba != NULL);
CU_ASSERT(spdk_bit_array_get(ba, 0) == false);
CU_ASSERT(spdk_bit_array_set(ba, 0) == 0);
CU_ASSERT(spdk_bit_array_get(ba, 0) == true);
/* Increase size to 2 bits */
SPDK_CU_ASSERT_FATAL(spdk_bit_array_resize(&ba, 2) == 0);
SPDK_CU_ASSERT_FATAL(ba != NULL);
CU_ASSERT(spdk_bit_array_get(ba, 1) == false);
CU_ASSERT(spdk_bit_array_set(ba, 1) == 0);
CU_ASSERT(spdk_bit_array_get(ba, 1) == true);
/* Shrink size back to 1 bit */
SPDK_CU_ASSERT_FATAL(spdk_bit_array_resize(&ba, 1) == 0);
SPDK_CU_ASSERT_FATAL(ba != NULL);
CU_ASSERT(spdk_bit_array_get(ba, 0) == true);
CU_ASSERT(spdk_bit_array_get(ba, 1) == false);
/* Increase size to 65 bits */
SPDK_CU_ASSERT_FATAL(spdk_bit_array_resize(&ba, 65) == 0);
SPDK_CU_ASSERT_FATAL(ba != NULL);
CU_ASSERT(spdk_bit_array_get(ba, 0) == true);
CU_ASSERT(spdk_bit_array_get(ba, 1) == false);
CU_ASSERT(spdk_bit_array_set(ba, 64) == 0);
CU_ASSERT(spdk_bit_array_get(ba, 64) == true);
/* Shrink size back to 0 bits */
SPDK_CU_ASSERT_FATAL(spdk_bit_array_resize(&ba, 0) == 0);
SPDK_CU_ASSERT_FATAL(ba != NULL);
CU_ASSERT(spdk_bit_array_get(ba, 0) == false);
CU_ASSERT(spdk_bit_array_get(ba, 1) == false);
spdk_bit_array_free(&ba);
}
int
main(int argc, char **argv)
{
CU_pSuite suite = NULL;
unsigned int num_failures;
if (CU_initialize_registry() != CUE_SUCCESS) {
return CU_get_error();
}
suite = CU_add_suite("bit_array", NULL, NULL);
if (suite == NULL) {
CU_cleanup_registry();
return CU_get_error();
}
if (
CU_add_test(suite, "test_1bit", test_1bit) == NULL ||
CU_add_test(suite, "test_64bit", test_64bit) == NULL ||
CU_add_test(suite, "test_find", test_find) == NULL ||
CU_add_test(suite, "test_resize", test_resize) == NULL) {
CU_cleanup_registry();
return CU_get_error();
}
CU_basic_set_mode(CU_BRM_VERBOSE);
CU_basic_run_tests();
num_failures = CU_get_number_of_failures();
CU_cleanup_registry();
return num_failures;
}

13
test/lib/util/util.sh Executable file
View File

@ -0,0 +1,13 @@
#!/usr/bin/env bash
set -xe
testdir=$(readlink -f $(dirname $0))
rootdir=$testdir/../../..
source $rootdir/scripts/autotest_common.sh
timing_enter util
$testdir/bit_array/bit_array_ut
timing_exit util

View File

@ -47,3 +47,7 @@ make -C test/lib/scsi/lun CONFIG_WERROR=y
test/lib/scsi/dev/dev_ut
test/lib/scsi/lun/lun_ut
#test/lib/scsi/scsi_bdev/scsi_bdev_ut
make -C test/lib/util/bit_array CONFIG_WERROR=y
test/lib/util/bit_array/bit_array_ut