├── .gitignore ├── .gitmodules ├── .travis.yml ├── CMakeLists.txt ├── LICENSE ├── README.md ├── appveyor.yml ├── cmake ├── CodeCoverage.cmake ├── FindGperftools.cmake └── utils.cmake ├── docs ├── CMakeLists.txt ├── Doxyfile.in ├── mainpage.h └── template │ ├── footer.html │ ├── git-buttons.js │ ├── header.html │ ├── layout.xml │ ├── static │ ├── GitHub-Mark-64px.png │ ├── favicon-32x32.png │ ├── favicon-96x96.png │ ├── favicon.ico │ └── logo.png │ ├── style.css │ └── style.js ├── include ├── cube.h └── qb │ ├── actor.h │ ├── actorid.h │ ├── core │ ├── Actor.h │ ├── Actor.tpl │ ├── ActorId.h │ ├── CoreSet.h │ ├── Event.h │ ├── ICallback.h │ ├── Main.h │ ├── Main.tpl │ ├── ProxyPipe.h │ ├── ProxyPipe.tpl │ ├── VirtualCore.h │ └── VirtualCore.tpl │ ├── coreset.h │ ├── event.h │ ├── icallback.h │ ├── io.h │ ├── main.h │ ├── network │ ├── epoll.h │ ├── helper.h │ ├── ip.h │ ├── sys.h │ ├── tcp.h │ └── udp.h │ ├── system │ ├── allocator │ │ └── pipe.h │ ├── cpu.h │ ├── lockfree │ │ ├── mpsc.h │ │ ├── spinlock.h │ │ └── spsc.h │ └── timestamp.h │ └── utility │ ├── branch_hints.h │ ├── build_macros.h │ ├── nocopy.h │ ├── prefix.h │ └── type_traits.h ├── modules └── nanolog │ ├── nanolog.cpp │ └── nanolog.h ├── ressources ├── BasicActorModel.svg ├── PhysicalCoreWorkflow.svg └── logo.svg ├── sample ├── CMakeLists.txt ├── pingpong │ ├── CMakeLists.txt │ ├── MyEvent.h │ ├── PingActor.h │ ├── PongActor.h │ └── main.cpp ├── producer-consumer │ ├── ActorConsumer.h │ ├── ActorProducer.h │ ├── CMakeLists.txt │ ├── MyEvent.h │ └── main.cpp └── starter │ ├── CMakeLists.txt │ ├── MyActor.h │ └── main.cpp ├── script ├── qb-new-module.sh └── qb-new-project.sh └── source ├── core ├── CMakeLists.txt ├── core.cpp ├── src │ ├── Actor.cpp │ ├── ActorId.cpp │ ├── CoreSet.cpp │ ├── Main.cpp │ ├── VirtualCore.cpp │ └── io.cpp └── tests │ ├── CMakeLists.txt │ ├── benchmark │ ├── CMakeLists.txt │ ├── benchmark_example.cpp │ ├── bm-disruptor-latency.cpp │ ├── bm-multicast-latency.cpp │ ├── bm-ping-pong-latency.cpp │ ├── bm-ping-pong.cpp │ └── bm-pipeline-latency.cpp │ ├── shared │ ├── TestConsumer.h │ ├── TestEvent.h │ ├── TestLatency.h │ └── TestProducer.h │ ├── system │ ├── CMakeLists.txt │ ├── test-actor-add.cpp │ ├── test-actor-callback.cpp │ ├── test-actor-dependency.cpp │ ├── test-actor-event.cpp │ ├── test-actor-service-event.cpp │ ├── test-io.cpp │ └── test-main.cpp │ └── unit │ ├── CMakeLists.txt │ └── test_example.cpp └── network ├── CMakeLists.txt ├── src ├── helper.cpp ├── ip.cpp ├── network-all.cpp ├── tcp.cpp └── udp.cpp └── tests ├── CMakeLists.txt └── system ├── CMakeLists.txt └── test-network.cpp /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "modules/googlebenchmark"] 2 | path = modules/googlebenchmark 3 | url = https://github.com/google/benchmark.git 4 | branch = master 5 | [submodule "modules/googletest"] 6 | path = modules/googletest 7 | url = https://github.com/google/googletest.git 8 | branch = master 9 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: cpp 2 | sudo: false 3 | notifications: 4 | email: false 5 | 6 | # Use Linux unless specified otherwise 7 | os: linux 8 | dist: trusty 9 | cache: 10 | directories: 11 | - ${TRAVIS_BUILD_DIR}/deps 12 | 13 | #addons: &global_addons 14 | # apt: 15 | # packages: 16 | # - lcov 17 | 18 | matrix: 19 | include: 20 | # Clang 5.0 21 | - env: COMPILER=clang++-5.0 BUILD_TYPE=Debug BUILD_COVER=OFF 22 | addons: &clang50 23 | apt: 24 | packages: 25 | - clang-5.0 26 | - g++-7 27 | sources: 28 | - ubuntu-toolchain-r-test 29 | - llvm-toolchain-trusty-5.0 30 | - sourceline: 'deb http://apt.llvm.org/trusty/ llvm-toolchain-trusty-5.0 main' 31 | key_url: 'https://apt.llvm.org/llvm-snapshot.gpg.key' 32 | 33 | - env: COMPILER=clang++-5.0 BUILD_TYPE=Release BUILD_COVER=OFF 34 | addons: *clang50 35 | 36 | # Clang 6.0 37 | - env: COMPILER=clang++-6.0 BUILD_TYPE=Debug BUILD_COVER=OFF 38 | addons: &clang60 39 | apt: 40 | packages: 41 | - clang-6.0 42 | - g++-7 43 | sources: 44 | - ubuntu-toolchain-r-test 45 | - llvm-toolchain-trusty-6.0 46 | - sourceline: 'deb http://apt.llvm.org/trusty/ llvm-toolchain-trusty-6.0 main' 47 | key_url: 'https://apt.llvm.org/llvm-snapshot.gpg.key' 48 | 49 | - env: COMPILER=clang++-6.0 BUILD_TYPE=Release BUILD_COVER=OFF 50 | addons: *clang60 51 | 52 | # Clang 7.0 53 | - env: COMPILER=clang++-7 BUILD_TYPE=Debug BUILD_COVER=OFF 54 | addons: &clang70 55 | apt: 56 | packages: 57 | - clang-7 58 | - g++-7 59 | sources: 60 | - ubuntu-toolchain-r-test 61 | - llvm-toolchain-trusty-7 62 | 63 | - env: COMPILER=clang++-7 BUILD_TYPE=Release BUILD_COVER=OFF 64 | addons: *clang70 65 | 66 | ########################################################################## 67 | # GCC on Linux 68 | ########################################################################## 69 | # GCC 7 70 | - env: COMPILER=g++-7 BUILD_TYPE=Debug BUILD_COVER=ON 71 | addons: &gcc7 72 | apt: 73 | packages: 74 | - g++-7 75 | - lcov 76 | - python3-dev 77 | - gcovr 78 | sources: 79 | - ubuntu-toolchain-r-test 80 | 81 | - env: COMPILER=g++-7 BUILD_TYPE=Release BUILD_COVER=OFF 82 | addons: *gcc7 83 | 84 | - env: COMPILER=clang++ BUILD_TYPE=Release BUILD_COVER=OFF 85 | os: osx 86 | osx_image: xcode10.2 87 | brew_packages: 88 | - cmake 89 | 90 | - env: COMPILER=g++ BUILD_TYPE=Release BUILD_COVER=OFF 91 | os: osx 92 | osx_image: xcode10.2 93 | brew_packages: 94 | - gcc 95 | - cmake 96 | 97 | install: 98 | # Dependencies required by the CI are installed in ${TRAVIS_BUILD_DIR}/deps/ 99 | - DEPS_DIR="${TRAVIS_BUILD_DIR}/deps" 100 | - mkdir -p "${DEPS_DIR}" 101 | - cd "${DEPS_DIR}" 102 | 103 | # Travis machines have 2 cores 104 | - JOBS=2 105 | 106 | ############################################################################ 107 | # Install a recent CMake (unless already installed on OS X) 108 | ############################################################################ 109 | # - CMAKE_VERSION=3.7.2 110 | # - | 111 | # if [[ "${TRAVIS_OS_NAME}" == "linux" ]]; then 112 | # CMAKE_URL="https://cmake.org/files/v${CMAKE_VERSION%.[0-9]}/cmake-${CMAKE_VERSION}-Linux-x86_64.tar.gz" 113 | # mkdir cmake && travis_retry wget --no-check-certificate -O - ${CMAKE_URL} | tar --strip-components=1 -xz -C cmake 114 | # export PATH=${DEPS_DIR}/cmake/bin:${PATH} 115 | # else 116 | # brew install cmake || brew upgrade cmake 117 | # fi 118 | - cmake --version 119 | 120 | ############################################################################ 121 | # [linux]: Install the right version of libc++ 122 | ############################################################################ 123 | - | 124 | LLVM_INSTALL=${DEPS_DIR}/llvm/install 125 | # if in linux and compiler clang and llvm not installed 126 | if [[ "${TRAVIS_OS_NAME}" == "linux" && "${CXX%%+*}" == "clang" && -n "$(ls -A ${LLVM_INSTALL})" ]]; then 127 | if [[ "${CXX}" == "clang++-3.6" ]]; then LLVM_VERSION="3.6.2"; 128 | elif [[ "${CXX}" == "clang++-3.7" ]]; then LLVM_VERSION="3.7.1"; 129 | elif [[ "${CXX}" == "clang++-3.8" ]]; then LLVM_VERSION="3.8.1"; 130 | elif [[ "${CXX}" == "clang++-3.9" ]]; then LLVM_VERSION="3.9.1"; 131 | fi 132 | LLVM_URL="http://llvm.org/releases/${LLVM_VERSION}/llvm-${LLVM_VERSION}.src.tar.xz" 133 | LIBCXX_URL="http://llvm.org/releases/${LLVM_VERSION}/libcxx-${LLVM_VERSION}.src.tar.xz" 134 | LIBCXXABI_URL="http://llvm.org/releases/${LLVM_VERSION}/libcxxabi-${LLVM_VERSION}.src.tar.xz" 135 | mkdir -p llvm llvm/build llvm/projects/libcxx llvm/projects/libcxxabi 136 | travis_retry wget -O - ${LLVM_URL} | tar --strip-components=1 -xJ -C llvm 137 | travis_retry wget -O - ${LIBCXX_URL} | tar --strip-components=1 -xJ -C llvm/projects/libcxx 138 | travis_retry wget -O - ${LIBCXXABI_URL} | tar --strip-components=1 -xJ -C llvm/projects/libcxxabi 139 | (cd llvm/build && cmake .. -DCMAKE_INSTALL_PREFIX=${LLVM_INSTALL}) 140 | (cd llvm/build/projects/libcxx && make install -j2) 141 | (cd llvm/build/projects/libcxxabi && make install -j2) 142 | export CXXFLAGS="-isystem ${LLVM_INSTALL}/include/c++/v1" 143 | export LDFLAGS="-L ${LLVM_INSTALL}/lib -l c++ -l c++abi" 144 | export LD_LIBRARY_PATH="${LD_LIBRARY_PATH}:${LLVM_INSTALL}/lib" 145 | fi 146 | before_script: 147 | # Set the ${CXX} variable properly 148 | - export CXX=${COMPILER} 149 | - ${CXX} --version 150 | # have CMake to generate build files 151 | - cd "${TRAVIS_BUILD_DIR}" 152 | - mkdir build && cd build 153 | - cmake -DCMAKE_BUILD_TYPE="${BUILD_TYPE}" -DQB_BUILD_TEST=ON -DQB_BUILD_COVERAGE="${BUILD_COVER}" -B. -H.. 154 | 155 | script: 156 | # build and run tests 157 | - cmake --build . -- -j${JOBS} 158 | - ctest -VV --output-on-failure -j${JOBS} 159 | - | 160 | if [${BUILD_COVER} == "ON"]; then 161 | make qb-coverage; 162 | fi 163 | after_success: 164 | - bash <(curl -s https://codecov.io/bash) || echo "Codecov did not collect coverage reports" -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # 2 | # qb - C++ Actor Framework 3 | # Copyright (C) 2011-2019 isndev (www.qbaf.io). All rights reserved. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | # 17 | 18 | cmake_minimum_required(VERSION 3.1) 19 | project(qb LANGUAGES CXX DESCRIPTION "C++17 Actor Framework") 20 | 21 | #set global variable 22 | set(QB_PREFIX ${PROJECT_NAME}) 23 | string(TOUPPER ${QB_PREFIX} QB_PREFIX_UPPER) 24 | set(QB_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) 25 | set(QB_VERSION_MAJOR 0) 26 | set(QB_VERSION_MINOR 9) 27 | set(QB_VERSION_PATCH 0) 28 | set(QB_VERSION_TWEAK 0) 29 | set(QB_VERSION "${QB_VERSION_MAJOR}.${QB_VERSION_MINOR}.${QB_VERSION_PATCH}.${QB_VERSION_TWEAK}") 30 | 31 | set(CMAKE_CXX_STANDARD 17) 32 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 33 | set(${QB_PREFIX_UPPER}_CXX_FLAGS "") 34 | #set(CMAKE_VERBOSE_MAKEFILE ON) 35 | 36 | list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/cmake") 37 | 38 | if(NOT CYGWIN) 39 | set(CMAKE_CXX_EXTENSIONS OFF) 40 | endif() 41 | 42 | option(QB_PATH "root" ${CMAKE_CURRENT_SOURCE_DIR}) 43 | option("${QB_PREFIX_UPPER}_BUILD_TEST" "Build Cube Tests" OFF) 44 | option("${QB_PREFIX_UPPER}_BUILD_BENCHMARK" "Build Cube Benchmarks" OFF) 45 | option("${QB_PREFIX_UPPER}_BUILD_SAMPLE" "Build Cube Samples" OFF) 46 | option("${QB_PREFIX_UPPER}_BUILD_DOC" "Build Cube Documentation" OFF) 47 | option("${QB_PREFIX_UPPER}_WITH_LOG" "Enable nanolog" ON) 48 | option("${QB_PREFIX_UPPER}_WITH_RTTI" "Build with RTTI" ON) 49 | option("${QB_PREFIX_UPPER}_WITH_TCMALLOC" "TCMalloc is ennabled" OFF) 50 | 51 | #default build type to Release 52 | if (NOT CMAKE_BUILD_TYPE) 53 | set(CMAKE_BUILD_TYPE "Release" CACHE STRING "" FORCE) 54 | endif() 55 | 56 | if (${QB_PREFIX_UPPER}_BUILD_TEST) 57 | include(CTest) 58 | enable_testing() 59 | if (${QB_PREFIX_UPPER}_BUILD_BENCHMARK) 60 | # add google benchmark module 61 | set(BENCHMARK_DOWNLOAD_DEPENDENCIES ON CACHE BOOL "" FORCE) 62 | set(BENCHMARK_ENABLE_TESTING OFF CACHE BOOL "" FORCE) 63 | set(GOOGLEBENCHMARK_DIR ${CMAKE_CURRENT_SOURCE_DIR}/modules/googlebenchmark) 64 | add_subdirectory(${GOOGLEBENCHMARK_DIR}) 65 | endif() 66 | if (MSVC) 67 | set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) 68 | endif() 69 | # add google test module 70 | set(GOOGLETEST_DIR ${CMAKE_CURRENT_SOURCE_DIR}/modules/googletest) 71 | add_subdirectory(${GOOGLETEST_DIR}) 72 | endif() 73 | 74 | if(CMAKE_BUILD_TYPE STREQUAL "Debug" AND NOT WIN32) 75 | message(STATUS "INFO: Added coverage target to the solution") 76 | if (${QB_PREFIX_UPPER}_BUILD_COVERAGE) 77 | include(cmake/CodeCoverage.cmake) 78 | APPEND_COVERAGE_COMPILER_FLAGS() 79 | if (LCOV_PATH AND GCOV_PATH AND Python_FOUND) 80 | set(${QB_PREFIX_UPPER}_COVERAGE ON) 81 | endif() 82 | endif() 83 | endif() 84 | 85 | # overload with our cmake utils 86 | include(cmake/utils.cmake) 87 | config_compiler_and_linker() # Defined in internal_utils.cmake. 88 | 89 | include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include) 90 | include_directories(${CMAKE_CURRENT_SOURCE_DIR}/modules) 91 | 92 | # Network Projects 93 | add_subdirectory(source/network) 94 | 95 | #TCMALLOC only available on linux for the moment 96 | if (NOT WIN32 AND ${QB_PREFIX_UPPER}_USE_TCMALLOC) 97 | set(GPERFTOOLS_USE_STATIC_LIBS ON CACHE BOOL "" FORCE) 98 | find_package(Gperftools) 99 | if (GPERFTOOLS_FOUND) 100 | message(STATUS "INFO: Will build ${QB_PREFIX} libraries with tcmalloc") 101 | if (GNU) 102 | set(${QB_PREFIX_UPPER}_CXX_FLAGS "-flto -fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-free") 103 | endif () 104 | link_libraries(${name} unwind) 105 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${${QB_PREFIX_UPPER}_CXX_FLAGS}") 106 | link_libraries(${GPERFTOOLS_TCMALLOC}) 107 | endif() 108 | endif() 109 | 110 | # Cube Main Library 111 | add_subdirectory(source/core) 112 | 113 | # Generate Documentation 114 | add_subdirectory(docs) 115 | 116 | if(${QB_PREFIX_UPPER}_WITH_RTTI) 117 | message(STATUS "INFO: Will build ${QB_PREFIX} libraries with RTTI") 118 | else() 119 | message(STATUS "INFO: Will build ${QB_PREFIX} libraries without RTTI") 120 | set(${QB_PREFIX_UPPER}_CXX_FLAGS "${${QB_PREFIX_UPPER}_CXX_FLAGS} ${cxx_no_rtti_flags}") 121 | endif() 122 | 123 | if(QB_MODULE_PATH) 124 | qb_load_modules(${QB_MODULE_PATH}) 125 | endif() 126 | 127 | if (${QB_PREFIX_UPPER}_COVERAGE) 128 | set(COVERAGE_LCOV_EXCLUDES 129 | '/usr/*' 130 | '*benchmark*' 131 | '*modules*' 132 | '*sample/*' 133 | ) 134 | SETUP_TARGET_FOR_COVERAGE_LCOV(NAME ${PROJECT_NAME}-coverage 135 | EXECUTABLE ctest 136 | DEPENDENCIES qb-core) 137 | set(COVERAGE_GCOVR_EXCLUDES 138 | ".*benchmark.*" 139 | ".*modules.*" 140 | ".*sample.*" 141 | ) 142 | SETUP_TARGET_FOR_COVERAGE_GCOVR_XML(NAME ${PROJECT_NAME}-coverage-xml 143 | EXECUTABLE ctest 144 | DEPENDENCIES qb-core) 145 | endif() 146 | 147 | # Sample Projects 148 | if (${QB_PREFIX_UPPER}_BUILD_SAMPLE) 149 | add_subdirectory(sample) 150 | endif() 151 | 152 | # share some variable to parent 153 | get_directory_property(hasParent PARENT_DIRECTORY) 154 | if(hasParent) 155 | set(CMAKE_CXX_FLAGS "${${QB_PREFIX_UPPER}_CXX_FLAGS}" PARENT_SCOPE) 156 | set(QB_PREFIX "${QB_PREFIX}" PARENT_SCOPE) 157 | set(QB_DIRECTORY "${QB_DIRECTORY}" PARENT_SCOPE) 158 | endif() -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | version: '{build}' 2 | branches: 3 | only: 4 | - master 5 | - develop 6 | - experimental 7 | clone_folder: C:\projects\project 8 | image: 9 | - Visual Studio 2017 10 | 11 | configuration: 12 | - Release 13 | - Debug 14 | platform: 15 | - x64 16 | environment: 17 | matrix: 18 | - arch: Win64 19 | # - arch: #does not work, Release|x64 not a valid target 20 | matrix: 21 | fast_finish: true 22 | 23 | # skip unsupported combinations 24 | init: 25 | - set arch= 26 | - if "%arch%"=="Win64" ( set arch= Win64) 27 | - echo %arch% 28 | - echo %APPVEYOR_BUILD_WORKER_IMAGE% 29 | - if "%APPVEYOR_BUILD_WORKER_IMAGE%"=="Visual Studio 2017" ( set generator="Visual Studio 15 2017%arch%" ) 30 | - echo %generator% 31 | 32 | before_build: 33 | - cmd: |- 34 | git submodule update --init --recursive 35 | mkdir build 36 | cd build 37 | cmake --version 38 | echo %generator% 39 | cmake -G %generator% -DQB_BUILD_TEST=ON -DQB_BUILD_SAMPLE=ON -H.. 40 | build_script: 41 | - cmd: |- 42 | cd C:\projects\project\build 43 | cmake --build . --target ALL_BUILD --config %configuration% -- /nologo 44 | 45 | only_commits: 46 | message: /build|merge/ 47 | files: 48 | - CMakeLists.txt 49 | - appveyor.yml 50 | - include/ 51 | - source/ 52 | - modules/ 53 | - sample/ 54 | - cmake/ -------------------------------------------------------------------------------- /cmake/FindGperftools.cmake: -------------------------------------------------------------------------------- 1 | # ------------- 2 | # 3 | # Find a Google gperftools installation. 4 | # 5 | # This module finds if Google gperftools is installed and selects a default 6 | # configuration to use. 7 | # 8 | # find_package(GPERFTOOLS COMPONENTS ...) 9 | # 10 | # Valid components are: 11 | # 12 | # TCMALLOC 13 | # PROFILER 14 | # TCMALLOC_MINIMAL 15 | # TCMALLOC_AND_PROFILER 16 | # 17 | # The following variables control which libraries are found:: 18 | # 19 | # GPERFTOOLS_USE_STATIC_LIBS - Set to ON to force use of static libraries. 20 | # 21 | # The following are set after the configuration is done: 22 | # 23 | # :: 24 | # 25 | # GPERFTOOLS_FOUND - Set to TRUE if gperftools was found 26 | # GPERFTOOLS_INCLUDE_DIRS - Include directories 27 | # GPERFTOOLS_LIBRARIES - Path to the gperftools libraries 28 | # GPERFTOOLS_LIBRARY_DIRS - Compile time link directories 29 | # GPERFTOOLS_ - Path to specified component 30 | # 31 | # 32 | # Sample usage: 33 | # 34 | # :: 35 | # 36 | # find_package(GPERFTOOLS) 37 | # if(GPERFTOOLS_FOUND) 38 | # target_link_libraries( ${GPERFTOOLS_LIBRARIES}) 39 | # endif() 40 | 41 | if(GPERFTOOLS_USE_STATIC_LIBS) 42 | set(_CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES}) 43 | set(CMAKE_FIND_LIBRARY_SUFFIXES .lib .a ${CMAKE_FIND_LIBRARY_SUFFIXES}) 44 | endif() 45 | 46 | macro(_find_library libvar libname) 47 | find_library(${libvar} 48 | NAMES ${libname} 49 | HINTS ENV LD_LIBRARY_PATH 50 | HINTS ENV DYLD_LIBRARY_PATH 51 | PATHS 52 | /usr/lib 53 | /usr/local/lib 54 | /usr/local/homebrew/lib 55 | /opt/local/lib 56 | ) 57 | if(NOT ${libvar}_NOTFOUND) 58 | set(${libvar}_FOUND TRUE) 59 | endif() 60 | endmacro() 61 | 62 | _find_library(GPERFTOOLS_TCMALLOC tcmalloc) 63 | _find_library(GPERFTOOLS_PROFILER profiler) 64 | _find_library(GPERFTOOLS_TCMALLOC_MINIMAL tcmalloc_minimal) 65 | _find_library(GPERFTOOLS_TCMALLOC_AND_PROFILER tcmalloc_and_profiler) 66 | 67 | find_path(GPERFTOOLS_INCLUDE_DIR 68 | NAMES gperftools/heap-profiler.h 69 | HINTS ${GPERFTOOLS_LIBRARY}/../../include 70 | PATHS 71 | /usr/include 72 | /usr/local/include 73 | /usr/local/homebrew/include 74 | /opt/local/include 75 | ) 76 | 77 | get_filename_component(GPERFTOOLS_LIBRARY_DIR ${GPERFTOOLS_TCMALLOC} DIRECTORY) 78 | # Set standard CMake FindPackage variables if found. 79 | set(GPERFTOOLS_LIBRARIES 80 | ${GPERFTOOLS_TCMALLOC} 81 | ${GPERFTOOLS_PROFILER} 82 | ) 83 | 84 | set(GPERFTOOLS_INCLUDE_DIRS ${GPERFTOOLS_INCLUDE_DIR}) 85 | set(GPERFTOOLS_LIBRARY_DIRS ${GPERFTOOLS_LIBRARY_DIR}) 86 | 87 | if(GPERFTOOLS_USE_STATIC_LIBS) 88 | set(CMAKE_FIND_LIBRARY_SUFFIXES ${_CMAKE_FIND_LIBRARY_SUFFIXES}) 89 | endif() 90 | 91 | include(FindPackageHandleStandardArgs) 92 | find_package_handle_standard_args( 93 | GPERFTOOLS 94 | REQUIRED_VARS 95 | GPERFTOOLS_INCLUDE_DIR 96 | HANDLE_COMPONENTS 97 | ) -------------------------------------------------------------------------------- /docs/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # 2 | # qb - C++ Actor Framework 3 | # Copyright (C) 2011-2019 isndev (www.qbaf.io). All rights reserved. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | # 17 | 18 | # Doxygen Build 19 | option(BUILD_DOC "Build Documentation" ON) 20 | 21 | find_package(Doxygen) 22 | if(DOXYGEN_FOUND) 23 | set(DOXYGEN_INPUT_DIR ${CMAKE_CURRENT_SOURCE_DIR}) 24 | set(DOXYGEN_OUTPUT_DIR ${CMAKE_SOURCE_DIR}/build/docs) 25 | set(BUILD_DOC_DIR ${CMAKE_SOURCE_DIR}/build/docs) 26 | if(NOT EXISTS ${BUILD_DOC_DIR}) 27 | file(MAKE_DIRECTORY ${BUILD_DOC_DIR}) 28 | endif() 29 | 30 | 31 | set(DOXYGEN_IN ${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile.in) 32 | set(DOXYGEN_OUT ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile) 33 | configure_file(${DOXYGEN_IN} ${DOXYGEN_OUT} @ONLY) 34 | 35 | if (${QB_PREFIX_UPPER}_BUILD_DOC) 36 | message(STATUS "INFO: Doxygen build added to solution") 37 | add_custom_target(${QB_PREFIX}-docs ALL 38 | COMMAND ${DOXYGEN_EXECUTABLE} ${DOXYGEN_OUT} 39 | WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} 40 | COMMENT "Generating API documentation with Doxygen" 41 | VERBATIM) 42 | endif() 43 | else(DOXYGEN_FOUND) 44 | message("Doxygen needs to be installed to generate the documentation.") 45 | endif(DOXYGEN_FOUND) -------------------------------------------------------------------------------- /docs/template/footer.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /docs/template/header.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | $projectname: $title 11 | qb - C++ Actor Framework: $title 12 | 13 | 14 | 15 | 16 | 17 | 18 | $treeview 19 | $search 20 | $mathjax 21 | 22 | 23 | 24 | 25 | $extrastylesheet 26 | 27 | 28 | 29 | 30 | 31 |
32 | -------------------------------------------------------------------------------- /docs/template/static/GitHub-Mark-64px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isndev/qb/3bd51b39ef1e063b1c461b34b24bd0eb2db92dd8/docs/template/static/GitHub-Mark-64px.png -------------------------------------------------------------------------------- /docs/template/static/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isndev/qb/3bd51b39ef1e063b1c461b34b24bd0eb2db92dd8/docs/template/static/favicon-32x32.png -------------------------------------------------------------------------------- /docs/template/static/favicon-96x96.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isndev/qb/3bd51b39ef1e063b1c461b34b24bd0eb2db92dd8/docs/template/static/favicon-96x96.png -------------------------------------------------------------------------------- /docs/template/static/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isndev/qb/3bd51b39ef1e063b1c461b34b24bd0eb2db92dd8/docs/template/static/favicon.ico -------------------------------------------------------------------------------- /docs/template/static/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isndev/qb/3bd51b39ef1e063b1c461b34b24bd0eb2db92dd8/docs/template/static/logo.png -------------------------------------------------------------------------------- /docs/template/style.js: -------------------------------------------------------------------------------- 1 | // Script for Generated Documentation -------------------------------------------------------------------------------- /include/cube.h: -------------------------------------------------------------------------------- 1 | /* 2 | * qb - C++ Actor Framework 3 | * Copyright (C) 2011-2019 isndev (www.qbaf.io). All rights reserved. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | #ifndef QB_QB_H 19 | #define QB_QB_H 20 | 21 | /*! 22 | * @defgroup Core Core 23 | * @defgroup Network Network 24 | * @defgroup TCP TCP 25 | * @ingroup Network 26 | * @defgroup UDP UDP 27 | * @ingroup Network 28 | */ 29 | 30 | #endif //QB_QB_H 31 | -------------------------------------------------------------------------------- /include/qb/actor.h: -------------------------------------------------------------------------------- 1 | /* 2 | * qb - C++ Actor Framework 3 | * Copyright (C) 2011-2019 isndev (www.qbaf.io). All rights reserved. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | #include "core/Actor.h" 19 | #include "core/Actor.tpl" 20 | #include "core/ProxyPipe.tpl" -------------------------------------------------------------------------------- /include/qb/actorid.h: -------------------------------------------------------------------------------- 1 | /* 2 | * qb - C++ Actor Framework 3 | * Copyright (C) 2011-2019 isndev (www.qbaf.io). All rights reserved. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | #include "core/ActorId.h" 19 | -------------------------------------------------------------------------------- /include/qb/core/Actor.tpl: -------------------------------------------------------------------------------- 1 | /* 2 | * qb - C++ Actor Framework 3 | * Copyright (C) 2011-2019 isndev (www.qbaf.io). All rights reserved. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | #include "VirtualCore.h" 19 | #include "VirtualCore.tpl" 20 | 21 | #ifndef QB_ACTOR_TPL 22 | # define QB_ACTOR_TPL 23 | 24 | namespace qb { 25 | 26 | template 27 | void Actor::registerCallback(_Actor &actor) const noexcept { 28 | VirtualCore::_handler->registerCallback(actor); 29 | } 30 | 31 | template 32 | void Actor::unregisterCallback(_Actor &actor) const noexcept { 33 | VirtualCore::_handler->unregisterCallback(actor.id()); 34 | } 35 | 36 | template 37 | void Actor::registerEvent(_Actor &actor) const noexcept { 38 | VirtualCore::_handler->registerEvent<_Event>(actor); 39 | } 40 | 41 | template 42 | void Actor::unregisterEvent(_Actor &actor) const noexcept { 43 | VirtualCore::_handler->unregisterEvent<_Event>(actor); 44 | } 45 | 46 | template 47 | void Actor::unregisterEvent() const noexcept { 48 | VirtualCore::_handler->unregisterEvent<_Event>(*this); 49 | } 50 | 51 | template 52 | _Actor *Actor::addRefActor(_Args &&...args) const { 53 | return VirtualCore::_handler->template addReferencedActor<_Actor>(std::forward<_Args>(args)...); 54 | } 55 | 56 | template 57 | _Event &Actor::push(ActorId const &dest, _Args &&...args) const noexcept { 58 | return VirtualCore::_handler->template push<_Event>(dest, id(), std::forward<_Args>(args)...); 59 | } 60 | 61 | template 62 | void Actor::send(ActorId const &dest, _Args &&...args) const noexcept { 63 | VirtualCore::_handler->template send<_Event, _Args...>(dest, id(), std::forward<_Args>(args)...); 64 | } 65 | 66 | template 67 | bool Actor::require_type() const noexcept { 68 | broadcast(type_id<_Required>()); 69 | return true; 70 | } 71 | 72 | template 73 | bool Actor::require() const noexcept { 74 | return (require_type<_Types>() && ...); 75 | } 76 | 77 | template 78 | void Actor::broadcast(_Args &&... args) const noexcept { 79 | VirtualCore::_handler->template broadcast<_Event, _Args...>(id(), std::forward<_Args>(args)...); 80 | } 81 | 82 | template 83 | ActorId Actor::getServiceId(CoreId const index) noexcept { 84 | return {VirtualCore::getServices()[type_id()], index}; 85 | } 86 | 87 | template 88 | Actor::EventBuilder &Actor::EventBuilder::push(_Args &&...args) noexcept { 89 | dest_pipe.push<_Event>(std::forward<_Args>(args)...); 90 | return *this; 91 | } 92 | 93 | template 94 | ServiceId Actor::registerIndex() noexcept { 95 | return VirtualCore::getServices()[type_id()] = ++VirtualCore::_nb_service; 96 | } 97 | 98 | } 99 | 100 | #endif -------------------------------------------------------------------------------- /include/qb/core/ActorId.h: -------------------------------------------------------------------------------- 1 | /* 2 | * qb - C++ Actor Framework 3 | * Copyright (C) 2011-2019 isndev (www.qbaf.io). All rights reserved. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | #ifndef QB_ACTORID_H 19 | # define QB_ACTORID_H 20 | # include 21 | # include 22 | # include 23 | // include from qb 24 | # include 25 | # include 26 | 27 | namespace qb { 28 | 29 | using CoreId = uint16_t; 30 | using ServiceId = uint16_t; 31 | using TypeId = uint16_t; 32 | using EventId = TypeId; 33 | 34 | /*! 35 | * @class ActorId core/ActorId.h qb/actorid.h 36 | * @ingroup Core 37 | * @brief Actor unique identifier 38 | * @details 39 | * ActorId is a composition of a Service Index (sid) and VirtualCore Index (index). 40 | */ 41 | class ActorId { 42 | friend class Main; 43 | friend class VirtualCore; 44 | friend class Actor; 45 | 46 | ServiceId _id; 47 | CoreId _index; 48 | 49 | protected: 50 | ActorId(ServiceId const id, CoreId const index) noexcept; 51 | public: 52 | static constexpr uint32_t NotFound = 0; 53 | static constexpr ServiceId BroadcastSid = (std::numeric_limits::max)(); 54 | 55 | /*! 56 | * ActorId() == ActorId::NotFound 57 | */ 58 | ActorId() noexcept; 59 | /*! 60 | * @private 61 | * internal function 62 | */ 63 | ActorId(uint32_t const id) noexcept; 64 | ActorId(ActorId const &) noexcept = default; 65 | 66 | operator const uint32_t &() const noexcept; 67 | 68 | /*! 69 | * @return Service index 70 | */ 71 | ServiceId sid() const noexcept; 72 | /*! 73 | * @return VirtualCore index 74 | */ 75 | CoreId index() const noexcept; 76 | 77 | bool isBroadcast() const noexcept; 78 | }; 79 | 80 | class BroadcastId : public ActorId { 81 | public: 82 | BroadcastId() = delete; 83 | explicit BroadcastId(uint32_t const core_id) noexcept 84 | : ActorId(BroadcastSid, static_cast(core_id)) {} 85 | }; 86 | 87 | using CoreIds = std::unordered_set; 88 | using ActorIds = std::unordered_set; 89 | 90 | } 91 | 92 | qb::io::stream &operator<<(qb::io::stream &os, qb::ActorId const &id); 93 | 94 | #endif //QB_ACTORID_H 95 | -------------------------------------------------------------------------------- /include/qb/core/CoreSet.h: -------------------------------------------------------------------------------- 1 | /* 2 | * qb - C++ Actor Framework 3 | * Copyright (C) 2011-2019 isndev (www.qbaf.io). All rights reserved. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | #ifndef QB_CORESET_H 19 | # define QB_CORESET_H 20 | # include 21 | # include 22 | # include 23 | 24 | namespace qb { 25 | 26 | /*! 27 | * @class CoreSet core/CoreSet.h qb/coreset.h 28 | * @ingroup Core 29 | * @brief Main initializer 30 | */ 31 | class CoreSet { 32 | friend class Main; 33 | 34 | const std::unordered_set _raw_set; 35 | const std::size_t _nb_core; 36 | std::vector _set; 37 | std::size_t _size; 38 | 39 | CoreId resolve(std::size_t const id) const noexcept; 40 | std::size_t getSize() const noexcept; 41 | std::size_t getNbCore() const noexcept; 42 | 43 | public: 44 | CoreSet() = delete; 45 | CoreSet(CoreSet const &) = default; 46 | explicit CoreSet(std::unordered_set const &set) noexcept; 47 | 48 | const std::unordered_set &raw() const noexcept; 49 | 50 | static CoreSet build(uint32_t const nb_core = std::thread::hardware_concurrency()) noexcept; 51 | }; 52 | 53 | } // namespace qb 54 | 55 | #endif //QB_CORESET_H 56 | -------------------------------------------------------------------------------- /include/qb/core/Event.h: -------------------------------------------------------------------------------- 1 | /* 2 | * qb - C++ Actor Framework 3 | * Copyright (C) 2011-2019 isndev (www.qbaf.io). All rights reserved. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | #ifndef QB_EVENT_H 19 | # define QB_EVENT_H 20 | # include 21 | # include 22 | // include from qb 23 | # include "ActorId.h" 24 | 25 | namespace qb { 26 | 27 | template 28 | struct type { 29 | constexpr static void id() {} 30 | }; 31 | 32 | template 33 | constexpr TypeId type_id() { return static_cast(reinterpret_cast(&type::id)); } 34 | 35 | /*! 36 | * @class Event core/Event.h qb/event.h 37 | * @ingroup Core 38 | * @brief Event base class 39 | */ 40 | class Event { 41 | friend class Main; 42 | friend class VirtualCore; 43 | friend class Actor; 44 | friend class ProxyPipe; 45 | friend struct ServiceEvent; 46 | 47 | EventId id; 48 | uint16_t bucket_size; 49 | std::bitset<32> state; 50 | // for users 51 | ActorId dest; 52 | ActorId source; 53 | 54 | public: 55 | Event() noexcept = default; 56 | 57 | inline ActorId getDestination() const noexcept { return dest; } 58 | inline ActorId getSource() const noexcept { return source; } 59 | }; 60 | 61 | /*! 62 | * @class ServiceEvent core/Event.h qb/event.h 63 | * @ingroup Core 64 | * @brief More flexible Event 65 | * @details 66 | * Section in construction 67 | */ 68 | struct ServiceEvent : public Event { 69 | ActorId forward; 70 | EventId service_event_id; 71 | 72 | inline void received() noexcept { 73 | std::swap(dest, forward); 74 | std::swap(id, service_event_id); 75 | live(true); 76 | } 77 | 78 | inline void live(bool flag) noexcept { 79 | state[0] = flag; 80 | } 81 | 82 | inline bool isLive() const noexcept { return state[0]; } 83 | 84 | inline uint16_t bucketSize() const noexcept { 85 | return bucket_size; 86 | } 87 | }; 88 | 89 | /*! 90 | * @class KillEvent core/Event.h qb/event.h 91 | * default registered event to kill Actor by event 92 | */ 93 | struct KillEvent : public Event {}; 94 | 95 | enum class ActorStatus : uint32_t { 96 | Alive, 97 | Dead 98 | }; 99 | 100 | /*! 101 | * @private 102 | * @class PingEvent core/Event.h qb/event.h 103 | * default registered event to kill Actor by event 104 | */ 105 | struct PingEvent : public Event { 106 | const uint32_t type; 107 | 108 | explicit PingEvent(uint32_t const actor_type) noexcept 109 | : type(actor_type) 110 | {} 111 | }; 112 | 113 | struct RequireEvent : public Event { 114 | const uint32_t type; 115 | const ActorStatus status; 116 | 117 | explicit RequireEvent(uint32_t const actor_type, ActorStatus const actor_status) noexcept 118 | : type(actor_type), status(actor_status) 119 | {} 120 | }; 121 | 122 | template 123 | struct WithData : public Event { 124 | std::tuple<_Args...> data; 125 | 126 | WithData(_Args &&...args) 127 | : data(std::forward<_Args>(args)...) 128 | {} 129 | }; 130 | 131 | template 132 | class WithoutData : public Event { 133 | }; 134 | 135 | /*! 136 | * @private 137 | * @tparam Data 138 | */ 139 | template 140 | struct AskData : public WithoutData<_Args...> { 141 | }; 142 | 143 | /*! 144 | * @private 145 | * @tparam Data 146 | */ 147 | template 148 | struct FillEvent : public WithData<_Args...> 149 | { 150 | using base_t = WithData<_Args...>; 151 | FillEvent() = default; 152 | explicit FillEvent(_Args &&...args) 153 | : base_t(std::forward<_Args>(args)...) 154 | {} 155 | }; 156 | 157 | } // namespace qb 158 | 159 | #endif //QB_EVENT_H 160 | -------------------------------------------------------------------------------- /include/qb/core/ICallback.h: -------------------------------------------------------------------------------- 1 | /* 2 | * qb - C++ Actor Framework 3 | * Copyright (C) 2011-2019 isndev (www.qbaf.io). All rights reserved. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | #ifndef QB_ICALLBACK_H 19 | #define QB_ICALLBACK_H 20 | 21 | namespace qb { 22 | 23 | /*! 24 | * @interface ICallback core/ICallback.h qb/icallback.h 25 | * @ingroup Core 26 | * @brief Actor callback interface 27 | * @details 28 | * DerivedActor must inherit from this interface 29 | * to register loop callback 30 | */ 31 | class ICallback { 32 | public: 33 | virtual ~ICallback() noexcept {} 34 | 35 | virtual void onCallback() = 0; 36 | }; 37 | 38 | } // namespace qb 39 | 40 | #endif //QB_ICALLBACK_H 41 | -------------------------------------------------------------------------------- /include/qb/core/Main.tpl: -------------------------------------------------------------------------------- 1 | /* 2 | * qb - C++ Actor Framework 3 | * Copyright (C) 2011-2019 isndev (www.qbaf.io). All rights reserved. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | #include "ActorId.h" 19 | #include "VirtualCore.h" 20 | #include "Main.h" 21 | 22 | #ifndef QB_MAIN_TPL 23 | #define QB_MAIN_TPL 24 | 25 | namespace qb { 26 | class Main; 27 | 28 | template 29 | ActorId Main::addActor(std::size_t cid, _Args &&...args) noexcept { 30 | const auto index = static_cast(cid); 31 | auto it = _core_set.raw().find(index); 32 | ActorId id = ActorId::NotFound; 33 | if (!Main::is_running && it != _core_set.raw().end()) { 34 | if constexpr (std::is_base_of::value) 35 | id = ActorId(_Actor::ServiceIndex, index); 36 | else 37 | id = ActorId(generated_sid++, index); 38 | auto fac = _actor_factories[index].find(id); 39 | if (fac == _actor_factories[index].end()) 40 | _actor_factories[index].insert({id, new TActorFactory<_Actor, _Args...>(id, std::forward<_Args>(args)...)}); 41 | else 42 | id = ActorId::NotFound; 43 | } 44 | return id; 45 | } 46 | 47 | template 48 | Main::CoreBuilder &Main::CoreBuilder::addActor(_Args &&...args) noexcept { 49 | auto id = _main.template addActor<_Actor, _Args...>(_index, std::forward<_Args>(args)...); 50 | if (id == ActorId::NotFound) 51 | _valid = false; 52 | 53 | _ret_ids.push_back(id); 54 | return *this; 55 | } 56 | 57 | } // namespace qb 58 | 59 | #endif //QB_MAIN_TPL -------------------------------------------------------------------------------- /include/qb/core/ProxyPipe.h: -------------------------------------------------------------------------------- 1 | /* 2 | * qb - C++ Actor Framework 3 | * Copyright (C) 2011-2019 isndev (www.qbaf.io). All rights reserved. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | #ifndef QB_PROXYPIPE_H 19 | #define QB_PROXYPIPE_H 20 | # include 21 | # include "ActorId.h" 22 | # include "Event.h" 23 | 24 | namespace qb { 25 | using Pipe = allocator::pipe; 26 | 27 | /*! 28 | * @brief Object returned by Actor::getPipe() 29 | * @class ProxyPipe ProxyPipe.h qb/actor.h 30 | * @details 31 | * to define 32 | */ 33 | class ProxyPipe { 34 | Pipe *pipe; 35 | ActorId dest; 36 | ActorId source; 37 | 38 | public: 39 | ProxyPipe() noexcept = default; 40 | ProxyPipe(ProxyPipe const &) noexcept = default; 41 | ProxyPipe &operator=(ProxyPipe const &) noexcept = default; 42 | 43 | ProxyPipe(Pipe &i_pipe, ActorId i_dest, ActorId i_source) noexcept 44 | : pipe(&i_pipe), dest(i_dest), source(i_source) {} 45 | 46 | /*! 47 | * 48 | * @tparam T 49 | * @tparam _Args 50 | * @param args 51 | * @return 52 | */ 53 | template 54 | T &push(_Args &&...args) const noexcept; 55 | 56 | /*! 57 | * 58 | * @tparam T 59 | * @tparam _Args 60 | * @param size 61 | * @param args 62 | * @return 63 | */ 64 | template 65 | T &allocated_push(std::size_t size, _Args &&...args) const noexcept; 66 | 67 | /*! 68 | * 69 | * @return 70 | */ 71 | inline ActorId getDestination() const noexcept { 72 | return dest; 73 | } 74 | 75 | /*! 76 | * 77 | * @return 78 | */ 79 | inline ActorId getSource() const noexcept { 80 | return source; 81 | } 82 | 83 | }; 84 | 85 | } // namespace qb 86 | 87 | #endif //QB_PROXYPIPE_H 88 | -------------------------------------------------------------------------------- /include/qb/core/ProxyPipe.tpl: -------------------------------------------------------------------------------- 1 | /* 2 | * qb - C++ Actor Framework 3 | * Copyright (C) 2011-2019 isndev (www.qbaf.io). All rights reserved. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | #include "ProxyPipe.h" 19 | 20 | #ifndef QB_PROXYPIPE_TPL 21 | #define QB_PROXYPIPE_TPL 22 | 23 | namespace qb { 24 | 25 | template 26 | T &ProxyPipe::push(_Args &&...args) const noexcept { 27 | constexpr std::size_t BUCKET_SIZE = allocator::getItemSize(); 28 | auto &data = pipe->template allocate_back(std::forward<_Args>(args)...); 29 | data.id = type_id(); 30 | data.dest = dest; 31 | data.source = source; 32 | if constexpr (std::is_base_of::value) { 33 | data.forward = source; 34 | std::swap(data.id, data.service_event_id); 35 | } 36 | 37 | data.bucket_size = BUCKET_SIZE; 38 | return data; 39 | } 40 | 41 | template 42 | T &ProxyPipe::allocated_push(std::size_t size, _Args &&...args) const noexcept { 43 | size += sizeof(T); 44 | size = size / sizeof(CacheLine) + static_cast(size % sizeof(CacheLine)); 45 | auto &data = *(new(reinterpret_cast(pipe->allocate_back(size))) T( 46 | std::forward<_Args>(args)...)); 47 | 48 | data.id = type_id(); 49 | data.dest = dest; 50 | data.source = source; 51 | if constexpr (std::is_base_of::value) { 52 | data.forward = source; 53 | std::swap(data.id, data.service_event_id); 54 | } 55 | 56 | data.bucket_size = static_cast(size); 57 | return data; 58 | } 59 | 60 | } // namespace qb 61 | 62 | #endif //QB_PROXYPIPE_TPL -------------------------------------------------------------------------------- /include/qb/core/VirtualCore.tpl: -------------------------------------------------------------------------------- 1 | /* 2 | * qb - C++ Actor Framework 3 | * Copyright (C) 2011-2019 isndev (www.qbaf.io). All rights reserved. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | #include "VirtualCore.h" 19 | 20 | #ifndef QB_CORE_TPL 21 | # define QB_CORE_TPL 22 | 23 | namespace qb { 24 | 25 | template 26 | void VirtualCore::registerEvent(_Actor &actor) noexcept { 27 | using handler_type = EventHandler<_Event>; 28 | using event_type = typename handler_type::template RegisteredEvent<_Actor>; 29 | auto ievent = new event_type(actor); 30 | auto it = _event_map.find(qb::type_id<_Event>()); 31 | if (it == _event_map.end()) 32 | _event_map.insert({qb::type_id<_Event>(), new handler_type{}}).first->second->registerEvent(ievent); 33 | else 34 | it->second->registerEvent(ievent); 35 | } 36 | 37 | template 38 | void VirtualCore::unregisterEvent(_Actor &actor) noexcept { 39 | auto it = _event_map.find(qb::type_id<_Event>()); 40 | if (it != _event_map.end()) { 41 | it->second->unregisterEvent(actor.id()); 42 | } else { 43 | LOG_WARN("" << *this << "Failed to unregister event"); 44 | } 45 | } 46 | 47 | template 48 | _Actor *VirtualCore::addReferencedActor(_Init &&...init) noexcept { 49 | auto actor = new _Actor(std::forward<_Init>(init)...); 50 | actor->id_type = type_id<_Actor>(); 51 | if (appendActor(*actor, std::is_base_of::value, true) != ActorId::NotFound) 52 | return actor; 53 | return nullptr; 54 | }; 55 | 56 | template 57 | void VirtualCore::registerCallback(_Actor &actor) noexcept { 58 | _actor_callbacks.insert({actor.id(), &actor}); 59 | } 60 | 61 | // Event API 62 | template 63 | inline void VirtualCore::fill_event(T &data, ActorId const dest, ActorId const source) const noexcept { 64 | data.id = type_id(); 65 | data.dest = dest; 66 | data.source = source; 67 | 68 | if constexpr (std::is_base_of::value) { 69 | data.forward = source; 70 | std::swap(data.id, data.service_event_id); 71 | } 72 | 73 | data.bucket_size = static_cast(allocator::getItemSize()); 74 | } 75 | 76 | template 77 | void VirtualCore::send(ActorId const dest, ActorId const source, _Init &&...init) noexcept { 78 | auto &pipe = __getPipe__(dest._index); 79 | auto &data = pipe.template allocate(std::forward<_Init>(init)...); 80 | 81 | fill_event(data, dest, source); 82 | 83 | if (try_send(data)) 84 | pipe.free(data.bucket_size); 85 | } 86 | 87 | 88 | template 89 | void VirtualCore::broadcast(ActorId const source, _Init &&...init) noexcept { 90 | for (const auto it : _engine._core_set.raw()) 91 | send(BroadcastId(it), source, std::forward<_Init>(init)...); 92 | } 93 | 94 | template 95 | T &VirtualCore::push(ActorId const dest, ActorId const source, _Init &&...init) noexcept { 96 | auto &pipe = __getPipe__(dest._index); 97 | auto &data = pipe.template allocate_back(std::forward<_Init>(init)...); 98 | 99 | fill_event(data, dest, source); 100 | 101 | return data; 102 | } 103 | //!Event Api 104 | 105 | template 106 | const ServiceId ServiceActor::ServiceIndex = Actor::registerIndex(); 107 | 108 | } 109 | 110 | #endif -------------------------------------------------------------------------------- /include/qb/coreset.h: -------------------------------------------------------------------------------- 1 | /* 2 | * qb - C++ Actor Framework 3 | * Copyright (C) 2011-2019 isndev (www.qbaf.io). All rights reserved. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | #include "core/CoreSet.h" 19 | -------------------------------------------------------------------------------- /include/qb/event.h: -------------------------------------------------------------------------------- 1 | /* 2 | * qb - C++ Actor Framework 3 | * Copyright (C) 2011-2019 isndev (www.qbaf.io). All rights reserved. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | #include "core/Event.h" 19 | -------------------------------------------------------------------------------- /include/qb/icallback.h: -------------------------------------------------------------------------------- 1 | /* 2 | * qb - C++ Actor Framework 3 | * Copyright (C) 2011-2019 isndev (www.qbaf.io). All rights reserved. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | #include "core/ICallback.h" 19 | -------------------------------------------------------------------------------- /include/qb/io.h: -------------------------------------------------------------------------------- 1 | /* 2 | * qb - C++ Actor Framework 3 | * Copyright (C) 2011-2019 isndev (www.qbaf.io). All rights reserved. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | #ifndef QB_TYPES_H 19 | # define QB_TYPES_H 20 | 21 | # include 22 | # include 23 | # include 24 | # include 25 | # include 26 | # include 27 | 28 | namespace qb { 29 | #ifdef NDEBUG 30 | constexpr static bool debug = false; 31 | #else 32 | constexpr static bool debug = true; 33 | #endif 34 | 35 | namespace io { 36 | using stream = nanolog::NanoLogLine; 37 | 38 | namespace log { 39 | using Level = nanolog::LogLevel; 40 | /*! 41 | * set log level 42 | * @param qb::io::log::Level 43 | */ 44 | void setLevel(Level lvl); 45 | /*! 46 | * @brief init logger 47 | * @details 48 | * @param file_path logfile path name 49 | * @param roll_MB Max roll file size in MB 50 | * @code 51 | * enum class LogLevel : uint8_t { 52 | * DEBUG, 53 | * VERBOSE, 54 | * INFO, 55 | * WARN, 56 | * ERROR, 57 | * CRIT }; 58 | * @endcode 59 | */ 60 | void init(std::string const &file_path, uint32_t const roll_MB = 128); 61 | } 62 | 63 | /*! 64 | * @class cout 65 | * @brief thread safe print in std::cout 66 | * @details 67 | * example: 68 | * @code 69 | * qb::cout() << ... ; 70 | * @endcode 71 | * @note prefer using logger than print 72 | */ 73 | class cout { 74 | static std::mutex io_lock; 75 | std::stringstream ss; 76 | public: 77 | cout() = default; 78 | cout(cout const &) = delete; 79 | ~cout(); 80 | 81 | template 82 | inline std::stringstream &operator<<(T const &data) { 83 | ss << data; 84 | return ss; 85 | } 86 | }; 87 | } 88 | } 89 | 90 | #endif //QB_TYPES_H -------------------------------------------------------------------------------- /include/qb/main.h: -------------------------------------------------------------------------------- 1 | /* 2 | * qb - C++ Actor Framework 3 | * Copyright (C) 2011-2019 isndev (www.qbaf.io). All rights reserved. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | #include "core/Main.h" 19 | #include "core/Main.tpl" -------------------------------------------------------------------------------- /include/qb/network/epoll.h: -------------------------------------------------------------------------------- 1 | /* 2 | * qb - C++ Actor Framework 3 | * Copyright (C) 2011-2019 isndev (www.qbaf.io). All rights reserved. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | #include 19 | #include 20 | #include 21 | #include "helper.h" 22 | 23 | #ifdef __WIN__SYSTEM__ 24 | #error "epoll is not available on windows" 25 | #endif 26 | 27 | #ifndef QB_NETWORK_EPOLL_H 28 | #define QB_NETWORK_EPOLL_H 29 | 30 | namespace qb { 31 | namespace network { 32 | namespace epoll { 33 | 34 | class Proxy { 35 | protected: 36 | int _epoll; 37 | public: 38 | Proxy() = default; 39 | 40 | Proxy(const int epoll) 41 | : _epoll(epoll) { 42 | } 43 | 44 | public: 45 | 46 | using item_type = epoll_event; 47 | 48 | Proxy(Proxy const &) = default; 49 | 50 | inline int 51 | ctl(item_type &item) const { 52 | return epoll_ctl(_epoll, EPOLL_CTL_MOD, item.data.fd, &item); 53 | } 54 | 55 | inline int 56 | add(item_type &item) const { 57 | return epoll_ctl(_epoll, EPOLL_CTL_ADD, item.data.fd, &item); 58 | } 59 | 60 | inline int 61 | remove(item_type const &item) { 62 | return epoll_ctl(_epoll, EPOLL_CTL_DEL, item.data.fd, nullptr); 63 | } 64 | }; 65 | 66 | /*! 67 | * @class Poller epoll.h qb/network/epoll.h 68 | * @ingroup Network 69 | * @note Available only on Linux >= 2.6 70 | * @tparam _MAX_EVENTS 71 | */ 72 | template 73 | class Poller 74 | : public Proxy { 75 | epoll_event _epvts[_MAX_EVENTS]; 76 | public: 77 | Poller() 78 | : Proxy(epoll_create(_MAX_EVENTS)) { 79 | if (unlikely(_epoll < 0)) 80 | throw std::runtime_error("failed to init epoll::Poller"); 81 | } 82 | 83 | Poller(Poller const &) = delete; 84 | 85 | ~Poller() { 86 | ::close(_epoll); 87 | } 88 | 89 | template 90 | inline void 91 | wait(_Func const &func, int const timeout = 0) { 92 | const int ret = epoll_wait(_epoll, _epvts, _MAX_EVENTS, timeout); 93 | if (unlikely(ret < 0)) { 94 | std::cerr << "epoll::Poller polling has failed " << std::endl; 95 | return; 96 | } 97 | for (int i = 0; i < ret; ++i) { 98 | func(_epvts[i]); 99 | } 100 | } 101 | }; 102 | 103 | } // namespace epoll 104 | } // namespace network 105 | } // namespace qb 106 | 107 | #endif // QB_NETWORK_EPOLL_H 108 | -------------------------------------------------------------------------------- /include/qb/network/helper.h: -------------------------------------------------------------------------------- 1 | /* 2 | * qb - C++ Actor Framework 3 | * Copyright (C) 2011-2019 isndev (www.qbaf.io). All rights reserved. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | #include 19 | #include 20 | 21 | #ifndef QB_NETWORK_HELPER_H_ 22 | # define QB_NETWORK_HELPER_H_ 23 | 24 | #ifdef __WIN__SYSTEM__ 25 | #include 26 | #include 27 | #else 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #endif 36 | 37 | namespace qb { 38 | namespace network { 39 | 40 | enum SocketType { 41 | TCP, 42 | UDP 43 | }; 44 | 45 | enum SocketStatus 46 | { 47 | Done, 48 | NotReady, 49 | Partial, 50 | Disconnected, 51 | Error 52 | }; 53 | 54 | #ifdef __WIN__SYSTEM__ 55 | typedef SOCKET SocketHandler; 56 | typedef int AddrLength; 57 | constexpr static const SocketHandler SOCKET_INVALID = INVALID_SOCKET; 58 | #else 59 | typedef int SocketHandler; 60 | typedef socklen_t AddrLength; 61 | constexpr static const SocketHandler SOCKET_INVALID = -1; 62 | #endif 63 | 64 | class QB_API helper { 65 | public: 66 | static sockaddr_in createAddress(uint32_t address, unsigned short port); 67 | static bool close(SocketHandler sock); 68 | static bool block(SocketHandler sock, bool block); 69 | static bool is_blocking(SocketHandler sock); 70 | static SocketStatus getErrorStatus(); 71 | }; 72 | 73 | } // namespace network 74 | } // namespace qb 75 | 76 | #endif // QB_NETWORK_HELPER_H_ 77 | -------------------------------------------------------------------------------- /include/qb/network/ip.h: -------------------------------------------------------------------------------- 1 | /* 2 | * qb - C++ Actor Framework 3 | * Copyright (C) 2011-2019 isndev (www.qbaf.io). All rights reserved. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | #include 19 | #include 20 | #include 21 | 22 | #ifndef QB_NETWORK_IP_H_ 23 | #define QB_NETWORK_IP_H_ 24 | 25 | namespace qb { 26 | namespace network { 27 | 28 | /*! 29 | * @class ip ip.h qb/network/ip.h 30 | * @ingroup Network 31 | */ 32 | class QB_API ip { 33 | uint32_t _address; 34 | 35 | void resolve(const std::string& address); 36 | friend QB_API bool operator <(const ip& left, const ip& right); 37 | public: 38 | ip(); 39 | ip(const std::string& address); 40 | ip(const char* address); 41 | ip(uint8_t byte0, uint8_t byte1, uint8_t byte2, uint8_t byte3); 42 | explicit ip(uint32_t address); 43 | 44 | std::string toString() const; 45 | uint32_t toInteger() const; 46 | 47 | static const ip None; 48 | static const ip Any; 49 | static const ip LocalHost; 50 | 51 | 52 | }; 53 | 54 | QB_API bool operator ==(const ip& left, const ip& right); 55 | QB_API bool operator !=(const ip& left, const ip& right); 56 | QB_API bool operator <(const ip& left, const ip& right); 57 | QB_API bool operator >(const ip& left, const ip& right); 58 | QB_API bool operator <=(const ip& left, const ip& right); 59 | QB_API bool operator >=(const ip& left, const ip& right); 60 | QB_API std::istream& operator >>(std::istream& stream, ip& address); 61 | QB_API std::ostream& operator <<(std::ostream& stream, const ip& address); 62 | 63 | } // namespace network 64 | } // namespace qb 65 | 66 | #endif // QB_NETWORK_IP_H_ -------------------------------------------------------------------------------- /include/qb/network/sys.h: -------------------------------------------------------------------------------- 1 | /* 2 | * qb - C++ Actor Framework 3 | * Copyright (C) 2011-2019 isndev (www.qbaf.io). All rights reserved. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | #include 19 | #include 20 | #include "helper.h" 21 | 22 | #ifndef QB_NETWORK_TSOCKET_H_ 23 | # define QB_NETWORK_TSOCKET_H_ 24 | 25 | namespace qb { 26 | namespace network { 27 | namespace sys { 28 | 29 | template 30 | class QB_API Socket{ 31 | protected: 32 | SocketHandler _handle; 33 | 34 | void init() { 35 | if (!good()) { 36 | SocketHandler handle; 37 | if constexpr (_Type == SocketType::TCP) 38 | handle = ::socket(PF_INET, SOCK_STREAM, 0); 39 | else 40 | handle = ::socket(PF_INET, SOCK_DGRAM, 0); 41 | init(handle); 42 | } 43 | } 44 | 45 | void init(SocketHandler handle) { 46 | if (!good() && (handle != SOCKET_INVALID)) { 47 | if constexpr (_Type == SocketType::TCP) { 48 | // Disable the Nagle algorithm (i.e. removes buffering of TCP packets) 49 | int yes = 1; 50 | if (setsockopt(handle, IPPROTO_TCP, TCP_NODELAY, reinterpret_cast(&yes), 51 | sizeof(yes)) == -1) { 52 | std::cerr << "Failed to set socket option \"TCP_NODELAY\" ; " 53 | << "all your TCP packets will be buffered" << std::endl; 54 | } 55 | } else { 56 | // Enable broadcast by default for UDP sockets 57 | int yes = 1; 58 | if (setsockopt(handle, SOL_SOCKET, SO_BROADCAST, reinterpret_cast(&yes), 59 | sizeof(yes)) == -1) 60 | std::cerr << "Failed to enable broadcast on UDP socket" << std::endl; 61 | } 62 | _handle = handle; 63 | } else { 64 | throw std::runtime_error("Failed to init socket"); 65 | } 66 | } 67 | 68 | public: 69 | constexpr static const SocketType type = _Type; 70 | 71 | Socket() 72 | : _handle(SOCKET_INVALID) 73 | {} 74 | 75 | ~Socket() { 76 | } 77 | 78 | SocketHandler raw() const { 79 | return _handle; 80 | } 81 | 82 | int setBlocking(bool new_state) const { 83 | return helper::block(_handle, new_state); 84 | } 85 | 86 | bool isBlocking() const { 87 | return helper::is_blocking(_handle); 88 | } 89 | 90 | bool setReceiveBufferSize(int size) const { 91 | return setsockopt(_handle, SOL_SOCKET, SO_RCVBUF, &size, sizeof(int)) != -1; 92 | } 93 | 94 | bool setSendBufferSize(int size) const { 95 | return setsockopt(_handle, SOL_SOCKET, SO_SNDBUF, &size, sizeof(int)) != -1; 96 | } 97 | 98 | bool good() const { 99 | return _handle != SOCKET_INVALID; 100 | } 101 | 102 | void close() { 103 | if (good()) { 104 | if(helper::close(_handle)) 105 | _handle = SOCKET_INVALID; 106 | else 107 | std::cerr << "Failed to close socket" << std::endl; 108 | } 109 | } 110 | }; 111 | 112 | } // namespace sys 113 | } // namespace network 114 | } // namespace qb 115 | 116 | #endif // QB_NETWORK_TSOCKET_H_ 117 | -------------------------------------------------------------------------------- /include/qb/network/tcp.h: -------------------------------------------------------------------------------- 1 | /* 2 | * qb - C++ Actor Framework 3 | * Copyright (C) 2011-2019 isndev (www.qbaf.io). All rights reserved. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | #include "ip.h" 19 | #include "sys.h" 20 | 21 | #ifndef QB_NETWORK_TCP_H_ 22 | # define QB_NETWORK_TCP_H_ 23 | 24 | namespace qb { 25 | namespace network { 26 | namespace tcp { 27 | 28 | /*! 29 | * @class Socket tcp.h qb/network/tcp.h 30 | * @ingroup TCP 31 | */ 32 | class QB_API Socket 33 | : public sys::Socket { 34 | public: 35 | Socket(); 36 | Socket(Socket const &rhs) = default; 37 | Socket(SocketHandler fd); 38 | 39 | ip getRemoteAddress() const; 40 | unsigned short getLocalPort() const; 41 | unsigned short getRemotePort() const; 42 | 43 | SocketStatus connect(const ip &remoteAddress, unsigned short remotePort, int timeout = 0); 44 | void disconnect(); 45 | 46 | SocketStatus send(const void *data, std::size_t size) const; 47 | SocketStatus send(const void *data, std::size_t size, std::size_t &sent) const; 48 | SocketStatus sendall(const void *data, std::size_t size, std::size_t &sent) const; 49 | SocketStatus receive(void *data, std::size_t size, std::size_t &received) const; 50 | 51 | private: 52 | friend class Listener; 53 | }; 54 | 55 | /*! 56 | * @class Listener tcp.h qb/network/tcp.h 57 | * @ingroup TCP 58 | */ 59 | class QB_API Listener 60 | : public Socket { 61 | public: 62 | Listener(); 63 | Listener(Listener const &) = delete; 64 | ~Listener(); 65 | 66 | unsigned short getLocalPort() const; 67 | 68 | SocketStatus listen(unsigned short port, const ip &address = ip::Any); 69 | SocketStatus accept(Socket &socket); 70 | }; 71 | 72 | } // namespace tcp 73 | } // namespace network 74 | } // namespace qb 75 | 76 | #endif // QB_NETWORK_TCP_H_ 77 | -------------------------------------------------------------------------------- /include/qb/network/udp.h: -------------------------------------------------------------------------------- 1 | /* 2 | * qb - C++ Actor Framework 3 | * Copyright (C) 2011-2019 isndev (www.qbaf.io). All rights reserved. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | #include "ip.h" 19 | #include "sys.h" 20 | 21 | #ifndef QB_NETWORK_UDP_H_ 22 | # define QB_NETWORK_UDP_H_ 23 | 24 | namespace qb { 25 | namespace network { 26 | namespace udp { 27 | 28 | /*! 29 | * @class Socket udp.h qb/network/udp.h 30 | * @ingroup UDP 31 | */ 32 | class QB_API Socket 33 | : public sys::Socket { 34 | public: 35 | constexpr static const std::size_t MaxDatagramSize = 65507; 36 | 37 | Socket(); 38 | 39 | unsigned short getLocalPort() const; 40 | 41 | SocketStatus bind(unsigned short port, const ip &address = ip::Any); 42 | 43 | void unbind(); 44 | 45 | SocketStatus 46 | send(const void *data, std::size_t size, const ip &remoteAddress, unsigned short remotePort) const; 47 | 48 | SocketStatus 49 | receive(void *data, std::size_t size, std::size_t &received, ip &remoteAddress, unsigned short &remotePort) const; 50 | 51 | }; 52 | 53 | } // namespace udp 54 | } // namespace network 55 | } // namespace qb 56 | 57 | #endif // QB_NETWORK_UDP_H_ 58 | -------------------------------------------------------------------------------- /include/qb/system/lockfree/spinlock.h: -------------------------------------------------------------------------------- 1 | /* 2 | * qb - C++ Actor Framework 3 | * Copyright (C) 2011-2019 isndev (www.qbaf.io). All rights reserved. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | #ifndef QB_LOCKFREE_SPINLOCK_H 19 | # define QB_LOCKFREE_SPINLOCK_H 20 | # include 21 | # include 22 | 23 | namespace qb { 24 | namespace lockfree { 25 | 26 | class SpinLock { 27 | public: 28 | SpinLock() noexcept : _lock(false) {} 29 | SpinLock(const SpinLock &) = delete; 30 | SpinLock(SpinLock &&) = default; 31 | 32 | ~SpinLock() = default; 33 | 34 | SpinLock &operator=(const SpinLock &) = delete; 35 | SpinLock &operator=(SpinLock &&) = default; 36 | 37 | bool locked() noexcept { 38 | return _lock.load(std::memory_order_acquire); 39 | } 40 | 41 | bool trylock() noexcept { 42 | return !_lock.exchange(true, std::memory_order_acquire); 43 | } 44 | 45 | bool trylock(int64_t spin) noexcept { 46 | // Try to acquire spin-lock at least one time 47 | do { 48 | if (trylock()) 49 | return true; 50 | } while (spin-- > 0); 51 | 52 | // Failed to acquire spin-lock 53 | return false; 54 | } 55 | 56 | bool trylock_for(const Timespan ×pan) noexcept { 57 | // Calculate a finish timestamp 58 | Timestamp finish = NanoTimestamp() + timespan; 59 | 60 | // Try to acquire spin-lock at least one time 61 | do { 62 | if (trylock()) 63 | return true; 64 | } while (NanoTimestamp() < finish); 65 | 66 | // Failed to acquire spin-lock 67 | return false; 68 | } 69 | 70 | bool trylock_until(const UtcTimestamp ×tamp) noexcept { 71 | return trylock_for(timestamp - UtcTimestamp()); 72 | } 73 | 74 | void lock() noexcept { 75 | while (_lock.exchange(true, std::memory_order_acquire)); 76 | } 77 | 78 | void unlock() noexcept { 79 | _lock.store(false, std::memory_order_release); 80 | } 81 | 82 | private: 83 | std::atomic _lock; 84 | }; 85 | 86 | } /* namespace lockfree */ 87 | } /* namespace qb */ 88 | 89 | #endif //QB_LOCKFREE_SPINLOCK_H 90 | -------------------------------------------------------------------------------- /include/qb/utility/branch_hints.h: -------------------------------------------------------------------------------- 1 | /* 2 | * qb - C++ Actor Framework 3 | * Copyright (C) 2011-2019 isndev (www.qbaf.io). All rights reserved. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | #ifndef QB_UTILS_BRANCH_HINTS_H 19 | #define QB_UTILS_BRANCH_HINTS_H 20 | 21 | namespace qb { 22 | /** \brief hint for the branch prediction */ 23 | inline bool likely(bool expr) { 24 | #ifdef __GNUC__ 25 | return __builtin_expect(expr, true); 26 | #else 27 | return expr; 28 | #endif 29 | } 30 | 31 | /** \brief hint for the branch prediction */ 32 | inline bool unlikely(bool expr) { 33 | #ifdef __GNUC__ 34 | return __builtin_expect(expr, false); 35 | #else 36 | return expr; 37 | #endif 38 | } 39 | 40 | } /* namespace qb */ 41 | 42 | #endif /* QB_UTILS_BRANCH_HINTS_H */ 43 | -------------------------------------------------------------------------------- /include/qb/utility/build_macros.h: -------------------------------------------------------------------------------- 1 | /* 2 | * qb - C++ Actor Framework 3 | * Copyright (C) 2011-2019 isndev (www.qbaf.io). All rights reserved. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | #include 19 | #include 20 | 21 | #ifndef QB_BUILD_MACROS_H_ 22 | #define QB_BUILD_MACROS_H_ 23 | 24 | #if defined(_WIN32) || defined(_WIN64) 25 | #define __WIN__SYSTEM__ 26 | #ifndef WIN32_LEAN_AND_MEAN 27 | #define WIN32_LEAN_AND_MEAN 28 | #endif 29 | #ifndef NOMINMAX 30 | #define NOMINMAX 31 | #endif 32 | 33 | #elif defined(__linux__) || defined(__unix) || defined(__unix__) || defined(__APPLE__) 34 | // Linux 35 | #define __LINUX__SYSTEM__ 36 | #else 37 | #error "Unsupported Operating System" 38 | #endif 39 | 40 | #if defined(__WIN__SYSTEM__) 41 | #define QB_GET __cdecl 42 | #ifdef QB_DYNAMIC 43 | // Windows platforms 44 | #ifndef QB_LINKED_AS_SHARED 45 | #pragma message ("WILL EXPORT DYNAMIC") 46 | // From DLL side, we must export 47 | #define QB_API __declspec(dllexport) 48 | #else 49 | #pragma message ("WILL IMPORT DYNAMIC") 50 | // From client application side, we must import 51 | #define QB_GET __cdecl 52 | #define QB_API __declspec(dllimport) 53 | #endif 54 | // For Visual C++ compilers, we also need to turn off this annoying C4251 warning. 55 | // You can read lots ot different things about it, but the point is the code will 56 | // just work fine, and so the simplest way to get rid of this warning is to disable it 57 | #ifdef _MSC_VER 58 | #pragma warning(disable : 4251) 59 | #pragma warning(disable : 4250) 60 | #endif 61 | #else 62 | // No specific directive needed for static build 63 | #define QB_API 64 | #endif 65 | #define QB_UNUSED_VAR 66 | #else 67 | // Other platforms don't need to define anything 68 | #define QB_GET 69 | #define QB_API 70 | #ifdef __clang__ 71 | #define QB_UNUSED_VAR __attribute__((unused)) 72 | #else 73 | #define QB_UNUSED_VAR 74 | #endif 75 | #endif 76 | 77 | #endif 78 | -------------------------------------------------------------------------------- /include/qb/utility/nocopy.h: -------------------------------------------------------------------------------- 1 | /* 2 | * qb - C++ Actor Framework 3 | * Copyright (C) 2011-2019 isndev (www.qbaf.io). All rights reserved. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | #ifndef QB_UTILS_NOCOPY_H 19 | #define QB_UTILS_NOCOPY_H 20 | 21 | namespace qb { 22 | struct nocopy { 23 | nocopy() = default; 24 | nocopy(nocopy const &) = delete; 25 | nocopy(nocopy const &&) = delete; 26 | nocopy &operator=(nocopy const &) = delete; 27 | }; 28 | } 29 | 30 | #endif //QB_UTILS_NOCOPY_H 31 | -------------------------------------------------------------------------------- /include/qb/utility/prefix.h: -------------------------------------------------------------------------------- 1 | /* 2 | * qb - C++ Actor Framework 3 | * Copyright (C) 2011-2019 isndev (www.qbaf.io). All rights reserved. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | #ifndef QB_UTILS_PREFIX_H 19 | #define QB_UTILS_PREFIX_H 20 | 21 | /* this file defines the following macros: 22 | QB_LOCKFREE_CACHELINE_BYTES: size of a cache line 23 | QB_LOCKFREE_PTR_COMPRESSION: use tag/pointer compression to utilize parts 24 | of the virtual address space as tag (at least 16bit) 25 | QB_LOCKFREE_DCAS_ALIGNMENT: symbol used for aligning structs at cache line 26 | boundaries 27 | */ 28 | 29 | #define QB_LOCKFREE_CACHELINE_BYTES 64 30 | 31 | #ifdef _MSC_VER 32 | 33 | #define QB_LOCKFREE_CACHELINE_ALIGNMENT __declspec(align(QB_LOCKFREE_CACHELINE_BYTES)) 34 | 35 | #if defined(_M_IX86) 36 | #define QB_LOCKFREE_DCAS_ALIGNMENT 37 | #elif defined(_M_X64) || defined(_M_IA64) 38 | #define QB_LOCKFREE_PTR_COMPRESSION 1 39 | #define QB_LOCKFREE_DCAS_ALIGNMENT __declspec(align(16)) 40 | #endif 41 | 42 | #endif /* _MSC_VER */ 43 | 44 | #ifdef __GNUC__ 45 | 46 | #define QB_LOCKFREE_CACHELINE_ALIGNMENT alignas(QB_LOCKFREE_CACHELINE_BYTES) 47 | //__attribute__((aligned(QB_LOCKFREE_CACHELINE_BYTES))) 48 | 49 | #if defined(__i386__) || defined(__ppc__) 50 | #define QB_LOCKFREE_DCAS_ALIGNMENT 51 | #elif defined(__x86_64__) 52 | #define QB_LOCKFREE_PTR_COMPRESSION 1 53 | #define QB_LOCKFREE_DCAS_ALIGNMENT __attribute__((aligned(16))) 54 | #elif defined(__alpha__) 55 | #define QB_LOCKFREE_PTR_COMPRESSION 1 56 | #define QB_LOCKFREE_DCAS_ALIGNMENT 57 | #endif 58 | #endif /* __GNUC__ */ 59 | 60 | struct QB_LOCKFREE_CACHELINE_ALIGNMENT CacheLine { 61 | uint32_t __raw__[16]; 62 | }; 63 | 64 | #endif /* QB_UTILS_PREFIX_H */ 65 | -------------------------------------------------------------------------------- /include/qb/utility/type_traits.h: -------------------------------------------------------------------------------- 1 | /* 2 | * qb - C++ Actor Framework 3 | * Copyright (C) 2011-2019 isndev (www.qbaf.io). All rights reserved. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | #ifndef QB_TYPE_TRAITS_H 19 | #define QB_TYPE_TRAITS_H 20 | 21 | namespace qb { 22 | template 23 | struct remove_reference_if { 24 | typedef T type; 25 | constexpr static bool value = false; 26 | }; 27 | 28 | template 29 | struct remove_reference_if { 30 | typedef typename std::remove_reference::type type; 31 | constexpr static bool value = true; 32 | }; 33 | } 34 | 35 | #endif //QB_TYPE_TRAITS_H 36 | -------------------------------------------------------------------------------- /modules/nanolog/nanolog.h: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Distributed under the MIT License (MIT) 4 | 5 | Copyright (c) 2016 Karthik Iyengar 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a copy of 8 | this software and associated documentation files (the "Software"), to deal in the 9 | Software without restriction, including without limitation the rights to 10 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 11 | of the Software, and to permit persons to whom the Software is furnished 12 | to do so, subject to the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be included 15 | in all copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 18 | INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS 20 | OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 21 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | 24 | */ 25 | 26 | #ifndef NANO_LOG_HEADER_GUARD 27 | #define NANO_LOG_HEADER_GUARD 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | 34 | namespace nanolog 35 | { 36 | enum class LogLevel : uint8_t { DEBUG, VERBOSE, INFO, WARN, CRIT }; 37 | 38 | class NanoLogLine 39 | { 40 | public: 41 | NanoLogLine(LogLevel level, char const * file, char const * function, uint32_t line); 42 | ~NanoLogLine(); 43 | 44 | NanoLogLine(NanoLogLine &&) = default; 45 | NanoLogLine& operator=(NanoLogLine &&) = default; 46 | 47 | void stringify(std::ostream & os); 48 | 49 | NanoLogLine& operator<<(char arg); 50 | NanoLogLine& operator<<(int32_t arg); 51 | NanoLogLine& operator<<(uint32_t arg); 52 | NanoLogLine& operator<<(int64_t arg); 53 | NanoLogLine& operator<<(uint64_t arg); 54 | NanoLogLine& operator<<(double arg); 55 | NanoLogLine& operator<<(std::string const & arg); 56 | 57 | template < size_t N > 58 | NanoLogLine& operator<<(const char (&arg)[N]) 59 | { 60 | encode(string_literal_t(arg)); 61 | return *this; 62 | } 63 | 64 | template < typename Arg > 65 | typename std::enable_if < std::is_same < Arg, char const * >::value, NanoLogLine& >::type 66 | operator<<(Arg const & arg) 67 | { 68 | encode(arg); 69 | return *this; 70 | } 71 | 72 | template < typename Arg > 73 | typename std::enable_if < std::is_same < Arg, char * >::value, NanoLogLine& >::type 74 | operator<<(Arg const & arg) 75 | { 76 | encode(arg); 77 | return *this; 78 | } 79 | 80 | struct string_literal_t 81 | { 82 | explicit string_literal_t(char const * s) : m_s(s) {} 83 | char const * m_s; 84 | }; 85 | 86 | private: 87 | char * buffer(); 88 | 89 | template < typename Arg > 90 | void encode(Arg arg); 91 | 92 | template < typename Arg > 93 | void encode(Arg arg, uint8_t type_id); 94 | 95 | void encode(char * arg); 96 | void encode(char const * arg); 97 | void encode(string_literal_t arg); 98 | void encode_c_string(char const * arg, size_t length); 99 | void resize_buffer_if_needed(size_t additional_bytes); 100 | void stringify(std::ostream & os, char * start, char const * const end); 101 | 102 | private: 103 | size_t m_bytes_used; 104 | size_t m_buffer_size; 105 | std::unique_ptr < char [] > m_heap_buffer; 106 | char m_stack_buffer[256 - 2 * sizeof(size_t) - sizeof(decltype(m_heap_buffer)) - 8 /* Reserved */]; 107 | }; 108 | 109 | struct NanoLog 110 | { 111 | /* 112 | * Ideally this should have been operator+= 113 | * Could not get that to compile, so here we are... 114 | */ 115 | bool operator==(NanoLogLine &); 116 | }; 117 | 118 | void set_log_level(LogLevel level); 119 | 120 | bool is_logged(LogLevel level); 121 | 122 | 123 | /* 124 | * Non guaranteed logging. Uses a ring buffer to hold log lines. 125 | * When the ring gets full, the previous log line in the slot will be dropped. 126 | * Does not block producer even if the ring buffer is full. 127 | * ring_buffer_size_mb - LogLines are pushed into a mpsc ring buffer whose size 128 | * is determined by this parameter. Since each LogLine is 256 bytes, 129 | * ring_buffer_size = ring_buffer_size_mb * 1024 * 1024 / 256 130 | */ 131 | struct NonGuaranteedLogger 132 | { 133 | NonGuaranteedLogger(uint32_t ring_buffer_size_mb_) : ring_buffer_size_mb(ring_buffer_size_mb_) {} 134 | uint32_t ring_buffer_size_mb; 135 | }; 136 | 137 | /* 138 | * Provides a guarantee log lines will not be dropped. 139 | */ 140 | struct GuaranteedLogger 141 | { 142 | }; 143 | 144 | /* 145 | * Ensure initialize() is called prior to any log statements. 146 | * log_directory - where to create the logs. For example - "/tmp/" 147 | * log_file_name - root of the file name. For example - "nanolog" 148 | * This will create log files of the form - 149 | * /tmp/nanolog.1.txt 150 | * /tmp/nanolog.2.txt 151 | * etc. 152 | * log_file_roll_size_mb - mega bytes after which we roll to next log file. 153 | */ 154 | void initialize(GuaranteedLogger gl, std::string const & log_file_path, uint32_t log_file_roll_size_mb); 155 | void initialize(NonGuaranteedLogger ngl, std::string const & log_file_path, uint32_t log_file_roll_size_mb); 156 | 157 | } // namespace nanolog 158 | 159 | 160 | 161 | #define NANO_LOG(LEVEL) nanolog::NanoLog() == nanolog::NanoLogLine(LEVEL, __FILE__, __func__, __LINE__) 162 | #ifdef QB_LOGGER 163 | #define LOG_DEBUG(X) nanolog::is_logged(nanolog::LogLevel::DEBUG) && NANO_LOG(nanolog::LogLevel::DEBUG) << X 164 | #define LOG_VERB(X) nanolog::is_logged(nanolog::LogLevel::VERBOSE) && NANO_LOG(nanolog::LogLevel::VERBOSE) << X 165 | #define LOG_INFO(X) nanolog::is_logged(nanolog::LogLevel::INFO) && NANO_LOG(nanolog::LogLevel::INFO) << X 166 | #define LOG_WARN(X) nanolog::is_logged(nanolog::LogLevel::WARN) && NANO_LOG(nanolog::LogLevel::WARN) << X 167 | #define LOG_CRIT(X) nanolog::is_logged(nanolog::LogLevel::CRIT) && NANO_LOG(nanolog::LogLevel::CRIT) << X 168 | #else 169 | #define LOG_DEBUG(X) 170 | #define LOG_VERB(X) 171 | #define LOG_INFO(X) 172 | #define LOG_WARN(X) 173 | #define LOG_CRIT(X) 174 | #endif 175 | #endif /* NANO_LOG_HEADER_GUARD */ 176 | 177 | -------------------------------------------------------------------------------- /ressources/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | image/svg+xml -------------------------------------------------------------------------------- /sample/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # 2 | # qb - C++ Actor Framework 3 | # Copyright (C) 2011-2019 isndev (www.qbaf.io). All rights reserved. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | # 17 | 18 | add_subdirectory(starter) 19 | add_subdirectory(pingpong) 20 | add_subdirectory(producer-consumer) -------------------------------------------------------------------------------- /sample/pingpong/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | 2 | project(${QB_PREFIX}-sample-pingpong) 3 | 4 | cxx_executable(${PROJECT_NAME} ${QB_PREFIX}-core main.cpp) -------------------------------------------------------------------------------- /sample/pingpong/MyEvent.h: -------------------------------------------------------------------------------- 1 | /* 2 | * qb - C++ Actor Framework 3 | * Copyright (C) 2011-2019 isndev (www.qbaf.io). All rights reserved. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | // MyEvent.h 19 | #include 20 | #include 21 | #ifndef MYEVENT_H_ 22 | # define MYEVENT_H_ 23 | // Event example 24 | struct MyEvent 25 | : public qb::Event // /!\ should inherit from qb event 26 | { 27 | int data; // trivial data 28 | std::vector container; // dynamic data 29 | // /!\ an event must never store an address of it own data 30 | // /!\ ex : int *ptr = &data; 31 | // /!\ avoid using std::string, instead use : 32 | // /!\ - fixed cstring 33 | // /!\ - pointer of std::string 34 | // /!\ - or compile with old ABI '-D_GLIBCXX_USE_CXX11_ABI=0' 35 | }; 36 | #endif -------------------------------------------------------------------------------- /sample/pingpong/PingActor.h: -------------------------------------------------------------------------------- 1 | /* 2 | * qb - C++ Actor Framework 3 | * Copyright (C) 2011-2019 isndev (www.qbaf.io). All rights reserved. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | // PingActor.h file 19 | #include 20 | #include "MyEvent.h" 21 | #ifndef PINGACTOR_H_ 22 | # define PINGACTOR_H_ 23 | 24 | class PongActor; 25 | class PingActor 26 | : public qb::Actor // /!\ should inherit from qb actor 27 | { 28 | public: 29 | PingActor() = default; // PingActor requires PongActor Actor 30 | 31 | // /!\ the engine will call this function before adding PingPongActor 32 | bool onInit() override final { 33 | registerEvent(*this); // id dependency 34 | require(); // require PongActor id 35 | 36 | return true; // init ok 37 | } 38 | 39 | void on(qb::RequireEvent const &event) { 40 | if (is(event.type)) { 41 | registerEvent(*this); // will listen MyEvent 42 | auto &e = push(event.getSource()); // push MyEvent to PongActor and keep a reference to the event 43 | e.data = 1337; // set trivial data 44 | e.container.push_back(7331); // set dynamic data 45 | // debug print 46 | qb::io::cout() << "PingActor id(" << id() << ") has sent MyEvent" << std::endl; 47 | } 48 | } 49 | 50 | // will call this function when PingActor receives MyEvent 51 | void on(MyEvent &) { 52 | // debug print 53 | qb::io::cout() << "PingActor id(" << id() << ") received MyEvent" << std::endl; 54 | kill(); // then notify engine to kill PingActor 55 | } 56 | }; 57 | 58 | #endif -------------------------------------------------------------------------------- /sample/pingpong/PongActor.h: -------------------------------------------------------------------------------- 1 | /* 2 | * qb - C++ Actor Framework 3 | * Copyright (C) 2011-2019 isndev (www.qbaf.io). All rights reserved. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | // PongActor.h file 19 | #include 20 | #include "MyEvent.h" 21 | #ifndef PONGACTOR_H_ 22 | # define PONGACTOR_H_ 23 | 24 | class PongActor 25 | : public qb::Actor // /!\ should inherit from qb actor 26 | { 27 | public: 28 | // /!\ never call any qb::Actor functions in constructor 29 | // /!\ use onInit function 30 | PongActor() = default; 31 | 32 | // /!\ the engine will call this function before adding PongActor 33 | bool onInit() override final { 34 | registerEvent(*this); // will just listen MyEvent 35 | 36 | return true; // init ok 37 | } 38 | // will call this function when PongActor receives MyEvent 39 | void on(MyEvent &event) { 40 | // debug print 41 | qb::io::cout() << "PongActor id(" << id() << ") received MyEvent" << std::endl; 42 | reply(event); // reply the event to SourceActor 43 | // debug print 44 | qb::io::cout() << "PongActor id(" << id() << ") has replied MyEvent" << std::endl; 45 | kill(); // then notify engine to kill PongActor 46 | } 47 | }; 48 | 49 | #endif -------------------------------------------------------------------------------- /sample/pingpong/main.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * qb - C++ Actor Framework 3 | * Copyright (C) 2011-2019 isndev (www.qbaf.io). All rights reserved. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | // main.cpp file 19 | #include 20 | #include "PingActor.h" 21 | #include "PongActor.h" 22 | 23 | int main (int, char *argv[]) { 24 | // (optional) initialize the qb logger 25 | qb::io::log::init(argv[0]); // filename 26 | 27 | // configure the Engine 28 | // Note : I will use only the core 0 and 1 29 | qb::Main main({0, 1}); 30 | 31 | // Build Pong Actor to core 0 32 | main.addActor(0); // default constructed 33 | // Build Ping Actor to core 1 with Pong ActorId as parameter 34 | main.addActor(1); // constructed with parameters 35 | 36 | main.start(); // start the engine asynchronously 37 | main.join(); // wait for the running engine 38 | // if all my actors had been destroyed then it will release the wait 39 | return 0; 40 | } -------------------------------------------------------------------------------- /sample/producer-consumer/ActorConsumer.h: -------------------------------------------------------------------------------- 1 | /* 2 | * qb - C++ Actor Framework 3 | * Copyright (C) 2011-2019 isndev (www.qbaf.io). All rights reserved. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | #include 19 | #include 20 | #include 21 | #include "MyEvent.h" 22 | 23 | #ifndef ACTORCONSUMER_H_ 24 | # define ACTORCONSUMER_H_ 25 | 26 | class ActorConsumer 27 | : public qb::Actor // /!\ should inherit from qb actor 28 | , public qb::ICallback // (optional) required to register actor callback 29 | { 30 | uint64_t timer; 31 | uint64_t counter; 32 | 33 | void reset_timer() { 34 | timer = qb::Timestamp::nano() + qb::Timestamp::seconds(1).nanoseconds(); 35 | } 36 | 37 | public: 38 | ActorConsumer() = default; // default constructor 39 | ~ActorConsumer() = default; 40 | 41 | // will call this function before adding MyActor 42 | virtual bool onInit() override final { 43 | registerEvent(*this); // will listen MyEvent 44 | registerCallback(*this); // each core loop will call onCallback 45 | reset_timer(); 46 | return true; // init ok, MyActor will be added 47 | } 48 | 49 | // will call this function each core loop 50 | virtual void onCallback() override final { 51 | if (qb::Timestamp::nano() > timer) { 52 | //qb::io::cout() << "Consumer(" << id() << ") received " << counter << "/s" << std::endl; 53 | LOG_INFO("Consumer(" << id() << ") received " << counter << "/s"); 54 | reset_timer(); 55 | counter = 0; 56 | } 57 | } 58 | 59 | // will call this function when MyActor received MyEvent 60 | void on(MyEvent const &) { 61 | ++counter; 62 | } 63 | }; 64 | 65 | #endif -------------------------------------------------------------------------------- /sample/producer-consumer/ActorProducer.h: -------------------------------------------------------------------------------- 1 | /* 2 | * qb - C++ Actor Framework 3 | * Copyright (C) 2011-2019 isndev (www.qbaf.io). All rights reserved. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | #include 19 | #include 20 | #include 21 | #include "MyEvent.h" 22 | 23 | #ifndef ACTORPRODUCER_H_ 24 | # define ACTORPRODUCER_H_ 25 | 26 | class ActorProducer 27 | : public qb::Actor // /!\ should inherit from qb actor 28 | , public qb::ICallback // (optional) required to register actor callback 29 | { 30 | std::vector const &_consumerIds; 31 | std::random_device _rand_dev; 32 | std::mt19937 _generator; 33 | std::uniform_int_distribution _random_number; 34 | public: 35 | ActorProducer() = delete; // delete default constructor 36 | ActorProducer(std::vector const &ids) // constructor with parameters 37 | : _consumerIds(ids) 38 | , _rand_dev() 39 | , _generator(_rand_dev()) 40 | , _random_number(0, static_cast(ids.size() - 1)) 41 | {} 42 | 43 | ~ActorProducer() = default; 44 | 45 | // will call this function before adding Actor 46 | virtual bool onInit() override final { 47 | registerCallback(*this);// each core loop will call onCallback 48 | return true; // init ok, MyActor will be added 49 | } 50 | 51 | // will call this function each core loop 52 | virtual void onCallback() override final { 53 | to(_consumerIds[_random_number(_generator)]).push(); 54 | } 55 | }; 56 | 57 | #endif -------------------------------------------------------------------------------- /sample/producer-consumer/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # 2 | # qb - C++ Actor Framework 3 | # Copyright (C) 2011-2019 isndev (www.qbaf.io). All rights reserved. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | # 17 | 18 | project(${QB_PREFIX}-sample-produceur-consumer) 19 | 20 | cxx_executable(${PROJECT_NAME} ${QB_PREFIX}-core main.cpp) -------------------------------------------------------------------------------- /sample/producer-consumer/MyEvent.h: -------------------------------------------------------------------------------- 1 | /* 2 | * qb - C++ Actor Framework 3 | * Copyright (C) 2011-2019 isndev (www.qbaf.io). All rights reserved. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | #include 19 | 20 | #ifndef CUBE_MYEVENT_H 21 | #define CUBE_MYEVENT_H 22 | 23 | // Event example 24 | struct MyEvent 25 | : public qb::Event // /!\ should inherit from qb event 26 | { 27 | // ... 28 | }; 29 | 30 | #endif //CUBE_MYEVENT_H 31 | -------------------------------------------------------------------------------- /sample/producer-consumer/main.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * qb - C++ Actor Framework 3 | * Copyright (C) 2011-2019 isndev (www.qbaf.io). All rights reserved. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | #include 19 | #include "ActorProducer.h" 20 | #include "ActorConsumer.h" 21 | 22 | int main (int, char *argv[]) { 23 | // (optional) initialize the logger 24 | qb::io::log::init(argv[0]); // filepath 25 | qb::io::log::setLevel(qb::io::log::Level::INFO); 26 | 27 | // configure the Core 28 | // Note : I will use only the core 0 and 1 29 | qb::Main main({0, 1}); 30 | 31 | const auto nb_consumer = 100; 32 | const auto nb_producer = 100; 33 | 34 | auto builder0 = main.core(0); 35 | for (int i = 0; i < nb_consumer; ++i) 36 | builder0.addActor(); 37 | // check if builder has add all consumers 38 | if (builder0) { 39 | auto builder1 = main.core(1); 40 | for (int i = 0; i < nb_producer; ++i) 41 | builder1.addActor(builder0.idList()); 42 | if (!builder1) 43 | return 1; 44 | } else 45 | return 1; 46 | 47 | qb::io::cout() << "Program is running Ctrl-C to stop" << std::endl; 48 | main.start(); // start the engine asynchronously 49 | main.join(); // Wait for the running engine 50 | qb::io::cout() << "Program has stopped" << std::endl; 51 | return 0; 52 | } -------------------------------------------------------------------------------- /sample/starter/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # 2 | # qb - C++ Actor Framework 3 | # Copyright (C) 2011-2019 isndev (www.qbaf.io). All rights reserved. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | # 17 | 18 | project(${QB_PREFIX}-sample-starter) 19 | 20 | cxx_executable(${PROJECT_NAME} ${QB_PREFIX}-core main.cpp) -------------------------------------------------------------------------------- /sample/starter/MyActor.h: -------------------------------------------------------------------------------- 1 | /* 2 | * qb - C++ Actor Framework 3 | * Copyright (C) 2011-2019 isndev (www.qbaf.io). All rights reserved. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | #include 19 | #include 20 | 21 | #ifndef MYACTOR_H_ 22 | # define MYACTOR_H_ 23 | 24 | // Event example 25 | struct MyEvent 26 | : public qb::Event // /!\ should inherit from qb event 27 | { 28 | int data; // trivial data 29 | std::vector container; // dynamic data 30 | // std::string str; /!\ avoid using stl string 31 | // instead use fixed cstring 32 | // or compile with old ABI '-D_GLIBCXX_USE_CXX11_ABI=0' 33 | 34 | MyEvent() = default; 35 | MyEvent(int param) 36 | : data(param) {} 37 | }; 38 | 39 | class MyActor 40 | : public qb::Actor // /!\ should inherit from qb actor 41 | , public qb::ICallback // (optional) required to register actor callback 42 | { 43 | public: 44 | MyActor() = default; // default constructor 45 | MyActor(int, int ) {} // constructor with parameters 46 | 47 | ~MyActor() {} 48 | 49 | // will call this function before adding MyActor 50 | virtual bool onInit() override final { 51 | registerEvent(*this); // will listen MyEvent 52 | registerCallback(*this); // each core loop will call onCallback 53 | 54 | // ex: just send MyEvent to myself ! forever alone ;( 55 | auto &event = push(id()); // and keep a reference to the event 56 | event.data = 1337; // set trivial data 57 | event.container.push_back(7331); // set dynamic data 58 | 59 | // other wait to send chain event setting data using constructors 60 | to(id()) 61 | .push() 62 | .push(7331); 63 | return true; // init ok, MyActor will be added 64 | } 65 | 66 | // will call this function each core loop 67 | virtual void onCallback() override final { 68 | // ... 69 | } 70 | 71 | // will call this function when MyActor received MyEvent 72 | void on(MyEvent const &) { 73 | // I am a dummy actor, notify the engine to remove me ! 74 | qb::io::cout() << "MyActor(" << id() << ") received MyEvent and will Die" << std::endl; 75 | kill(); // /!\ after this line MyActor is not able to receive events 76 | } 77 | }; 78 | 79 | #endif -------------------------------------------------------------------------------- /sample/starter/main.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * qb - C++ Actor Framework 3 | * Copyright (C) 2011-2019 isndev (www.qbaf.io). All rights reserved. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | #include 19 | #include "MyActor.h" 20 | 21 | int main (int, char *argv[]) { 22 | // (optional) initialize the logger 23 | qb::io::log::init(argv[0]); // filepath 24 | qb::io::log::setLevel(qb::io::log::Level::WARN); // log only warning, error an critical 25 | // usage 26 | LOG_INFO("I will not be logged :("); 27 | 28 | // configure the Core 29 | // Note : I will use only the core 0 and 1 30 | qb::Main main({0, 1}); 31 | 32 | // First way to add actors at start 33 | main.addActor(0); // in VirtualCore id=0, default constructed 34 | main.addActor(1, 1337, 7331); // in VirtualCore id=1, constructed with parameters 35 | 36 | // Other way to add actors retrieving core builder 37 | main.core(0) 38 | .addActor() 39 | .addActor(1337, 7331); 40 | 41 | main.start(); // start the engine asynchronously 42 | main.join(); // Wait for the running engine 43 | // if all my actors had been destroyed then it will release the wait ! 44 | return 0; 45 | } -------------------------------------------------------------------------------- /script/qb-new-module.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Exit if name argument is not given 4 | if [ -z "$*" ]; then 5 | echo "A module name argument must be provided." 6 | exit 0 7 | fi 8 | 9 | NAME=$1 10 | 11 | 12 | ################################################################################ 13 | 14 | 15 | # Clone template repository 16 | git clone https://github.com/isndev/qb-sample-module.git 17 | 18 | # Create bare repository 19 | git --bare init ${NAME} 20 | 21 | # Push template master branch to bare repository 22 | cd qb-sample-module 23 | git push ../${NAME} +master:master 24 | 25 | # Convert bare repository into a normal repository 26 | cd ../${NAME} 27 | mkdir .git 28 | mv * .git 29 | git config --local --bool core.bare false 30 | git reset --hard 31 | git submodule update --init --recursive 32 | # Clean Up 33 | rm -rf ../qb-sample-module 34 | -------------------------------------------------------------------------------- /script/qb-new-project.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Exit if name argument is not given 4 | if [ -z "$*" ]; then 5 | echo "A project name argument must be provided." 6 | exit 0 7 | fi 8 | 9 | NAME=$1 10 | 11 | 12 | ################################################################################ 13 | 14 | 15 | # Clone template repository 16 | git clone https://github.com/isndev/qb-sample-project.git 17 | 18 | # Create bare repository 19 | git --bare init ${NAME} 20 | 21 | # Push template master branch to bare repository 22 | cd qb-sample-project 23 | git push ../${NAME} +master:master 24 | 25 | # Convert bare repository into a normal repository 26 | cd ../${NAME} 27 | mkdir .git 28 | mv * .git 29 | git config --local --bool core.bare false 30 | git reset --hard 31 | git submodule update --init --recursive 32 | # Clean Up 33 | rm -rf ../qb-sample-project 34 | -------------------------------------------------------------------------------- /source/core/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # 2 | # qb - C++ Actor Framework 3 | # Copyright (C) 2011-2019 isndev (www.qbaf.io). All rights reserved. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | # 17 | 18 | project(${QB_PREFIX}-core LANGUAGES CXX VERSION ${QB_VERSION} DESCRIPTION "A simple actor library") 19 | 20 | cxx_library(${PROJECT_NAME} ${cxx_default_lib} core.cpp) 21 | set_target_properties(${PROJECT_NAME} PROPERTIES VERSION ${QB_VERSION} SOVERSION ${QB_VERSION_MAJOR}) 22 | target_include_directories(${PROJECT_NAME} INTERFACE 23 | "$" 24 | "$/${CMAKE_INSTALL_INCLUDEDIR}>") 25 | 26 | if (${QB_PREFIX_UPPER}_WITH_LOG) 27 | message(STATUS "INFO: Will build ${QB_PREFIX} libraries with logger") 28 | target_compile_definitions(${QB_PREFIX}-core PUBLIC QB_LOGGER=1) 29 | else() 30 | message(STATUS "INFO: Will build ${QB_PREFIX} libraries without logger") 31 | endif() 32 | 33 | if (${QB_PREFIX_UPPER}_BUILD_TEST) 34 | add_subdirectory(tests) 35 | endif() -------------------------------------------------------------------------------- /source/core/core.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * qb - C++ Actor Framework 3 | * Copyright (C) 2011-2019 isndev (www.qbaf.io). All rights reserved. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | #include "nanolog/nanolog.cpp" 19 | #include "src/ActorId.cpp" 20 | #include "src/VirtualCore.cpp" 21 | #include "src/Actor.cpp" 22 | #include "src/CoreSet.cpp" 23 | #include "src/Main.cpp" 24 | #include "src/io.cpp" -------------------------------------------------------------------------------- /source/core/src/Actor.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * qb - C++ Actor Framework 3 | * Copyright (C) 2011-2019 isndev (www.qbaf.io). All rights reserved. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | namespace qb { 24 | 25 | void Actor::__set_id(ActorId const &id) noexcept { 26 | static_cast(*this) = id; 27 | } 28 | 29 | void Actor::__set_id(ServiceId const sid, CoreId const cid) noexcept { 30 | static_cast(*this) = {sid, cid}; 31 | } 32 | 33 | void Actor::on(PingEvent const &event) noexcept { 34 | if (event.type == id_type) 35 | send(event.source, event.type, ActorStatus::Alive); 36 | } 37 | 38 | void Actor::on(KillEvent const &) noexcept { 39 | kill(); 40 | } 41 | 42 | uint64_t Actor::time() const noexcept { 43 | return VirtualCore::_handler->time(); 44 | } 45 | 46 | bool Actor::isAlive() const noexcept{ 47 | return _alive; 48 | } 49 | 50 | ProxyPipe Actor::getPipe(ActorId const dest) const noexcept { 51 | return VirtualCore::_handler->getProxyPipe(dest, id()); 52 | } 53 | 54 | CoreId Actor::getIndex() const noexcept { 55 | return VirtualCore::_handler->getIndex(); 56 | } 57 | 58 | void Actor::unregisterCallback() const noexcept { 59 | VirtualCore::_handler->unregisterCallback(id()); 60 | } 61 | 62 | void Actor::kill() const noexcept { 63 | _alive = false; 64 | VirtualCore::_handler->killActor(id()); 65 | } 66 | 67 | Actor::EventBuilder::EventBuilder(ProxyPipe const &pipe) noexcept 68 | : dest_pipe(pipe) {} 69 | 70 | Actor::EventBuilder Actor::to(ActorId const dest) const noexcept { 71 | return {getPipe(dest)}; 72 | } 73 | 74 | void Actor::reply(Event &event) const noexcept { 75 | if (unlikely(event.dest.isBroadcast())) { 76 | LOG_WARN("" << *this << " failed to reply broadcast event"); 77 | return; 78 | } 79 | VirtualCore::_handler->reply(event); 80 | } 81 | 82 | void Actor::forward(ActorId const dest, Event &event) const noexcept { 83 | event.source = id(); 84 | if (unlikely(event.dest.isBroadcast())) { 85 | LOG_WARN("" << *this << " failed to forward broadcast event"); 86 | return; 87 | } 88 | VirtualCore::_handler->forward(dest, event); 89 | } 90 | 91 | // OpenApi : internal future use 92 | void Actor::send(Event const &event) const noexcept { 93 | VirtualCore::_handler->send(event); 94 | } 95 | 96 | void Actor::push(Event const &event) const noexcept { 97 | VirtualCore::_handler->push(event); 98 | } 99 | 100 | bool Actor::try_send(Event const &event) const noexcept { 101 | return VirtualCore::_handler->try_send(event); 102 | } 103 | } 104 | 105 | qb::io::stream &operator<<(qb::io::stream &os, qb::Actor const &actor){ 106 | std::stringstream ss; 107 | ss << "Actor(" << actor.id().index() << "." << actor.id().sid() << ")"; 108 | os << ss.str(); 109 | return os; 110 | } -------------------------------------------------------------------------------- /source/core/src/ActorId.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * qb - C++ Actor Framework 3 | * Copyright (C) 2011-2019 isndev (www.qbaf.io). All rights reserved. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | #include 19 | 20 | namespace qb { 21 | ActorId::ActorId() noexcept : _id(0), _index(0) {} 22 | ActorId::ActorId(ServiceId const id, CoreId const index) noexcept 23 | : _id(id), _index(index) {} 24 | 25 | ActorId::ActorId(uint32_t const id) noexcept { 26 | *reinterpret_cast(this) = id; 27 | } 28 | 29 | ActorId::operator const uint32_t &() const noexcept { 30 | return *reinterpret_cast(this); 31 | } 32 | 33 | ServiceId ActorId::sid() const noexcept { 34 | return _id; 35 | } 36 | 37 | CoreId ActorId::index() const noexcept { 38 | return _index; 39 | } 40 | 41 | bool ActorId::isBroadcast() const noexcept { 42 | return _id == BroadcastSid; 43 | } 44 | } 45 | 46 | qb::io::stream &operator<<(qb::io::stream &os, qb::ActorId const &id) { 47 | std::stringstream ss; 48 | ss << id.index() << "." << id.sid(); 49 | os << ss.str(); 50 | return os; 51 | } 52 | -------------------------------------------------------------------------------- /source/core/src/CoreSet.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * qb - C++ Actor Framework 3 | * Copyright (C) 2011-2019 isndev (www.qbaf.io). All rights reserved. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | #include 19 | 20 | namespace qb { 21 | 22 | CoreSet::CoreSet(std::unordered_set const &set) noexcept 23 | : _raw_set(set) 24 | ,_nb_core(set.size()) 25 | , _size(*std::max_element(set.cbegin(), set.cend()) + 1) { 26 | _set.resize(_size); 27 | CoreId idx = 0; 28 | for (auto id : set) 29 | _set[id] = idx++; 30 | } 31 | 32 | CoreId CoreSet::resolve(std::size_t const id) const noexcept { 33 | return _set[id]; 34 | } 35 | 36 | std::size_t CoreSet::getSize() const noexcept { 37 | return _size; 38 | } 39 | 40 | std::size_t CoreSet::getNbCore() const noexcept { 41 | return _nb_core; 42 | } 43 | 44 | const std::unordered_set &CoreSet::raw() const noexcept { 45 | return _raw_set; 46 | } 47 | 48 | CoreSet CoreSet::build(uint32_t const nb_core) noexcept { 49 | std::unordered_set set; 50 | for (CoreId i = 0; i < nb_core; ++i) 51 | set.insert(i); 52 | return CoreSet{std::move(set)}; 53 | } 54 | } -------------------------------------------------------------------------------- /source/core/src/Main.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * qb - C++ Actor Framework 3 | * Copyright (C) 2011-2019 isndev (www.qbaf.io). All rights reserved. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | namespace qb { 24 | 25 | void Main::onSignal(int signal) { 26 | io::cout() << "Received signal(" << signal << ") will stop the engine" << std::endl; 27 | is_running = false; 28 | } 29 | 30 | void Main::__init__() noexcept { 31 | _cores.resize(_core_set.getNbCore()); 32 | for (auto core_id : _core_set._raw_set) { 33 | const auto nb_producers = _core_set.getNbCore(); 34 | _mail_boxes[_core_set.resolve(core_id)] = new MPSCBuffer(nb_producers); 35 | } 36 | sync_start.store(0, std::memory_order_release); 37 | is_running = false; 38 | generated_sid = VirtualCore::_nb_service + 1; 39 | LOG_INFO("[MAIN] Init with " << getNbCore() << " cores"); 40 | } 41 | 42 | Main::Main(CoreSet const &core_set) noexcept 43 | : _core_set (core_set) 44 | , _mail_boxes(_core_set.getSize()) 45 | { 46 | __init__(); 47 | } 48 | 49 | Main::Main(std::unordered_set const &core_set) noexcept 50 | : _core_set (core_set) 51 | , _mail_boxes(_core_set.getSize()) 52 | { 53 | __init__(); 54 | } 55 | 56 | Main::~Main() { 57 | for (auto mailbox : _mail_boxes) { 58 | if (mailbox) 59 | delete mailbox; 60 | } 61 | for (auto &actor_factory : _actor_factories) 62 | for (auto factory : actor_factory.second) 63 | delete factory.second; 64 | } 65 | 66 | bool Main::send(Event const &event) const noexcept { 67 | CoreId source_index = _core_set.resolve(event.source._index); 68 | 69 | return _mail_boxes[_core_set.resolve(event.dest._index)]->enqueue(source_index, 70 | reinterpret_cast(&event), 71 | event.bucket_size); 72 | } 73 | 74 | void Main::start_thread(CoreId coreId, Main &engine) noexcept { 75 | VirtualCore core(coreId, engine); 76 | VirtualCore::_handler = &core; 77 | try { 78 | // Init VirtualCore 79 | auto &core_factory = engine._actor_factories[coreId]; 80 | core.__init__(); 81 | if (!core_factory.size()) { 82 | LOG_CRIT("" << core << " Started with 0 Actor"); 83 | Main::sync_start.store(VirtualCore::Error::NoActor, std::memory_order_release); 84 | return; 85 | } 86 | else if (std::any_of(core_factory.begin(), core_factory.end(), 87 | [&core](auto it) { 88 | return !core.appendActor(*it.second->create(), it.second->isService()); 89 | })) 90 | { 91 | LOG_CRIT("Actor at " << core << " failed to init"); 92 | Main::sync_start.store(VirtualCore::Error::BadActorInit, std::memory_order_release); 93 | } 94 | core.__init__actors__(); 95 | if (!core.__wait__all__cores__ready()) 96 | return; 97 | core.__workflow__(); 98 | } catch (std::exception &e) { 99 | (void)e; 100 | LOG_CRIT("Exception thrown on " << core << " what:" << e.what()); 101 | Main::sync_start.store(VirtualCore::Error::ExceptionThrown, std::memory_order_release); 102 | Main::is_running = false; 103 | } 104 | } 105 | 106 | void Main::start(bool async) { 107 | is_running = true; 108 | auto i = 0u; 109 | for (auto &coreId : _core_set.raw()) { 110 | const auto index = _core_set.resolve(coreId); 111 | if (!async && i == (_core_set.getNbCore() - 1)) 112 | start_thread(coreId, *this); 113 | else 114 | _cores[index] = std::thread(start_thread, coreId, std::ref(*this)); 115 | ++i; 116 | } 117 | 118 | uint64_t ret = 0; 119 | do { 120 | std::this_thread::yield(); 121 | ret = sync_start.load(std::memory_order_acquire); 122 | } 123 | while (ret < _cores.size()); 124 | if (ret < VirtualCore::Error::BadInit) { 125 | LOG_INFO("[Main] Init Success"); 126 | std::signal(SIGINT, &onSignal); 127 | } else { 128 | LOG_CRIT("[Main] Init Failed"); 129 | io::cout() << "CRITICAL: Core Init Failed -> show logs to have more details" << std::endl; 130 | } 131 | } 132 | 133 | bool Main::hasError() noexcept{ 134 | return sync_start.load(std::memory_order_acquire) >= VirtualCore::Error::BadInit; 135 | } 136 | 137 | void Main::stop() noexcept { 138 | if (is_running) 139 | std::raise(SIGINT); 140 | } 141 | 142 | void Main::join() { 143 | for (auto &core : _cores) { 144 | if (core.joinable()) 145 | core.join(); 146 | } 147 | } 148 | 149 | Main::MPSCBuffer &Main::getMailBox(CoreId const id) const noexcept { 150 | return *_mail_boxes[_core_set.resolve(id)]; 151 | } 152 | 153 | CoreId Main::getNbCore() const noexcept { 154 | return static_cast(_core_set.getNbCore()); 155 | } 156 | 157 | std::atomic Main::sync_start(0); 158 | bool Main::is_running(false); 159 | ServiceId Main::generated_sid = 0; 160 | 161 | Main::CoreBuilder::CoreBuilder(CoreBuilder const &rhs) noexcept 162 | : _index(rhs._index) 163 | , _main(rhs._main) 164 | , _ret_ids(std::move(rhs._ret_ids)) 165 | , _valid(rhs._valid) 166 | {} 167 | 168 | bool Main::CoreBuilder::valid() const noexcept { return _valid; } 169 | Main::CoreBuilder::operator bool() const noexcept { return valid(); } 170 | Main::CoreBuilder::ActorIdList const &Main::CoreBuilder::idList() const noexcept { 171 | return _ret_ids; 172 | } 173 | 174 | Main::CoreBuilder Main::core(CoreId const index) noexcept { 175 | return {*this, index}; 176 | } 177 | 178 | } -------------------------------------------------------------------------------- /source/core/src/io.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * qb - C++ Actor Framework 3 | * Copyright (C) 2011-2019 isndev (www.qbaf.io). All rights reserved. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | #include 19 | 20 | void qb::io::log::init(std::string const &file_path, uint32_t const roll_MB) { 21 | nanolog::initialize(nanolog::GuaranteedLogger(), file_path, roll_MB); 22 | } 23 | 24 | void qb::io::log::setLevel(io::log::Level lvl) { 25 | nanolog::set_log_level(lvl); 26 | } 27 | 28 | std::mutex qb::io::cout::io_lock; 29 | 30 | qb::io::cout::~cout() { 31 | std::lock_guard lock(io_lock); 32 | std::cout << ss.str() << std::flush; 33 | } 34 | 35 | #ifdef QB_LOGGER 36 | struct LogInitializer { 37 | static LogInitializer initializer; 38 | LogInitializer() { 39 | qb::io::log::init("./qb", 512); 40 | #ifdef NDEBUG 41 | qb::io::log::setLevel(qb::io::log::Level::INFO); 42 | #else 43 | qb::io::log::setLevel(qb::io::log::Level::DEBUG); 44 | #endif 45 | } 46 | }; 47 | 48 | LogInitializer LogInitializer::initializer = {}; 49 | #endif -------------------------------------------------------------------------------- /source/core/tests/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # 2 | # qb - C++ Actor Framework 3 | # Copyright (C) 2011-2019 isndev (www.qbaf.io). All rights reserved. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | # 17 | 18 | add_subdirectory(system) 19 | if (${QB_PREFIX_UPPER}_BUILD_BENCHMARK) 20 | add_subdirectory(benchmark) 21 | endif() -------------------------------------------------------------------------------- /source/core/tests/benchmark/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # 2 | # qb - C++ Actor Framework 3 | # Copyright (C) 2011-2019 isndev (www.qbaf.io). All rights reserved. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | # 17 | 18 | #cxx_benchmark(${PROJECT_NAME}-benchmark-example "${PROJECT_NAME}" benchmark_example.cpp) 19 | cxx_benchmark(${PROJECT_NAME}-benchmark-ping-pong "${PROJECT_NAME}" bm-ping-pong.cpp) 20 | cxx_benchmark(${PROJECT_NAME}-benchmark-disruptor-latency "${PROJECT_NAME}" bm-disruptor-latency.cpp) 21 | cxx_benchmark(${PROJECT_NAME}-benchmark-pipeline-latency "${PROJECT_NAME}" bm-pipeline-latency.cpp) 22 | cxx_benchmark(${PROJECT_NAME}-benchmark-multicast-latency "${PROJECT_NAME}" bm-multicast-latency.cpp) 23 | cxx_benchmark(${PROJECT_NAME}-benchmark-ping-pong-latency "${PROJECT_NAME}" bm-ping-pong-latency.cpp) -------------------------------------------------------------------------------- /source/core/tests/benchmark/benchmark_example.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * qb - C++ Actor Framework 3 | * Copyright (C) 2011-2019 isndev (www.qbaf.io). All rights reserved. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | #include 19 | #include 20 | #include 21 | 22 | static void BM_Main_Example(benchmark::State& state) { 23 | for (auto _ : state) { 24 | qb::Main main{0}; 25 | 26 | main.start(); 27 | main.join(); 28 | } 29 | } 30 | // Register the function as a benchmark 31 | BENCHMARK(BM_Main_Example); 32 | 33 | BENCHMARK_MAIN(); -------------------------------------------------------------------------------- /source/core/tests/benchmark/bm-multicast-latency.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * qb - C++ Actor Framework 3 | * Copyright (C) 2011-2019 isndev (www.qbaf.io). All rights reserved. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | #include 19 | #include 20 | #include "../shared/TestProducer.h" 21 | #include "../shared/TestConsumer.h" 22 | #include "../shared/TestEvent.h" 23 | #include "../shared/TestLatency.h" 24 | 25 | template 26 | static void BM_Multicast_Latency(benchmark::State& state) { 27 | for (auto _ : state) { 28 | const auto nb_events = state.range(0); 29 | const auto nb_actor = state.range(1); 30 | const auto nb_core = static_cast(state.range(2)); 31 | qb::Main main(qb::CoreSet::build(nb_core)); 32 | 33 | qb::ActorIds ids = {}; 34 | for (auto i = 0; i < nb_actor; ++i) { 35 | const auto coreid = (i % (nb_core - (nb_core > 1))) + (nb_core > 1); 36 | ids.insert(main.addActor>(coreid)); 37 | } 38 | main.addActor>(0, ids, nb_events); 39 | 40 | main.start(false); 41 | main.join(); 42 | } 43 | } 44 | 45 | static void CustomArguments(benchmark::internal::Benchmark* b) { 46 | auto nb_core = std::thread::hardware_concurrency(); 47 | for (auto i = 1u; i <= nb_core; i *= 2) { 48 | for (int j = i - 1; j <= static_cast(nb_core * 10); j *= 10) { 49 | if (!j) 50 | j = 1; 51 | b->Args({1000000, j, i}); 52 | } 53 | } 54 | } 55 | 56 | // Register the function as a benchmark 57 | BENCHMARK_TEMPLATE(BM_Multicast_Latency, LightEvent) 58 | ->Apply(CustomArguments) 59 | ->ArgNames({"NB_EVENTS", "NB_ACTORS", "NB_CORE"}) 60 | ->Unit(benchmark::kMillisecond);; 61 | 62 | BENCHMARK_MAIN(); -------------------------------------------------------------------------------- /source/core/tests/benchmark/bm-ping-pong-latency.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * qb - C++ Actor Framework 3 | * Copyright (C) 2011-2019 isndev (www.qbaf.io). All rights reserved. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | #include 19 | #include 20 | #include 21 | #include "../shared/TestEvent.h" 22 | #include "../shared/TestLatency.h" 23 | 24 | class PongActor : public qb::Actor { 25 | public: 26 | virtual bool onInit() override final { 27 | registerEvent(*this); 28 | return true; 29 | } 30 | 31 | void on(LightEvent &event) { 32 | --event._ttl; 33 | reply(event); 34 | } 35 | 36 | }; 37 | 38 | class PingActor : public qb::Actor { 39 | pg::latency<1000 * 1000, 900000> _latency; 40 | public: 41 | ~PingActor() { 42 | _latency.generate(std::cout, "ns"); 43 | } 44 | 45 | virtual bool onInit() override final { 46 | registerEvent(*this); 47 | registerEvent(*this); 48 | require(); 49 | return true; 50 | } 51 | 52 | void on(qb::RequireEvent const &event) { 53 | send(event.getSource(), 1000000); 54 | } 55 | 56 | void on(LightEvent const &event) { 57 | _latency.add(std::chrono::high_resolution_clock::now() - event._timepoint); 58 | if (event._ttl) 59 | send(event.getSource(), event._ttl); 60 | else { 61 | kill(); 62 | send(event.getSource()); 63 | } 64 | } 65 | }; 66 | 67 | bool run = true; 68 | void thread_ping(qb::lockfree::spsc::ringbuffer *spsc) { 69 | auto &latency = *new pg::latency<1000 * 1000, 900000>{}; 70 | LightEvent events[4096]; 71 | 72 | spsc[1].enqueue(LightEvent(1000000)); 73 | while (qb::likely(run)) { 74 | // received 75 | spsc[0].dequeue([&] (auto event, auto nb_events) { 76 | for (auto i = 0u; i < nb_events; ++i) { 77 | latency.add(std::chrono::high_resolution_clock::now() - event[i]._timepoint); 78 | if (event[i]._ttl) 79 | spsc[1].enqueue(LightEvent(event[i]._ttl)); 80 | else { 81 | run = false; 82 | } 83 | } 84 | }, events, 4096u); 85 | } 86 | latency.generate(std::cout, "ns"); 87 | delete &latency; 88 | } 89 | 90 | void thread_pong(qb::lockfree::spsc::ringbuffer *spsc) { 91 | LightEvent events[4096]; 92 | 93 | while (qb::likely(run)) { 94 | // received 95 | spsc[1].dequeue([&] (auto event, auto nb_events) { 96 | for (auto i = 0u; i < nb_events; ++i) { 97 | --event[i]._ttl; 98 | spsc[0].enqueue(LightEvent(event[i]._ttl)); 99 | } 100 | }, events, 4096u); 101 | } 102 | } 103 | 104 | static void BM_Reference_Multi_PingPong_Latency(benchmark::State& state) { 105 | for (auto _ : state) { 106 | auto spsc = new qb::lockfree::spsc::ringbuffer[2]; 107 | std::thread threads[2]; 108 | 109 | threads[0] = std::thread(thread_ping, spsc); 110 | threads[1] = std::thread(thread_pong, spsc); 111 | 112 | for (auto &thread : threads) { 113 | if (thread.joinable()) 114 | thread.join(); 115 | } 116 | delete[] spsc; 117 | } 118 | } 119 | 120 | static void BM_Mono_PingPong_Latency(benchmark::State& state) { 121 | for (auto _ : state) { 122 | qb::Main main({0}); 123 | 124 | main.addActor(0); 125 | main.addActor(0); 126 | 127 | main.start(true); 128 | main.join(); 129 | } 130 | } 131 | 132 | static void BM_Multi_PingPong_Latency(benchmark::State& state) { 133 | for (auto _ : state) { 134 | qb::Main main({0, 1}); 135 | 136 | main.addActor(0); 137 | main.addActor(1); 138 | 139 | main.start(true); 140 | main.join(); 141 | } 142 | } 143 | // Register the function as a benchmark 144 | BENCHMARK(BM_Reference_Multi_PingPong_Latency); 145 | BENCHMARK(BM_Mono_PingPong_Latency); 146 | BENCHMARK(BM_Multi_PingPong_Latency); 147 | 148 | BENCHMARK_MAIN(); -------------------------------------------------------------------------------- /source/core/tests/benchmark/bm-ping-pong.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * qb - C++ Actor Framework 3 | * Copyright (C) 2011-2019 isndev (www.qbaf.io). All rights reserved. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | #include 19 | #include 20 | #include 21 | 22 | struct TinyEvent : qb::Event { 23 | uint64_t _ttl; 24 | explicit TinyEvent(uint64_t y) : _ttl(y) {} 25 | }; 26 | 27 | struct BigEvent : qb::Event { 28 | uint64_t _ttl; 29 | uint64_t padding[127]; 30 | explicit BigEvent(uint64_t y) : _ttl(y), padding() {} 31 | }; 32 | 33 | struct DynamicEvent : qb::Event { 34 | uint64_t _ttl; 35 | std::vector vec; 36 | explicit DynamicEvent(uint64_t y) : _ttl(y), vec(512, 8) {} 37 | }; 38 | 39 | template 40 | class ActorPong : public qb::Actor { 41 | const uint64_t max_sends; 42 | const qb::ActorId actor_to_send; 43 | 44 | public: 45 | ActorPong(uint64_t const max, qb::ActorId const id = qb::ActorId()) 46 | : max_sends(max) 47 | , actor_to_send(id) {} 48 | 49 | bool onInit() override final { 50 | registerEvent(*this); 51 | if (actor_to_send) 52 | push(actor_to_send, 0u); 53 | return true; 54 | } 55 | 56 | void on(EventTrait &event) const { 57 | if (event.x >= max_sends) 58 | kill(); 59 | if (event.x <= max_sends) { 60 | ++event.x; 61 | reply(event); 62 | } 63 | } 64 | }; 65 | 66 | template 67 | class PongActor : public qb::Actor { 68 | public: 69 | virtual bool onInit() override final { 70 | registerEvent(*this); 71 | return true; 72 | } 73 | 74 | void on(TestEvent &event) { 75 | --event._ttl; 76 | reply(event); 77 | } 78 | 79 | }; 80 | 81 | template 82 | class PingActor : public qb::Actor { 83 | const uint64_t max_sends; 84 | const qb::ActorId actor_to_send; 85 | public: 86 | PingActor(uint64_t const max, qb::ActorId const id) 87 | : max_sends(max), actor_to_send(id) {} 88 | ~PingActor() = default; 89 | 90 | virtual bool onInit() override final { 91 | registerEvent(*this); 92 | send(actor_to_send, max_sends); 93 | return true; 94 | } 95 | 96 | void on(TestEvent &event) { 97 | if (event._ttl) 98 | reply(event); 99 | else { 100 | kill(); 101 | send(event.getSource()); 102 | } 103 | } 104 | }; 105 | 106 | template 107 | static void BM_PINGPONG(benchmark::State& state) { 108 | for (auto _ : state) { 109 | state.PauseTiming(); 110 | const auto nb_core = static_cast(state.range(0)); 111 | qb::Main main(qb::CoreSet::build(nb_core)); 112 | const auto max_events = state.range(1); 113 | const auto nb_actor = state.range(2) / nb_core; 114 | for (int i = 0; i < nb_actor; ++i) { 115 | for (auto j = 0u; j < nb_core; ++j) { 116 | main.addActor>(j, max_events, 117 | main.addActor>(((j + 1) % nb_core))); 118 | } 119 | } 120 | 121 | main.start(); 122 | state.ResumeTiming(); 123 | main.join(); 124 | } 125 | } 126 | 127 | BENCHMARK_TEMPLATE(BM_PINGPONG, TinyEvent) 128 | ->RangeMultiplier(2) 129 | ->Ranges({{1, std::thread::hardware_concurrency()}, {4096, 8<<10}, {512, 1024}}) 130 | ->ArgNames({"NB_CORE", "NB_PING_PER_ACTOR", "NB_ACTOR"}) 131 | ->Unit(benchmark::kMillisecond); 132 | BENCHMARK_TEMPLATE(BM_PINGPONG, BigEvent) 133 | ->RangeMultiplier(2) 134 | ->Ranges({{1, std::thread::hardware_concurrency()}, {4096, 8<<10}, {512, 1024}}) 135 | ->ArgNames({"NB_CORE", "NB_PING_PER_ACTOR", "NB_ACTOR"}) 136 | ->Unit(benchmark::kMillisecond); 137 | BENCHMARK_TEMPLATE(BM_PINGPONG, DynamicEvent) 138 | ->RangeMultiplier(2) 139 | ->Ranges({{1, std::thread::hardware_concurrency()}, {4096, 8<<10}, {512, 1024}}) 140 | ->ArgNames({"NB_CORE", "NB_PING_PER_ACTOR", "NB_ACTOR"}) 141 | ->Unit(benchmark::kMillisecond); 142 | 143 | BENCHMARK_MAIN(); -------------------------------------------------------------------------------- /source/core/tests/benchmark/bm-pipeline-latency.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * qb - C++ Actor Framework 3 | * Copyright (C) 2011-2019 isndev (www.qbaf.io). All rights reserved. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | #include 19 | #include 20 | #include "../shared/TestProducer.h" 21 | #include "../shared/TestConsumer.h" 22 | #include "../shared/TestEvent.h" 23 | #include "../shared/TestLatency.h" 24 | 25 | template 26 | static void BM_Unicast_Latency(benchmark::State& state) { 27 | for (auto _ : state) { 28 | const auto nb_events = state.range(0); 29 | const auto nb_actor = state.range(1); 30 | const auto nb_core = static_cast(state.range(2)); 31 | qb::Main main(qb::CoreSet::build(nb_core)); 32 | 33 | qb::ActorIds ids = {}; 34 | for (auto i = 0; i < nb_actor; ++i) { 35 | const auto coreid = (i % (nb_core - (nb_core > 1))) + (nb_core > 1); 36 | ids = {main.addActor>(coreid, qb::ActorIds(ids))}; 37 | } 38 | main.addActor>(0, qb::ActorIds(ids), nb_events); 39 | 40 | main.start(false); 41 | main.join(); 42 | } 43 | } 44 | 45 | static void CustomArguments(benchmark::internal::Benchmark* b) { 46 | auto nb_core = std::thread::hardware_concurrency(); 47 | for (auto i = 1u; i <= nb_core; i *= 2) { 48 | for (int j = i - 1; j <= static_cast(nb_core * 10); j *= 10) { 49 | if (!j) 50 | j = 1; 51 | b->Args({1000000, j, i}); 52 | } 53 | } 54 | } 55 | 56 | // Register the function as a benchmark 57 | BENCHMARK_TEMPLATE(BM_Unicast_Latency, LightEvent) 58 | ->Apply(CustomArguments) 59 | ->ArgNames({"NB_EVENTS", "NB_ACTORS", "NB_CORE"}) 60 | ->Unit(benchmark::kMillisecond);; 61 | 62 | BENCHMARK_MAIN(); -------------------------------------------------------------------------------- /source/core/tests/shared/TestConsumer.h: -------------------------------------------------------------------------------- 1 | /* 2 | * qb - C++ Actor Framework 3 | * Copyright (C) 2011-2019 isndev (www.qbaf.io). All rights reserved. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | #ifndef QB_TESTCONSUMER_H 19 | #define QB_TESTCONSUMER_H 20 | 21 | #include 22 | 23 | template 24 | class ConsumerActor 25 | : public qb::Actor { 26 | const qb::ActorIds _idList; 27 | public: 28 | 29 | explicit ConsumerActor(qb::ActorIds const ids = {}) 30 | : _idList(ids) 31 | { 32 | } 33 | 34 | virtual bool onInit() override final { 35 | registerEvent(*this); 36 | return true; 37 | } 38 | 39 | void on(Event &event) { 40 | if (_idList.size()) { 41 | for (auto to : _idList) 42 | send(to, event); 43 | } else 44 | send(event._ttl, event); 45 | } 46 | }; 47 | 48 | #endif //QB_TESTCONSUMER_H 49 | -------------------------------------------------------------------------------- /source/core/tests/shared/TestEvent.h: -------------------------------------------------------------------------------- 1 | /* 2 | * qb - C++ Actor Framework 3 | * Copyright (C) 2011-2019 isndev (www.qbaf.io). All rights reserved. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | #ifndef QB_TESTEVENT_H 25 | #define QB_TESTEVENT_H 26 | 27 | struct LightEvent : public qb::Event { 28 | std::chrono::high_resolution_clock::time_point _timepoint; 29 | uint32_t _ttl; 30 | 31 | LightEvent() 32 | : _timepoint(std::chrono::high_resolution_clock::now()) 33 | {} 34 | 35 | LightEvent(uint32_t const ttl) 36 | : _timepoint(std::chrono::high_resolution_clock::now()) 37 | , _ttl(ttl) 38 | {} 39 | }; 40 | 41 | struct TestEvent : public qb::Event 42 | { 43 | uint8_t _data[32]; 44 | uint32_t _sum; 45 | std::chrono::high_resolution_clock::time_point _timepoint; 46 | uint32_t _ttl; 47 | bool has_extra_data = false; 48 | 49 | TestEvent() { 50 | __init__(); 51 | } 52 | 53 | TestEvent(uint32_t const ttl) { 54 | __init__(); 55 | _ttl = ttl; 56 | } 57 | 58 | 59 | bool checkSum() const { 60 | auto ret = true; 61 | if (has_extra_data) { 62 | ret = !memcmp(_data, reinterpret_cast(this) + sizeof(TestEvent), sizeof(_data)); 63 | } 64 | 65 | return std::accumulate(std::begin(_data), std::end(_data), 0u) == _sum && ret; 66 | } 67 | 68 | private: 69 | void __init__() { 70 | std::random_device rand_dev; 71 | std::mt19937 generator(rand_dev()); 72 | 73 | std::uniform_int_distribution random_number(0, 255); 74 | std::generate(std::begin(_data), std::end(_data), [&](){ 75 | auto number = static_cast(random_number(generator)); 76 | _sum += number; 77 | return number; 78 | }); 79 | _timepoint = std::chrono::high_resolution_clock::now(); 80 | } 81 | }; 82 | 83 | #endif //QB_TESTEVENT_H 84 | -------------------------------------------------------------------------------- /source/core/tests/shared/TestLatency.h: -------------------------------------------------------------------------------- 1 | // 2 | // created by @sfarny 3 | // 4 | 5 | #ifndef QB_TESTLATENCY_H 6 | #define QB_TESTLATENCY_H 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | namespace pg 14 | { 15 | template 16 | class latency 17 | { 18 | private: 19 | size_t count { 0 }; 20 | std::chrono::nanoseconds bucketDuration{TMaxDurationNs / TBucketCount}; 21 | std::array buckets{0}; 22 | size_t outOufBoundCount { 0 }; 23 | std::chrono::nanoseconds maxDuration; 24 | 25 | public: 26 | template 27 | void add(T duration) 28 | { 29 | count++; 30 | 31 | auto bucketIndex = (std::uint64_t)(duration / bucketDuration); 32 | if (bucketIndex <= TBucketCount) 33 | { 34 | buckets[bucketIndex]++; 35 | return; 36 | } 37 | 38 | outOufBoundCount++; 39 | if (duration > maxDuration) 40 | maxDuration = duration; 41 | } 42 | 43 | template 44 | void generate(O& output, const char* unit) 45 | { 46 | // output << std::setw(20) << "duration" 47 | // << std::setw(21) << "percentile" 48 | // << std::setw(20) << "count" 49 | // << std::endl; 50 | 51 | size_t cum = 0; 52 | size_t q50 = 0; 53 | size_t q99 = 0; 54 | size_t q999 = 0; 55 | double mean = 0; 56 | 57 | for(size_t i = 0; i < TBucketCount; i++) 58 | { 59 | auto current = buckets[i]; 60 | accumulate_and_print(output, unit, cum, mean, q50, q99, q999, current, std::chrono::duration_cast((i+1) * bucketDuration)); 61 | } 62 | 63 | accumulate_and_print(output, unit, cum, mean, q50, q99, q999, outOufBoundCount, std::chrono::duration_cast(maxDuration)); 64 | 65 | output << "# Mean " << std::setw(10) << std::chrono::duration_cast(mean * bucketDuration).count() << unit << std::setw(10) 66 | << "# Q50 " << std::setw(10) << std::chrono::duration_cast(q50 * bucketDuration).count() << unit << std::setw(10) 67 | << "# Q99 " << std::setw(10) << std::chrono::duration_cast(q99 * bucketDuration).count() << unit << std::setw(10) 68 | << "# Q99.9 " << std::setw(10) << std::chrono::duration_cast(q999 * bucketDuration).count() << unit << std::endl; 69 | } 70 | 71 | template 72 | void accumulate_and_print(O&, const char*, size_t& cum, double& mean, size_t& q50, size_t& q99, size_t& q999, size_t current, T duration) 73 | { 74 | if (current == 0) 75 | return; 76 | 77 | cum += current; 78 | 79 | auto percentile = (double)cum / count * 100.0; 80 | // output << std::setw(20) << duration.count() << unit 81 | // << std::setw(20) << percentile << "%" 82 | // << std::setw(20) << current 83 | // << std::endl; 84 | 85 | mean = (mean * (cum-current) + current * (duration / bucketDuration)) / cum; 86 | 87 | if (q50 == 0 && percentile > 50.0) 88 | q50 = duration / bucketDuration; 89 | if (q99 == 0 && percentile > 99.0) 90 | q99 = duration / bucketDuration; 91 | if (q999 == 0 && percentile > 99.9) 92 | q999 = duration / bucketDuration; 93 | } 94 | }; 95 | } 96 | 97 | #endif //QB_TESTLATENCY_H 98 | -------------------------------------------------------------------------------- /source/core/tests/shared/TestProducer.h: -------------------------------------------------------------------------------- 1 | /* 2 | * qb - C++ Actor Framework 3 | * Copyright (C) 2011-2019 isndev (www.qbaf.io). All rights reserved. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | #ifndef QB_TESTPRODUCER_H 19 | #define QB_TESTPRODUCER_H 20 | 21 | #include 22 | #include "TestLatency.h" 23 | 24 | template 25 | class ProducerActor 26 | : public qb::Actor 27 | { 28 | const qb::ActorIds _idList; 29 | uint64_t _max_events; 30 | pg::latency<1000 * 1000, 900000> _latency; 31 | 32 | public: 33 | 34 | ~ProducerActor() { 35 | _latency.generate(std::cout, "ns"); 36 | } 37 | 38 | ProducerActor(qb::ActorIds const ids, uint64_t const max) 39 | : _idList(ids) 40 | , _max_events(max) 41 | { 42 | } 43 | 44 | virtual bool onInit() override final { 45 | registerEvent(*this); 46 | for (auto to : _idList) 47 | send(to, id()); 48 | return true; 49 | } 50 | 51 | void on(Event &event) { 52 | _latency.add(std::chrono::high_resolution_clock::now() - event._timepoint); 53 | --_max_events; 54 | if (!_max_events) { 55 | kill(); 56 | broadcast(); 57 | } else if (!(_max_events % _idList.size())){ 58 | for (auto to : _idList) 59 | send(to, id()); 60 | } 61 | } 62 | }; 63 | 64 | #endif //QB_TESTPRODUCER_H 65 | -------------------------------------------------------------------------------- /source/core/tests/system/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # 2 | # qb - C++ Actor Framework 3 | # Copyright (C) 2011-2019 isndev (www.qbaf.io). All rights reserved. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | # 17 | 18 | cxx_gtest(${PROJECT_NAME}-gtest-system-main "${PROJECT_NAME}" test-main.cpp) 19 | cxx_gtest(${PROJECT_NAME}-gtest-system-io "${PROJECT_NAME}" test-io.cpp) 20 | cxx_gtest(${PROJECT_NAME}-gtest-system-actor-add "${PROJECT_NAME}" test-actor-add.cpp) 21 | cxx_gtest(${PROJECT_NAME}-gtest-system-actor-callback "${PROJECT_NAME}" test-actor-callback.cpp) 22 | cxx_gtest(${PROJECT_NAME}-gtest-system-actor-dependency "${PROJECT_NAME}" test-actor-dependency.cpp) 23 | cxx_gtest(${PROJECT_NAME}-gtest-system-actor-event "${PROJECT_NAME}" test-actor-event.cpp) 24 | cxx_gtest(${PROJECT_NAME}-gtest-system-actor-service-event "${PROJECT_NAME}" test-actor-service-event.cpp) -------------------------------------------------------------------------------- /source/core/tests/system/test-actor-add.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * qb - C++ Actor Framework 3 | * Copyright (C) 2011-2019 isndev (www.qbaf.io). All rights reserved. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | #include 19 | #include 20 | #include 21 | 22 | struct Tag {}; 23 | 24 | class TestServiceActor : public qb::ServiceActor 25 | { 26 | bool _ret_init; 27 | public: 28 | TestServiceActor() = delete; 29 | explicit TestServiceActor(bool init) 30 | : _ret_init(init) {} 31 | 32 | virtual bool onInit() override final { 33 | EXPECT_NE(static_cast(id()), 0u); 34 | kill(); 35 | return _ret_init; 36 | } 37 | }; 38 | 39 | class TestActor : public qb::Actor 40 | { 41 | bool _ret_init; 42 | public: 43 | TestActor() = delete; 44 | explicit TestActor(bool init) 45 | : _ret_init(init) {} 46 | 47 | virtual bool onInit() override final { 48 | EXPECT_NE(static_cast(id()), 0u); 49 | kill(); 50 | return _ret_init; 51 | } 52 | }; 53 | 54 | class TestRefActor : public qb::Actor 55 | { 56 | bool _ret_init; 57 | public: 58 | TestRefActor() = delete; 59 | explicit TestRefActor(bool init) 60 | : _ret_init(init) {} 61 | 62 | virtual bool onInit() override final { 63 | EXPECT_NE(static_cast(id()), 0u); 64 | auto actor = addRefActor(_ret_init); 65 | 66 | kill(); 67 | return actor != nullptr; 68 | } 69 | }; 70 | 71 | TEST(AddActor, EngineShouldAbortIfActorFailedToInitAtStart) { 72 | qb::Main main({0}); 73 | 74 | main.addActor(0, false); 75 | 76 | main.start(false); 77 | EXPECT_TRUE(main.hasError()); 78 | } 79 | 80 | TEST(AddActor, ShouldReturnValidActorIdAtStart) { 81 | qb::Main main({0}); 82 | 83 | auto id = main.addActor(0, true); 84 | EXPECT_NE(static_cast(id), 0u); 85 | 86 | main.start(false); 87 | EXPECT_FALSE(main.hasError()); 88 | } 89 | 90 | TEST(AddActor, ShouldReturnValidServiceActorIdAtStart) { 91 | qb::Main main({0}); 92 | 93 | auto id = main.addActor(0, true); 94 | EXPECT_EQ(static_cast(id), 1u); 95 | 96 | main.start(false); 97 | EXPECT_FALSE(main.hasError()); 98 | } 99 | 100 | TEST(AddActorUsingCoreBuilder, ShouldNotAddActorOnBadCoreIndex) { 101 | qb::Main main({0}); 102 | 103 | auto builder = main.core(1) 104 | .addActor(true); 105 | EXPECT_FALSE(static_cast(builder)); 106 | main.start(false); 107 | EXPECT_TRUE(main.hasError()); 108 | } 109 | 110 | TEST(AddActorUsingCoreBuilder, ShouldRetrieveValidOrderedActorIdList) { 111 | qb::Main main({0}); 112 | 113 | auto builder = main.core(0) 114 | .addActor(true) 115 | .addActor(true); 116 | EXPECT_TRUE(static_cast(builder)); 117 | EXPECT_EQ(builder.idList().size(), 2u); 118 | EXPECT_EQ(static_cast(builder.idList()[0]), 1u); 119 | EXPECT_NE(static_cast(builder.idList()[1]), 0u); 120 | builder.addActor(true); 121 | EXPECT_FALSE(static_cast(builder)); 122 | EXPECT_EQ(builder.idList().size(), 3u); 123 | EXPECT_EQ(static_cast(builder.idList()[2]), 0u); 124 | 125 | main.start(false); 126 | EXPECT_FALSE(main.hasError()); 127 | } 128 | 129 | TEST(AddReferencedActor, ShouldReturnNullptrIfActorFailedToInit) { 130 | qb::Main main({0}); 131 | 132 | main.addActor(0, false); 133 | main.start(false); 134 | EXPECT_TRUE(main.hasError()); 135 | } 136 | 137 | TEST(AddReferencedActor, ShouldReturnActorPtrOnSucess) { 138 | qb::Main main({0}); 139 | 140 | main.addActor(0, true); 141 | main.start(false); 142 | EXPECT_FALSE(main.hasError()); 143 | } 144 | 145 | class TestKillSenderActor : public qb::Actor 146 | { 147 | public: 148 | TestKillSenderActor() = default; 149 | 150 | virtual bool onInit() override final { 151 | EXPECT_NE(static_cast(id()), 0u); 152 | push(id()); 153 | push(qb::BroadcastId(1)); 154 | return true; 155 | } 156 | }; 157 | 158 | class TestKillActor : public qb::Actor 159 | { 160 | public: 161 | TestKillActor() = default; 162 | 163 | virtual bool onInit() override final { 164 | EXPECT_NE(static_cast(id()), 0u); 165 | return true; 166 | } 167 | }; 168 | 169 | TEST(KillActor, UsingEvent) { 170 | qb::Main main({0, 1}); 171 | 172 | main.addActor(0); 173 | auto builder = main.core(1); 174 | for (auto i = 0u; i < 1024; ++i) 175 | builder.addActor(); 176 | main.start(false); 177 | main.join(); 178 | EXPECT_FALSE(main.hasError()); 179 | } -------------------------------------------------------------------------------- /source/core/tests/system/test-actor-callback.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * qb - C++ Actor Framework 3 | * Copyright (C) 2011-2019 isndev (www.qbaf.io). All rights reserved. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | #include 19 | #include 20 | #include 21 | 22 | struct UnregisterCallbackEvent : public qb::Event {}; 23 | 24 | class TestActor 25 | : public qb::Actor 26 | , public qb::ICallback 27 | { 28 | const uint64_t _max_loop; 29 | uint64_t _count_loop; 30 | public: 31 | TestActor() = delete; 32 | explicit TestActor(uint64_t const max_loop) 33 | : _max_loop(max_loop), _count_loop(0) {} 34 | 35 | ~TestActor() { 36 | if (_max_loop == 1000) { 37 | EXPECT_EQ(_count_loop, _max_loop); 38 | } 39 | } 40 | 41 | virtual bool onInit() override final { 42 | registerEvent(*this); 43 | if (_max_loop) 44 | registerCallback(*this); 45 | else 46 | kill(); 47 | return true; 48 | } 49 | 50 | virtual void onCallback() override final { 51 | if (_max_loop == 10000) 52 | push(id()); 53 | if (++_count_loop >= _max_loop) 54 | kill(); 55 | } 56 | 57 | void on(UnregisterCallbackEvent &) { 58 | unregisterCallback(*this); 59 | push(id()); 60 | } 61 | }; 62 | 63 | TEST(CallbackActor, ShouldNotCallOnCallbackIfNotRegistred) { 64 | qb::Main main({0}); 65 | 66 | main.addActor(0, 0); 67 | 68 | main.start(false); 69 | EXPECT_FALSE(main.hasError()); 70 | } 71 | 72 | TEST(CallbackActor, ShouldCallOnCallbackIfRegistred) { 73 | qb::Main main({0}); 74 | 75 | main.addActor(0, 1000); 76 | 77 | main.start(false); 78 | EXPECT_FALSE(main.hasError()); 79 | } 80 | 81 | TEST(CallbackActor, ShouldNotCallOnCallbackAnymoreIfUnregistred) { 82 | qb::Main main({0}); 83 | 84 | main.addActor(0, 1000); 85 | 86 | main.start(false); 87 | EXPECT_FALSE(main.hasError()); 88 | } -------------------------------------------------------------------------------- /source/core/tests/system/test-actor-dependency.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * qb - C++ Actor Framework 3 | * Copyright (C) 2011-2019 isndev (www.qbaf.io). All rights reserved. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | #include 19 | #include 20 | #include 21 | 22 | constexpr uint32_t MAX_ACTOR = 2048; 23 | 24 | class TestActor : public qb::Actor 25 | { 26 | public: 27 | TestActor() = default; 28 | virtual bool onInit() override final { 29 | return true; 30 | } 31 | }; 32 | 33 | class TestActorDependency 34 | : public qb::Actor 35 | { 36 | qb::Main::CoreBuilder::ActorIdList const _ids; 37 | public: 38 | explicit TestActorDependency(qb::Main::CoreBuilder::ActorIdList const &ids = {}) 39 | : _ids(std::move(ids)) {} 40 | 41 | virtual bool onInit() override final { 42 | if (!_ids.size()) { 43 | registerEvent(*this); 44 | require(); 45 | } else { 46 | for (auto id : _ids) 47 | push(id); 48 | kill(); 49 | } 50 | return true; 51 | } 52 | 53 | uint32_t counter = 0; 54 | void on(qb::RequireEvent const &event) { 55 | if (is(event)) { 56 | ++counter; 57 | send(event.getSource()); 58 | } 59 | if (counter == MAX_ACTOR) 60 | kill(); 61 | } 62 | }; 63 | 64 | TEST(ActorDependency, GetActorIdDependencyFromAddActorAtStart) { 65 | qb::Main main({0, 1}); 66 | 67 | qb::Main::CoreBuilder::ActorIdList list; 68 | for (auto i = 0u; i < MAX_ACTOR; ++i) { 69 | list.push_back(main.addActor(0)); 70 | } 71 | main.addActor(1, list); 72 | 73 | main.start(false); 74 | main.join(); 75 | EXPECT_FALSE(main.hasError()); 76 | } 77 | 78 | TEST(ActorDependency, GetActorIdDependencyFromCoreBuilderAtStart) { 79 | qb::Main main({0, 1}); 80 | 81 | auto builder = main.core(0); 82 | for (auto i = 0u; i < MAX_ACTOR; ++i) { 83 | builder.addActor(); 84 | } 85 | main.addActor(1, builder.idList()); 86 | 87 | main.start(false); 88 | main.join(); 89 | EXPECT_FALSE(main.hasError()); 90 | } 91 | 92 | TEST(ActorDependency, GetActorIdDependencyFromRequireEvent) { 93 | qb::Main main({0, 1}); 94 | 95 | auto builder = main.core(0); 96 | for (auto i = 0u; i < MAX_ACTOR; ++i) { 97 | builder.addActor(); 98 | } 99 | main.addActor(1); 100 | 101 | main.start(false); 102 | main.join(); 103 | EXPECT_FALSE(main.hasError()); 104 | } -------------------------------------------------------------------------------- /source/core/tests/system/test-actor-service-event.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * qb - C++ Actor Framework 3 | * Copyright (C) 2011-2019 isndev (www.qbaf.io). All rights reserved. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | struct TestEvent : public qb::Event 25 | { 26 | uint8_t _data[32]; 27 | uint32_t _sum; 28 | bool has_extra_data = false; 29 | 30 | TestEvent() : _sum(0) { 31 | std::random_device rand_dev; 32 | std::mt19937 generator(rand_dev()); 33 | 34 | std::uniform_int_distribution random_number(0, 255); 35 | std::generate(std::begin(_data), std::end(_data), [&](){ 36 | auto number = static_cast(random_number(generator)); 37 | _sum += number; 38 | return number; 39 | }); 40 | } 41 | 42 | bool checkSum() const { 43 | auto ret = true; 44 | if (has_extra_data) { 45 | ret = !memcmp(_data, reinterpret_cast(this) + sizeof(TestEvent), sizeof(_data)); 46 | } 47 | 48 | return std::accumulate(std::begin(_data), std::end(_data), 0u) == _sum && ret; 49 | } 50 | }; 51 | 52 | struct MyTag {}; 53 | 54 | template 55 | class BaseActorSender 56 | : public qb::ServiceActor 57 | { 58 | protected: 59 | qb::ActorId _to; 60 | public: 61 | BaseActorSender()= default; 62 | 63 | virtual bool onInit() override final { 64 | registerEvent(*this); 65 | _to = getServiceId((getIndex() + 1) % std::thread::hardware_concurrency()); 66 | if (!getIndex()) 67 | static_cast(*this).doSend(); 68 | return true; 69 | } 70 | 71 | void on(TestEvent const &event) { 72 | EXPECT_TRUE(event.checkSum()); 73 | if (getIndex() != 0) 74 | static_cast(*this).doSend(); 75 | kill(); 76 | } 77 | }; 78 | 79 | struct BasicPushActor : public BaseActorSender 80 | { 81 | void doSend() { 82 | push(_to); 83 | } 84 | }; 85 | 86 | struct BasicSendActor : public BaseActorSender 87 | { 88 | void doSend() { 89 | send(_to); 90 | } 91 | }; 92 | 93 | struct EventBuilderPushActor : public BaseActorSender 94 | { 95 | void doSend() { 96 | to(_to).push(); 97 | } 98 | }; 99 | 100 | struct PipePushActor : public BaseActorSender 101 | { 102 | void doSend() { 103 | getPipe(_to).push(); 104 | } 105 | }; 106 | 107 | struct AllocatedPipePushActor : public BaseActorSender 108 | { 109 | void doSend() { 110 | auto &e = getPipe(_to).allocated_push(32); 111 | e.has_extra_data = true; 112 | memcpy(reinterpret_cast(&e) + sizeof(TestEvent), e._data, sizeof(e._data)); 113 | } 114 | }; 115 | 116 | 117 | template 118 | class ActorEventMulti : public testing::Test 119 | { 120 | protected: 121 | const uint32_t max_core; 122 | qb::Main main; 123 | ActorEventMulti() 124 | : max_core(std::thread::hardware_concurrency()) 125 | , main(qb::CoreSet::build(max_core)) 126 | {} 127 | 128 | virtual void SetUp() { 129 | for (auto i = 0u; i < max_core; ++i) 130 | { 131 | main.addActor(i); 132 | } 133 | } 134 | virtual void TearDown() {} 135 | }; 136 | 137 | typedef testing::Types < 138 | BasicPushActor, 139 | BasicSendActor, 140 | EventBuilderPushActor, 141 | PipePushActor, 142 | AllocatedPipePushActor 143 | > Implementations; 144 | 145 | TYPED_TEST_SUITE(ActorEventMulti, Implementations); 146 | 147 | TYPED_TEST(ActorEventMulti, SendEvents) { 148 | EXPECT_GT(this->max_core, 1u); 149 | this->main.start(); 150 | this->main.join(); 151 | EXPECT_FALSE(this->main.hasError()); 152 | } -------------------------------------------------------------------------------- /source/core/tests/system/test-io.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * qb - C++ Actor Framework 3 | * Copyright (C) 2011-2019 isndev (www.qbaf.io). All rights reserved. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | struct TestEvent : public qb::Event {}; 24 | 25 | class TestActor : public qb::Actor 26 | { 27 | public: 28 | TestActor() { 29 | EXPECT_EQ(static_cast(id()), 0u); 30 | LOG_DEBUG("TestActor had been constructed"); 31 | } 32 | 33 | ~TestActor() { 34 | LOG_CRIT("TestActor id dead"); 35 | } 36 | 37 | virtual bool onInit() override final { 38 | EXPECT_NE(static_cast(id()), 0u); 39 | LOG_VERB("TestActor had been initialized at" << qb::Timestamp::nano()); 40 | registerEvent(*this); 41 | push(id()); 42 | qb::io::cout() << "Test Actor(" << id() << "): Hello master !" << std::endl; 43 | return true; 44 | } 45 | 46 | void on(TestEvent const &) { 47 | LOG_INFO("TestActor received TestEvent at" << qb::Timestamp::nano()); 48 | kill(); 49 | LOG_WARN("TestActor will be killed at" << qb::Timestamp::nano()); 50 | } 51 | }; 52 | 53 | TEST(IO, BasicTestMonoCore) { 54 | qb::io::log::init("./test-mono-io", 128); 55 | qb::io::log::setLevel(qb::io::log::Level::DEBUG); 56 | qb::Main main({0}); 57 | 58 | LOG_INFO("Broadcast id=" << qb::BroadcastId(0)); 59 | main.addActor(0); 60 | 61 | main.start(); 62 | main.join(); 63 | EXPECT_FALSE(main.hasError()); 64 | } 65 | 66 | TEST(IO, BasicTestMultiCore) { 67 | nanolog::initialize(nanolog::NonGuaranteedLogger(1), "./test.io", 128); 68 | nanolog::set_log_level(nanolog::LogLevel::VERBOSE); 69 | 70 | EXPECT_FALSE(nanolog::is_logged(nanolog::LogLevel::DEBUG)); 71 | EXPECT_TRUE(nanolog::is_logged(nanolog::LogLevel::VERBOSE)); 72 | 73 | const auto max_core = std::thread::hardware_concurrency(); 74 | 75 | EXPECT_GT(max_core, 1u); 76 | qb::Main main(qb::CoreSet::build(max_core)); 77 | 78 | for (auto i = 0u; i < max_core; ++i) 79 | main.addActor(i); 80 | 81 | main.start(); 82 | main.join(); 83 | EXPECT_FALSE(main.hasError()); 84 | } -------------------------------------------------------------------------------- /source/core/tests/system/test-main.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * qb - C++ Actor Framework 3 | * Copyright (C) 2011-2019 isndev (www.qbaf.io). All rights reserved. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | #include 19 | #include 20 | #include 21 | 22 | class TestActor : public qb::Actor 23 | { 24 | bool keep_live = false; 25 | bool throw_except; 26 | public: 27 | TestActor() = default; 28 | TestActor(bool live, bool except = false) : keep_live(live), throw_except(except) {} 29 | virtual bool onInit() override final { 30 | if (throw_except) 31 | throw std::runtime_error("Test Exception Error"); 32 | 33 | if (!keep_live) 34 | kill(); 35 | return true; 36 | } 37 | }; 38 | 39 | TEST(Main, StartMonoCoreShouldAbortIfNoActor) { 40 | qb::Main main({0}); 41 | 42 | main.start(); 43 | main.join(); 44 | EXPECT_TRUE(main.hasError()); 45 | } 46 | 47 | TEST(Main, StartMultiCoreShouldAbortIfNoActor) { 48 | const auto max_core = std::thread::hardware_concurrency(); 49 | std::srand(static_cast(std::time(nullptr))); 50 | const auto fail_core = std::rand() % max_core; 51 | 52 | EXPECT_GT(max_core, 1u); 53 | qb::Main main(qb::CoreSet::build(max_core)); 54 | 55 | for (auto i = 0u; i < max_core; ++i) { 56 | if (i != fail_core) 57 | main.addActor(i); 58 | } 59 | 60 | main.start(); 61 | main.join(); 62 | EXPECT_TRUE(main.hasError()); 63 | } 64 | 65 | TEST(Main, StartMonoCoreShouldAbortIfNoExistingCore) { 66 | qb::Main main({255}); 67 | 68 | main.addActor(255, true); 69 | 70 | main.start(); 71 | main.join(); 72 | EXPECT_TRUE(main.hasError()); 73 | } 74 | 75 | TEST(Main, StartMonoCoreShouldAbortIfCoreHasThrownException) { 76 | qb::Main main({0}); 77 | 78 | main.addActor(0, true, true); 79 | 80 | main.start(); 81 | main.join(); 82 | EXPECT_TRUE(main.hasError()); 83 | } 84 | 85 | TEST(Main, StartMonoCoreWithNoError) { 86 | qb::Main main({0}); 87 | 88 | main.addActor(0); 89 | main.start(); 90 | main.join(); 91 | EXPECT_FALSE(main.hasError()); 92 | } 93 | 94 | TEST(Main, StartMultiCoreWithNoError) { 95 | const auto max_core = std::thread::hardware_concurrency(); 96 | 97 | EXPECT_GT(max_core, 1u); 98 | qb::Main main(qb::CoreSet::build(max_core)); 99 | 100 | for (auto i = 0u; i < max_core; ++i) 101 | main.addActor(i); 102 | 103 | main.start(); 104 | main.join(); 105 | EXPECT_FALSE(main.hasError()); 106 | } 107 | 108 | TEST(Main, StopMonoCoreWithNoError) { 109 | qb::Main main({0}); 110 | 111 | main.addActor(0, true); 112 | main.start(); 113 | main.stop(); 114 | main.join(); 115 | EXPECT_FALSE(main.hasError()); 116 | } 117 | 118 | TEST(Main, StopMultiCoreWithNoError) { 119 | const auto max_core = std::thread::hardware_concurrency(); 120 | 121 | EXPECT_GT(max_core, 1u); 122 | qb::Main main(qb::CoreSet::build(max_core)); 123 | 124 | for (auto i = 0u; i < max_core; ++i) 125 | main.addActor(i, true); 126 | 127 | main.start(); 128 | main.stop(); 129 | main.join(); 130 | EXPECT_FALSE(main.hasError()); 131 | } -------------------------------------------------------------------------------- /source/core/tests/unit/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # 2 | # qb - C++ Actor Framework 3 | # Copyright (C) 2011-2019 isndev (www.qbaf.io). All rights reserved. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | # 17 | 18 | cxx_gtest(${PROJECT_NAME}-gtest-unit-example "${PROJECT_NAME}" test_example.cpp) -------------------------------------------------------------------------------- /source/core/tests/unit/test_example.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * qb - C++ Actor Framework 3 | * Copyright (C) 2011-2019 isndev (www.qbaf.io). All rights reserved. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | #include 19 | #include 20 | 21 | TEST(Example, StartEngine) { 22 | qb::Main main({0}); 23 | 24 | main.start(); 25 | main.join(); 26 | EXPECT_TRUE(main.hasError()); 27 | } -------------------------------------------------------------------------------- /source/network/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # 2 | # qb - C++ Actor Framework 3 | # Copyright (C) 2011-2019 isndev (www.qbaf.io). All rights reserved. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | # 17 | 18 | project(${QB_PREFIX}-network LANGUAGES CXX VERSION ${QB_VERSION} DESCRIPTION "A simple network library") 19 | 20 | cxx_library(${PROJECT_NAME} ${cxx_default_lib} src/network-all.cpp) 21 | set_target_properties(${PROJECT_NAME} PROPERTIES VERSION ${QB_VERSION} SOVERSION ${QB_VERSION_MAJOR}) 22 | target_include_directories(${PROJECT_NAME} INTERFACE 23 | "$" 24 | "$/${CMAKE_INSTALL_INCLUDEDIR}>") 25 | 26 | cxx_shared_library(${PROJECT_NAME}-shared ${cxx_default_lib} src/network-all.cpp) 27 | set_target_properties(${PROJECT_NAME}-shared PROPERTIES VERSION ${QB_VERSION} SOVERSION ${QB_VERSION_MAJOR}) 28 | target_include_directories(${PROJECT_NAME}-shared INTERFACE 29 | "$" 30 | "$/${CMAKE_INSTALL_INCLUDEDIR}>") 31 | 32 | if (WIN32) 33 | target_link_libraries(${PROJECT_NAME} ws2_32) 34 | target_link_libraries(${PROJECT_NAME}-shared ws2_32) 35 | endif() 36 | 37 | if (${QB_PREFIX_UPPER}_BUILD_TEST) 38 | add_subdirectory(tests) 39 | endif() -------------------------------------------------------------------------------- /source/network/src/helper.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * qb - C++ Actor Framework 3 | * Copyright (C) 2011-2019 isndev (www.qbaf.io). All rights reserved. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | #include 19 | 20 | namespace qb { 21 | namespace network { 22 | #ifdef __WIN__SYSTEM__ 23 | 24 | sockaddr_in helper::createAddress(uint32_t address, unsigned short port) 25 | { 26 | sockaddr_in addr; 27 | std::memset(&addr, 0, sizeof(addr)); 28 | addr.sin_addr.s_addr = htonl(address); 29 | addr.sin_family = AF_INET; 30 | addr.sin_port = htons(port); 31 | 32 | return addr; 33 | } 34 | 35 | bool helper::close(SocketHandler socket) { 36 | return !closesocket(socket); 37 | } 38 | 39 | bool helper::block(SocketHandler socket, bool block) { 40 | unsigned long new_state = static_cast(!block); 41 | return !ioctlsocket(socket, FIONBIO, &new_state); 42 | } 43 | 44 | SocketStatus helper::getErrorStatus() { 45 | const auto err = WSAGetLastError(); 46 | switch (err) { 47 | case WSAEWOULDBLOCK: 48 | return SocketStatus::NotReady; 49 | case WSAEALREADY: 50 | return SocketStatus::NotReady; 51 | case WSAECONNABORTED: 52 | return SocketStatus::Disconnected; 53 | case WSAECONNRESET: 54 | return SocketStatus::Disconnected; 55 | case WSAETIMEDOUT: 56 | return SocketStatus::Disconnected; 57 | case WSAENETRESET: 58 | return SocketStatus::Disconnected; 59 | case WSAENOTCONN: 60 | return SocketStatus::Disconnected; 61 | case WSAEISCONN: 62 | return SocketStatus::Done; // when connecting a non-blocking socket 63 | default: 64 | return SocketStatus::Error; 65 | } 66 | } 67 | 68 | bool helper::is_blocking(SocketHandler) 69 | { 70 | return true; 71 | } 72 | 73 | struct SocketInitializer { 74 | SocketInitializer() { 75 | WSADATA InitData; 76 | WSAStartup(MAKEWORD(2, 2), &InitData); 77 | } 78 | 79 | ~SocketInitializer() { 80 | WSACleanup(); 81 | } 82 | }; 83 | 84 | SocketInitializer GlobalInitializer; 85 | #else 86 | #include 87 | #include 88 | 89 | sockaddr_in helper::createAddress(uint32_t address, unsigned short port) 90 | { 91 | sockaddr_in addr; 92 | std::memset(&addr, 0, sizeof(addr)); 93 | addr.sin_addr.s_addr = htonl(address); 94 | addr.sin_family = AF_INET; 95 | addr.sin_port = htons(port); 96 | 97 | return addr; 98 | } 99 | 100 | bool helper::close(SocketHandler sock) 101 | { 102 | return !::close(sock); 103 | } 104 | 105 | bool helper::block(SocketHandler sock, bool newst) 106 | { 107 | int status = fcntl(sock, F_GETFL); 108 | 109 | return (newst ? 110 | fcntl(sock, F_SETFL, status & ~O_NONBLOCK) != -1 : 111 | fcntl(sock, F_SETFL, status | O_NONBLOCK) != -1); 112 | } 113 | 114 | SocketStatus helper::getErrorStatus() 115 | { 116 | if ((errno == EAGAIN) || (errno == EINPROGRESS)) 117 | return SocketStatus::NotReady; 118 | 119 | switch (errno) 120 | { 121 | case EWOULDBLOCK: return SocketStatus::NotReady; 122 | case ECONNABORTED: return SocketStatus::Disconnected; 123 | case ECONNRESET: return SocketStatus::Disconnected; 124 | case ETIMEDOUT: return SocketStatus::Disconnected; 125 | case ENETRESET: return SocketStatus::Disconnected; 126 | case ENOTCONN: return SocketStatus::Disconnected; 127 | case EPIPE: return SocketStatus::Disconnected; 128 | default: return SocketStatus::Error; 129 | } 130 | } 131 | 132 | bool helper::is_blocking(SocketHandler sock) 133 | { 134 | int status = fcntl(sock, F_GETFL); 135 | 136 | return !(status & O_NONBLOCK); 137 | } 138 | #endif 139 | 140 | } // namespace network 141 | } // namespace qb 142 | 143 | -------------------------------------------------------------------------------- /source/network/src/ip.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * qb - C++ Actor Framework 3 | * Copyright (C) 2011-2019 isndev (www.qbaf.io). All rights reserved. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | #include 19 | #include 20 | 21 | namespace qb { 22 | namespace network { 23 | 24 | const ip ip::None(INADDR_NONE); 25 | const ip ip::Any(0, 0, 0, 0); 26 | const ip ip::LocalHost(127, 0, 0, 1); 27 | 28 | ip::ip() : 29 | _address(INADDR_NONE) { 30 | } 31 | 32 | ip::ip(const std::string &address) : 33 | _address(0) { 34 | resolve(address); 35 | } 36 | 37 | ip::ip(const char *address) : 38 | _address(0) { 39 | resolve(address); 40 | } 41 | 42 | ip::ip(uint8_t byte0, uint8_t byte1, uint8_t byte2, uint8_t byte3) : 43 | _address(htonl((byte0 << 24) | (byte1 << 16) | (byte2 << 8) | byte3)) { 44 | } 45 | 46 | ip::ip(uint32_t address) : 47 | _address(htonl(address)) { 48 | } 49 | 50 | std::string ip::toString() const { 51 | char buffer[32]; 52 | in_addr address; 53 | address.s_addr = _address; 54 | inet_ntop(AF_INET, &address, buffer, 32); 55 | return {buffer}; 56 | } 57 | 58 | uint32_t ip::toInteger() const { 59 | return ntohl(_address); 60 | } 61 | 62 | void ip::resolve(const std::string &address) { 63 | _address = 0; 64 | 65 | if (address == "255.255.255.255") { 66 | // The broadcast address needs to be handled explicitly, 67 | // because it is also the value returned by inet_addr on error 68 | _address = INADDR_BROADCAST; 69 | } else if (address == "0.0.0.0") { 70 | _address = INADDR_ANY; 71 | } else { 72 | // Try to convert the address as a byte representation ("xxx.xxx.xxx.xxx") 73 | in_addr addr; 74 | 75 | if (inet_pton(AF_INET, address.c_str(), &addr)) { 76 | _address = static_cast(addr.s_addr); 77 | } else { 78 | // Not a valid address, try to convert it as a host name 79 | addrinfo hints; 80 | std::memset(&hints, 0, sizeof(hints)); 81 | hints.ai_family = AF_INET; 82 | addrinfo *result = NULL; 83 | if (getaddrinfo(address.c_str(), NULL, &hints, &result) == 0) { 84 | if (result) { 85 | uint32_t newip = reinterpret_cast(result->ai_addr)->sin_addr.s_addr; 86 | freeaddrinfo(result); 87 | _address = newip; 88 | } 89 | } 90 | } 91 | } 92 | } 93 | 94 | bool operator==(const ip &left, const ip &right) { 95 | return !(left < right) && !(right < left); 96 | } 97 | 98 | bool operator!=(const ip &left, const ip &right) { 99 | return !(left == right); 100 | } 101 | 102 | bool operator<(const ip &left, const ip &right) { 103 | return left._address < right._address; 104 | } 105 | 106 | bool operator>(const ip &left, const ip &right) { 107 | return right < left; 108 | } 109 | 110 | bool operator<=(const ip &left, const ip &right) { 111 | return !(right < left); 112 | } 113 | 114 | bool operator>=(const ip &left, const ip &right) { 115 | return !(left < right); 116 | } 117 | 118 | std::istream &operator>>(std::istream &stream, ip &address) { 119 | std::string str; 120 | stream >> str; 121 | address = ip(str); 122 | 123 | return stream; 124 | } 125 | 126 | std::ostream &operator<<(std::ostream &stream, const ip &address) { 127 | return stream << address.toString(); 128 | } 129 | 130 | } // namespace network 131 | } // namespace qb -------------------------------------------------------------------------------- /source/network/src/network-all.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * qb - C++ Actor Framework 3 | * Copyright (C) 2011-2019 isndev (www.qbaf.io). All rights reserved. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | #include "helper.cpp" 19 | #include "ip.cpp" 20 | #include "tcp.cpp" 21 | #include "udp.cpp" -------------------------------------------------------------------------------- /source/network/src/udp.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * qb - C++ Actor Framework 3 | * Copyright (C) 2011-2019 isndev (www.qbaf.io). All rights reserved. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | #include 19 | #include 20 | 21 | namespace qb { 22 | namespace network { 23 | namespace udp { 24 | 25 | Socket::Socket() : 26 | sys::Socket() { 27 | init(); 28 | } 29 | 30 | unsigned short Socket::getLocalPort() const { 31 | if (good()) { 32 | // Retrieve informations about the local end of the socket 33 | sockaddr_in address; 34 | AddrLength size = sizeof(address); 35 | if (getsockname(_handle, reinterpret_cast(&address), &size) != -1) { 36 | return ntohs(address.sin_port); 37 | } 38 | } 39 | 40 | // We failed to retrieve the port 41 | return 0; 42 | } 43 | 44 | SocketStatus Socket::bind(unsigned short port, const ip &address) { 45 | 46 | // Create the internal socket if it doesn't exist 47 | init(); 48 | 49 | // Check if the address is valid 50 | if ((address == ip::None)) 51 | return SocketStatus::Error; 52 | 53 | // Bind the socket 54 | sockaddr_in addr = helper::createAddress(address.toInteger(), port); 55 | if (::bind(_handle, reinterpret_cast(&addr), sizeof(addr))) { 56 | std::cerr << "Failed to bind socket to port " << port << std::endl; 57 | return SocketStatus::Error; 58 | } 59 | 60 | return SocketStatus::Done; 61 | } 62 | 63 | void Socket::unbind() { 64 | // Simply close the socket 65 | close(); 66 | } 67 | 68 | SocketStatus 69 | Socket::send(const void *data, std::size_t size, const ip &remoteAddress, unsigned short remotePort) const { 70 | 71 | // Build the target address 72 | sockaddr_in address = helper::createAddress(remoteAddress.toInteger(), remotePort); 73 | 74 | // Send the data (unlike TCP, all the data is always sent in one call) 75 | int sent = sendto(_handle, static_cast(data), static_cast(size), 0, 76 | reinterpret_cast(&address), sizeof(address)); 77 | 78 | // Check for errors 79 | if (sent < 0) 80 | return helper::getErrorStatus(); 81 | 82 | return SocketStatus::Done; 83 | } 84 | 85 | SocketStatus Socket::receive(void *data, std::size_t size, std::size_t &received, ip &remoteAddress, 86 | unsigned short &remotePort) const { 87 | // First clear the variables to fill 88 | received = 0; 89 | remoteAddress = ip(); 90 | remotePort = 0; 91 | 92 | // Data that will be filled with the other computer's address 93 | sockaddr_in address = helper::createAddress(INADDR_ANY, 0); 94 | 95 | // Receive a chunk of bytes 96 | AddrLength addressSize = sizeof(address); 97 | int sizeReceived = recvfrom(_handle, static_cast(data), static_cast(size), 0, 98 | reinterpret_cast(&address), &addressSize); 99 | 100 | // Check for errors 101 | if (sizeReceived < 0) 102 | return helper::getErrorStatus(); 103 | 104 | // Fill the sender informations 105 | received = static_cast(sizeReceived); 106 | remoteAddress = ip(ntohl(address.sin_addr.s_addr)); 107 | remotePort = ntohs(address.sin_port); 108 | 109 | return SocketStatus::Done; 110 | } 111 | 112 | } // namespace udp 113 | } // namespace network 114 | } // namespace qb 115 | -------------------------------------------------------------------------------- /source/network/tests/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # 2 | # qb - C++ Actor Framework 3 | # Copyright (C) 2011-2019 isndev (www.qbaf.io). All rights reserved. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | # 17 | 18 | add_subdirectory(system) -------------------------------------------------------------------------------- /source/network/tests/system/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # 2 | # qb - C++ Actor Framework 3 | # Copyright (C) 2011-2019 isndev (www.qbaf.io). All rights reserved. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | # 17 | 18 | cxx_gtest(${PROJECT_NAME}-gtest-tcp-udp "${PROJECT_NAME}" test-network.cpp) --------------------------------------------------------------------------------