diff --git a/.github/workflows/auto-pr-autodelete.yml b/.github/workflows/auto-pr-autodelete.yml index 8ea28010..21bdfc58 100644 --- a/.github/workflows/auto-pr-autodelete.yml +++ b/.github/workflows/auto-pr-autodelete.yml @@ -15,6 +15,7 @@ jobs: - uses: actions/checkout@v4 with: fetch-depth: 0 + token: ${{ secrets.AUTOPR_SECRET }} - name: set git config run: | diff --git a/.github/workflows/ci.linux.arm.yml b/.github/workflows/ci.linux.arm.yml index ff262255..ad645838 100644 --- a/.github/workflows/ci.linux.arm.yml +++ b/.github/workflows/ci.linux.arm.yml @@ -7,8 +7,8 @@ on: branches: [ "main", "release/*" ] jobs: - gcc921: - runs-on: [self-hosted, Linux, ARM64] + arm-linux-build-and-test: + runs-on: ubuntu-24.04-arm container: image: ghcr.io/alibaba/photon-ut-base:latest @@ -23,7 +23,7 @@ jobs: - uses: actions/checkout@v4 - - name: Build + - name: Build-Debug-921-C++14 run: | source /opt/rh/gcc-toolset-9/enable cmake -B build -D CMAKE_BUILD_TYPE=MinSizeRel \ @@ -36,6 +36,7 @@ jobs: -D PHOTON_ENABLE_EXTFS=ON cmake --build build -j $(nproc) +<<<<<<< HEAD - name: Test run: | cd build @@ -50,11 +51,15 @@ jobs: steps: - uses: actions/checkout@v4 - name: Build +======= + - name: Build-Debug-921-C++17 +>>>>>>> aaabc01 (make it compiles with C++17/20/23) run: | dnf install -y 'dnf-command(config-manager)' dnf config-manager --set-enabled powertools dnf -q -y install git gcc-c++ cmake gcc-toolset-9-gcc-c++ nasm source /opt/rh/gcc-toolset-9/enable +<<<<<<< HEAD cmake -B build -D CMAKE_BUILD_TYPE=Debug \ -D PHOTON_BUILD_DEPENDENCIES=ON \ -D PHOTON_BUILD_TESTING=ON \ @@ -65,3 +70,51 @@ jobs: -D PHOTON_ENABLE_LIBCURL=OFF \ -D PHOTON_ENABLE_EXTFS=OFF cmake --build build -j $(nproc) +======= + rm -fr build + cmake -B build \ + -D PHOTON_CXX_STANDARD=17 \ + -D CMAKE_BUILD_TYPE=Debug \ + -D PHOTON_ENABLE_ECOSYSTEM=ON \ + -D PHOTON_BUILD_TESTING=ON \ + -D PHOTON_ENABLE_SASL=ON \ + -D PHOTON_ENABLE_FUSE=ON \ + -D PHOTON_ENABLE_LIBCURL=ON \ + -D PHOTON_ENABLE_EXTFS=ON + cmake --build build -j $(nproc) -- VERBOSE=1 + + - name: Build-Debug-1121-C++20 + run: | + source /opt/rh/gcc-toolset-11/enable + rm -fr build + cmake -B build \ + -D PHOTON_CXX_STANDARD=20 \ + -D CMAKE_BUILD_TYPE=Debug \ + -D PHOTON_ENABLE_ECOSYSTEM=ON \ + -D PHOTON_BUILD_TESTING=ON \ + -D PHOTON_ENABLE_SASL=ON \ + -D PHOTON_ENABLE_FUSE=ON \ + -D PHOTON_ENABLE_LIBCURL=ON \ + -D PHOTON_ENABLE_EXTFS=ON + cmake --build build -j $(nproc) -- VERBOSE=1 + + - name: Build-Debug-1211-C++23 + run: | + source /opt/rh/gcc-toolset-12/enable + rm -fr build + cmake -B build \ + -D PHOTON_CXX_STANDARD=23 \ + -D CMAKE_BUILD_TYPE=Debug \ + -D PHOTON_ENABLE_ECOSYSTEM=ON \ + -D PHOTON_BUILD_TESTING=ON \ + -D PHOTON_ENABLE_SASL=ON \ + -D PHOTON_ENABLE_FUSE=ON \ + -D PHOTON_ENABLE_LIBCURL=ON \ + -D PHOTON_ENABLE_EXTFS=ON + cmake --build build -j $(nproc) -- VERBOSE=1 + + - name: Test + run: | + cd build + ctest -E test-lockfree --timeout 3600 -V +>>>>>>> aaabc01 (make it compiles with C++17/20/23) diff --git a/common/consistent-hash-map.h b/common/consistent-hash-map.h index b108a4e3..3e953141 100644 --- a/common/consistent-hash-map.h +++ b/common/consistent-hash-map.h @@ -55,10 +55,10 @@ class consistent_hash_map const allocator_type& alloc = allocator_type()) : m_comp(comp), m_vector(alloc) { } - using reference = typename allocator_type::reference; - using const_reference = typename allocator_type::const_reference; - using pointer = typename allocator_type::pointer; - using const_pointer = typename allocator_type::const_pointer; + using reference = mapped_type&; + using const_reference = const mapped_type&; + using pointer = mapped_type*; + using const_pointer = const mapped_type*; using container_type = std::vector; using iterator = typename container_type::iterator; using const_iterator = typename container_type::const_iterator; diff --git a/common/enumerable.h b/common/enumerable.h index ab86c4e7..312f2d9b 100644 --- a/common/enumerable.h +++ b/common/enumerable.h @@ -41,7 +41,12 @@ struct Enumerable if (obj && !obj->valid()) this->obj = nullptr; } +#if __cplusplus < 201703L using R = typename std::result_of::type; +#else + using R = typename std::invoke_result::type; +#endif + R operator*() { return obj ? obj->get() : R{}; } bool operator==(const iterator& rhs) const { return obj == rhs.obj; } bool operator!=(const iterator& rhs) const { return !(*this == rhs); } diff --git a/common/executor/executor.h b/common/executor/executor.h index 7c681185..49a701cf 100644 --- a/common/executor/executor.h +++ b/common/executor/executor.h @@ -41,7 +41,11 @@ class Executor { template < typename Context = AutoContext, typename Func, +#if __cplusplus < 201703L typename R = typename std::result_of::type, +#else + typename R = typename std::invoke_result::type, +#endif typename _ = typename std::enable_if::value, R>::type> R perform(Func &&act) { R result; @@ -60,7 +64,11 @@ class Executor { template < typename Context = AutoContext, typename Func, +#if __cplusplus < 201703L typename R = typename std::result_of::type, +#else + typename R = typename std::invoke_result::type, +#endif typename _ = typename std::enable_if::value, R>::type> void perform(Func &&act) { Awaiter aop; diff --git a/common/expirecontainer.h b/common/expirecontainer.h index 11557378..74cea369 100644 --- a/common/expirecontainer.h +++ b/common/expirecontainer.h @@ -463,3 +463,4 @@ class ObjectCache> Base::release(typename Base::Item(key), recycle, destroy)); } }; + diff --git a/common/test/test.cpp b/common/test/test.cpp index 9303dcf0..9a4b64b3 100644 --- a/common/test/test.cpp +++ b/common/test/test.cpp @@ -509,7 +509,7 @@ TEST(iovector, test1) EXPECT_EQ(iov.sum(), 0); EXPECT_TRUE(iov.empty()); EXPECT_EQ(iov.front_free_iovcnt(), IOVector::default_preserve); - EXPECT_EQ(iov.back_free_iovcnt(), IOVector::capacity - IOVector::default_preserve); + EXPECT_EQ(iov.back_free_iovcnt(), (uint16_t)IOVector::capacity - (uint16_t)IOVector::default_preserve); EXPECT_EQ(iov.begin(), iov.iovec()); iovec v{nullptr, 33}, v2{nullptr, 44}; @@ -525,7 +525,7 @@ TEST(iovector, test1) EXPECT_EQ(iov.back(), v); EXPECT_EQ(iov.iovcnt(), 3); EXPECT_EQ(iov.front_free_iovcnt(), IOVector::default_preserve - 3); - EXPECT_EQ(iov.back_free_iovcnt(), IOVector::capacity - IOVector::default_preserve); + EXPECT_EQ(iov.back_free_iovcnt(), (uint16_t)IOVector::capacity - (uint16_t)IOVector::default_preserve); EXPECT_EQ(iov.sum(), 44+55+33); iov.push_back(77); @@ -540,7 +540,7 @@ TEST(iovector, test1) EXPECT_EQ(iov.back(), v); EXPECT_EQ(iov.iovcnt(), 6); EXPECT_EQ(iov.front_free_iovcnt(), IOVector::default_preserve - 3); - EXPECT_EQ(iov.back_free_iovcnt(), IOVector::capacity - IOVector::default_preserve - 3); + EXPECT_EQ(iov.back_free_iovcnt(), (uint16_t)IOVector::capacity - (uint16_t)IOVector::default_preserve - 3); EXPECT_EQ(iov.sum(), 44+55+33 + 77+44+33); EXPECT_EQ(iov.pop_front(), 44); diff --git a/common/test/test_objcache.cpp b/common/test/test_objcache.cpp index 5f1c73a2..36b2dd38 100644 --- a/common/test/test_objcache.cpp +++ b/common/test/test_objcache.cpp @@ -22,6 +22,7 @@ limitations under the License. #undef private #undef protected + #include #include #include diff --git a/common/timeout.h b/common/timeout.h index 2e6e07ad..c28face6 100644 --- a/common/timeout.h +++ b/common/timeout.h @@ -15,9 +15,19 @@ limitations under the License. */ #pragma once -#include #include #include +#ifdef private +#define _PHOTON_UNIT_TEST +#undef private +#undef protected +#endif +#include +#ifdef _PHOTON_UNIT_TEST +#undef _PHOTON_UNIT_TEST +#define private public +#define protected public +#endif namespace photon { diff --git a/examples/sync-primitive/sync-primitive.cpp b/examples/sync-primitive/sync-primitive.cpp index 131493b5..ae29b083 100644 --- a/examples/sync-primitive/sync-primitive.cpp +++ b/examples/sync-primitive/sync-primitive.cpp @@ -77,8 +77,8 @@ int main() { message.sem.wait(1); auto end = std::chrono::steady_clock::now(); auto duration_us = std::chrono::duration_cast(end - message.start).count(); - latency.fetch_add(duration_us, std::memory_order::memory_order_relaxed); - qps.fetch_add(1, std::memory_order::memory_order_relaxed); + latency.fetch_add(duration_us, std::memory_order_relaxed); + qps.fetch_add(1, std::memory_order_relaxed); } })); } diff --git a/fs/async_filesystem.cpp b/fs/async_filesystem.cpp index 477ede11..9f69b6da 100644 --- a/fs/async_filesystem.cpp +++ b/fs/async_filesystem.cpp @@ -85,7 +85,11 @@ namespace fs { public: template::type > +#else + typename R = typename std::invoke_result::type> +#endif R perform(IF* _if, Func func, ARGS...args) { return th_performer().call(_if, func, args...); diff --git a/fs/exportfs.cpp b/fs/exportfs.cpp index d60b6546..10cbc160 100644 --- a/fs/exportfs.cpp +++ b/fs/exportfs.cpp @@ -142,8 +142,13 @@ namespace fs __attribute__((visibility("hidden"))) Delegate ExportBase::op; __attribute__((visibility("hidden"))) ThreadPoolBase* ExportBase::pool = nullptr; +#if __cplusplus > 202000L +#define PERFORM(ID, expr) \ + perform(timeout, new auto([=, this]() { do_callback(ID, expr, done); })); +#else #define PERFORM(ID, expr) \ perform(timeout, new auto([=]() { do_callback(ID, expr, done); })); +#endif class ExportAsAsyncFile : public ExportBase, public IAsyncFile, public IAsyncFileXAttr { diff --git a/fs/test/test.cpp b/fs/test/test.cpp index 4e4dca84..eb91df6e 100644 --- a/fs/test/test.cpp +++ b/fs/test/test.cpp @@ -571,12 +571,17 @@ TEST(AsyncFS, AsyncFS) tafs.do_test(f); } +#if __cplusplus < 202000 +#define CAPTURE = +#else +#define CAPTURE =,this +#endif class AFile : public ExampleAsyncFile { public: OVERRIDE_ASYNC(ssize_t, pread, void *buf, size_t count, off_t offset) { - std::thread t([=]() + std::thread t([CAPTURE]() { ::sleep(1); callback_umimplemented(done); @@ -588,7 +593,7 @@ class AFile : public ExampleAsyncFile { LOG_DEBUG("into afile pwrite `", timeout); - std::thread t([=]() + std::thread t([CAPTURE]() { ::usleep(timeout); //only return count/2 for timeout fired @@ -604,7 +609,7 @@ class ExampleAsyncDir: public AsyncDIR { OVERRIDE_ASYNC0(int, closedir) { } OVERRIDE_ASYNC0(dirent*, get) { - std::thread t([=]() + std::thread t([CAPTURE]() { ::usleep(timeout); AsyncResult r; @@ -631,7 +636,7 @@ class AFS : public ExampleAsyncFileSystem { public: OVERRIDE_ASYNC(IAsyncFile*, open, const char *pathname, int flags) { - std::thread t([=]() + std::thread t([CAPTURE]() { callback(done, UINT32_MAX, exampleAfile, 0); }); @@ -640,7 +645,7 @@ class AFS : public ExampleAsyncFileSystem { OVERRIDE_ASYNC(AsyncDIR*, opendir, const char *name) { - std::thread t([=]() + std::thread t([CAPTURE]() { ::usleep(timeout); if (name[0] == 's') { diff --git a/net/http/client.cpp b/net/http/client.cpp index f745ccc6..606979f2 100644 --- a/net/http/client.cpp +++ b/net/http/client.cpp @@ -263,6 +263,7 @@ class ClientImpl : public Client { resp.reset((char *)buf, kMinimalHeadersSize, true, sock.release(), true, req.verb()); } if (op->resp.receive_header(tmo.timeout()) != 0) { + sock->close(); req.reset_status(); LOG_ERROR_RETURN(0, ROUNDTRIP_NEED_RETRY, "read response header failed"); } diff --git a/thread/thread.cpp b/thread/thread.cpp index 3d06790c..98cbbe3a 100644 --- a/thread/thread.cpp +++ b/thread/thread.cpp @@ -169,6 +169,54 @@ namespace photon void* _ptr; }; +<<<<<<< HEAD +======= + #if defined(__has_feature) + # if __has_feature(address_sanitizer) // for clang + # define __SANITIZE_ADDRESS__ // GCC already sets this + # endif + #endif + + #ifdef __SANITIZE_ADDRESS__ + extern "C" { + // Check out sanitizer/asan-interface.h in compiler-rt for documentation. + void __sanitizer_start_switch_fiber(void** fake_stack_save, const void* bottom, + size_t size); + void __sanitizer_finish_switch_fiber(void* fake_stack_save, + const void** bottom_old, size_t* size_old); + } + + static void asan_start(void** save, thread* to) { + void* bottom = to->buf ? to->buf : to->stackful_alloc_top; + __sanitizer_start_switch_fiber(save, bottom, + to->stack_size); + } + + static void asan_finish(void* save) { + __sanitizer_finish_switch_fiber(save, nullptr, nullptr); + } + +#define ASAN_START() asan_finish((void*)nullptr); + +#define ASAN_SWITCH(to) \ + void* __save; \ + asan_start(&__save, to); \ + DEFER({ asan_finish(__save); }); + +#define ASAN_DIE_SWITCH(to) \ + asan_start(nullptr, to); + +#else +#define ASAN_START(ptr) +#define ASAN_SWITCH(to) +#define ASAN_DIE_SWITCH(to) +#endif + + static void _asan_start() asm("_asan_start"); + + __attribute__((used)) static void _asan_start() { ASAN_START(); } + +>>>>>>> aaabc01 (make it compiles with C++17/20/23) struct thread_list; struct thread : public intrusive_list_node { volatile vcpu_t* vcpu; @@ -680,7 +728,8 @@ namespace photon inline void prepare_switch(thread* from, thread* to) { assert(from->vcpu == to->vcpu); assert(to->state == states::RUNNING); - to->get_vcpu()->switch_count++; + auto& cnt = to->get_vcpu()->switch_count; + (*(uint64_t*)&cnt)++; // increment of volatile variable is deprecated } #pragma GCC diagnostic push diff --git a/thread/workerpool.cpp b/thread/workerpool.cpp index b57f8b46..daa740ce 100644 --- a/thread/workerpool.cpp +++ b/thread/workerpool.cpp @@ -121,7 +121,7 @@ class WorkPool::impl { auto task = ring.recv(running_tasks.load() ? 0 : QUEUE_YIELD_COUNT, QUEUE_YIELD_US); if (!task) break; - running_tasks.fetch_add(std::memory_order_acq_rel); + running_tasks.fetch_add(1, std::memory_order_acq_rel); TaskLB tasklb{task, &running_tasks}; if (mode < 0) { delegate_helper(&tasklb); @@ -143,7 +143,7 @@ class WorkPool::impl { // must copy to keep tasklb alive TaskLB tasklb = *(TaskLB*)arg; tasklb.task(); - tasklb.count->fetch_sub(std::memory_order_acq_rel); + tasklb.count->fetch_sub(1, std::memory_order_acq_rel); return nullptr; }