Tweaks to bitset.h, established a C test framework.
This commit is contained in:
35
Rakefile
35
Rakefile
@@ -5,6 +5,9 @@ OBJECTS = SOURCES.map { |s| "#{s}.o" }
|
|||||||
LIBS = %w( pthread )
|
LIBS = %w( pthread )
|
||||||
CCFLAGS = %w( -Wall )
|
CCFLAGS = %w( -Wall )
|
||||||
LDFLAGS = []
|
LDFLAGS = []
|
||||||
|
LIBCHECK = "/usr/lib/libcheck.a"
|
||||||
|
|
||||||
|
TEST_MODULES = Dir["tests/check_*.c"].map { |n| n[12..-3] }
|
||||||
|
|
||||||
if DEBUG
|
if DEBUG
|
||||||
LDFLAGS << ["-g"]
|
LDFLAGS << ["-g"]
|
||||||
@@ -14,17 +17,39 @@ end
|
|||||||
|
|
||||||
rule 'default' => 'flexnbd'
|
rule 'default' => 'flexnbd'
|
||||||
|
|
||||||
rule 'flexnbd' => OBJECTS do |t|
|
namespace "test" do
|
||||||
|
task 'build' => TEST_MODULES.map { |n| "tests/check_#{n}" }
|
||||||
|
task 'run' => 'build' do
|
||||||
|
TEST_MODULES.each do |n|
|
||||||
|
ENV['EF_DISABLE_BANNER'] = '1'
|
||||||
|
sh "./tests/check_#{n}"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def gcc_link(target, objects)
|
||||||
sh "gcc #{LDFLAGS.join(' ')} "+
|
sh "gcc #{LDFLAGS.join(' ')} "+
|
||||||
LIBS.map { |l| "-l#{l}" }.join(" ")+
|
LIBS.map { |l| "-l#{l}" }.join(" ")+
|
||||||
" -o #{t.name} "+
|
" -o #{target} "+
|
||||||
t.sources.join(" ")
|
objects.join(" ")
|
||||||
|
end
|
||||||
|
|
||||||
|
rule 'flexnbd' => OBJECTS do |t|
|
||||||
|
gcc_link(t.name, t.sources)
|
||||||
|
end
|
||||||
|
|
||||||
|
rule(/tests\/check_[a-z]+$/ => [ proc { |target| target+".o" } ]) do |t|
|
||||||
|
gcc_link(t.name, t.sources + [LIBCHECK])
|
||||||
end
|
end
|
||||||
|
|
||||||
rule '.o' => '.c' do |t|
|
rule '.o' => '.c' do |t|
|
||||||
sh "gcc -c #{CCFLAGS.join(' ')} -o #{t.name} #{t.source} "
|
sh "gcc -I. -c #{CCFLAGS.join(' ')} -o #{t.name} #{t.source} "
|
||||||
end
|
end
|
||||||
|
|
||||||
rule 'clean' do
|
rule 'clean' do
|
||||||
sh "rm -f flexnbd "+OBJECTS.join(" ")
|
sh "rm -f flexnbd " + (
|
||||||
|
OBJECTS +
|
||||||
|
TEST_MODULES.map { |n| ["tests/check_#{n}", "tests/check_#{n}.o"] }.flatten
|
||||||
|
).
|
||||||
|
join(" ")
|
||||||
end
|
end
|
||||||
|
74
bitset.h
74
bitset.h
@@ -3,6 +3,9 @@
|
|||||||
|
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
static inline char char_with_bit_set(int num) { return 1<<(num%8); }
|
static inline char char_with_bit_set(int num) { return 1<<(num%8); }
|
||||||
|
|
||||||
@@ -20,9 +23,11 @@ static inline int bit_has_value(char* b, int idx, int value) {
|
|||||||
}
|
}
|
||||||
static inline void bit_set(char* b, int idx) {
|
static inline void bit_set(char* b, int idx) {
|
||||||
b[idx/8] |= char_with_bit_set(idx);
|
b[idx/8] |= char_with_bit_set(idx);
|
||||||
|
//__sync_fetch_and_or(b+(idx/8), char_with_bit_set(idx));
|
||||||
}
|
}
|
||||||
static inline void bit_clear(char* b, int idx) {
|
static inline void bit_clear(char* b, int idx) {
|
||||||
b[idx/8] &= ~char_with_bit_set(idx);
|
b[idx/8] &= ~char_with_bit_set(idx);
|
||||||
|
//__sync_fetch_and_nand(b+(idx/8), char_with_bit_set(idx));
|
||||||
}
|
}
|
||||||
static inline void bit_set_range(char* b, int from, int len) {
|
static inline void bit_set_range(char* b, int from, int len) {
|
||||||
for (; from%8 != 0 && len > 0; len--)
|
for (; from%8 != 0 && len > 0; len--)
|
||||||
@@ -67,5 +72,74 @@ static inline int bit_run_count(char* b, int from, int len) {
|
|||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct bitset_mapping {
|
||||||
|
uint64_t size;
|
||||||
|
int resolution;
|
||||||
|
char bits[];
|
||||||
|
};
|
||||||
|
|
||||||
|
static inline struct bitset_mapping* bitset_alloc(
|
||||||
|
uint64_t size,
|
||||||
|
int resolution
|
||||||
|
)
|
||||||
|
{
|
||||||
|
struct bitset_mapping *bitset = xmalloc(
|
||||||
|
sizeof(struct bitset_mapping)+
|
||||||
|
(size+resolution-1)/resolution
|
||||||
|
);
|
||||||
|
bitset->size = size;
|
||||||
|
bitset->resolution = resolution;
|
||||||
|
return bitset;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define INT_FIRST_AND_LAST \
|
||||||
|
int first = from/set->resolution, \
|
||||||
|
last = (from+len-1)/set->resolution, \
|
||||||
|
bitlen = last-first+1
|
||||||
|
|
||||||
|
static inline void bitset_set_range(
|
||||||
|
struct bitset_mapping* set,
|
||||||
|
uint64_t from,
|
||||||
|
uint64_t len)
|
||||||
|
{
|
||||||
|
INT_FIRST_AND_LAST;
|
||||||
|
bit_set_range(set->bits, first, bitlen);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void bitset_clear_range(
|
||||||
|
struct bitset_mapping* set,
|
||||||
|
uint64_t from,
|
||||||
|
uint64_t len)
|
||||||
|
{
|
||||||
|
INT_FIRST_AND_LAST;
|
||||||
|
bit_clear_range(set->bits, first, bitlen);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int bitset_run_count(
|
||||||
|
struct bitset_mapping* set,
|
||||||
|
uint64_t from,
|
||||||
|
uint64_t len)
|
||||||
|
{
|
||||||
|
INT_FIRST_AND_LAST;
|
||||||
|
return bit_run_count(set->bits, first, bitlen) * set->resolution;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int bitset_is_clear_at(
|
||||||
|
struct bitset_mapping* set,
|
||||||
|
uint64_t at
|
||||||
|
)
|
||||||
|
{
|
||||||
|
return bit_is_clear(set->bits, at/set->resolution);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int bitset_is_set_at(
|
||||||
|
struct bitset_mapping* set,
|
||||||
|
uint64_t at
|
||||||
|
)
|
||||||
|
{
|
||||||
|
return bit_is_set(set->bits, at/set->resolution);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
57
tests/check_bitset.c
Normal file
57
tests/check_bitset.c
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
#include <check.h>
|
||||||
|
|
||||||
|
#include "bitset.h"
|
||||||
|
|
||||||
|
START_TEST(test_bit_set)
|
||||||
|
{
|
||||||
|
unsigned char num;
|
||||||
|
char *bits = (char*) #
|
||||||
|
|
||||||
|
#define TEST_BIT_SET(bit, newvalue) \
|
||||||
|
bit_set(bits, (bit)); \
|
||||||
|
fail_unless(num == (newvalue), "num was %x instead of %x", num, (newvalue));
|
||||||
|
|
||||||
|
TEST_BIT_SET(0, 1);
|
||||||
|
TEST_BIT_SET(1, 3);
|
||||||
|
TEST_BIT_SET(2, 7);
|
||||||
|
TEST_BIT_SET(7, 0x87);
|
||||||
|
}
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
START_TEST(test_bit_clear)
|
||||||
|
{
|
||||||
|
unsigned char num = 255;
|
||||||
|
char *bits = (char*) #
|
||||||
|
|
||||||
|
#define TEST_BIT_CLEAR(bit, newvalue) \
|
||||||
|
bit_clear(bits, (bit)); \
|
||||||
|
fail_unless(num == (newvalue), "num was %x instead of %x", num, (newvalue));
|
||||||
|
|
||||||
|
TEST_BIT_CLEAR(0, 0xfe);
|
||||||
|
TEST_BIT_CLEAR(1, 0xfc);
|
||||||
|
TEST_BIT_CLEAR(2, 0xf8);
|
||||||
|
TEST_BIT_CLEAR(7, 0x78);
|
||||||
|
}
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
Suite* bitset_suite()
|
||||||
|
{
|
||||||
|
Suite *s = suite_create("bitset");
|
||||||
|
TCase *tc_core = tcase_create("bitset");
|
||||||
|
tcase_add_test(tc_core, test_bit_set);
|
||||||
|
tcase_add_test(tc_core, test_bit_clear);
|
||||||
|
suite_add_tcase(s, tc_core);
|
||||||
|
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
int number_failed;
|
||||||
|
Suite *s = bitset_suite();
|
||||||
|
SRunner *sr = srunner_create(s);
|
||||||
|
srunner_run_all(sr, CK_NORMAL);
|
||||||
|
number_failed = srunner_ntests_failed(sr);
|
||||||
|
srunner_free(sr);
|
||||||
|
return (number_failed == 0) ? 0 : 1;
|
||||||
|
}
|
1
util.h
1
util.h
@@ -24,6 +24,7 @@ void* xmalloc(size_t size);
|
|||||||
error(0, client->socket, msg, ##__VA_ARGS__)
|
error(0, client->socket, msg, ##__VA_ARGS__)
|
||||||
#define CLIENT_ERROR_ON_FAILURE(test, msg, ...) \
|
#define CLIENT_ERROR_ON_FAILURE(test, msg, ...) \
|
||||||
if (test < 0) { error(1, client->socket, msg, ##__VA_ARGS__); }
|
if (test < 0) { error(1, client->socket, msg, ##__VA_ARGS__); }
|
||||||
|
|
||||||
#define SERVER_ERROR(msg, ...) \
|
#define SERVER_ERROR(msg, ...) \
|
||||||
error(0, 0, msg, ##__VA_ARGS__)
|
error(0, 0, msg, ##__VA_ARGS__)
|
||||||
#define SERVER_ERROR_ON_FAILURE(test, msg, ...) \
|
#define SERVER_ERROR_ON_FAILURE(test, msg, ...) \
|
||||||
|
Reference in New Issue
Block a user