diff --git a/.github/workflows/cmake-multi-platform.yml b/.github/workflows/cmake-multi-platform.yml new file mode 100644 index 00000000..b00dc139 --- /dev/null +++ b/.github/workflows/cmake-multi-platform.yml @@ -0,0 +1,76 @@ +# This starter workflow is for a CMake project running on multiple platforms. There is a different starter workflow if you just want a single platform. +# See: https://github.com/actions/starter-workflows/blob/main/ci/cmake-single-platform.yml +name: CMake on multiple platforms + +on: + push: + branches: [ "master" ] + pull_request: + branches: [ "master" ] + +jobs: + build: + runs-on: ${{ matrix.os }} + + strategy: + # Set fail-fast to false to ensure that feedback is delivered for all matrix combinations. Consider changing this to true when your workflow is stable. + fail-fast: false + + # Set up a matrix to run the following 3 configurations: + # 1. + # 2. + # 3. + # + # To add more build types (Release, Debug, RelWithDebInfo, etc.) customize the build_type list. + # todo: add windows-latest + matrix: + os: [ubuntu-latest] + build_type: [Release, Debug] + c_compiler: [gcc, clang, cl] + include: + # - os: windows-latest + # c_compiler: cl + # cpp_compiler: cl + - os: ubuntu-latest + c_compiler: gcc + cpp_compiler: g++ + - os: ubuntu-latest + c_compiler: clang + cpp_compiler: clang++ + exclude: + # - os: windows-latest + # c_compiler: gcc + # - os: windows-latest + # c_compiler: clang + - os: ubuntu-latest + c_compiler: cl + + steps: + - uses: actions/checkout@v4 + + - name: Set reusable strings + # Turn repeated input strings (such as the build output directory) into step outputs. These step outputs can be used throughout the workflow file. + id: strings + shell: bash + run: | + echo "build-output-dir=${{ github.workspace }}/build" >> "$GITHUB_OUTPUT" + + - name: Configure CMake + # Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only required if you are using a single-configuration generator such as make. + # See https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html?highlight=cmake_build_type + run: > + cmake -B ${{ steps.strings.outputs.build-output-dir }} + -DCMAKE_CXX_COMPILER=${{ matrix.cpp_compiler }} + -DCMAKE_C_COMPILER=${{ matrix.c_compiler }} + -DCMAKE_BUILD_TYPE=${{ matrix.build_type }} + -S ${{ github.workspace }} + + - name: Build + # Build your program with the given configuration. Note that --config is needed because the default Windows generator is a multi-config generator (Visual Studio generator). + run: cmake --build ${{ steps.strings.outputs.build-output-dir }} --config ${{ matrix.build_type }} + + - name: Test + working-directory: ${{ steps.strings.outputs.build-output-dir }} + # Execute tests defined by the CMake configuration. Note that --build-config is needed because the default Windows generator is a multi-config generator (Visual Studio generator). + # See https://cmake.org/cmake/help/latest/manual/ctest.1.html for more detail + run: ctest --build-config ${{ matrix.build_type }} diff --git a/.github/workflows/cmake-single-platform.yml b/.github/workflows/cmake-single-platform.yml deleted file mode 100644 index 4bd1c79b..00000000 --- a/.github/workflows/cmake-single-platform.yml +++ /dev/null @@ -1,39 +0,0 @@ -# This starter workflow is for a CMake project running on a single platform. There is a different starter workflow if you need cross-platform coverage. -# See: https://github.com/actions/starter-workflows/blob/main/ci/cmake-multi-platform.yml -name: CMake on a single platform - -on: - push: - branches: [ "master" ] - pull_request: - branches: [ "master" ] - -env: - # Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.) - BUILD_TYPE: Release - -jobs: - build: - # The CMake configure and build commands are platform agnostic and should work equally well on Windows or Mac. - # You can convert this to a matrix build if you need cross-platform coverage. - # See: https://docs.github.com/en/free-pro-team@latest/actions/learn-github-actions/managing-complex-workflows#using-a-build-matrix - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v4 - - - name: Configure CMake - # Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only required if you are using a single-configuration generator such as make. - # See https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html?highlight=cmake_build_type - run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} - - - name: Build - # Build your program with the given configuration - run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} - - - name: Test - working-directory: ${{github.workspace}}/build - # Execute tests defined by the CMake configuration. - # See https://cmake.org/cmake/help/latest/manual/ctest.1.html for more detail - run: ctest -C ${{env.BUILD_TYPE}} - diff --git a/src/fifo.c b/src/fifo.c index 01f5449a..60152a67 100644 --- a/src/fifo.c +++ b/src/fifo.c @@ -1,7 +1,6 @@ #define _GNU_SOURCE // For distros like Centos for syscall interface #include #include -#include #include #include #include @@ -100,8 +99,8 @@ struct fifo *fifo_create(unsigned int size) fifo->memfd = fd; fifo->base_addr = base_addr; fifo->base_addr_len = total_page_map_size; - fifo->in = 0; - fifo->out = 0; + atomic_init(&fifo->in, 0); + atomic_init(&fifo->out, 0); fifo->mask = data_page_p2_size - 1; return fifo; @@ -126,55 +125,22 @@ void fifo_destroy(struct fifo *fifo) close(fd); } -char *fifo_in_ref(struct fifo *fifo, unsigned int size) -{ - unsigned int free_size = - fifo_size(fifo) - (fifo->in - atomic_load_explicit(&fifo->out, memory_order_acquire)); - if (size > free_size) { - /* zc_error("fifo not enough space"); */ - return NULL; - } - - return &fifo->data[fifo->in & fifo->mask]; -} - -void fifo_in_commit(struct fifo *fifo, unsigned int size) -{ - assert(fifo_unused(fifo) >= size); - atomic_store_explicit(&fifo->in, fifo->in + size, memory_order_release); -} - -unsigned int fifo_out_ref(struct fifo *fifo, char **buf) -{ - unsigned int used_size = atomic_load_explicit(&fifo->in, memory_order_acquire) - fifo->out; - if (used_size == 0) - return 0; - - *buf = &fifo->data[fifo->out & fifo->mask]; - return used_size; -} - -void fifo_out_commit(struct fifo *fifo, unsigned int size) -{ - assert(size <= fifo_used(fifo)); - atomic_store_explicit(&fifo->out, fifo->out + size, memory_order_release); -} - struct msg_head *fifo_reserve(struct fifo *fifo, unsigned int size) { + unsigned old_in = atomic_load_explicit(&fifo->in, memory_order_relaxed); unsigned int free_size = - fifo_size(fifo) - (fifo->in - atomic_load_explicit(&fifo->out, memory_order_acquire)); + fifo_size(fifo) - (old_in - atomic_load_explicit(&fifo->out, memory_order_acquire)); unsigned total_size = size + msg_head_size(); if (total_size > free_size) { zc_error("fifo not enough space"); return NULL; } - struct msg_head *head = (struct msg_head *)&fifo->data[fifo->in & fifo->mask]; + struct msg_head *head = (struct msg_head *)&fifo->data[old_in & fifo->mask]; head->total_size = total_size; - head->flags = MSG_HEAD_FLAG_RESERVED; + atomic_load_explicit(&head->flags, memory_order_relaxed); - atomic_store_explicit(&fifo->in, fifo->in + total_size, memory_order_release); + atomic_store_explicit(&fifo->in, old_in + total_size, memory_order_release); return head; } @@ -196,16 +162,18 @@ void fifo_discard(struct fifo *fifo, struct msg_head *head) struct msg_head *fifo_peek(struct fifo *fifo) { - unsigned int used_size = atomic_load_explicit(&fifo->in, memory_order_acquire) - fifo->out; + unsigned out = atomic_load_explicit(&fifo->out, memory_order_relaxed); + unsigned int used_size = atomic_load_explicit(&fifo->in, memory_order_acquire) - out; if (used_size == 0) return NULL; - struct msg_head *head = (struct msg_head *)&fifo->data[fifo->out & fifo->mask]; + struct msg_head *head = (struct msg_head *)&fifo->data[out & fifo->mask]; return head; } void fifo_out(struct fifo *fifo, struct msg_head *head) { - atomic_store_explicit(&fifo->out, fifo->out + head->total_size, memory_order_release); + unsigned out = atomic_load_explicit(&fifo->out, memory_order_relaxed); + atomic_store_explicit(&fifo->out, out + head->total_size, memory_order_release); } diff --git a/src/fifo.h b/src/fifo.h index 165371e0..3934b966 100644 --- a/src/fifo.h +++ b/src/fifo.h @@ -1,6 +1,7 @@ #ifndef __FIFO_H #define __FIFO_H +#include #include /* todo: optimize page size macro */ @@ -23,8 +24,8 @@ struct fifo { unsigned char *base_addr; unsigned base_addr_len; - unsigned in; - unsigned out; + atomic_uint in; + atomic_uint out; unsigned mask; int memfd; _Alignas(PAGE_SIZE) char data[]; @@ -33,12 +34,6 @@ struct fifo { struct fifo *fifo_create(unsigned int size); void fifo_destroy(struct fifo *fifo); -char *fifo_in_ref(struct fifo *fifo, unsigned int size); -void fifo_in_commit(struct fifo *fifo, unsigned int size); - -unsigned int fifo_out_ref(struct fifo *fifo, char **buf); -void fifo_out_commit(struct fifo *fifo, unsigned int size); - /** * fifo_in_reserve - * @@ -58,7 +53,8 @@ static inline size_t fifo_size(struct fifo *fifo) static inline unsigned int fifo_used(struct fifo *fifo) { - return fifo->in - fifo->out; + return atomic_load_explicit(&fifo->in, memory_order_relaxed) - + atomic_load_explicit(&fifo->out, memory_order_relaxed); } static inline unsigned int fifo_unused(struct fifo *fifo) diff --git a/src/misc.h b/src/misc.h index 571aa9fc..d82b592d 100644 --- a/src/misc.h +++ b/src/misc.h @@ -3,6 +3,7 @@ #include #include +#include #include #define container_of(ptr, type, member) ((type *)((char *)(ptr) - offsetof(type, member))) @@ -33,7 +34,7 @@ enum msg_head_flag { struct msg_head { unsigned total_size; - unsigned flags; + atomic_uint flags; char data[]; }; diff --git a/src/thread.c b/src/thread.c index 0f520aa9..68e6e6b9 100644 --- a/src/thread.c +++ b/src/thread.c @@ -63,7 +63,8 @@ void zlog_thread_del(zlog_thread_t * a_thread) zc_debug("fullcnt %d\n", a_thread->producer.full_cnt); } zc_debug("zlog_thread_del[%lx], producer en %d, cnt %d", a_thread->event->tid, - a_thread->producer.en, a_thread->producer.refcnt); + a_thread->producer.en, + atomic_load_explicit(&a_thread->producer.refcnt, memory_order_relaxed)); if (a_thread->mdc) zlog_mdc_del(a_thread->mdc); if (a_thread->event) @@ -142,7 +143,8 @@ zlog_thread_t *zlog_thread_new(int init_version, size_t buf_size_min, size_t buf if (conf->log_consumer.en) { a_thread->producer.en = true; atomic_init(&a_thread->producer.refcnt, 1); - zc_debug("init %lx, refcnt %d", pthread_self(), a_thread->producer.refcnt); + zc_debug("init %lx, refcnt %d", pthread_self(), + atomic_load_explicit(&a_thread->producer.refcnt, memory_order_relaxed)); } // zlog_thread_profile(a_thread, ZC_DEBUG); @@ -226,5 +228,6 @@ void zlog_thread_rebuild_producer(zlog_thread_t * thread, bool en) thread->producer.en = en; thread->producer.full_cnt = 0; atomic_init(&thread->producer.refcnt, 1); - zc_debug("init %lx, refcnt %d", pthread_self(), thread->producer.refcnt); + zc_debug("init %lx, refcnt %d", pthread_self(), + atomic_load_explicit(&thread->producer.refcnt, memory_order_relaxed)); } diff --git a/src/thread.h b/src/thread.h index 1d54670b..0cbfeca2 100644 --- a/src/thread.h +++ b/src/thread.h @@ -16,6 +16,7 @@ #ifndef __zlog_thread_h #define __zlog_thread_h +#include #include #include "zc_defs.h" @@ -44,7 +45,7 @@ typedef struct zlog_thread_s { struct { /* change per conf start */ bool en; - int refcnt; + atomic_int refcnt; /* change per conf end */ unsigned int full_cnt; } producer;