Commit d6286506 authored by Hanspeter Portner's avatar Hanspeter Portner

Squashed 'varchunk/' changes from 7a418eed..9201fa96

9201fa96 meson: reduce iterations in unit test.
bbf8fb88 increase test timeout in gitlab CI recipe.
03da9f79 fix last commit.
dbe21852 fix gitlab CI recipe for mingw32 testing.
5697f8c2 use gitlab CI provided meson cross scripts.
d148bbaa fix test on mingw.
8da75979 meson: conditionally link test against librt.
e4421424 remove artifacts from gitlab CI recipe.
fa8cf43f some code cleanup.
a4f7da9e remove travis CI recipe, fix gitlab CI recipe.
c6c39426 fix gitlab CI recipe.
8a09a709 fix pedantic compiler warnings.
2bdfe845 initial migration to meson.

git-subtree-dir: varchunk
git-subtree-split: 9201fa969a3a19f97c09186df18f8e3b07873531
parent 477b129a
stages:
- test
.variables_template: &variables_definition
variables:
BASE_NAME: "varchunk"
PKG_CONFIG_PATH: "/opt/lv2/lib/pkgconfig:/opt/${CI_BUILD_NAME}/lib/pkgconfig:/usr/lib/${CI_BUILD_NAME}/pkgconfig"
.common_template: &common_definition
<<: *variables_definition
stage: test
.build_template: &build_definition
<<: *common_definition
script:
- meson --cross-file "${CI_BUILD_NAME}" build
- ninja -C build
.test_template: &test_definition
<<: *common_definition
script:
- meson --cross-file "${CI_BUILD_NAME}" build
- ninja -C build
- cd build
- meson test --verbose --wrap "${CI_BUILD_NAME}.wrap"
.universal_linux_template: &universal_linux_definition
image: ventosus/universal-linux-gnu
<<: *test_definition
.arm_linux_template: &arm_linux_definition
image: ventosus/arm-linux-gnueabihf
<<: *test_definition
.universal_w64_template: &universal_w64_definition
image: ventosus/universal-w64-mingw32
before_script:
- ln -s /usr/i686-w64-mingw32/lib/libwinpthread-1.dll /opt/i686-w64-mingw32/lib/libwinpthread-1.dll
- ln -s /usr/x86_64-w64-mingw32/lib/libwinpthread-1.dll /opt/x86_64-w64-mingw32/lib/libwinpthread-1.dll
<<: *test_definition
.universal_apple_template: &universal_apple_definition
image: ventosus/universal-apple-darwin
<<: *build_definition
# building in docker
x86_64-linux-gnu:
<<: *universal_linux_definition
i686-linux-gnu:
<<: *universal_linux_definition
arm-linux-gnueabihf:
<<: *arm_linux_definition
x86_64-w64-mingw32:
<<: *universal_w64_definition
i686-w64-mingw32:
<<: *universal_w64_definition
universal-apple-darwin:
<<: *universal_apple_definition
language: c
os: linux
compiler:
- gcc
- clang
before_install:
- if [ "$CC" = "clang" ]; then sudo add-apt-repository -y ppa:h-rayflood/llvm-upper; fi
- sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test
- sudo apt-get -q update
install:
- if [ "$CC" = "clang" ]; then sudo apt-get install -y clang-3.6 libstdc++-5-dev; fi
- if [ "$CC" = "gcc" ]; then sudo apt-get install -y gcc-5 g++-5; fi
before_script:
- if [ "$CC" = "clang" ]; then export CXX="clang++-3.6" CC="clang-3.6" CFLAGS="-ffreestanding"; fi
- if [ "$CC" = "gcc" ]; then export CXX="g++-5" CC="gcc-5"; fi
- mkdir build && pushd build && cmake -DBUILD_TESTING=1 -DCMAKE_BUILD_TYPE=Debug .. && popd
script:
- pushd build && make && ARGS="-VV" make test && popd
cmake_minimum_required(VERSION 2.8)
project(varchunk)
set(CMAKE_C_FLAGS "-std=gnu11 -Wextra -Wno-unused-parameter -ffast-math -fvisibility=hidden ${CMAKE_C_FLAGS}")
set(CMAKE_C_FLAGS "-Wshadow -Wimplicit-function-declaration -Wmissing-prototypes -Wstrict-prototypes ${CMAKE_C_FLAGS}")
include_directories(${CMAKE_CURRENT_SOURCE_DIR})
# find pthreads
set(THREADS_PREFER_PTHREAD_FLAG ON)
find_package(Threads REQUIRED)
include(CTest)
if(${BUILD_TESTING})
add_executable(test_varchunk
test_varchunk.c)
target_link_libraries(test_varchunk ${CMAKE_THREAD_LIBS_INIT} rt)
add_test(API-Test test_varchunk)
endif()
......@@ -13,79 +13,86 @@
### Build Status
[![Build Status](https://travis-ci.org/OpenMusicKontrollers/varchunk.svg)](https://travis-ci.org/OpenMusicKontrollers/varchunk)
[![build status](https://gitlab.com/OpenMusicKontrollers/varchunk/badges/master/build.svg)](https://gitlab.com/OpenMusicKontrollers/varchunk/commits/master)
### Usage
### Build / test
git clone https://git.open-music-kontrollers.ch/lad/varchunk
cd varchunk
meson build
cd build
ninja -j4
ninja test
``` c
#include <pthread.h>
#include <varchunk.h>
### Usage
static void *
producer_main(void *arg)
{
varchunk_t *varchunk = arg;
void *ptr;
const size_t towrite = sizeof(uint32_t);
uint32_t counter = 0;
#include <pthread.h>
#include <varchunk.h>
while(counter <= 1000000)
static void *
producer_main(void *arg)
{
if( (ptr = varchunk_write_request(varchunk, towrite)) )
varchunk_t *varchunk = arg;
void *ptr;
const size_t towrite = sizeof(uint32_t);
uint32_t counter = 0;
while(counter <= 1000000)
{
// write 'towrite' bytes to 'ptr'
*(uint32_t *)ptr = counter++;
varchunk_write_advance(varchunk, towrite);
if( (ptr = varchunk_write_request(varchunk, towrite)) )
{
// write 'towrite' bytes to 'ptr'
*(uint32_t *)ptr = counter++;
varchunk_write_advance(varchunk, towrite);
}
}
}
return NULL;
}
static void *
consumer_main(void *arg)
{
varchunk_t *varchunk = arg;
const void *ptr;
size_t toread;
return NULL;
}
while(1)
static void *
consumer_main(void *arg)
{
if( (ptr = varchunk_read_request(varchunk, &toread)) )
varchunk_t *varchunk = arg;
const void *ptr;
size_t toread;
while(1)
{
// read 'toread' bytes from 'ptr'
if(*(uint32_t *)ptr >= 1000000)
break;
varchunk_read_advance(varchunk);
if( (ptr = varchunk_read_request(varchunk, &toread)) )
{
// read 'toread' bytes from 'ptr'
if(*(uint32_t *)ptr >= 1000000)
break;
varchunk_read_advance(varchunk);
}
}
}
return NULL;
}
return NULL;
}
int
main(int argc, char **argv)
{
if(!varchunk_is_lock_free())
return -1;
int
main(int argc, char **argv)
{
if(!varchunk_is_lock_free())
return -1;
pthread_t producer;
pthread_t consumer;
varchunk_t *varchunk = varchunk_new(8192, true);
if(!varchunk)
return -1;
pthread_t producer;
pthread_t consumer;
varchunk_t *varchunk = varchunk_new(8192, true);
if(!varchunk)
return -1;
pthread_create(&consumer, NULL, consumer_main, varchunk);
pthread_create(&producer, NULL, producer_main, varchunk);
pthread_create(&consumer, NULL, consumer_main, varchunk);
pthread_create(&producer, NULL, producer_main, varchunk);
pthread_join(producer, NULL);
pthread_join(consumer, NULL);
pthread_join(producer, NULL);
pthread_join(consumer, NULL);
varchunk_free(varchunk);
varchunk_free(varchunk);
return 0;
}
```
return 0;
}
### License
......
0.1.67
project('varchunk', 'c', default_options : [
'buildtype=release',
'warning_level=3',
'werror=true',
'b_lto=true',
'c_std=c11'])
version = run_command('cat', 'VERSION').stdout().strip()
add_project_arguments('-D_GNU_SOURCE', language : 'c')
conf_data = configuration_data()
cc = meson.get_compiler('c')
thread_dep = dependency('threads')
deps = [thread_dep]
if host_machine.system() == 'linux'
rt_dep = cc.find_library('rt')
deps += rt_dep
endif
test_varchunk = executable('test_varchunk',
'test_varchunk.c',
dependencies : deps,
install : false)
test('Test', test_varchunk,
args : ['100000'],
timeout : 360) # seconds
......@@ -30,49 +30,48 @@
# include <fcntl.h>
# include <string.h>
# define VARCHUNK_USE_SHARED_MEM
#endif
#define ITERATIONS 10000000
#define THRESHOLD (RAND_MAX / 256)
static const struct timespec req = {
.tv_sec = 0,
.tv_nsec = 1
};
#endif
typedef struct _varchunk_shm_t varchunk_shm_t;
struct _varchunk_shm_t {
char *name;
int fd;
varchunk_t *varchunk;
};
static uint64_t iterations = 10000000;
#define THRESHOLD (RAND_MAX / 256)
#define PAD(SIZE) ( ( (size_t)(SIZE) + 7U ) & ( ~7U ) )
static void *
producer_main(void *arg)
{
varchunk_t *varchunk = arg;
void *ptr;
const void *end;
uint8_t *ptr;
const uint8_t *end;
size_t written;
uint64_t cnt = 0;
while(cnt < ITERATIONS)
while(cnt < iterations)
{
#if !defined(_WIN32)
if(rand() < THRESHOLD)
{
nanosleep(&req, NULL);
}
#endif
written = rand() * 1024.f / RAND_MAX;
written = PAD(rand() * 1024.f / RAND_MAX);
size_t maximum;
if( (ptr = varchunk_write_request_max(varchunk, written, &maximum)) )
{
assert(maximum >= written);
end = ptr + written;
for(void *src=ptr; src<end; src+=sizeof(uint64_t))
for(uint8_t *src=ptr; src<end; src+=sizeof(uint64_t))
{
*(uint64_t *)src = cnt;
assert(*(uint64_t *)src == cnt);
}
varchunk_write_advance(varchunk, written);
//fprintf(stdout, "P %"PRIu64" %zu %zu\n", cnt, written, maximum);
cnt++;
}
else
......@@ -88,23 +87,28 @@ static void *
consumer_main(void *arg)
{
varchunk_t *varchunk = arg;
const void *ptr;
const void *end;
const uint8_t *ptr;
const uint8_t *end;
size_t toread;
uint64_t cnt = 0;
while(cnt < ITERATIONS)
while(cnt < iterations)
{
#if !defined(_WIN32)
if(rand() < THRESHOLD)
{
nanosleep(&req, NULL);
}
#endif
if( (ptr = varchunk_read_request(varchunk, &toread)) )
{
end = ptr + toread;
for(const void *src=ptr; src<end; src+=sizeof(uint64_t))
for(const uint8_t *src=ptr; src<end; src+=sizeof(uint64_t))
{
assert(*(const uint64_t *)src == cnt);
}
varchunk_read_advance(varchunk);
//fprintf(stdout, "C %"PRIu64" %zu\n", cnt, toread);
cnt++;
}
else
......@@ -133,6 +137,15 @@ test_threaded()
varchunk_free(varchunk);
}
#if defined(VARCHUNK_USE_SHARED_MEM)
typedef struct _varchunk_shm_t varchunk_shm_t;
struct _varchunk_shm_t {
char *name;
int fd;
varchunk_t *varchunk;
};
static int
varchunk_shm_init(varchunk_shm_t *varchunk_shm, const char *name, size_t minimum, bool release_and_acquire)
{
......@@ -141,7 +154,9 @@ varchunk_shm_init(varchunk_shm_t *varchunk_shm, const char *name, size_t minimum
varchunk_shm->name = strdup(name);
if(!varchunk_shm->name)
{
return -1;
}
bool is_first = true;
varchunk_shm->fd = shm_open(varchunk_shm->name, O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR);
......@@ -167,7 +182,9 @@ varchunk_shm_init(varchunk_shm_t *varchunk_shm, const char *name, size_t minimum
}
if(is_first)
{
varchunk_init(varchunk_shm->varchunk, body_size, release_and_acquire);
}
return 0;
}
......@@ -183,13 +200,14 @@ varchunk_shm_deinit(varchunk_shm_t *varchunk_shm)
free(varchunk_shm->name);
}
#if defined(VARCHUNK_USE_SHARED_MEM)
static void
test_shared()
{
const char *name = "/varchunk_shm_test";
pid_t pid = fork();
assert(pid != -1);
if(pid == 0) // child
{
varchunk_shm_t varchunk_shm;
......@@ -214,8 +232,15 @@ test_shared()
int
main(int argc, char **argv)
{
#if !defined(_WIN32)
const int seed = time(NULL);
srand(seed);
#endif
if(argc >= 2)
{
iterations = atoi(argv[1]);
}
assert(varchunk_is_lock_free());
......
......@@ -93,7 +93,7 @@ struct _varchunk_t {
atomic_size_t head;
atomic_size_t tail;
uint8_t buf [0] __attribute__((aligned(sizeof(varchunk_elmnt_t))));
uint8_t buf [] __attribute__((aligned(sizeof(varchunk_elmnt_t))));
};
static inline bool
......@@ -195,13 +195,13 @@ varchunk_write_request_max(varchunk_t *varchunk, size_t minimum, size_t *maximum
if(end > varchunk->size) // available region wraps over at end of buffer
{
// get first part of available buffer
void *buf1 = varchunk->buf + head;
uint8_t *buf1 = varchunk->buf + head;
const size_t len1 = varchunk->size - head;
if(len1 < padded) // not enough space left on first part of buffer
{
// get second part of available buffer
void *buf2 = varchunk->buf;
uint8_t *buf2 = varchunk->buf;
const size_t len2 = end & varchunk->mask;
if(len2 < padded) // not enough space left on second buffer, either
......@@ -232,7 +232,7 @@ varchunk_write_request_max(varchunk_t *varchunk, size_t minimum, size_t *maximum
}
else // available region is contiguous
{
void *buf = varchunk->buf + head;
uint8_t *buf = varchunk->buf + head;
if(space < padded) // no space left on contiguous buffer
{
......@@ -271,7 +271,7 @@ varchunk_write_advance(varchunk_t *varchunk, size_t written)
if(varchunk->gapd > 0)
{
// fill end of first buffer with gap
varchunk_elmnt_t *elmnt = (void *)varchunk->buf + head;
varchunk_elmnt_t *elmnt = (varchunk_elmnt_t *)(varchunk->buf + head);
elmnt->size = varchunk->gapd - sizeof(varchunk_elmnt_t);
elmnt->gap = 1;
......@@ -283,7 +283,7 @@ varchunk_write_advance(varchunk_t *varchunk, size_t written)
else // varchunk->gapd == 0
{
// fill written element header
varchunk_elmnt_t *elmnt = (void *)varchunk->buf + head;
varchunk_elmnt_t *elmnt = (varchunk_elmnt_t *)(varchunk->buf + head);
elmnt->size = written;
elmnt->gap = 0;
}
......@@ -322,9 +322,9 @@ varchunk_read_request(varchunk_t *varchunk, size_t *toread)
if(end > varchunk->size) // available buffer wraps around at end
{
// first part of available buffer
const void *buf1 = varchunk->buf + tail;
const uint8_t *buf1 = varchunk->buf + tail;
const size_t len1 = varchunk->size - tail;
const varchunk_elmnt_t *elmnt = buf1;
const varchunk_elmnt_t *elmnt = (const varchunk_elmnt_t *)buf1;
if(elmnt->gap) // gap elmnt?
{
......@@ -332,8 +332,9 @@ varchunk_read_request(varchunk_t *varchunk, size_t *toread)
_varchunk_read_advance_raw(varchunk, tail, len1);
// second part of available buffer
const void *buf2 = varchunk->buf;
elmnt = buf2; // there will always be at least on element after a gap
const uint8_t *buf2 = varchunk->buf;
// there will always be at least on element after a gap
elmnt = (const varchunk_elmnt_t *)buf2;
*toread = elmnt->size;
return buf2 + sizeof(varchunk_elmnt_t);
......@@ -347,8 +348,8 @@ varchunk_read_request(varchunk_t *varchunk, size_t *toread)
else // available buffer is contiguous
{
// get buffer
const void *buf = varchunk->buf + tail;
const varchunk_elmnt_t *elmnt = buf;
const uint8_t *buf = varchunk->buf + tail;
const varchunk_elmnt_t *elmnt = (const varchunk_elmnt_t *)buf;
*toread = elmnt->size;
return buf + sizeof(varchunk_elmnt_t);
......@@ -367,7 +368,7 @@ varchunk_read_advance(varchunk_t *varchunk)
assert(varchunk);
// get elmnt header from tail (for size)
const size_t tail = atomic_load_explicit(&varchunk->tail, memory_order_relaxed);
const varchunk_elmnt_t *elmnt = (const void *)varchunk->buf + tail;
const varchunk_elmnt_t *elmnt = (const varchunk_elmnt_t *)(varchunk->buf + tail);
// advance read tail
_varchunk_read_advance_raw(varchunk, tail,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment