├── CMakeLists.txt ├── LICENSE ├── README.md ├── ext ├── gmock │ └── CMakeLists.txt └── gtest │ └── CMakeLists.txt ├── include └── disruptor4cpp │ ├── batch_event_processor.h │ ├── disruptor4cpp.h │ ├── event_handler.h │ ├── exceptions │ ├── alert_exception.h │ ├── insufficient_capacity_exception.h │ └── timeout_exception.h │ ├── fixed_sequence_group.h │ ├── multi_producer_sequencer.h │ ├── no_op_event_processor.h │ ├── producer_type.h │ ├── ring_buffer.h │ ├── sequence.h │ ├── sequence_barrier.h │ ├── sequencer_traits.h │ ├── single_producer_sequencer.h │ ├── utils │ ├── cache_line_storage.h │ └── util.h │ └── wait_strategies │ ├── blocking_wait_strategy.h │ ├── busy_spin_wait_strategy.h │ ├── lite_blocking_wait_strategy.h │ ├── phased_backoff_wait_strategy.h │ ├── sleeping_wait_strategy.h │ ├── timeout_blocking_wait_strategy.h │ └── yielding_wait_strategy.h └── test ├── dummy_sequence_barrier.h ├── fixed_sequence_group_test.cpp ├── main.cpp ├── multi_producer_sequencer_test.cpp ├── sequence_barrier_test.cpp ├── sequencer_test.cpp ├── support └── stub_event.h ├── utils ├── count_down_latch.h └── thread_barrier.h └── wait_strategies ├── busy_spin_wait_strategy_test.cpp ├── phased_backoff_wait_strategy_test.cpp ├── sequence_updater.h ├── sleeping_wait_strategy_test.cpp ├── timeout_blocking_wait_strategy_test.cpp ├── wait_strategy_test_util.h └── yielding_wait_strategy_test.cpp /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 2.8.8) 2 | set(PROJECT_NAME_STR disruptor4cpp) 3 | project(${PROJECT_NAME_STR} C CXX) 4 | 5 | include(ExternalProject) 6 | 7 | find_package(Threads REQUIRED) 8 | if(UNIX) 9 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -std=c++11") 10 | endif() 11 | 12 | #------------------- 13 | # set common include folder for module 14 | #------------------- 15 | set(PROJECT_INCLUDE_DIR ${PROJECT_SOURCE_DIR}/include) 16 | set(PROJECT_TEST_DIR ${PROJECT_SOURCE_DIR}/test) 17 | set(EXT_PROJECTS_DIR ${PROJECT_SOURCE_DIR}/ext) 18 | 19 | #------------------- 20 | # Module source 21 | #------------------- 22 | add_subdirectory(${EXT_PROJECTS_DIR}/gtest) 23 | add_subdirectory(${EXT_PROJECTS_DIR}/gmock) 24 | 25 | #------------------- 26 | # Test 27 | #------------------- 28 | enable_testing() 29 | set(PROJECT_TEST_NAME ${PROJECT_NAME_STR}_test) 30 | file(GLOB TEST_SRC_FILES ${PROJECT_TEST_DIR}/*.cpp) 31 | add_executable(${PROJECT_TEST_NAME} ${TEST_SRC_FILES}) 32 | 33 | add_dependencies(${PROJECT_TEST_NAME} gmock gtest) 34 | include_directories(${GMOCK_INCLUDE_DIR} ${GTEST_INCLUDE_DIR} ${PROJECT_INCLUDE_DIR}) 35 | 36 | target_link_libraries(${PROJECT_TEST_NAME} libgmock) 37 | target_link_libraries(${PROJECT_TEST_NAME} libgtest) 38 | target_link_libraries(${PROJECT_TEST_NAME} ${CMAKE_THREAD_LIBS_INIT}) 39 | 40 | add_test(disruptor4cpp_test ${PROJECT_TEST_NAME}) 41 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015, Alex Man-fui Lee 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 10 | * Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | * Neither the name of disruptor4cpp nor the names of its 15 | contributors may be used to endorse or promote products derived from 16 | this software without specific prior written permission. 17 | 18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 22 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 25 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | 29 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # disruptor4cpp 2 | C++ port of LMAX disruptor. 3 | 4 | I try to implement it as closely as possible to the Java version, with C++ features in mind. 5 | 6 | The library requires C++11 features. Currently, it has been tested in GCC 4.8. 7 | 8 | ## What's new? 9 | 2015-09-01: 10 | The core features except DSL from Java version **3.3.2** have been ported. 11 | 12 | ## Getting Started 13 | The library is header-only. Clone and copy the "include" folder. For example, 14 | ``` 15 | $ git clone https://github.com/alexleemanfui/disruptor4cpp.git 16 | $ cd disruptor4cpp 17 | $ mkdir /opt/disruptor4cpp/ 18 | $ cp -pr include/ /opt/disruptor4cpp/ 19 | ``` 20 | 21 | To run the test, 22 | ``` 23 | $ git clone https://github.com/alexleemanfui/disruptor4cpp.git 24 | $ cd disruptor4cpp 25 | $ mkdir build 26 | $ cd build 27 | $ cmake .. 28 | $ make 29 | $ ./disruptor4cpp_test 30 | ``` 31 | 32 | To use it, include the below header file 33 | ```cpp 34 | #include 35 | ``` 36 | 37 | ## Example 38 | ```cpp 39 | #include 40 | #include 41 | #include 42 | #include 43 | 44 | #include 45 | 46 | class int_handler : public disruptor4cpp::event_handler 47 | { 48 | public: 49 | int_handler() = default; 50 | virtual ~int_handler() = default; 51 | virtual void on_start() { } 52 | virtual void on_shutdown() { } 53 | virtual void on_event(int& event, int64_t sequence, bool end_of_batch) 54 | { 55 | std::cout << "Received integer: " << event << std::endl; 56 | } 57 | virtual void on_timeout(int64_t sequence) { } 58 | virtual void on_event_exception(const std::exception& ex, int64_t sequence, int* event) { } 59 | virtual void on_start_exception(const std::exception& ex) { } 60 | virtual void on_shutdown_exception(const std::exception& ex) { } 61 | }; 62 | 63 | int main(int argc, char* argv[]) 64 | { 65 | using namespace disruptor4cpp; 66 | 67 | // Create the ring buffer. 68 | ring_buffer ring_buffer; 69 | 70 | // Create and run the consumer on another thread. 71 | auto barrier = ring_buffer.new_barrier(); 72 | int_handler handler; 73 | batch_event_processor processor(ring_buffer, std::move(barrier), handler); 74 | std::thread processor_thread([&processor] { processor.run(); }); 75 | 76 | // Publish some integers. 77 | for (int i = 0; i < 1000; i++) 78 | { 79 | int64_t seq = ring_buffer.next(); 80 | ring_buffer[seq] = i; 81 | ring_buffer.publish(seq); 82 | } 83 | 84 | // Stop the consumer. 85 | std::this_thread::sleep_for(std::chrono::seconds(1)); 86 | processor.halt(); 87 | processor_thread.join(); 88 | return 0; 89 | } 90 | ``` 91 | -------------------------------------------------------------------------------- /ext/gmock/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 2.8.8) 2 | include(ExternalProject) 3 | 4 | find_package(Threads REQUIRED) 5 | 6 | # Prefer static libraries. 7 | if(WIN32) 8 | set(CMAKE_FIND_LIBRARY_SUFFIXES .lib) 9 | else() 10 | set(CMAKE_FIND_LIBRARY_SUFFIXES .a) 11 | endif() 12 | 13 | # Download gmock. 14 | set(GMOCK_DIR "${CMAKE_CURRENT_BINARY_DIR}/gmock") 15 | set(GENERATED_DIR "${CMAKE_CURRENT_BINARY_DIR}/generated") 16 | 17 | file(MAKE_DIRECTORY ${GENERATED_DIR}) 18 | file(WRITE ${GENERATED_DIR}/CMakeLists.txt 19 | "cmake_minimum_required(VERSION 2.8.8)\n" 20 | "add_subdirectory(googlemock)\n" 21 | ) 22 | 23 | ExternalProject_Add(gmock 24 | GIT_REPOSITORY https://github.com/google/googletest.git 25 | PREFIX "${GMOCK_DIR}" 26 | UPDATE_COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_BINARY_DIR}/generated/CMakeLists.txt ${GMOCK_DIR}/src/gmock/ 27 | INSTALL_COMMAND "" 28 | ) 29 | 30 | ExternalProject_Get_Property(gmock source_dir binary_dir) 31 | set(GMOCK_INCLUDE_DIR "${source_dir}/googlemock/include" PARENT_SCOPE) 32 | set(GMOCK_LIBS_DIR "${binary_dir}/googlemock" PARENT_SCOPE) 33 | set(GMOCK_LIB_PATH "${binary_dir}/googlemock/${CMAKE_FIND_LIBRARY_PREFIXES}gmock${CMAKE_FIND_LIBRARY_SUFFIXES}") 34 | 35 | add_library(libgmock IMPORTED STATIC GLOBAL) 36 | add_dependencies(libgmock gmock) 37 | set_target_properties(libgmock PROPERTIES 38 | IMPORTED_LOCATION "${GMOCK_LIB_PATH}" 39 | IMPORTED_LINK_INTERFACE_LIBRARIES "${CMAKE_THREAD_LIBS_INIT}" 40 | ) 41 | 42 | -------------------------------------------------------------------------------- /ext/gtest/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 2.8.8) 2 | include(ExternalProject) 3 | 4 | find_package(Threads REQUIRED) 5 | 6 | # Prefer static libraries. 7 | if(WIN32) 8 | set(CMAKE_FIND_LIBRARY_SUFFIXES .lib) 9 | else() 10 | set(CMAKE_FIND_LIBRARY_SUFFIXES .a) 11 | endif() 12 | 13 | # Download gtest. 14 | set(GTEST_DIR "${CMAKE_CURRENT_BINARY_DIR}/gtest") 15 | set(GENERATED_DIR "${CMAKE_CURRENT_BINARY_DIR}/generated") 16 | 17 | file(MAKE_DIRECTORY ${GENERATED_DIR}) 18 | file(WRITE ${GENERATED_DIR}/CMakeLists.txt 19 | "cmake_minimum_required(VERSION 2.8.8)\n" 20 | "add_subdirectory(googletest)\n" 21 | ) 22 | 23 | ExternalProject_Add(gtest 24 | GIT_REPOSITORY https://github.com/google/googletest.git 25 | PREFIX "${GTEST_DIR}" 26 | UPDATE_COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_BINARY_DIR}/generated/CMakeLists.txt ${GTEST_DIR}/src/gtest/ 27 | INSTALL_COMMAND "" 28 | ) 29 | 30 | ExternalProject_Get_Property(gtest source_dir binary_dir) 31 | set(GTEST_INCLUDE_DIR "${source_dir}/googletest/include" PARENT_SCOPE) 32 | set(GTEST_LIBS_DIR "${binary_dir}/googletest" PARENT_SCOPE) 33 | set(GTEST_LIB_PATH "${binary_dir}/googletest/${CMAKE_FIND_LIBRARY_PREFIXES}gtest${CMAKE_FIND_LIBRARY_SUFFIXES}") 34 | 35 | add_library(libgtest IMPORTED STATIC GLOBAL) 36 | add_dependencies(libgtest gtest) 37 | set_target_properties(libgtest PROPERTIES 38 | IMPORTED_LOCATION "${GTEST_LIB_PATH}" 39 | IMPORTED_LINK_INTERFACE_LIBRARIES "${CMAKE_THREAD_LIBS_INIT}" 40 | ) 41 | 42 | -------------------------------------------------------------------------------- /include/disruptor4cpp/batch_event_processor.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2015, Alex Man-fui Lee 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | 8 | * Redistributions of source code must retain the above copyright notice, this 9 | list of conditions and the following disclaimer. 10 | 11 | * Redistributions in binary form must reproduce the above copyright notice, 12 | this list of conditions and the following disclaimer in the documentation 13 | and/or other materials provided with the distribution. 14 | 15 | * Neither the name of disruptor4cpp nor the names of its 16 | contributors may be used to endorse or promote products derived from 17 | this software without specific prior written permission. 18 | 19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 20 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 23 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 25 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 26 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 27 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | */ 30 | 31 | #ifndef DISRUPTOR4CPP_BATCH_EVENT_PROCESSOR_H_ 32 | #define DISRUPTOR4CPP_BATCH_EVENT_PROCESSOR_H_ 33 | 34 | #include 35 | #include 36 | #include 37 | #include 38 | 39 | #include "event_handler.h" 40 | #include "exceptions/alert_exception.h" 41 | #include "exceptions/timeout_exception.h" 42 | #include "sequence.h" 43 | 44 | namespace disruptor4cpp 45 | { 46 | template 47 | class batch_event_processor 48 | { 49 | public: 50 | batch_event_processor(TRingBuffer& ring_buffer, 51 | typename TRingBuffer::sequence_barrier_type& sequence_barrier, 52 | event_handler& evt_handler) 53 | : sequence_(), 54 | ring_buffer_(ring_buffer), 55 | sequence_barrier_(sequence_barrier), 56 | event_handler_(evt_handler), 57 | running_(false) 58 | { 59 | } 60 | 61 | batch_event_processor(TRingBuffer& ring_buffer, 62 | std::unique_ptr sequence_barrier_ptr, 63 | event_handler& evt_handler) 64 | : sequence_(), 65 | ring_buffer_(ring_buffer), 66 | sequence_barrier_(*sequence_barrier_ptr), 67 | event_handler_(evt_handler), 68 | sequence_barrier_ptr_(std::move(sequence_barrier_ptr)), 69 | running_(false) 70 | { 71 | } 72 | 73 | typename TRingBuffer::sequence_type& get_sequence() 74 | { 75 | return sequence_; 76 | } 77 | 78 | void halt() 79 | { 80 | running_.store(false, std::memory_order_release); 81 | sequence_barrier_.alert(); 82 | } 83 | 84 | bool is_running() const 85 | { 86 | return running_.load(std::memory_order_acquire); 87 | } 88 | 89 | void run() 90 | { 91 | bool expected_running_state = false; 92 | if (!running_.compare_exchange_strong(expected_running_state, true)) 93 | throw std::runtime_error("Thread is already running"); 94 | 95 | sequence_barrier_.clear_alert(); 96 | notify_start(); 97 | 98 | typename TRingBuffer::event_type* event; 99 | int64_t next_sequence = sequence_.get() + 1; 100 | try 101 | { 102 | while (true) 103 | { 104 | try 105 | { 106 | const int64_t available_sequence = sequence_barrier_.wait_for(next_sequence); 107 | while (next_sequence <= available_sequence) 108 | { 109 | event = &ring_buffer_[next_sequence]; 110 | event_handler_.on_event(*event, next_sequence, next_sequence == available_sequence); 111 | next_sequence++; 112 | } 113 | sequence_.set(available_sequence); 114 | } 115 | catch (timeout_exception& timeout_ex) 116 | { 117 | notify_timeout(sequence_.get()); 118 | } 119 | catch (alert_exception& alert_ex) 120 | { 121 | if (!running_.load(std::memory_order_acquire)) 122 | break; 123 | } 124 | catch (std::exception& ex) 125 | { 126 | event_handler_.on_event_exception(ex, next_sequence, event); 127 | sequence_.set(next_sequence); 128 | next_sequence++; 129 | } 130 | } 131 | } 132 | catch (...) 133 | { 134 | notify_shutdown(); 135 | running_.store(false, std::memory_order_release); 136 | throw; 137 | } 138 | notify_shutdown(); 139 | running_.store(false, std::memory_order_release); 140 | } 141 | 142 | private: 143 | void notify_timeout(int64_t available_sequence) 144 | { 145 | try 146 | { 147 | event_handler_.on_timeout(available_sequence); 148 | } 149 | catch (std::exception& ex) 150 | { 151 | event_handler_.on_event_exception(ex, available_sequence, nullptr); 152 | } 153 | } 154 | 155 | void notify_start() 156 | { 157 | try 158 | { 159 | event_handler_.on_start(); 160 | } 161 | catch (std::exception& ex) 162 | { 163 | event_handler_.on_start_exception(ex); 164 | } 165 | } 166 | 167 | void notify_shutdown() 168 | { 169 | try 170 | { 171 | event_handler_.on_shutdown(); 172 | } 173 | catch (std::exception& ex) 174 | { 175 | event_handler_.on_shutdown_exception(ex); 176 | } 177 | } 178 | 179 | typename TRingBuffer::sequence_type sequence_; 180 | TRingBuffer& ring_buffer_; 181 | typename TRingBuffer::sequence_barrier_type& sequence_barrier_; 182 | event_handler& event_handler_; 183 | std::unique_ptr sequence_barrier_ptr_; 184 | std::atomic running_; 185 | }; 186 | } 187 | 188 | #endif 189 | -------------------------------------------------------------------------------- /include/disruptor4cpp/disruptor4cpp.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2015, Alex Man-fui Lee 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | 8 | * Redistributions of source code must retain the above copyright notice, this 9 | list of conditions and the following disclaimer. 10 | 11 | * Redistributions in binary form must reproduce the above copyright notice, 12 | this list of conditions and the following disclaimer in the documentation 13 | and/or other materials provided with the distribution. 14 | 15 | * Neither the name of disruptor4cpp nor the names of its 16 | contributors may be used to endorse or promote products derived from 17 | this software without specific prior written permission. 18 | 19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 20 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 23 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 25 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 26 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 27 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | */ 30 | 31 | #ifndef DISRUPTOR4CPP_DISRUPTOR4CPP_H_ 32 | #define DISRUPTOR4CPP_DISRUPTOR4CPP_H_ 33 | 34 | #include "exceptions/alert_exception.h" 35 | #include "exceptions/insufficient_capacity_exception.h" 36 | #include "exceptions/timeout_exception.h" 37 | #include "batch_event_processor.h" 38 | #include "event_handler.h" 39 | #include "no_op_event_processor.h" 40 | #include "producer_type.h" 41 | #include "ring_buffer.h" 42 | #include "sequence_barrier.h" 43 | #include "sequence.h" 44 | #include "wait_strategies/blocking_wait_strategy.h" 45 | #include "wait_strategies/busy_spin_wait_strategy.h" 46 | #include "wait_strategies/lite_blocking_wait_strategy.h" 47 | #include "wait_strategies/phased_backoff_wait_strategy.h" 48 | #include "wait_strategies/sleeping_wait_strategy.h" 49 | #include "wait_strategies/timeout_blocking_wait_strategy.h" 50 | #include "wait_strategies/yielding_wait_strategy.h" 51 | 52 | #endif 53 | -------------------------------------------------------------------------------- /include/disruptor4cpp/event_handler.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2015, Alex Man-fui Lee 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | 8 | * Redistributions of source code must retain the above copyright notice, this 9 | list of conditions and the following disclaimer. 10 | 11 | * Redistributions in binary form must reproduce the above copyright notice, 12 | this list of conditions and the following disclaimer in the documentation 13 | and/or other materials provided with the distribution. 14 | 15 | * Neither the name of disruptor4cpp nor the names of its 16 | contributors may be used to endorse or promote products derived from 17 | this software without specific prior written permission. 18 | 19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 20 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 23 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 25 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 26 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 27 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | */ 30 | 31 | #ifndef DISRUPTOR4CPP_EVENT_HANDLER_H_ 32 | #define DISRUPTOR4CPP_EVENT_HANDLER_H_ 33 | 34 | #include 35 | #include 36 | 37 | namespace disruptor4cpp 38 | { 39 | template 40 | class event_handler 41 | { 42 | public: 43 | virtual ~event_handler() { } 44 | virtual void on_start() = 0; 45 | virtual void on_shutdown() = 0; 46 | virtual void on_event(TEvent& event, int64_t sequence, bool end_of_batch) = 0; 47 | virtual void on_timeout(int64_t sequence) = 0; 48 | virtual void on_event_exception(const std::exception& ex, int64_t sequence, TEvent* event) = 0; 49 | virtual void on_start_exception(const std::exception& ex) = 0; 50 | virtual void on_shutdown_exception(const std::exception& ex) = 0; 51 | }; 52 | } 53 | 54 | #endif 55 | -------------------------------------------------------------------------------- /include/disruptor4cpp/exceptions/alert_exception.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2015, Alex Man-fui Lee 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | 8 | * Redistributions of source code must retain the above copyright notice, this 9 | list of conditions and the following disclaimer. 10 | 11 | * Redistributions in binary form must reproduce the above copyright notice, 12 | this list of conditions and the following disclaimer in the documentation 13 | and/or other materials provided with the distribution. 14 | 15 | * Neither the name of disruptor4cpp nor the names of its 16 | contributors may be used to endorse or promote products derived from 17 | this software without specific prior written permission. 18 | 19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 20 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 23 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 25 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 26 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 27 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | */ 30 | 31 | #ifndef DISRUPTOR4CPP_EXCEPTIONS_ALERT_EXCEPTION_H_ 32 | #define DISRUPTOR4CPP_EXCEPTIONS_ALERT_EXCEPTION_H_ 33 | 34 | #include 35 | 36 | namespace disruptor4cpp 37 | { 38 | class alert_exception : public std::exception 39 | { 40 | }; 41 | } 42 | 43 | #endif 44 | -------------------------------------------------------------------------------- /include/disruptor4cpp/exceptions/insufficient_capacity_exception.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2015, Alex Man-fui Lee 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | 8 | * Redistributions of source code must retain the above copyright notice, this 9 | list of conditions and the following disclaimer. 10 | 11 | * Redistributions in binary form must reproduce the above copyright notice, 12 | this list of conditions and the following disclaimer in the documentation 13 | and/or other materials provided with the distribution. 14 | 15 | * Neither the name of disruptor4cpp nor the names of its 16 | contributors may be used to endorse or promote products derived from 17 | this software without specific prior written permission. 18 | 19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 20 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 23 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 25 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 26 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 27 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | */ 30 | 31 | #ifndef DISRUPTOR4CPP_EXCEPTIONS_INSUFFICIENT_CAPACITY_EXCEPTION_H_ 32 | #define DISRUPTOR4CPP_EXCEPTIONS_INSUFFICIENT_CAPACITY_EXCEPTION_H_ 33 | 34 | #include 35 | 36 | namespace disruptor4cpp 37 | { 38 | class insufficient_capacity_exception : public std::exception 39 | { 40 | }; 41 | } 42 | 43 | #endif 44 | -------------------------------------------------------------------------------- /include/disruptor4cpp/exceptions/timeout_exception.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2015, Alex Man-fui Lee 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | 8 | * Redistributions of source code must retain the above copyright notice, this 9 | list of conditions and the following disclaimer. 10 | 11 | * Redistributions in binary form must reproduce the above copyright notice, 12 | this list of conditions and the following disclaimer in the documentation 13 | and/or other materials provided with the distribution. 14 | 15 | * Neither the name of disruptor4cpp nor the names of its 16 | contributors may be used to endorse or promote products derived from 17 | this software without specific prior written permission. 18 | 19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 20 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 23 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 25 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 26 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 27 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | */ 30 | 31 | #ifndef DISRUPTOR4CPP_EXCEPTIONS_TIMEOUT_EXCEPTION_H_ 32 | #define DISRUPTOR4CPP_EXCEPTIONS_TIMEOUT_EXCEPTION_H_ 33 | 34 | #include 35 | 36 | namespace disruptor4cpp 37 | { 38 | class timeout_exception : public std::exception 39 | { 40 | }; 41 | } 42 | 43 | #endif 44 | -------------------------------------------------------------------------------- /include/disruptor4cpp/fixed_sequence_group.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2015, Alex Man-fui Lee 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | 8 | * Redistributions of source code must retain the above copyright notice, this 9 | list of conditions and the following disclaimer. 10 | 11 | * Redistributions in binary form must reproduce the above copyright notice, 12 | this list of conditions and the following disclaimer in the documentation 13 | and/or other materials provided with the distribution. 14 | 15 | * Neither the name of disruptor4cpp nor the names of its 16 | contributors may be used to endorse or promote products derived from 17 | this software without specific prior written permission. 18 | 19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 20 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 23 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 25 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 26 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 27 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | */ 30 | 31 | #ifndef DISRUPTOR4CPP_FIXED_SEQUENCE_GROUP_H_ 32 | #define DISRUPTOR4CPP_FIXED_SEQUENCE_GROUP_H_ 33 | 34 | #include 35 | #include 36 | #include 37 | 38 | #include "sequence.h" 39 | #include "utils/util.h" 40 | 41 | namespace disruptor4cpp 42 | { 43 | template 44 | class fixed_sequence_group 45 | { 46 | public: 47 | static fixed_sequence_group create(const std::vector& sequences) 48 | { 49 | fixed_sequence_group group; 50 | group.sequences_.insert(group.sequences_.begin(), sequences.begin(), sequences.end()); 51 | return group; 52 | } 53 | 54 | static fixed_sequence_group create(const std::vector& sequences) 55 | { 56 | fixed_sequence_group group; 57 | group.sequences_.insert(group.sequences_.begin(), sequences.begin(), sequences.end()); 58 | return group; 59 | } 60 | 61 | static fixed_sequence_group create(const TSequence& sequence) 62 | { 63 | fixed_sequence_group group; 64 | group.sequences_.push_back(&sequence); 65 | return group; 66 | } 67 | 68 | fixed_sequence_group() = default; 69 | ~fixed_sequence_group() = default; 70 | 71 | int64_t get() const 72 | { 73 | return sequences_.size() == 1 ? sequences_[0]->get() 74 | : util::get_minimum_sequence(sequences_); 75 | } 76 | 77 | private: 78 | std::vector sequences_; 79 | }; 80 | } 81 | 82 | #endif 83 | -------------------------------------------------------------------------------- /include/disruptor4cpp/multi_producer_sequencer.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2015, Alex Man-fui Lee 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | 8 | * Redistributions of source code must retain the above copyright notice, this 9 | list of conditions and the following disclaimer. 10 | 11 | * Redistributions in binary form must reproduce the above copyright notice, 12 | this list of conditions and the following disclaimer in the documentation 13 | and/or other materials provided with the distribution. 14 | 15 | * Neither the name of disruptor4cpp nor the names of its 16 | contributors may be used to endorse or promote products derived from 17 | this software without specific prior written permission. 18 | 19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 20 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 23 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 25 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 26 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 27 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | */ 30 | 31 | #ifndef DISRUPTOR4CPP_MULTI_PRODUCER_SEQUENCER_H_ 32 | #define DISRUPTOR4CPP_MULTI_PRODUCER_SEQUENCER_H_ 33 | 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | 42 | #include "exceptions/insufficient_capacity_exception.h" 43 | #include "sequence.h" 44 | #include "sequence_barrier.h" 45 | #include "utils/util.h" 46 | 47 | namespace disruptor4cpp 48 | { 49 | template 50 | class multi_producer_sequencer 51 | { 52 | public: 53 | typedef TWaitStrategy wait_strategy_type; 54 | typedef TSequence sequence_type; 55 | typedef sequence_barrier< 56 | multi_producer_sequencer> sequence_barrier_type; 57 | 58 | static constexpr int64_t INITIAL_CURSOR_VALUE = -1; 59 | static constexpr std::size_t BUFFER_SIZE = BufferSize; 60 | 61 | multi_producer_sequencer() 62 | : cursor_(), 63 | gating_sequence_cache_(), 64 | wait_strategy_(), 65 | gating_sequences_() 66 | { 67 | std::memset(available_buffer_, ~0, sizeof(available_buffer_)); 68 | } 69 | 70 | ~multi_producer_sequencer() = default; 71 | 72 | int64_t get_cursor() const 73 | { 74 | return cursor_.get(); 75 | } 76 | 77 | constexpr std::size_t get_buffer_size() const 78 | { 79 | return BUFFER_SIZE; 80 | } 81 | 82 | TWaitStrategy& get_wait_strategy() 83 | { 84 | return wait_strategy_; 85 | } 86 | 87 | void add_gating_sequences(const std::vector& sequences_to_add) 88 | { 89 | // TODO: It is different from the java version. 90 | // The java version allows to change gating sequences after disruptor is started. 91 | int64_t cursor_sequence = cursor_.get(); 92 | for (auto seq : sequences_to_add) 93 | { 94 | seq->set(cursor_sequence); 95 | gating_sequences_.push_back(seq); 96 | } 97 | } 98 | 99 | bool remove_gating_sequence(const TSequence& seq) 100 | { 101 | // TODO: It is different from the java version. 102 | // The java version allows to change gating sequences after disruptor is started. 103 | bool removed = false; 104 | for (auto iter = gating_sequences_.begin(); iter != gating_sequences_.end();) 105 | { 106 | if (*iter == &seq) 107 | { 108 | removed = true; 109 | iter = gating_sequences_.erase(iter); 110 | } 111 | else 112 | ++iter; 113 | } 114 | return removed; 115 | } 116 | 117 | int64_t get_minimum_sequence() const 118 | { 119 | return util::get_minimum_sequence(gating_sequences_); 120 | } 121 | 122 | std::unique_ptr new_barrier() 123 | { 124 | return new_barrier(std::vector()); 125 | } 126 | 127 | std::unique_ptr new_barrier(const std::vector& sequences_to_track) 128 | { 129 | return std::unique_ptr( 130 | new sequence_barrier_type(*this, wait_strategy_, cursor_, sequences_to_track)); 131 | } 132 | 133 | bool has_available_capacity(int required_capacity) 134 | { 135 | return has_available_capacity(required_capacity, cursor_.get()); 136 | } 137 | 138 | int64_t next() 139 | { 140 | return next(1); 141 | } 142 | 143 | int64_t next(int n) 144 | { 145 | if (n < 1) 146 | throw std::invalid_argument("n must be > 0"); 147 | 148 | int64_t current; 149 | int64_t next; 150 | do 151 | { 152 | current = cursor_.get(); 153 | next = current + n; 154 | 155 | int64_t wrap_point = next - BufferSize; 156 | int64_t cached_gating_sequence = gating_sequence_cache_.get(); 157 | if (wrap_point > cached_gating_sequence || cached_gating_sequence > current) 158 | { 159 | int64_t gating_sequence = util::get_minimum_sequence(gating_sequences_, current); 160 | if (wrap_point > gating_sequence) 161 | { 162 | std::this_thread::yield(); 163 | continue; 164 | } 165 | gating_sequence_cache_.set(gating_sequence); 166 | } 167 | else if (cursor_.compare_and_set(current, next)) 168 | break; 169 | } 170 | while (true); 171 | return next; 172 | } 173 | 174 | int64_t try_next() 175 | { 176 | return try_next(1); 177 | } 178 | 179 | int64_t try_next(int n) 180 | { 181 | if (n < 1) 182 | throw std::invalid_argument("n must be > 0"); 183 | 184 | int64_t current; 185 | int64_t next; 186 | do 187 | { 188 | current = cursor_.get(); 189 | next = current + n; 190 | if (!has_available_capacity(n, current)) 191 | throw insufficient_capacity_exception(); 192 | } 193 | while (!cursor_.compare_and_set(current, next)); 194 | return next; 195 | } 196 | 197 | int64_t remaining_capacity() const 198 | { 199 | int64_t consumed = util::get_minimum_sequence(gating_sequences_, cursor_.get()); 200 | int64_t produced = cursor_.get(); 201 | return BufferSize - (produced - consumed); 202 | } 203 | 204 | void claim(int64_t seq) 205 | { 206 | cursor_.set(seq); 207 | } 208 | 209 | void publish(int64_t seq) 210 | { 211 | set_available(seq); 212 | wait_strategy_.signal_all_when_blocking(); 213 | } 214 | 215 | void publish(int64_t lo, int64_t hi) 216 | { 217 | for (int64_t i = lo; i <= hi; i++) 218 | { 219 | set_available(i); 220 | } 221 | wait_strategy_.signal_all_when_blocking(); 222 | } 223 | 224 | bool is_available(int64_t seq) const 225 | { 226 | int index = calculate_index(seq); 227 | int flag = calculate_availability_flag(seq); 228 | return available_buffer_[index] == flag; 229 | } 230 | 231 | int64_t get_highest_published_sequence(int64_t lower_bound, int64_t available_sequence) const 232 | { 233 | for (int64_t seq = lower_bound; seq <= available_sequence; seq++) 234 | { 235 | if (!is_available(seq)) 236 | return seq - 1; 237 | } 238 | return available_sequence; 239 | } 240 | 241 | private: 242 | multi_producer_sequencer(const multi_producer_sequencer&) = delete; 243 | multi_producer_sequencer& operator=(const multi_producer_sequencer&) = delete; 244 | multi_producer_sequencer(multi_producer_sequencer&&) = delete; 245 | multi_producer_sequencer& operator=(multi_producer_sequencer&&) = delete; 246 | 247 | static constexpr int INDEX_MASK = BufferSize - 1; 248 | static constexpr int INDEX_SHIFT = util::log2(BufferSize); 249 | 250 | bool has_available_capacity(int required_capacity, int cursor_value) 251 | { 252 | int64_t wrap_point = (cursor_value + required_capacity) - BufferSize; 253 | int64_t cached_gating_sequence = gating_sequence_cache_.get(); 254 | if (wrap_point > cached_gating_sequence || cached_gating_sequence > cursor_value) 255 | { 256 | int64_t min_sequence = util::get_minimum_sequence(gating_sequences_, cursor_value); 257 | gating_sequence_cache_.set(min_sequence); 258 | if (wrap_point > min_sequence) 259 | return false; 260 | } 261 | return true; 262 | } 263 | 264 | void set_available(int64_t seq) 265 | { 266 | int index = calculate_index(seq); 267 | int flag = calculate_availability_flag(seq); 268 | available_buffer_[index] = flag; 269 | } 270 | 271 | int calculate_availability_flag(int64_t seq) const 272 | { 273 | return (int)(((uint64_t)seq) >> INDEX_SHIFT); 274 | } 275 | 276 | int calculate_index(int64_t seq) const 277 | { 278 | return ((int)seq) & INDEX_MASK; 279 | } 280 | 281 | TSequence cursor_; 282 | TSequence gating_sequence_cache_; 283 | TWaitStrategy wait_strategy_; 284 | std::vector gating_sequences_; 285 | int available_buffer_[BufferSize]; 286 | }; 287 | } 288 | 289 | #endif 290 | -------------------------------------------------------------------------------- /include/disruptor4cpp/no_op_event_processor.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2015, Alex Man-fui Lee 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | 8 | * Redistributions of source code must retain the above copyright notice, this 9 | list of conditions and the following disclaimer. 10 | 11 | * Redistributions in binary form must reproduce the above copyright notice, 12 | this list of conditions and the following disclaimer in the documentation 13 | and/or other materials provided with the distribution. 14 | 15 | * Neither the name of disruptor4cpp nor the names of its 16 | contributors may be used to endorse or promote products derived from 17 | this software without specific prior written permission. 18 | 19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 20 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 23 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 25 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 26 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 27 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | */ 30 | 31 | #ifndef DISRUPTOR4CPP_NO_OP_EVENT_PROCESSOR_H_ 32 | #define DISRUPTOR4CPP_NO_OP_EVENT_PROCESSOR_H_ 33 | 34 | #include 35 | #include 36 | #include 37 | #include 38 | 39 | #include "event_handler.h" 40 | #include "exceptions/alert_exception.h" 41 | #include "exceptions/timeout_exception.h" 42 | #include "sequence.h" 43 | 44 | namespace disruptor4cpp 45 | { 46 | template 47 | class no_op_event_processor 48 | { 49 | public: 50 | no_op_event_processor(TRingBuffer& ring_buffer, 51 | typename TRingBuffer::sequence_barrier_type& sequence_barrier) 52 | : sequence_(), 53 | ring_buffer_(ring_buffer), 54 | sequence_barrier_(sequence_barrier), 55 | running_(false) 56 | { 57 | } 58 | 59 | no_op_event_processor(TRingBuffer& ring_buffer, 60 | std::unique_ptr sequence_barrier_ptr) 61 | : sequence_(), 62 | ring_buffer_(ring_buffer), 63 | sequence_barrier_(*sequence_barrier_ptr), 64 | sequence_barrier_ptr_(std::move(sequence_barrier_ptr)), 65 | running_(false) 66 | { 67 | } 68 | 69 | typename TRingBuffer::sequence_type& get_sequence() 70 | { 71 | return sequence_; 72 | } 73 | 74 | void halt() 75 | { 76 | running_.store(false, std::memory_order_release); 77 | } 78 | 79 | bool is_running() const 80 | { 81 | return running_.load(std::memory_order_acquire); 82 | } 83 | 84 | void run() 85 | { 86 | bool expected_running_state = false; 87 | if (!running_.compare_exchange_strong(expected_running_state, true)) 88 | throw std::runtime_error("Thread is already running"); 89 | 90 | // Implemenent with the same logic in batch event processor without notification. 91 | // Different from the java version. 92 | sequence_barrier_.clear_alert(); 93 | int64_t next_sequence = sequence_.get() + 1; 94 | try 95 | { 96 | while (true) 97 | { 98 | try 99 | { 100 | const int64_t available_sequence = sequence_barrier_.wait_for(next_sequence); 101 | while (next_sequence <= available_sequence) 102 | { 103 | next_sequence++; 104 | } 105 | sequence_.set(available_sequence); 106 | } 107 | catch (timeout_exception& timeout_ex) 108 | { 109 | } 110 | catch (alert_exception& alert_ex) 111 | { 112 | if (!running_.load(std::memory_order_acquire)) 113 | break; 114 | } 115 | catch (std::exception& ex) 116 | { 117 | sequence_.set(next_sequence); 118 | next_sequence++; 119 | } 120 | } 121 | } 122 | catch (...) 123 | { 124 | running_.store(false, std::memory_order_release); 125 | throw; 126 | } 127 | running_.store(false, std::memory_order_release); 128 | } 129 | 130 | private: 131 | typename TRingBuffer::sequence_type sequence_; 132 | TRingBuffer& ring_buffer_; 133 | typename TRingBuffer::sequence_barrier_type& sequence_barrier_; 134 | std::unique_ptr sequence_barrier_ptr_; 135 | std::atomic running_; 136 | }; 137 | } 138 | 139 | #endif 140 | -------------------------------------------------------------------------------- /include/disruptor4cpp/producer_type.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2015, Alex Man-fui Lee 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | 8 | * Redistributions of source code must retain the above copyright notice, this 9 | list of conditions and the following disclaimer. 10 | 11 | * Redistributions in binary form must reproduce the above copyright notice, 12 | this list of conditions and the following disclaimer in the documentation 13 | and/or other materials provided with the distribution. 14 | 15 | * Neither the name of disruptor4cpp nor the names of its 16 | contributors may be used to endorse or promote products derived from 17 | this software without specific prior written permission. 18 | 19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 20 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 23 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 25 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 26 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 27 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | */ 30 | 31 | #ifndef DISRUPTOR4CPP_PRODUCER_TYPE_H_ 32 | #define DISRUPTOR4CPP_PRODUCER_TYPE_H_ 33 | 34 | namespace disruptor4cpp 35 | { 36 | enum class producer_type : int 37 | { 38 | single, 39 | multi 40 | }; 41 | } 42 | 43 | #endif 44 | -------------------------------------------------------------------------------- /include/disruptor4cpp/ring_buffer.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2015, Alex Man-fui Lee 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | 8 | * Redistributions of source code must retain the above copyright notice, this 9 | list of conditions and the following disclaimer. 10 | 11 | * Redistributions in binary form must reproduce the above copyright notice, 12 | this list of conditions and the following disclaimer in the documentation 13 | and/or other materials provided with the distribution. 14 | 15 | * Neither the name of disruptor4cpp nor the names of its 16 | contributors may be used to endorse or promote products derived from 17 | this software without specific prior written permission. 18 | 19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 20 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 23 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 25 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 26 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 27 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | */ 30 | 31 | #ifndef DISRUPTOR4CPP_RING_BUFFER_H_ 32 | #define DISRUPTOR4CPP_RING_BUFFER_H_ 33 | 34 | #include 35 | #include 36 | #include 37 | 38 | #include "producer_type.h" 39 | #include "sequencer_traits.h" 40 | #include "utils/cache_line_storage.h" 41 | 42 | namespace disruptor4cpp 43 | { 44 | template 46 | class ring_buffer : 47 | public sequencer_traits::sequencer_type 48 | { 49 | public: 50 | static_assert(std::is_default_constructible::value, "Event type must be default constructible"); 51 | static_assert((BufferSize & (~BufferSize + 1)) == BufferSize, "Ring buffer size must be a power of 2"); 52 | 53 | typedef TEvent event_type; 54 | typedef TWaitStrategy wait_strategy_type; 55 | typedef TSequence sequence_type; 56 | typedef typename sequencer_traits::sequence_barrier_type sequence_barrier_type; 57 | 58 | static constexpr std::size_t BUFFER_SIZE = BufferSize; 59 | static constexpr producer_type PRODUCER_TYPE = ProducerType; 60 | 61 | ring_buffer() = default; 62 | 63 | explicit ring_buffer(const TEvent& value) 64 | { 65 | for (int i = 0; i < BufferSize; i++) 66 | { 67 | events_[i].data = value; 68 | } 69 | } 70 | 71 | ~ring_buffer() = default; 72 | 73 | TEvent& operator[](int64_t seq) 74 | { 75 | return events_[seq & (BufferSize - 1)].data; 76 | } 77 | 78 | const TEvent& operator[](int64_t seq) const 79 | { 80 | return events_[seq & (BufferSize - 1)].data; 81 | } 82 | 83 | private: 84 | ring_buffer(const ring_buffer&) = delete; 85 | ring_buffer& operator=(const ring_buffer&) = delete; 86 | ring_buffer(ring_buffer&&) = delete; 87 | ring_buffer& operator=(ring_buffer&&) = delete; 88 | 89 | cache_line_storage events_[BufferSize]; 90 | }; 91 | } 92 | 93 | #endif 94 | -------------------------------------------------------------------------------- /include/disruptor4cpp/sequence.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2015, Alex Man-fui Lee 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | 8 | * Redistributions of source code must retain the above copyright notice, this 9 | list of conditions and the following disclaimer. 10 | 11 | * Redistributions in binary form must reproduce the above copyright notice, 12 | this list of conditions and the following disclaimer in the documentation 13 | and/or other materials provided with the distribution. 14 | 15 | * Neither the name of disruptor4cpp nor the names of its 16 | contributors may be used to endorse or promote products derived from 17 | this software without specific prior written permission. 18 | 19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 20 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 23 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 25 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 26 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 27 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | */ 30 | 31 | #ifndef DISRUPTOR4CPP_SEQUENCE_H_ 32 | #define DISRUPTOR4CPP_SEQUENCE_H_ 33 | 34 | #include 35 | #include 36 | 37 | #include "utils/cache_line_storage.h" 38 | 39 | namespace disruptor4cpp 40 | { 41 | class sequence 42 | { 43 | public: 44 | static constexpr int64_t INITIAL_VALUE = -1; 45 | 46 | sequence() 47 | : sequence_(INITIAL_VALUE) 48 | { 49 | } 50 | 51 | explicit sequence(int64_t initial_value) 52 | : sequence_(initial_value) 53 | { 54 | } 55 | 56 | ~sequence() = default; 57 | 58 | int64_t get() const 59 | { 60 | return sequence_.load(std::memory_order_acquire); 61 | } 62 | 63 | void set(int64_t value) 64 | { 65 | sequence_.store(value, std::memory_order_release); 66 | } 67 | 68 | bool compare_and_set(int64_t expected_value, int64_t new_value) 69 | { 70 | return sequence_.compare_exchange_weak(expected_value, new_value); 71 | } 72 | 73 | int64_t increment_and_get() 74 | { 75 | return add_and_get(1); 76 | } 77 | 78 | int64_t add_and_get(int64_t increment) 79 | { 80 | return sequence_.fetch_add(increment, std::memory_order_release) + increment; 81 | } 82 | 83 | private: 84 | sequence(const sequence&) = delete; 85 | sequence& operator=(const sequence&) = delete; 86 | sequence(sequence&&) = delete; 87 | sequence& operator=(sequence&&) = delete; 88 | 89 | alignas(CACHE_LINE_SIZE) std::atomic sequence_; 90 | char padding[CACHE_LINE_SIZE - sizeof(std::atomic)]; 91 | }; 92 | } 93 | 94 | #endif 95 | -------------------------------------------------------------------------------- /include/disruptor4cpp/sequence_barrier.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2015, Alex Man-fui Lee 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | 8 | * Redistributions of source code must retain the above copyright notice, this 9 | list of conditions and the following disclaimer. 10 | 11 | * Redistributions in binary form must reproduce the above copyright notice, 12 | this list of conditions and the following disclaimer in the documentation 13 | and/or other materials provided with the distribution. 14 | 15 | * Neither the name of disruptor4cpp nor the names of its 16 | contributors may be used to endorse or promote products derived from 17 | this software without specific prior written permission. 18 | 19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 20 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 23 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 25 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 26 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 27 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | */ 30 | 31 | #ifndef DISRUPTOR4CPP_SEQUENCE_BARRIER_H_ 32 | #define DISRUPTOR4CPP_SEQUENCE_BARRIER_H_ 33 | 34 | #include 35 | #include 36 | 37 | #include "exceptions/alert_exception.h" 38 | #include "fixed_sequence_group.h" 39 | #include "sequence.h" 40 | #include "utils/util.h" 41 | 42 | namespace disruptor4cpp 43 | { 44 | template 45 | class sequence_barrier 46 | { 47 | public: 48 | typedef TSequencer sequencer_type; 49 | typedef typename TSequencer::wait_strategy_type wait_strategy_type; 50 | typedef typename TSequencer::sequence_type sequence_type; 51 | 52 | sequence_barrier(const TSequencer& sequencer, 53 | wait_strategy_type& wait_strategy, 54 | const sequence_type& cursor_sequence, 55 | const std::vector dependent_sequences) 56 | : dependent_sequence_(dependent_sequences.empty() 57 | ? fixed_sequence_group::create(cursor_sequence) 58 | : fixed_sequence_group::create(dependent_sequences)), 59 | sequencer_(sequencer), 60 | wait_strategy_(wait_strategy), 61 | cursor_sequence_(cursor_sequence), 62 | alerted_(false) 63 | { 64 | } 65 | 66 | ~sequence_barrier() = default; 67 | 68 | int64_t wait_for(int64_t seq) 69 | { 70 | check_alert(); 71 | 72 | int64_t available_sequence = wait_strategy_.wait_for(seq, cursor_sequence_, dependent_sequence_, *this); 73 | if (available_sequence < seq) 74 | return available_sequence; 75 | return sequencer_.get_highest_published_sequence(seq, available_sequence); 76 | } 77 | 78 | int64_t get_cursor() const 79 | { 80 | return dependent_sequence_.get(); 81 | } 82 | 83 | bool is_alerted() const 84 | { 85 | return alerted_.load(std::memory_order_acquire); 86 | } 87 | 88 | void alert() 89 | { 90 | alerted_.store(true, std::memory_order_release); 91 | wait_strategy_.signal_all_when_blocking(); 92 | } 93 | 94 | void clear_alert() 95 | { 96 | alerted_.store(false, std::memory_order_release); 97 | } 98 | 99 | void check_alert() const 100 | { 101 | if (is_alerted()) 102 | throw alert_exception(); 103 | } 104 | 105 | private: 106 | sequence_barrier(const sequence_barrier&) = delete; 107 | sequence_barrier& operator=(const sequence_barrier&) = delete; 108 | sequence_barrier(sequence_barrier&&) = delete; 109 | sequence_barrier& operator=(sequence_barrier&&) = delete; 110 | 111 | fixed_sequence_group dependent_sequence_; 112 | const TSequencer& sequencer_; 113 | wait_strategy_type& wait_strategy_; 114 | const sequence_type& cursor_sequence_; 115 | std::atomic alerted_; 116 | }; 117 | } 118 | 119 | #endif 120 | -------------------------------------------------------------------------------- /include/disruptor4cpp/sequencer_traits.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2015, Alex Man-fui Lee 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | 8 | * Redistributions of source code must retain the above copyright notice, this 9 | list of conditions and the following disclaimer. 10 | 11 | * Redistributions in binary form must reproduce the above copyright notice, 12 | this list of conditions and the following disclaimer in the documentation 13 | and/or other materials provided with the distribution. 14 | 15 | * Neither the name of disruptor4cpp nor the names of its 16 | contributors may be used to endorse or promote products derived from 17 | this software without specific prior written permission. 18 | 19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 20 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 23 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 25 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 26 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 27 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | */ 30 | 31 | #ifndef DISRUPTOR4CPP_SEQUENCER_TRAITS_H_ 32 | #define DISRUPTOR4CPP_SEQUENCER_TRAITS_H_ 33 | 34 | #include 35 | 36 | #include "multi_producer_sequencer.h" 37 | #include "producer_type.h" 38 | #include "sequence_barrier.h" 39 | #include "single_producer_sequencer.h" 40 | 41 | namespace disruptor4cpp 42 | { 43 | template 45 | struct sequencer_traits; 46 | 47 | template 48 | struct sequencer_traits 49 | { 50 | typedef TWaitStrategy wait_strategy_type; 51 | typedef TSequence sequence_type; 52 | typedef single_producer_sequencer sequencer_type; 53 | typedef sequence_barrier sequence_barrier_type; 54 | 55 | static constexpr std::size_t BUFFER_SIZE = BufferSize; 56 | static constexpr producer_type PRODUCER_TYPE = producer_type::single; 57 | }; 58 | 59 | template 60 | struct sequencer_traits 61 | { 62 | typedef TWaitStrategy wait_strategy_type; 63 | typedef TSequence sequence_type; 64 | typedef multi_producer_sequencer sequencer_type; 65 | typedef sequence_barrier sequence_barrier_type; 66 | 67 | static constexpr std::size_t BUFFER_SIZE = BufferSize; 68 | static constexpr producer_type PRODUCER_TYPE = producer_type::multi; 69 | }; 70 | } 71 | 72 | #endif 73 | -------------------------------------------------------------------------------- /include/disruptor4cpp/single_producer_sequencer.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2015, Alex Man-fui Lee 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | 8 | * Redistributions of source code must retain the above copyright notice, this 9 | list of conditions and the following disclaimer. 10 | 11 | * Redistributions in binary form must reproduce the above copyright notice, 12 | this list of conditions and the following disclaimer in the documentation 13 | and/or other materials provided with the distribution. 14 | 15 | * Neither the name of disruptor4cpp nor the names of its 16 | contributors may be used to endorse or promote products derived from 17 | this software without specific prior written permission. 18 | 19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 20 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 23 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 25 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 26 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 27 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | */ 30 | 31 | #ifndef DISRUPTOR4CPP_SINGLE_PRODUCER_SEQUENCER_H_ 32 | #define DISRUPTOR4CPP_SINGLE_PRODUCER_SEQUENCER_H_ 33 | 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | 41 | #include "exceptions/insufficient_capacity_exception.h" 42 | #include "sequence.h" 43 | #include "sequence_barrier.h" 44 | #include "utils/util.h" 45 | 46 | namespace disruptor4cpp 47 | { 48 | template 49 | class single_producer_sequencer 50 | { 51 | public: 52 | typedef TWaitStrategy wait_strategy_type; 53 | typedef TSequence sequence_type; 54 | typedef sequence_barrier< 55 | single_producer_sequencer> sequence_barrier_type; 56 | 57 | static constexpr int64_t INITIAL_CURSOR_VALUE = -1; 58 | static constexpr std::size_t BUFFER_SIZE = BufferSize; 59 | 60 | single_producer_sequencer() 61 | : cursor_(), 62 | wait_strategy_(), 63 | gating_sequences_(), 64 | next_value_(TSequence::INITIAL_VALUE), 65 | cached_value_(TSequence::INITIAL_VALUE) 66 | { 67 | } 68 | 69 | ~single_producer_sequencer() = default; 70 | 71 | int64_t get_cursor() const 72 | { 73 | return cursor_.get(); 74 | } 75 | 76 | constexpr std::size_t get_buffer_size() const 77 | { 78 | return BUFFER_SIZE; 79 | } 80 | 81 | TWaitStrategy& get_wait_strategy() 82 | { 83 | return wait_strategy_; 84 | } 85 | 86 | void add_gating_sequences(const std::vector& sequences_to_add) 87 | { 88 | // TODO: It is different from the java version. 89 | // The java version allows to change gating sequences after disruptor is started. 90 | int64_t cursor_sequence = cursor_.get(); 91 | for (auto seq : sequences_to_add) 92 | { 93 | seq->set(cursor_sequence); 94 | gating_sequences_.push_back(seq); 95 | } 96 | } 97 | 98 | bool remove_gating_sequence(const TSequence& seq) 99 | { 100 | // TODO: It is different from the java version. 101 | // The java version allows to change gating sequences after disruptor is started. 102 | bool removed = false; 103 | for (auto iter = gating_sequences_.begin(); iter != gating_sequences_.end();) 104 | { 105 | if (*iter == &seq) 106 | { 107 | removed = true; 108 | iter = gating_sequences_.erase(iter); 109 | } 110 | else 111 | ++iter; 112 | } 113 | return removed; 114 | } 115 | 116 | int64_t get_minimum_sequence() const 117 | { 118 | return util::get_minimum_sequence(gating_sequences_); 119 | } 120 | 121 | std::unique_ptr new_barrier() 122 | { 123 | return new_barrier(std::vector()); 124 | } 125 | 126 | std::unique_ptr new_barrier(const std::vector& sequences_to_track) 127 | { 128 | return std::unique_ptr( 129 | new sequence_barrier_type(*this, wait_strategy_, cursor_, sequences_to_track)); 130 | } 131 | 132 | bool has_available_capacity(int required_capacity) 133 | { 134 | int64_t next_value = next_value_; 135 | int64_t wrap_point = (next_value + required_capacity) - BufferSize; 136 | int64_t cached_gating_sequence = cached_value_; 137 | if (wrap_point > cached_gating_sequence || cached_gating_sequence > next_value) 138 | { 139 | int64_t min_sequence = util::get_minimum_sequence(gating_sequences_, next_value); 140 | cached_value_ = min_sequence; 141 | if (wrap_point > min_sequence) 142 | return false; 143 | } 144 | return true; 145 | } 146 | 147 | int64_t next() 148 | { 149 | return next(1); 150 | } 151 | 152 | int64_t next(int n) 153 | { 154 | if (n < 1) 155 | throw std::invalid_argument("n must be > 0"); 156 | 157 | int64_t next_value = next_value_; 158 | int64_t next_sequence = next_value + n; 159 | int64_t wrap_point = next_sequence - BufferSize; 160 | int64_t cached_gating_sequence = cached_value_; 161 | 162 | if (wrap_point > cached_gating_sequence || cached_gating_sequence > next_value) 163 | { 164 | int64_t min_sequence; 165 | while (wrap_point > (min_sequence = util::get_minimum_sequence(gating_sequences_, next_value))) 166 | { 167 | std::this_thread::yield(); 168 | } 169 | cached_value_ = min_sequence; 170 | } 171 | next_value_ = next_sequence; 172 | return next_sequence; 173 | } 174 | 175 | int64_t try_next() 176 | { 177 | return try_next(1); 178 | } 179 | 180 | int64_t try_next(int n) 181 | { 182 | if (n < 1) 183 | throw std::invalid_argument("n must be > 0"); 184 | if (!has_available_capacity(n)) 185 | throw insufficient_capacity_exception(); 186 | 187 | int64_t next_sequence = (next_value_ += n); 188 | return next_sequence; 189 | } 190 | 191 | int64_t remaining_capacity() const 192 | { 193 | int64_t next_value = next_value_; 194 | int64_t consumed = util::get_minimum_sequence(gating_sequences_, next_value); 195 | int64_t produced = next_value; 196 | return BufferSize - (produced - consumed); 197 | } 198 | 199 | void claim(int64_t seq) 200 | { 201 | next_value_ = seq; 202 | } 203 | 204 | void publish(int64_t seq) 205 | { 206 | cursor_.set(seq); 207 | wait_strategy_.signal_all_when_blocking(); 208 | } 209 | 210 | void publish(int64_t lo, int64_t hi) 211 | { 212 | publish(hi); 213 | } 214 | 215 | bool is_available(int64_t seq) const 216 | { 217 | return seq <= cursor_.get(); 218 | } 219 | 220 | int64_t get_highest_published_sequence(int64_t lower_bound, int64_t available_sequence) const 221 | { 222 | return available_sequence; 223 | } 224 | 225 | private: 226 | single_producer_sequencer(const single_producer_sequencer&) = delete; 227 | single_producer_sequencer& operator=(const single_producer_sequencer&) = delete; 228 | single_producer_sequencer(single_producer_sequencer&&) = delete; 229 | single_producer_sequencer& operator=(single_producer_sequencer&&) = delete; 230 | 231 | TSequence cursor_; 232 | TWaitStrategy wait_strategy_; 233 | std::vector gating_sequences_; 234 | int64_t next_value_; 235 | int64_t cached_value_; 236 | }; 237 | } 238 | 239 | #endif 240 | -------------------------------------------------------------------------------- /include/disruptor4cpp/utils/cache_line_storage.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2015, Alex Man-fui Lee 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | 8 | * Redistributions of source code must retain the above copyright notice, this 9 | list of conditions and the following disclaimer. 10 | 11 | * Redistributions in binary form must reproduce the above copyright notice, 12 | this list of conditions and the following disclaimer in the documentation 13 | and/or other materials provided with the distribution. 14 | 15 | * Neither the name of disruptor4cpp nor the names of its 16 | contributors may be used to endorse or promote products derived from 17 | this software without specific prior written permission. 18 | 19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 20 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 23 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 25 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 26 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 27 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | */ 30 | 31 | #ifndef DISRUPTOR4CPP_UTILS_CACHE_LINE_STORAGE_H_ 32 | #define DISRUPTOR4CPP_UTILS_CACHE_LINE_STORAGE_H_ 33 | 34 | #ifndef CACHE_LINE_SIZE 35 | #define CACHE_LINE_SIZE 64 36 | #endif 37 | 38 | namespace disruptor4cpp 39 | { 40 | template 41 | struct cache_line_storage 42 | { 43 | alignas(CACHE_LINE_SIZE) T data; 44 | 45 | private: 46 | char padding[CACHE_LINE_SIZE > sizeof(T) ? CACHE_LINE_SIZE - sizeof(T) : 1]; 47 | }; 48 | } 49 | 50 | #endif 51 | -------------------------------------------------------------------------------- /include/disruptor4cpp/utils/util.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2015, Alex Man-fui Lee 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | 8 | * Redistributions of source code must retain the above copyright notice, this 9 | list of conditions and the following disclaimer. 10 | 11 | * Redistributions in binary form must reproduce the above copyright notice, 12 | this list of conditions and the following disclaimer in the documentation 13 | and/or other materials provided with the distribution. 14 | 15 | * Neither the name of disruptor4cpp nor the names of its 16 | contributors may be used to endorse or promote products derived from 17 | this software without specific prior written permission. 18 | 19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 20 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 23 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 25 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 26 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 27 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | */ 30 | 31 | #ifndef DISRUPTOR4CPP_UTILS_UTIL_H_ 32 | #define DISRUPTOR4CPP_UTILS_UTIL_H_ 33 | 34 | #include 35 | #include 36 | #include 37 | 38 | namespace disruptor4cpp 39 | { 40 | class util 41 | { 42 | public: 43 | template 44 | static int64_t get_minimum_sequence(const std::vector& sequences) 45 | { 46 | return get_minimum_sequence(sequences, LLONG_MAX); 47 | } 48 | 49 | template 50 | static int64_t get_minimum_sequence(const std::vector& sequences, int64_t minimum) 51 | { 52 | for (const auto& seq : sequences) 53 | { 54 | int64_t value = seq->get(); 55 | if (value < minimum) 56 | minimum = value; 57 | } 58 | return minimum; 59 | } 60 | 61 | template 62 | static int64_t get_minimum_sequence(const std::vector& sequences) 63 | { 64 | return get_minimum_sequence(sequences, LLONG_MAX); 65 | } 66 | 67 | template 68 | static int64_t get_minimum_sequence(const std::vector& sequences, int64_t minimum) 69 | { 70 | for (const auto& seq : sequences) 71 | { 72 | int64_t value = seq->get(); 73 | if (value < minimum) 74 | minimum = value; 75 | } 76 | return minimum; 77 | } 78 | 79 | constexpr static int log2(int value) 80 | { 81 | return value > 0 82 | ? (value < 2 ? 0 : log2(value / 2) + 1) 83 | : throw std::invalid_argument("value must be > 0"); 84 | } 85 | }; 86 | } 87 | 88 | #endif 89 | -------------------------------------------------------------------------------- /include/disruptor4cpp/wait_strategies/blocking_wait_strategy.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2015, Alex Man-fui Lee 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | 8 | * Redistributions of source code must retain the above copyright notice, this 9 | list of conditions and the following disclaimer. 10 | 11 | * Redistributions in binary form must reproduce the above copyright notice, 12 | this list of conditions and the following disclaimer in the documentation 13 | and/or other materials provided with the distribution. 14 | 15 | * Neither the name of disruptor4cpp nor the names of its 16 | contributors may be used to endorse or promote products derived from 17 | this software without specific prior written permission. 18 | 19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 20 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 23 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 25 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 26 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 27 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | */ 30 | 31 | #ifndef DISRUPTOR4CPP_WAIT_STRATEGIES_BLOCKING_WAIT_STRATEGY_H_ 32 | #define DISRUPTOR4CPP_WAIT_STRATEGIES_BLOCKING_WAIT_STRATEGY_H_ 33 | 34 | #include 35 | #include 36 | #include 37 | 38 | #include "../fixed_sequence_group.h" 39 | 40 | namespace disruptor4cpp 41 | { 42 | class blocking_wait_strategy 43 | { 44 | public: 45 | blocking_wait_strategy() = default; 46 | ~blocking_wait_strategy() = default; 47 | 48 | template 49 | int64_t wait_for(int64_t seq, const TSequence& cursor_sequence, 50 | const fixed_sequence_group& dependent_sequence, 51 | const TSequenceBarrier& seq_barrier) 52 | { 53 | int64_t available_sequence = 0; 54 | if ((available_sequence = cursor_sequence.get()) < seq) 55 | { 56 | std::unique_lock lock(mutex_); 57 | while ((available_sequence = cursor_sequence.get()) < seq) 58 | { 59 | seq_barrier.check_alert(); 60 | processor_notify_condition_.wait(lock); 61 | } 62 | } 63 | 64 | while ((available_sequence = dependent_sequence.get()) < seq) 65 | { 66 | seq_barrier.check_alert(); 67 | } 68 | return available_sequence; 69 | } 70 | 71 | void signal_all_when_blocking() 72 | { 73 | std::lock_guard lock(mutex_); 74 | processor_notify_condition_.notify_all(); 75 | } 76 | 77 | private: 78 | blocking_wait_strategy(const blocking_wait_strategy&) = delete; 79 | blocking_wait_strategy& operator=(const blocking_wait_strategy&) = delete; 80 | blocking_wait_strategy(blocking_wait_strategy&&) = delete; 81 | blocking_wait_strategy& operator=(blocking_wait_strategy&&) = delete; 82 | 83 | std::recursive_mutex mutex_; 84 | std::condition_variable_any processor_notify_condition_; 85 | }; 86 | } 87 | 88 | #endif 89 | -------------------------------------------------------------------------------- /include/disruptor4cpp/wait_strategies/busy_spin_wait_strategy.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2015, Alex Man-fui Lee 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | 8 | * Redistributions of source code must retain the above copyright notice, this 9 | list of conditions and the following disclaimer. 10 | 11 | * Redistributions in binary form must reproduce the above copyright notice, 12 | this list of conditions and the following disclaimer in the documentation 13 | and/or other materials provided with the distribution. 14 | 15 | * Neither the name of disruptor4cpp nor the names of its 16 | contributors may be used to endorse or promote products derived from 17 | this software without specific prior written permission. 18 | 19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 20 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 23 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 25 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 26 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 27 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | */ 30 | 31 | #ifndef DISRUPTOR4CPP_WAIT_STRATEGIES_BUSY_SPIN_WAIT_STRATEGY_H_ 32 | #define DISRUPTOR4CPP_WAIT_STRATEGIES_BUSY_SPIN_WAIT_STRATEGY_H_ 33 | 34 | #include 35 | 36 | #include "../fixed_sequence_group.h" 37 | 38 | namespace disruptor4cpp 39 | { 40 | class busy_spin_wait_strategy 41 | { 42 | public: 43 | busy_spin_wait_strategy() = default; 44 | ~busy_spin_wait_strategy() = default; 45 | 46 | template 47 | int64_t wait_for(int64_t seq, const TSequence& cursor_sequence, 48 | const fixed_sequence_group& dependent_sequence, 49 | const TSequenceBarrier& seq_barrier) 50 | { 51 | int64_t available_sequence = 0; 52 | while ((available_sequence = dependent_sequence.get()) < seq) 53 | { 54 | seq_barrier.check_alert(); 55 | } 56 | return available_sequence; 57 | } 58 | 59 | void signal_all_when_blocking() 60 | { 61 | } 62 | 63 | private: 64 | busy_spin_wait_strategy(const busy_spin_wait_strategy&) = delete; 65 | busy_spin_wait_strategy& operator=(const busy_spin_wait_strategy&) = delete; 66 | busy_spin_wait_strategy(busy_spin_wait_strategy&&) = delete; 67 | busy_spin_wait_strategy& operator=(busy_spin_wait_strategy&&) = delete; 68 | }; 69 | } 70 | 71 | #endif 72 | -------------------------------------------------------------------------------- /include/disruptor4cpp/wait_strategies/lite_blocking_wait_strategy.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2015, Alex Man-fui Lee 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | 8 | * Redistributions of source code must retain the above copyright notice, this 9 | list of conditions and the following disclaimer. 10 | 11 | * Redistributions in binary form must reproduce the above copyright notice, 12 | this list of conditions and the following disclaimer in the documentation 13 | and/or other materials provided with the distribution. 14 | 15 | * Neither the name of disruptor4cpp nor the names of its 16 | contributors may be used to endorse or promote products derived from 17 | this software without specific prior written permission. 18 | 19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 20 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 23 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 25 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 26 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 27 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | */ 30 | 31 | #ifndef DISRUPTOR4CPP_WAIT_STRATEGIES_LITE_BLOCKING_WAIT_STRATEGY_H_ 32 | #define DISRUPTOR4CPP_WAIT_STRATEGIES_LITE_BLOCKING_WAIT_STRATEGY_H_ 33 | 34 | #include 35 | #include 36 | #include 37 | #include 38 | 39 | #include "../fixed_sequence_group.h" 40 | 41 | namespace disruptor4cpp 42 | { 43 | class lite_blocking_wait_strategy 44 | { 45 | public: 46 | lite_blocking_wait_strategy() 47 | : signal_needed_(false) 48 | { 49 | } 50 | 51 | ~lite_blocking_wait_strategy() = default; 52 | 53 | template 54 | int64_t wait_for(int64_t seq, const TSequence& cursor_sequence, 55 | const fixed_sequence_group& dependent_sequence, 56 | const TSequenceBarrier& seq_barrier) 57 | { 58 | int64_t available_sequence = 0; 59 | if ((available_sequence = cursor_sequence.get()) < seq) 60 | { 61 | std::unique_lock lock(mutex_); 62 | do 63 | { 64 | signal_needed_.store(true, std::memory_order_release); 65 | if ((available_sequence = cursor_sequence.get()) >= seq) 66 | break; 67 | 68 | seq_barrier.check_alert(); 69 | processor_notify_condition_.wait(lock); 70 | } 71 | while ((available_sequence = cursor_sequence.get()) < seq); 72 | } 73 | 74 | while ((available_sequence = dependent_sequence.get()) < seq) 75 | { 76 | seq_barrier.check_alert(); 77 | } 78 | return available_sequence; 79 | } 80 | 81 | void signal_all_when_blocking() 82 | { 83 | if (signal_needed_.exchange(false, std::memory_order_release)) 84 | { 85 | std::lock_guard lock(mutex_); 86 | processor_notify_condition_.notify_all(); 87 | } 88 | } 89 | 90 | private: 91 | lite_blocking_wait_strategy(const lite_blocking_wait_strategy&) = delete; 92 | lite_blocking_wait_strategy& operator=(const lite_blocking_wait_strategy&) = delete; 93 | lite_blocking_wait_strategy(lite_blocking_wait_strategy&&) = delete; 94 | lite_blocking_wait_strategy& operator=(lite_blocking_wait_strategy&&) = delete; 95 | 96 | std::recursive_mutex mutex_; 97 | std::condition_variable_any processor_notify_condition_; 98 | std::atomic signal_needed_; 99 | }; 100 | } 101 | 102 | #endif 103 | -------------------------------------------------------------------------------- /include/disruptor4cpp/wait_strategies/phased_backoff_wait_strategy.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2015, Alex Man-fui Lee 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | 8 | * Redistributions of source code must retain the above copyright notice, this 9 | list of conditions and the following disclaimer. 10 | 11 | * Redistributions in binary form must reproduce the above copyright notice, 12 | this list of conditions and the following disclaimer in the documentation 13 | and/or other materials provided with the distribution. 14 | 15 | * Neither the name of disruptor4cpp nor the names of its 16 | contributors may be used to endorse or promote products derived from 17 | this software without specific prior written permission. 18 | 19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 20 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 23 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 25 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 26 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 27 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | */ 30 | 31 | #ifndef DISRUPTOR4CPP_WAIT_STRATEGIES_PHASED_BACKOFF_WAIT_STRATEGY_H_ 32 | #define DISRUPTOR4CPP_WAIT_STRATEGIES_PHASED_BACKOFF_WAIT_STRATEGY_H_ 33 | 34 | #include 35 | #include 36 | #include 37 | #include 38 | 39 | #include "../fixed_sequence_group.h" 40 | 41 | namespace disruptor4cpp 42 | { 43 | template 45 | class phased_backoff_wait_strategy 46 | { 47 | public: 48 | phased_backoff_wait_strategy() = default; 49 | ~phased_backoff_wait_strategy() = default; 50 | 51 | template 52 | int64_t wait_for(int64_t seq, const TSequence& cursor_sequence, 53 | const fixed_sequence_group& dependent_sequence, 54 | const TSequenceBarrier& seq_barrier) 55 | { 56 | int64_t available_sequence = 0; 57 | std::chrono::system_clock::time_point start_time; 58 | int counter = SPIN_TRIES; 59 | 60 | do 61 | { 62 | if ((available_sequence = dependent_sequence.get()) >= seq) 63 | return available_sequence; 64 | 65 | --counter; 66 | if (counter == 0) 67 | { 68 | if (start_time.time_since_epoch() == std::chrono::system_clock::duration::zero()) 69 | start_time = std::chrono::system_clock::now(); 70 | else 71 | { 72 | int64_t time_delta = std::chrono::duration_cast( 73 | std::chrono::system_clock::now() - start_time).count(); 74 | if (time_delta > YieldTimeoutNanoseconds) 75 | return fallback_strategy_.wait_for(seq, cursor_sequence, dependent_sequence, seq_barrier); 76 | else if (time_delta > SpinTimeoutNanoseconds) 77 | std::this_thread::yield(); 78 | } 79 | counter = SPIN_TRIES; 80 | } 81 | } 82 | while (true); 83 | } 84 | 85 | void signal_all_when_blocking() 86 | { 87 | fallback_strategy_.signal_all_when_blocking(); 88 | } 89 | 90 | private: 91 | phased_backoff_wait_strategy(const phased_backoff_wait_strategy&) = delete; 92 | phased_backoff_wait_strategy& operator=(const phased_backoff_wait_strategy&) = delete; 93 | phased_backoff_wait_strategy(phased_backoff_wait_strategy&&) = delete; 94 | phased_backoff_wait_strategy& operator=(phased_backoff_wait_strategy&&) = delete; 95 | 96 | static constexpr int SPIN_TRIES = 10000; 97 | 98 | TFallbackStrategy fallback_strategy_; 99 | }; 100 | } 101 | 102 | #endif 103 | -------------------------------------------------------------------------------- /include/disruptor4cpp/wait_strategies/sleeping_wait_strategy.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2015, Alex Man-fui Lee 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | 8 | * Redistributions of source code must retain the above copyright notice, this 9 | list of conditions and the following disclaimer. 10 | 11 | * Redistributions in binary form must reproduce the above copyright notice, 12 | this list of conditions and the following disclaimer in the documentation 13 | and/or other materials provided with the distribution. 14 | 15 | * Neither the name of disruptor4cpp nor the names of its 16 | contributors may be used to endorse or promote products derived from 17 | this software without specific prior written permission. 18 | 19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 20 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 23 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 25 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 26 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 27 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | */ 30 | 31 | #ifndef DISRUPTOR4CPP_WAIT_STRATEGIES_SLEEPING_WAIT_STRATEGY_H_ 32 | #define DISRUPTOR4CPP_WAIT_STRATEGIES_SLEEPING_WAIT_STRATEGY_H_ 33 | 34 | #include 35 | #include 36 | #include 37 | 38 | #include "../fixed_sequence_group.h" 39 | 40 | namespace disruptor4cpp 41 | { 42 | template 43 | class sleeping_wait_strategy 44 | { 45 | public: 46 | sleeping_wait_strategy() = default; 47 | ~sleeping_wait_strategy() = default; 48 | 49 | template 50 | int64_t wait_for(int64_t seq, const TSequence& cursor_sequence, 51 | const fixed_sequence_group& dependent_sequence, 52 | const TSequenceBarrier& seq_barrier) 53 | { 54 | int64_t available_sequence = 0; 55 | int counter = Retries; 56 | 57 | while ((available_sequence = dependent_sequence.get()) < seq) 58 | { 59 | counter = apply_wait_method(seq_barrier, counter); 60 | } 61 | return available_sequence; 62 | } 63 | 64 | void signal_all_when_blocking() 65 | { 66 | } 67 | 68 | private: 69 | sleeping_wait_strategy(const sleeping_wait_strategy&) = delete; 70 | sleeping_wait_strategy& operator=(const sleeping_wait_strategy&) = delete; 71 | sleeping_wait_strategy(sleeping_wait_strategy&&) = delete; 72 | sleeping_wait_strategy& operator=(sleeping_wait_strategy&&) = delete; 73 | 74 | template 75 | int apply_wait_method(const TSequenceBarrier& seq_barrier, int counter) 76 | { 77 | seq_barrier.check_alert(); 78 | if (counter > 100) 79 | --counter; 80 | else if (counter > 0) 81 | { 82 | --counter; 83 | std::this_thread::yield(); 84 | } 85 | else 86 | std::this_thread::sleep_for(std::chrono::nanoseconds(1)); 87 | return counter; 88 | } 89 | }; 90 | } 91 | 92 | #endif 93 | -------------------------------------------------------------------------------- /include/disruptor4cpp/wait_strategies/timeout_blocking_wait_strategy.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2015, Alex Man-fui Lee 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | 8 | * Redistributions of source code must retain the above copyright notice, this 9 | list of conditions and the following disclaimer. 10 | 11 | * Redistributions in binary form must reproduce the above copyright notice, 12 | this list of conditions and the following disclaimer in the documentation 13 | and/or other materials provided with the distribution. 14 | 15 | * Neither the name of disruptor4cpp nor the names of its 16 | contributors may be used to endorse or promote products derived from 17 | this software without specific prior written permission. 18 | 19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 20 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 23 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 25 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 26 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 27 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | */ 30 | 31 | #ifndef DISRUPTOR4CPP_WAIT_STRATEGIES_TIMEOUT_BLOCKING_WAIT_STRATEGY_H_ 32 | #define DISRUPTOR4CPP_WAIT_STRATEGIES_TIMEOUT_BLOCKING_WAIT_STRATEGY_H_ 33 | 34 | #include 35 | #include 36 | #include 37 | #include 38 | 39 | #include "../exceptions/timeout_exception.h" 40 | #include "../fixed_sequence_group.h" 41 | 42 | namespace disruptor4cpp 43 | { 44 | template 45 | class timeout_blocking_wait_strategy 46 | { 47 | public: 48 | timeout_blocking_wait_strategy() = default; 49 | ~timeout_blocking_wait_strategy() = default; 50 | 51 | template 52 | int64_t wait_for(int64_t seq, const TSequence& cursor_sequence, 53 | const fixed_sequence_group& dependent_sequence, 54 | const TSequenceBarrier& seq_barrier) 55 | { 56 | int64_t available_sequence = 0; 57 | if ((available_sequence = cursor_sequence.get()) < seq) 58 | { 59 | std::unique_lock lock(mutex_); 60 | while ((available_sequence = cursor_sequence.get()) < seq) 61 | { 62 | seq_barrier.check_alert(); 63 | std::cv_status status = processor_notify_condition_.wait_for(lock, 64 | std::chrono::nanoseconds(TimeoutNanoseconds)); 65 | if (status == std::cv_status::timeout) 66 | throw timeout_exception(); 67 | } 68 | } 69 | 70 | while ((available_sequence = dependent_sequence.get()) < seq) 71 | { 72 | seq_barrier.check_alert(); 73 | } 74 | return available_sequence; 75 | } 76 | 77 | void signal_all_when_blocking() 78 | { 79 | std::lock_guard lock(mutex_); 80 | processor_notify_condition_.notify_all(); 81 | } 82 | 83 | private: 84 | timeout_blocking_wait_strategy(const timeout_blocking_wait_strategy&) = delete; 85 | timeout_blocking_wait_strategy& operator=(const timeout_blocking_wait_strategy&) = delete; 86 | timeout_blocking_wait_strategy(timeout_blocking_wait_strategy&&) = delete; 87 | timeout_blocking_wait_strategy& operator=(timeout_blocking_wait_strategy&&) = delete; 88 | 89 | std::recursive_mutex mutex_; 90 | std::condition_variable_any processor_notify_condition_; 91 | }; 92 | } 93 | 94 | #endif 95 | -------------------------------------------------------------------------------- /include/disruptor4cpp/wait_strategies/yielding_wait_strategy.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2015, Alex Man-fui Lee 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | 8 | * Redistributions of source code must retain the above copyright notice, this 9 | list of conditions and the following disclaimer. 10 | 11 | * Redistributions in binary form must reproduce the above copyright notice, 12 | this list of conditions and the following disclaimer in the documentation 13 | and/or other materials provided with the distribution. 14 | 15 | * Neither the name of disruptor4cpp nor the names of its 16 | contributors may be used to endorse or promote products derived from 17 | this software without specific prior written permission. 18 | 19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 20 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 23 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 25 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 26 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 27 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | */ 30 | 31 | #ifndef DISRUPTOR4CPP_WAIT_STRATEGIES_YIELDING_WAIT_STRATEGY_H_ 32 | #define DISRUPTOR4CPP_WAIT_STRATEGIES_YIELDING_WAIT_STRATEGY_H_ 33 | 34 | #include 35 | #include 36 | 37 | #include "../fixed_sequence_group.h" 38 | 39 | namespace disruptor4cpp 40 | { 41 | template 42 | class yielding_wait_strategy 43 | { 44 | public: 45 | yielding_wait_strategy() = default; 46 | ~yielding_wait_strategy() = default; 47 | 48 | template 49 | int64_t wait_for(int64_t seq, const TSequence& cursor_sequence, 50 | const fixed_sequence_group& dependent_sequence, 51 | const TSequenceBarrier& seq_barrier) 52 | { 53 | int64_t available_sequence = 0; 54 | int counter = SpinTries; 55 | 56 | while ((available_sequence = dependent_sequence.get()) < seq) 57 | { 58 | counter = apply_wait_method(seq_barrier, counter); 59 | } 60 | return available_sequence; 61 | } 62 | 63 | void signal_all_when_blocking() 64 | { 65 | } 66 | 67 | private: 68 | yielding_wait_strategy(const yielding_wait_strategy&) = delete; 69 | yielding_wait_strategy& operator=(const yielding_wait_strategy&) = delete; 70 | yielding_wait_strategy(yielding_wait_strategy&&) = delete; 71 | yielding_wait_strategy& operator=(yielding_wait_strategy&&) = delete; 72 | 73 | template 74 | int apply_wait_method(const TSequenceBarrier& seq_barrier, int counter) 75 | { 76 | seq_barrier.check_alert(); 77 | if (counter == 0) 78 | std::this_thread::yield(); 79 | else 80 | --counter; 81 | return counter; 82 | } 83 | }; 84 | } 85 | 86 | #endif 87 | -------------------------------------------------------------------------------- /test/dummy_sequence_barrier.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2015, Alex Man-fui Lee 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | 8 | * Redistributions of source code must retain the above copyright notice, this 9 | list of conditions and the following disclaimer. 10 | 11 | * Redistributions in binary form must reproduce the above copyright notice, 12 | this list of conditions and the following disclaimer in the documentation 13 | and/or other materials provided with the distribution. 14 | 15 | * Neither the name of disruptor4cpp nor the names of its 16 | contributors may be used to endorse or promote products derived from 17 | this software without specific prior written permission. 18 | 19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 20 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 23 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 25 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 26 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 27 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | */ 30 | 31 | #ifndef DISRUPTOR4CPP_TEST_DUMMY_SEQUENCE_BARRIER_H_ 32 | #define DISRUPTOR4CPP_TEST_DUMMY_SEQUENCE_BARRIER_H_ 33 | 34 | #include 35 | 36 | namespace disruptor4cpp 37 | { 38 | namespace test 39 | { 40 | class dummy_sequence_barrier 41 | { 42 | public: 43 | dummy_sequence_barrier() = default; 44 | ~dummy_sequence_barrier() = default; 45 | 46 | int64_t wait_for(int64_t seq) 47 | { 48 | return 0; 49 | } 50 | 51 | int64_t get_cursor() const 52 | { 53 | return 0; 54 | } 55 | 56 | bool is_alerted() const 57 | { 58 | return false; 59 | } 60 | 61 | void alert() 62 | { 63 | } 64 | 65 | void clear_alert() 66 | { 67 | } 68 | 69 | void check_alert() const 70 | { 71 | } 72 | 73 | private: 74 | dummy_sequence_barrier(const dummy_sequence_barrier&) = delete; 75 | dummy_sequence_barrier& operator=(const dummy_sequence_barrier&) = delete; 76 | dummy_sequence_barrier(dummy_sequence_barrier&&) = delete; 77 | dummy_sequence_barrier& operator=(dummy_sequence_barrier&&) = delete; 78 | }; 79 | } 80 | } 81 | 82 | #endif 83 | -------------------------------------------------------------------------------- /test/fixed_sequence_group_test.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2015, Alex Man-fui Lee 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | 8 | * Redistributions of source code must retain the above copyright notice, this 9 | list of conditions and the following disclaimer. 10 | 11 | * Redistributions in binary form must reproduce the above copyright notice, 12 | this list of conditions and the following disclaimer in the documentation 13 | and/or other materials provided with the distribution. 14 | 15 | * Neither the name of disruptor4cpp nor the names of its 16 | contributors may be used to endorse or promote products derived from 17 | this software without specific prior written permission. 18 | 19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 20 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 23 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 25 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 26 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 27 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | */ 30 | 31 | #include 32 | 33 | #include 34 | 35 | #include 36 | 37 | namespace disruptor4cpp 38 | { 39 | namespace test 40 | { 41 | TEST(fixed_sequence_group_test, should_return_minimum_of_2_sequences) 42 | { 43 | sequence sequence1(34); 44 | sequence sequence2(47); 45 | auto group = fixed_sequence_group::create(std::vector { &sequence1, &sequence2 }); 46 | 47 | ASSERT_EQ(34, group.get()); 48 | sequence1.set(35); 49 | ASSERT_EQ(35, group.get()); 50 | sequence1.set(48); 51 | ASSERT_EQ(47, group.get()); 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /test/main.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2015, Alex Man-fui Lee 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | 8 | * Redistributions of source code must retain the above copyright notice, this 9 | list of conditions and the following disclaimer. 10 | 11 | * Redistributions in binary form must reproduce the above copyright notice, 12 | this list of conditions and the following disclaimer in the documentation 13 | and/or other materials provided with the distribution. 14 | 15 | * Neither the name of disruptor4cpp nor the names of its 16 | contributors may be used to endorse or promote products derived from 17 | this software without specific prior written permission. 18 | 19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 20 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 23 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 25 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 26 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 27 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | */ 30 | 31 | #include 32 | #include 33 | 34 | int main(int argc, char* argv[]) 35 | { 36 | testing::InitGoogleTest(&argc, argv); 37 | testing::InitGoogleMock(&argc, argv); 38 | return RUN_ALL_TESTS(); 39 | } 40 | -------------------------------------------------------------------------------- /test/multi_producer_sequencer_test.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2015, Alex Man-fui Lee 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | 8 | * Redistributions of source code must retain the above copyright notice, this 9 | list of conditions and the following disclaimer. 10 | 11 | * Redistributions in binary form must reproduce the above copyright notice, 12 | this list of conditions and the following disclaimer in the documentation 13 | and/or other materials provided with the distribution. 14 | 15 | * Neither the name of disruptor4cpp nor the names of its 16 | contributors may be used to endorse or promote products derived from 17 | this software without specific prior written permission. 18 | 19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 20 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 23 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 25 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 26 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 27 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | */ 30 | 31 | #include 32 | 33 | #include 34 | 35 | #include 36 | 37 | namespace disruptor4cpp 38 | { 39 | namespace test 40 | { 41 | TEST(multi_producer_sequencer_test, should_only_allow_messages_to_be_available_if_specifically_published) 42 | { 43 | multi_producer_sequencer<1024, blocking_wait_strategy> publisher; 44 | publisher.publish(3); 45 | publisher.publish(5); 46 | 47 | ASSERT_FALSE(publisher.is_available(0)); 48 | ASSERT_FALSE(publisher.is_available(1)); 49 | ASSERT_FALSE(publisher.is_available(2)); 50 | ASSERT_TRUE(publisher.is_available(3)); 51 | ASSERT_FALSE(publisher.is_available(4)); 52 | ASSERT_TRUE(publisher.is_available(5)); 53 | ASSERT_FALSE(publisher.is_available(6)); 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /test/sequence_barrier_test.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2015, Alex Man-fui Lee 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | 8 | * Redistributions of source code must retain the above copyright notice, this 9 | list of conditions and the following disclaimer. 10 | 11 | * Redistributions in binary form must reproduce the above copyright notice, 12 | this list of conditions and the following disclaimer in the documentation 13 | and/or other materials provided with the distribution. 14 | 15 | * Neither the name of disruptor4cpp nor the names of its 16 | contributors may be used to endorse or promote products derived from 17 | this software without specific prior written permission. 18 | 19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 20 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 23 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 25 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 26 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 27 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | */ 30 | 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | 38 | #include 39 | #include 40 | 41 | #include 42 | #include "support/stub_event.h" 43 | #include "utils/count_down_latch.h" 44 | 45 | namespace disruptor4cpp 46 | { 47 | namespace test 48 | { 49 | class stub_event_processor 50 | { 51 | public: 52 | stub_event_processor() = default; 53 | ~stub_event_processor() = default; 54 | 55 | void set_sequence(int64_t value) 56 | { 57 | sequence_.set(value); 58 | } 59 | 60 | sequence& get_sequence() 61 | { 62 | return sequence_; 63 | } 64 | 65 | void halt() 66 | { 67 | running_.store(false, std::memory_order_release); 68 | } 69 | 70 | bool is_running() const 71 | { 72 | return running_.load(std::memory_order_acquire); 73 | } 74 | 75 | void run() 76 | { 77 | bool expected_running_state = false; 78 | if (!running_.compare_exchange_strong(expected_running_state, true)) 79 | throw std::runtime_error("Thread is already running"); 80 | } 81 | 82 | private: 83 | sequence sequence_; 84 | std::atomic running_; 85 | }; 86 | 87 | class count_down_latch_sequence 88 | { 89 | public: 90 | count_down_latch_sequence() 91 | : sequence_(-1), 92 | default_latch_(0), 93 | latch_(default_latch_) 94 | { 95 | } 96 | 97 | count_down_latch_sequence(int64_t initial_value, count_down_latch& latch) 98 | : sequence_(initial_value), 99 | default_latch_(0), 100 | latch_(latch) 101 | { 102 | } 103 | 104 | ~count_down_latch_sequence() = default; 105 | 106 | int64_t get() const 107 | { 108 | latch_.count_down(); 109 | return sequence_.load(std::memory_order_acquire); 110 | } 111 | 112 | void set(int64_t value) 113 | { 114 | sequence_.store(value, std::memory_order_release); 115 | } 116 | 117 | bool compare_and_set(int64_t expected_value, int64_t new_value) 118 | { 119 | return sequence_.compare_exchange_weak(expected_value, new_value); 120 | } 121 | 122 | int64_t increment_and_get() 123 | { 124 | return add_and_get(1); 125 | } 126 | 127 | int64_t add_and_get(int64_t increment) 128 | { 129 | return sequence_.fetch_add(increment, std::memory_order_release) + increment; 130 | } 131 | 132 | private: 133 | count_down_latch_sequence(const count_down_latch_sequence&) = delete; 134 | count_down_latch_sequence& operator=(const count_down_latch_sequence&) = delete; 135 | count_down_latch_sequence(count_down_latch_sequence&&) = delete; 136 | count_down_latch_sequence& operator=(count_down_latch_sequence&&) = delete; 137 | 138 | std::atomic sequence_; 139 | count_down_latch default_latch_; 140 | count_down_latch& latch_; 141 | }; 142 | 143 | class mock_event_processor 144 | { 145 | public: 146 | MOCK_CONST_METHOD0(get_sequence, sequence&()); 147 | }; 148 | 149 | class mock_event_processor_latch 150 | { 151 | public: 152 | MOCK_CONST_METHOD0(get_sequence, count_down_latch_sequence&()); 153 | }; 154 | 155 | class sequencer_barrier_test : public testing::Test 156 | { 157 | protected: 158 | void SetUp() override 159 | { 160 | auto seq_barrier = ring_buffer_.new_barrier(); 161 | no_op_event_processor_.reset( 162 | new no_op_event_processor(ring_buffer_, std::move(seq_barrier))); 163 | ring_buffer_.add_gating_sequences(std::vector { &no_op_event_processor_->get_sequence() }); 164 | } 165 | 166 | template 167 | void fill_ring_buffer(TRingBuffer& ring_buffer, int64_t expected_number_messages) 168 | { 169 | for (int64_t i = 0; i < expected_number_messages; i++) 170 | { 171 | int64_t seq = ring_buffer.next(); 172 | auto& event = ring_buffer[seq]; 173 | event.set_value((int)i); 174 | ring_buffer.publish(seq); 175 | } 176 | } 177 | 178 | static constexpr int BUFFER_SIZE = 64; 179 | 180 | ring_buffer ring_buffer_; 181 | testing::NiceMock event_processor1_; 182 | testing::NiceMock event_processor2_; 183 | testing::NiceMock event_processor3_; 184 | std::unique_ptr> no_op_event_processor_; 185 | }; 186 | 187 | TEST_F(sequencer_barrier_test, should_wait_for_work_complete_where_complete_work_threshold_is_ahead) 188 | { 189 | int64_t expected_number_messages = 10; 190 | int64_t expected_work_sequence = 9; 191 | fill_ring_buffer(this->ring_buffer_, expected_number_messages); 192 | 193 | sequence sequence1(expected_number_messages); 194 | sequence sequence2(expected_work_sequence); 195 | sequence sequence3(expected_number_messages); 196 | 197 | EXPECT_CALL(event_processor1_, get_sequence()) 198 | .WillOnce(testing::ReturnRef(sequence1)); 199 | EXPECT_CALL(event_processor2_, get_sequence()) 200 | .WillOnce(testing::ReturnRef(sequence2)); 201 | EXPECT_CALL(event_processor3_, get_sequence()) 202 | .WillOnce(testing::ReturnRef(sequence3)); 203 | 204 | auto seq_barrier = ring_buffer_.new_barrier(std::vector 205 | { 206 | &event_processor1_.get_sequence(), 207 | &event_processor2_.get_sequence(), 208 | &event_processor3_.get_sequence() 209 | }); 210 | int64_t completed_work_sequence = seq_barrier->wait_for(expected_work_sequence); 211 | ASSERT_GE(completed_work_sequence, expected_work_sequence); 212 | } 213 | 214 | TEST_F(sequencer_barrier_test, should_wait_for_work_complete_where_all_workers_are_blocked_on_ring_buffer) 215 | { 216 | int64_t expected_number_messages = 10; 217 | fill_ring_buffer(this->ring_buffer_, expected_number_messages); 218 | 219 | std::array workers; 220 | std::vector sequences_to_track; 221 | for (auto& stub_worker : workers) 222 | { 223 | stub_worker.set_sequence(expected_number_messages - 1); 224 | sequences_to_track.push_back(&stub_worker.get_sequence()); 225 | } 226 | auto seq_barrier = ring_buffer_.new_barrier(sequences_to_track); 227 | 228 | std::thread t([this, &workers]() 229 | { 230 | int64_t seq = ring_buffer_.next(); 231 | auto& event = ring_buffer_[seq]; 232 | event.set_value((int)seq); 233 | ring_buffer_.publish(seq); 234 | for (auto& stub_worker : workers) 235 | { 236 | stub_worker.set_sequence(seq); 237 | } 238 | }); 239 | 240 | int64_t expected_work_sequence = expected_number_messages; 241 | int64_t completed_work_sequence = seq_barrier->wait_for(expected_number_messages); 242 | ASSERT_GE(completed_work_sequence, expected_work_sequence); 243 | t.join(); 244 | } 245 | 246 | TEST_F(sequencer_barrier_test, should_interrupt_during_busy_spin) 247 | { 248 | ring_buffer ring_buffer; 250 | 251 | testing::NiceMock event_processor1; 252 | testing::NiceMock event_processor2; 253 | testing::NiceMock event_processor3; 254 | 255 | int64_t expected_number_messages = 10; 256 | fill_ring_buffer(ring_buffer, expected_number_messages); 257 | 258 | count_down_latch latch(3); 259 | count_down_latch_sequence sequence1(8, latch); 260 | count_down_latch_sequence sequence2(8, latch); 261 | count_down_latch_sequence sequence3(8, latch); 262 | 263 | EXPECT_CALL(event_processor1, get_sequence()) 264 | .WillOnce(testing::ReturnRef(sequence1)); 265 | EXPECT_CALL(event_processor2, get_sequence()) 266 | .WillOnce(testing::ReturnRef(sequence2)); 267 | EXPECT_CALL(event_processor3, get_sequence()) 268 | .WillOnce(testing::ReturnRef(sequence3)); 269 | 270 | auto seq_barrier = ring_buffer.new_barrier(std::vector 271 | { 272 | &event_processor1.get_sequence(), 273 | &event_processor2.get_sequence(), 274 | &event_processor3.get_sequence() 275 | }); 276 | 277 | bool alerted = false; 278 | std::thread t([&expected_number_messages, &seq_barrier, &alerted]() 279 | { 280 | try 281 | { 282 | seq_barrier->wait_for(expected_number_messages - 1); 283 | } 284 | catch (alert_exception&) 285 | { 286 | alerted = true; 287 | } 288 | catch (...) 289 | { 290 | } 291 | }); 292 | 293 | latch.wait(std::chrono::seconds(3)); 294 | seq_barrier->alert(); 295 | t.join(); 296 | 297 | ASSERT_TRUE(alerted); 298 | } 299 | 300 | TEST_F(sequencer_barrier_test, should_wait_for_work_complete_where_complete_work_threshold_is_behind) 301 | { 302 | int64_t expected_number_messages = 10; 303 | fill_ring_buffer(this->ring_buffer_, expected_number_messages); 304 | 305 | std::array workers; 306 | std::vector sequences_to_track; 307 | for (auto& stub_worker : workers) 308 | { 309 | stub_worker.set_sequence(expected_number_messages - 2); 310 | sequences_to_track.push_back(&stub_worker.get_sequence()); 311 | } 312 | auto seq_barrier = ring_buffer_.new_barrier(sequences_to_track); 313 | 314 | std::thread t([this, &workers]() 315 | { 316 | for (auto& stub_worker : workers) 317 | { 318 | stub_worker.set_sequence(stub_worker.get_sequence().get() + 1); 319 | } 320 | }); 321 | t.join(); 322 | 323 | int64_t expected_work_sequence = expected_number_messages - 1; 324 | int64_t completed_work_sequence = seq_barrier->wait_for(expected_work_sequence); 325 | ASSERT_GE(completed_work_sequence, expected_work_sequence); 326 | } 327 | 328 | TEST_F(sequencer_barrier_test, should_set_and_clear_alert_status) 329 | { 330 | auto seq_barrier = ring_buffer_.new_barrier(); 331 | ASSERT_FALSE(seq_barrier->is_alerted()); 332 | 333 | seq_barrier->alert(); 334 | ASSERT_TRUE(seq_barrier->is_alerted()); 335 | 336 | seq_barrier->clear_alert(); 337 | ASSERT_FALSE(seq_barrier->is_alerted()); 338 | } 339 | } 340 | } 341 | -------------------------------------------------------------------------------- /test/sequencer_test.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2015, Alex Man-fui Lee 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | 8 | * Redistributions of source code must retain the above copyright notice, this 9 | list of conditions and the following disclaimer. 10 | 11 | * Redistributions in binary form must reproduce the above copyright notice, 12 | this list of conditions and the following disclaimer in the documentation 13 | and/or other materials provided with the distribution. 14 | 15 | * Neither the name of disruptor4cpp nor the names of its 16 | contributors may be used to endorse or promote products derived from 17 | this software without specific prior written permission. 18 | 19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 20 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 23 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 25 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 26 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 27 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | */ 30 | 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | 37 | #include 38 | #include 39 | 40 | #include 41 | 42 | namespace disruptor4cpp 43 | { 44 | namespace test 45 | { 46 | class mock_wait_strategy 47 | { 48 | public: 49 | MOCK_CONST_METHOD0(signal_all_when_blocking, void()); 50 | }; 51 | 52 | struct producer_type_single 53 | { 54 | static constexpr producer_type value = producer_type::single; 55 | }; 56 | 57 | struct producer_type_multi 58 | { 59 | static constexpr producer_type value = producer_type::multi; 60 | }; 61 | 62 | template 63 | class sequencer_test : public testing::Test 64 | { 65 | protected: 66 | static constexpr int BUFFER_SIZE = 16; 67 | 68 | typename sequencer_traits::sequencer_type sequencer_; 70 | typename sequencer_traits, 71 | sequence, TProducerType::value>::sequencer_type mock_sequencer_; 72 | sequence gating_sequence_; 73 | }; 74 | 75 | typedef ::testing::Types producer_types; 76 | TYPED_TEST_CASE(sequencer_test, producer_types); 77 | 78 | TYPED_TEST(sequencer_test, should_start_with_initial_value) 79 | { 80 | ASSERT_EQ(0, this->sequencer_.next()); 81 | } 82 | 83 | TYPED_TEST(sequencer_test, should_batch_claim) 84 | { 85 | ASSERT_EQ(3, this->sequencer_.next(4)); 86 | } 87 | 88 | TYPED_TEST(sequencer_test, should_indicate_has_available_capacity) 89 | { 90 | this->sequencer_.add_gating_sequences(std::vector { &this->gating_sequence_ }); 91 | 92 | ASSERT_TRUE(this->sequencer_.has_available_capacity(1)); 93 | ASSERT_TRUE(this->sequencer_.has_available_capacity(this->BUFFER_SIZE)); 94 | ASSERT_FALSE(this->sequencer_.has_available_capacity(this->BUFFER_SIZE + 1)); 95 | 96 | this->sequencer_.publish(this->sequencer_.next()); 97 | ASSERT_TRUE(this->sequencer_.has_available_capacity(this->BUFFER_SIZE - 1)); 98 | ASSERT_FALSE(this->sequencer_.has_available_capacity(this->BUFFER_SIZE)); 99 | } 100 | 101 | TYPED_TEST(sequencer_test, should_indicate_no_available_capacity) 102 | { 103 | this->sequencer_.add_gating_sequences(std::vector { &this->gating_sequence_ }); 104 | int64_t seq = this->sequencer_.next(this->BUFFER_SIZE); 105 | this->sequencer_.publish(seq - (this->BUFFER_SIZE - 1), seq); 106 | 107 | ASSERT_FALSE(this->sequencer_.has_available_capacity(1)); 108 | } 109 | 110 | TYPED_TEST(sequencer_test, should_hold_up_publisher_when_buffer_is_full) 111 | { 112 | this->sequencer_.add_gating_sequences(std::vector { &this->gating_sequence_ }); 113 | int64_t seq = this->sequencer_.next(this->BUFFER_SIZE); 114 | this->sequencer_.publish(seq - (this->BUFFER_SIZE - 1), seq); 115 | 116 | std::mutex waiting_mutex; 117 | std::condition_variable waiting_condition; 118 | bool is_waiting = false; 119 | bool is_done = false; 120 | int64_t expected_full_seq = decltype(this->sequencer_)::INITIAL_CURSOR_VALUE + this->sequencer_.get_buffer_size(); 121 | ASSERT_EQ(expected_full_seq, this->sequencer_.get_cursor()); 122 | 123 | std::thread t([this, &waiting_mutex, &waiting_condition, &is_waiting, &is_done] 124 | { 125 | { 126 | std::lock_guard lock(waiting_mutex); 127 | is_waiting = true; 128 | } 129 | waiting_condition.notify_one(); 130 | 131 | int64_t next = this->sequencer_.next(); 132 | this->sequencer_.publish(next); 133 | 134 | { 135 | std::lock_guard lock(waiting_mutex); 136 | is_done = true; 137 | } 138 | waiting_condition.notify_one(); 139 | }); 140 | { 141 | std::unique_lock lock(waiting_mutex); 142 | waiting_condition.wait(lock, [&is_waiting] { return is_waiting; }); 143 | } 144 | ASSERT_EQ(expected_full_seq, this->sequencer_.get_cursor()); 145 | 146 | this->gating_sequence_.set(decltype(this->sequencer_)::INITIAL_CURSOR_VALUE + 1); 147 | 148 | { 149 | std::unique_lock lock(waiting_mutex); 150 | waiting_condition.wait(lock, [&is_done] { return is_done; }); 151 | } 152 | ASSERT_EQ(expected_full_seq + 1, this->sequencer_.get_cursor()); 153 | 154 | t.join(); 155 | } 156 | 157 | TYPED_TEST(sequencer_test, should_throw_insufficient_capacity_exception_when_sequencer_is_full) 158 | { 159 | this->sequencer_.add_gating_sequences(std::vector { &this->gating_sequence_ }); 160 | for (int i = 0; i < this->BUFFER_SIZE; i++) 161 | { 162 | this->sequencer_.next(); 163 | } 164 | ASSERT_THROW(this->sequencer_.try_next(), insufficient_capacity_exception); 165 | } 166 | 167 | TYPED_TEST(sequencer_test, should_calculate_remaining_capacity) 168 | { 169 | this->sequencer_.add_gating_sequences(std::vector { &this->gating_sequence_ }); 170 | ASSERT_EQ((int64_t)this->BUFFER_SIZE, this->sequencer_.remaining_capacity()); 171 | for (int i = 1; i < this->BUFFER_SIZE; i++) 172 | { 173 | this->sequencer_.next(); 174 | ASSERT_EQ((int64_t)this->BUFFER_SIZE - i, this->sequencer_.remaining_capacity()); 175 | } 176 | } 177 | 178 | TYPED_TEST(sequencer_test, should_not_be_available_until_published) 179 | { 180 | int64_t next = this->sequencer_.next(6); 181 | for (int i = 0; i <= 5; i++) 182 | { 183 | ASSERT_FALSE(this->sequencer_.is_available(i)); 184 | } 185 | 186 | this->sequencer_.publish(next - (6 - 1), next); 187 | 188 | for (int i = 0; i <= 5; i++) 189 | { 190 | ASSERT_TRUE(this->sequencer_.is_available(i)); 191 | } 192 | ASSERT_FALSE(this->sequencer_.is_available(6)); 193 | } 194 | 195 | TYPED_TEST(sequencer_test, should_notify_wait_strategy_on_publish) 196 | { 197 | auto& wait_strategy = this->mock_sequencer_.get_wait_strategy(); 198 | EXPECT_CALL(wait_strategy, signal_all_when_blocking()).Times(1); 199 | 200 | this->mock_sequencer_.publish(this->mock_sequencer_.next()); 201 | } 202 | 203 | TYPED_TEST(sequencer_test, should_notify_wait_strategy_on_publish_batch) 204 | { 205 | auto& wait_strategy = this->mock_sequencer_.get_wait_strategy(); 206 | EXPECT_CALL(wait_strategy, signal_all_when_blocking()).Times(1); 207 | 208 | int64_t next = this->mock_sequencer_.next(4); 209 | this->mock_sequencer_.publish(next - (4 - 1), next); 210 | } 211 | 212 | TYPED_TEST(sequencer_test, should_wait_on_publication) 213 | { 214 | auto barrier = this->sequencer_.new_barrier(); 215 | 216 | int64_t next = this->sequencer_.next(10); 217 | int64_t lo = next - (10 - 1); 218 | int64_t mid = next - 5; 219 | 220 | for (int64_t i = lo; i < mid; i++) 221 | { 222 | this->sequencer_.publish(i); 223 | } 224 | ASSERT_EQ(mid - 1, barrier->wait_for(-1)); 225 | 226 | for (int64_t i = mid; i <= next; i++) 227 | { 228 | this->sequencer_.publish(i); 229 | } 230 | ASSERT_EQ(next, barrier->wait_for(-1)); 231 | } 232 | 233 | TYPED_TEST(sequencer_test, should_try_next) 234 | { 235 | this->sequencer_.add_gating_sequences(std::vector { &this->gating_sequence_ }); 236 | for (int64_t i = 0; i < this->BUFFER_SIZE; i++) 237 | { 238 | this->sequencer_.publish(this->sequencer_.try_next()); 239 | } 240 | ASSERT_THROW(this->sequencer_.try_next(), insufficient_capacity_exception); 241 | } 242 | 243 | TYPED_TEST(sequencer_test, should_claim_specific_sequence) 244 | { 245 | int64_t seq = 14; 246 | 247 | this->sequencer_.claim(seq); 248 | this->sequencer_.publish(seq); 249 | ASSERT_EQ(seq + 1, this->sequencer_.next()); 250 | } 251 | 252 | TYPED_TEST(sequencer_test, should_not_allow_bulk_next_less_than_zero) 253 | { 254 | ASSERT_THROW(this->sequencer_.next(-1), std::invalid_argument); 255 | } 256 | 257 | TYPED_TEST(sequencer_test, should_not_allow_bulk_next_of_zero) 258 | { 259 | ASSERT_THROW(this->sequencer_.next(0), std::invalid_argument); 260 | } 261 | 262 | TYPED_TEST(sequencer_test, should_not_allow_bulk_try_next_less_than_zero) 263 | { 264 | ASSERT_THROW(this->sequencer_.try_next(-1), std::invalid_argument); 265 | } 266 | 267 | TYPED_TEST(sequencer_test, should_not_allow_bulk_try_next_of_zero) 268 | { 269 | ASSERT_THROW(this->sequencer_.try_next(0), std::invalid_argument); 270 | } 271 | } 272 | } 273 | -------------------------------------------------------------------------------- /test/support/stub_event.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2015, Alex Man-fui Lee 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | 8 | * Redistributions of source code must retain the above copyright notice, this 9 | list of conditions and the following disclaimer. 10 | 11 | * Redistributions in binary form must reproduce the above copyright notice, 12 | this list of conditions and the following disclaimer in the documentation 13 | and/or other materials provided with the distribution. 14 | 15 | * Neither the name of disruptor4cpp nor the names of its 16 | contributors may be used to endorse or promote products derived from 17 | this software without specific prior written permission. 18 | 19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 20 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 23 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 25 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 26 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 27 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | */ 30 | 31 | #ifndef DISRUPTOR4CPP_TEST_SUPPORT_STUB_EVENT_H_ 32 | #define DISRUPTOR4CPP_TEST_SUPPORT_STUB_EVENT_H_ 33 | 34 | #include 35 | 36 | namespace disruptor4cpp 37 | { 38 | namespace test 39 | { 40 | class stub_event 41 | { 42 | public: 43 | stub_event() 44 | : value_(-1) 45 | { 46 | } 47 | 48 | stub_event(int value) 49 | : value_(value) 50 | { 51 | } 52 | 53 | void copy(const stub_event& event) 54 | { 55 | value_ = event.value_; 56 | } 57 | 58 | int get_value() const 59 | { 60 | return value_; 61 | } 62 | 63 | void set_value(int value) 64 | { 65 | value_ = value; 66 | } 67 | 68 | const std::string& get_test_string() const 69 | { 70 | return test_string_; 71 | } 72 | 73 | void set_test_string(const std::string& test_string) 74 | { 75 | test_string_ = test_string; 76 | } 77 | 78 | private: 79 | int value_; 80 | std::string test_string_; 81 | }; 82 | } 83 | } 84 | 85 | #endif 86 | -------------------------------------------------------------------------------- /test/utils/count_down_latch.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2015, Alex Man-fui Lee 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | 8 | * Redistributions of source code must retain the above copyright notice, this 9 | list of conditions and the following disclaimer. 10 | 11 | * Redistributions in binary form must reproduce the above copyright notice, 12 | this list of conditions and the following disclaimer in the documentation 13 | and/or other materials provided with the distribution. 14 | 15 | * Neither the name of disruptor4cpp nor the names of its 16 | contributors may be used to endorse or promote products derived from 17 | this software without specific prior written permission. 18 | 19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 20 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 23 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 25 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 26 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 27 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | */ 30 | 31 | #ifndef DISRUPTOR4CPP_TEST_UTILS_COUNT_DOWN_LATCH_H_ 32 | #define DISRUPTOR4CPP_TEST_UTILS_COUNT_DOWN_LATCH_H_ 33 | 34 | #include 35 | #include 36 | #include 37 | #include 38 | 39 | namespace disruptor4cpp 40 | { 41 | namespace test 42 | { 43 | class count_down_latch 44 | { 45 | public: 46 | explicit count_down_latch(int count) 47 | : count_(count) 48 | { 49 | } 50 | 51 | ~count_down_latch() = default; 52 | 53 | void wait() 54 | { 55 | std::unique_lock lock(mutex_); 56 | condition_.wait(lock, [this] { return count_ == 0; }); 57 | } 58 | 59 | // Return true if the count reached zero 60 | // and false if the waiting time elapsed before the count reached zero. 61 | template< class Rep, class Period> 62 | bool wait(const std::chrono::duration& timeout) 63 | { 64 | std::unique_lock lock(mutex_); 65 | return condition_.wait_for(lock, timeout, [this] { return count_ <= 0; }); 66 | } 67 | 68 | void count_down() 69 | { 70 | std::lock_guard lock(mutex_); 71 | if (--count_ <= 0) 72 | condition_.notify_all(); 73 | } 74 | 75 | private: 76 | count_down_latch(const count_down_latch&) = delete; 77 | count_down_latch& operator=(const count_down_latch&) = delete; 78 | count_down_latch(count_down_latch&&) = delete; 79 | count_down_latch& operator=(count_down_latch&&) = delete; 80 | 81 | std::mutex mutex_; 82 | std::condition_variable condition_; 83 | int count_; 84 | }; 85 | } 86 | } 87 | 88 | #endif 89 | -------------------------------------------------------------------------------- /test/utils/thread_barrier.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2015, Alex Man-fui Lee 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | 8 | * Redistributions of source code must retain the above copyright notice, this 9 | list of conditions and the following disclaimer. 10 | 11 | * Redistributions in binary form must reproduce the above copyright notice, 12 | this list of conditions and the following disclaimer in the documentation 13 | and/or other materials provided with the distribution. 14 | 15 | * Neither the name of disruptor4cpp nor the names of its 16 | contributors may be used to endorse or promote products derived from 17 | this software without specific prior written permission. 18 | 19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 20 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 23 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 25 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 26 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 27 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | */ 30 | 31 | #ifndef DISRUPTOR4CPP_TEST_UTILS_THREAD_BARRIER_H_ 32 | #define DISRUPTOR4CPP_TEST_UTILS_THREAD_BARRIER_H_ 33 | 34 | #include 35 | #include 36 | #include 37 | 38 | namespace disruptor4cpp 39 | { 40 | namespace test 41 | { 42 | class thread_barrier 43 | { 44 | public: 45 | explicit thread_barrier(std::size_t count) 46 | : total_wait_count_(count), 47 | current_wait_count_(count), 48 | generation_(0) 49 | { 50 | } 51 | 52 | ~thread_barrier() = default; 53 | 54 | void wait() 55 | { 56 | std::size_t gen = generation_; 57 | std::unique_lock lock(mutex_); 58 | if (--current_wait_count_ == 0) 59 | { 60 | generation_++; 61 | current_wait_count_ = total_wait_count_; 62 | condition_.notify_all(); 63 | } 64 | else 65 | condition_.wait(lock, [this, gen] { return gen != generation_; }); 66 | } 67 | 68 | private: 69 | thread_barrier(const thread_barrier&) = delete; 70 | thread_barrier& operator=(const thread_barrier&) = delete; 71 | thread_barrier(thread_barrier&&) = delete; 72 | thread_barrier& operator=(thread_barrier&&) = delete; 73 | 74 | std::mutex mutex_; 75 | std::condition_variable condition_; 76 | std::size_t total_wait_count_; 77 | std::size_t current_wait_count_; 78 | std::size_t generation_; 79 | }; 80 | } 81 | } 82 | 83 | #endif 84 | -------------------------------------------------------------------------------- /test/wait_strategies/busy_spin_wait_strategy_test.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2015, Alex Man-fui Lee 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | 8 | * Redistributions of source code must retain the above copyright notice, this 9 | list of conditions and the following disclaimer. 10 | 11 | * Redistributions in binary form must reproduce the above copyright notice, 12 | this list of conditions and the following disclaimer in the documentation 13 | and/or other materials provided with the distribution. 14 | 15 | * Neither the name of disruptor4cpp nor the names of its 16 | contributors may be used to endorse or promote products derived from 17 | this software without specific prior written permission. 18 | 19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 20 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 23 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 25 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 26 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 27 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | */ 30 | 31 | #include 32 | #include 33 | 34 | #include 35 | 36 | #include 37 | #include "wait_strategy_test_util.h" 38 | 39 | namespace disruptor4cpp 40 | { 41 | namespace test 42 | { 43 | TEST(busy_spin_wait_strategy_test, should_wait_for_value) 44 | { 45 | busy_spin_wait_strategy wait_strategy; 46 | wait_strategy_test_util::assert_wait_for_with_delay_of(std::chrono::milliseconds(50), wait_strategy); 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /test/wait_strategies/phased_backoff_wait_strategy_test.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2015, Alex Man-fui Lee 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | 8 | * Redistributions of source code must retain the above copyright notice, this 9 | list of conditions and the following disclaimer. 10 | 11 | * Redistributions in binary form must reproduce the above copyright notice, 12 | this list of conditions and the following disclaimer in the documentation 13 | and/or other materials provided with the distribution. 14 | 15 | * Neither the name of disruptor4cpp nor the names of its 16 | contributors may be used to endorse or promote products derived from 17 | this software without specific prior written permission. 18 | 19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 20 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 23 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 25 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 26 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 27 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | */ 30 | 31 | #include 32 | 33 | #include 34 | 35 | #include 36 | #include "wait_strategy_test_util.h" 37 | 38 | namespace disruptor4cpp 39 | { 40 | namespace test 41 | { 42 | TEST(phased_backoff_wait_strategy_test, should_handle_immediate_sequence_change) 43 | { 44 | phased_backoff_wait_strategy<1000000, 1000000, blocking_wait_strategy> wait_strategy_with_lock; 45 | wait_strategy_test_util::assert_wait_for_with_delay_of(std::chrono::milliseconds(0), wait_strategy_with_lock); 46 | phased_backoff_wait_strategy<1000000, 1000000, sleeping_wait_strategy<0>> wait_strategy_with_sleep; 47 | wait_strategy_test_util::assert_wait_for_with_delay_of(std::chrono::milliseconds(0), wait_strategy_with_sleep); 48 | } 49 | 50 | TEST(phased_backoff_wait_strategy_test, should_handle_sequence_change_with_one_millisecond_delay) 51 | { 52 | phased_backoff_wait_strategy<1000000, 1000000, blocking_wait_strategy> wait_strategy_with_lock; 53 | wait_strategy_test_util::assert_wait_for_with_delay_of(std::chrono::milliseconds(1), wait_strategy_with_lock); 54 | phased_backoff_wait_strategy<1000000, 1000000, sleeping_wait_strategy<0>> wait_strategy_with_sleep; 55 | wait_strategy_test_util::assert_wait_for_with_delay_of(std::chrono::milliseconds(1), wait_strategy_with_sleep); 56 | } 57 | 58 | TEST(phased_backoff_wait_strategy_test, should_handle_sequence_change_with_two_millisecond_delay) 59 | { 60 | phased_backoff_wait_strategy<1000000, 1000000, blocking_wait_strategy> wait_strategy_with_lock; 61 | wait_strategy_test_util::assert_wait_for_with_delay_of(std::chrono::milliseconds(2), wait_strategy_with_lock); 62 | phased_backoff_wait_strategy<1000000, 1000000, sleeping_wait_strategy<0>> wait_strategy_with_sleep; 63 | wait_strategy_test_util::assert_wait_for_with_delay_of(std::chrono::milliseconds(2), wait_strategy_with_sleep); 64 | } 65 | 66 | TEST(phased_backoff_wait_strategy_test, should_handle_sequence_change_with_ten_millisecond_delay) 67 | { 68 | phased_backoff_wait_strategy<1000000, 1000000, blocking_wait_strategy> wait_strategy_with_lock; 69 | wait_strategy_test_util::assert_wait_for_with_delay_of(std::chrono::milliseconds(10), wait_strategy_with_lock); 70 | phased_backoff_wait_strategy<1000000, 1000000, sleeping_wait_strategy<0>> wait_strategy_with_sleep; 71 | wait_strategy_test_util::assert_wait_for_with_delay_of(std::chrono::milliseconds(10), wait_strategy_with_sleep); 72 | } 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /test/wait_strategies/sequence_updater.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2015, Alex Man-fui Lee 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | 8 | * Redistributions of source code must retain the above copyright notice, this 9 | list of conditions and the following disclaimer. 10 | 11 | * Redistributions in binary form must reproduce the above copyright notice, 12 | this list of conditions and the following disclaimer in the documentation 13 | and/or other materials provided with the distribution. 14 | 15 | * Neither the name of disruptor4cpp nor the names of its 16 | contributors may be used to endorse or promote products derived from 17 | this software without specific prior written permission. 18 | 19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 20 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 23 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 25 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 26 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 27 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | */ 30 | 31 | #ifndef DISRUPTOR4CPP_TEST_WAIT_STRATEGIES_SEQUENCE_UPDATER_H_ 32 | #define DISRUPTOR4CPP_TEST_WAIT_STRATEGIES_SEQUENCE_UPDATER_H_ 33 | 34 | #include 35 | #include 36 | 37 | #include 38 | #include "../utils/thread_barrier.h" 39 | 40 | namespace disruptor4cpp 41 | { 42 | namespace test 43 | { 44 | template 45 | class sequence_updater 46 | { 47 | public: 48 | sequence_updater(const std::chrono::duration& sleep_time, 49 | TWaitStrategy& wait_strategy) 50 | : sequence_(), 51 | thread_barrier_(2), 52 | sleep_time_(sleep_time), 53 | wait_strategy_(wait_strategy) 54 | { 55 | } 56 | 57 | void run() 58 | { 59 | thread_barrier_.wait(); 60 | if (sleep_time_.count() == 0) 61 | std::this_thread::sleep_for(sleep_time_); 62 | sequence_.increment_and_get(); 63 | wait_strategy_.signal_all_when_blocking(); 64 | } 65 | 66 | void wait_for_startup() 67 | { 68 | thread_barrier_.wait(); 69 | } 70 | 71 | sequence& get_sequence() 72 | { 73 | return sequence_; 74 | } 75 | 76 | private: 77 | sequence sequence_; 78 | thread_barrier thread_barrier_; 79 | std::chrono::duration sleep_time_; 80 | TWaitStrategy& wait_strategy_; 81 | }; 82 | } 83 | } 84 | 85 | #endif 86 | -------------------------------------------------------------------------------- /test/wait_strategies/sleeping_wait_strategy_test.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | 6 | /* 7 | Copyright (c) 2015, Alex Man-fui Lee 8 | All rights reserved. 9 | 10 | Redistribution and use in source and binary forms, with or without 11 | modification, are permitted provided that the following conditions are met: 12 | 13 | * Redistributions of source code must retain the above copyright notice, this 14 | list of conditions and the following disclaimer. 15 | 16 | * Redistributions in binary form must reproduce the above copyright notice, 17 | this list of conditions and the following disclaimer in the documentation 18 | and/or other materials provided with the distribution. 19 | 20 | * Neither the name of disruptor4cpp nor the names of its 21 | contributors may be used to endorse or promote products derived from 22 | this software without specific prior written permission. 23 | 24 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 25 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 27 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 28 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 30 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 31 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 32 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 33 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34 | */ 35 | 36 | #include 37 | #include "wait_strategy_test_util.h" 38 | 39 | namespace disruptor4cpp 40 | { 41 | namespace test 42 | { 43 | TEST(sleeping_wait_strategy_test, should_wait_for_value) 44 | { 45 | sleeping_wait_strategy<> wait_strategy; 46 | wait_strategy_test_util::assert_wait_for_with_delay_of(std::chrono::milliseconds(50), wait_strategy); 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /test/wait_strategies/timeout_blocking_wait_strategy_test.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2015, Alex Man-fui Lee 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | 8 | * Redistributions of source code must retain the above copyright notice, this 9 | list of conditions and the following disclaimer. 10 | 11 | * Redistributions in binary form must reproduce the above copyright notice, 12 | this list of conditions and the following disclaimer in the documentation 13 | and/or other materials provided with the distribution. 14 | 15 | * Neither the name of disruptor4cpp nor the names of its 16 | contributors may be used to endorse or promote products derived from 17 | this software without specific prior written permission. 18 | 19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 20 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 23 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 25 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 26 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 27 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | */ 30 | 31 | #include 32 | #include 33 | 34 | #include 35 | #include 36 | 37 | #include 38 | #include "wait_strategy_test_util.h" 39 | 40 | namespace 41 | { 42 | class mock_sequence_barrier 43 | { 44 | public: 45 | MOCK_CONST_METHOD0(check_alert, void()); 46 | }; 47 | } 48 | 49 | namespace disruptor4cpp 50 | { 51 | namespace test 52 | { 53 | TEST(timeout_blocking_wait_strategy_test, should_timeout_wait_for) 54 | { 55 | const int64_t timeout_nanos = 500 * 1000000; 56 | timeout_blocking_wait_strategy wait_strategy; 57 | sequence cursor(5); 58 | auto dependent_sequences = fixed_sequence_group::create(std::vector { &cursor }); 59 | 60 | mock_sequence_barrier seq_barrier; 61 | EXPECT_CALL(seq_barrier, check_alert()); 62 | 63 | auto t0 = std::chrono::system_clock::now(); 64 | try 65 | { 66 | wait_strategy.wait_for(6, cursor, dependent_sequences, seq_barrier); 67 | } 68 | catch (timeout_exception& ex) 69 | { 70 | } 71 | auto t1 = std::chrono::system_clock::now(); 72 | int64_t time_waiting = std::chrono::duration_cast(t1 - t0).count(); 73 | ASSERT_GE(time_waiting, timeout_nanos); 74 | } 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /test/wait_strategies/wait_strategy_test_util.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2015, Alex Man-fui Lee 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | 8 | * Redistributions of source code must retain the above copyright notice, this 9 | list of conditions and the following disclaimer. 10 | 11 | * Redistributions in binary form must reproduce the above copyright notice, 12 | this list of conditions and the following disclaimer in the documentation 13 | and/or other materials provided with the distribution. 14 | 15 | * Neither the name of disruptor4cpp nor the names of its 16 | contributors may be used to endorse or promote products derived from 17 | this software without specific prior written permission. 18 | 19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 20 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 23 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 25 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 26 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 27 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | */ 30 | 31 | #ifndef DISRUPTOR4CPP_TEST_WAIT_STRATEGIES_WAIT_STRATEGY_TEST_UTIL_H_ 32 | #define DISRUPTOR4CPP_TEST_WAIT_STRATEGIES_WAIT_STRATEGY_TEST_UTIL_H_ 33 | 34 | #include 35 | #include 36 | 37 | #include 38 | 39 | #include 40 | #include "sequence_updater.h" 41 | #include "../dummy_sequence_barrier.h" 42 | 43 | namespace disruptor4cpp 44 | { 45 | namespace test 46 | { 47 | class wait_strategy_test_util 48 | { 49 | public: 50 | template 51 | static void assert_wait_for_with_delay_of(const std::chrono::duration& sleep_time, 52 | TWaitStrategy& wait_strategy) 53 | { 54 | sequence_updater seq_updater(sleep_time, wait_strategy); 55 | std::thread t([&seq_updater] { seq_updater.run(); }); 56 | seq_updater.wait_for_startup(); 57 | 58 | sequence cursor(0); 59 | dummy_sequence_barrier seq_barrier; 60 | auto dependent_sequences = fixed_sequence_group::create(seq_updater.get_sequence()); 61 | int64_t seq = wait_strategy.wait_for(0, cursor, dependent_sequences, seq_barrier); 62 | ASSERT_EQ(0, seq); 63 | 64 | t.join(); 65 | } 66 | }; 67 | } 68 | } 69 | 70 | #endif 71 | -------------------------------------------------------------------------------- /test/wait_strategies/yielding_wait_strategy_test.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2015, Alex Man-fui Lee 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | 8 | * Redistributions of source code must retain the above copyright notice, this 9 | list of conditions and the following disclaimer. 10 | 11 | * Redistributions in binary form must reproduce the above copyright notice, 12 | this list of conditions and the following disclaimer in the documentation 13 | and/or other materials provided with the distribution. 14 | 15 | * Neither the name of disruptor4cpp nor the names of its 16 | contributors may be used to endorse or promote products derived from 17 | this software without specific prior written permission. 18 | 19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 20 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 23 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 25 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 26 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 27 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | */ 30 | 31 | #include 32 | #include 33 | 34 | #include 35 | 36 | #include 37 | #include "wait_strategy_test_util.h" 38 | 39 | namespace disruptor4cpp 40 | { 41 | namespace test 42 | { 43 | TEST(yielding_wait_strategy_test, should_wait_for_value) 44 | { 45 | yielding_wait_strategy<> wait_strategy; 46 | wait_strategy_test_util::assert_wait_for_with_delay_of(std::chrono::milliseconds(50), wait_strategy); 47 | } 48 | } 49 | } 50 | --------------------------------------------------------------------------------