Skip to content

Commit

Permalink
Add cmake boilerplate to install ichor
Browse files Browse the repository at this point in the history
Also fix a threading issue in HttpHost
  • Loading branch information
Oipo committed Nov 6, 2022
1 parent 5f628b3 commit 530a9b9
Show file tree
Hide file tree
Showing 16 changed files with 249 additions and 86 deletions.
228 changes: 171 additions & 57 deletions CMakeLists.txt

Large diffs are not rendered by default.

24 changes: 24 additions & 0 deletions IchorConfig.cmake.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
@PACKAGE_INIT@

include(CMakeFindDependencyMacro)

set(ICHOR_USE_SYSTEM_MIMALLOC @ICHOR_USE_SYSTEM_MIMALLOC@)
set(ICHOR_USE_ABSEIL @ICHOR_USE_ABSEIL@)
set(ICHOR_USE_SDEVENT @ICHOR_USE_SDEVENT@)
set(ICHOR_USE_BOOST_BEAST @ICHOR_USE_BOOST_BEAST@)

if(ICHOR_USE_SYSTEM_MIMALLOC)
find_dependency(mimalloc REQUIRED)
endif()
if(ICHOR_USE_ABSEIL)
find_dependency(absl REQUIRED)
endif()
if(ICHOR_USE_SDEVENT)
find_dependency(PkgConfig REQUIRED)
pkg_check_modules(Systemd IMPORTED_TARGET GLOBAL libsystemd)
endif()
if(ICHOR_USE_BOOST_BEAST)
find_dependency(boost_coroutine REQUIRED)
endif()

include("${CMAKE_CURRENT_LIST_DIR}/IchorTargets.cmake")
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
MIT License

Copyright (c) 2020 Michael de Lang
Copyright (c) 2022 Michael de Lang

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Expand Down
4 changes: 2 additions & 2 deletions build.sh
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#!/bin/bash

#sudo rm -rf * ../bin/* /usr/include/ichor/ ../../ichor-install/ /usr/lib/cmake/ichor && cmake -GNinja -DICHOR_BUILD_TESTING=OFF -DICHOR_BUILD_EXAMPLES=OFF -DICHOR_BUILD_BENCHMARKS=OFF -DCMAKE_BUILD_TYPE=Debug -DICHOR_USE_SANITIZERS=ON -DICHOR_ARCH_OPTIMIZATION=X86_64_AVX512 -DICHOR_USE_ABSEIL=ON -DICHOR_SERIALIZATION_FRAMEWORK=BOOST_JSON -DICHOR_USE_BOOST_BEAST=ON -DICHOR_USE_SPDLOG=ON -DCMAKE_INSTALL_PREFIX=/usr .. && ninja && sudo ninja install
cleanup ()
{
kill -s SIGTERM $!
Expand Down Expand Up @@ -63,4 +63,4 @@ for i in ${!ccompilers[@]}; do
ninja test || exit 1
run_examples
run_benchmarks
done
done
4 changes: 2 additions & 2 deletions cloc.sh
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#!/bin/bash
cloc src/ include/ test/ examples/ benchmarks/ --exclude-dir=etcd,etcd_example,tl
cloc src/ include/ test/ examples/ benchmarks/ --exclude-dir=etcd,etcd_example,tl,sole
echo ""
cloc src/ include/ test/ examples/ benchmarks/ --exclude-dir=etcd,etcd_example,tl --by-file
cloc src/ include/ test/ examples/ benchmarks/ --exclude-dir=etcd,etcd_example,tl,sole --by-file
25 changes: 22 additions & 3 deletions docs/GettingStarted.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
## Compiling Ichor

Compiling is done through the help of CMake. Ichor requires at least gcc 11.3 (due to [this gcc bug](https://gcc.gnu.org/bugzilla/show_bug.cgi?id=95137)) or clang 14, and is tested with gcc 11.3, 12.1, clang 14, clang 15 and clang 16.

### Dependencies

#### Ubuntu 20.04:
Expand Down Expand Up @@ -62,6 +63,20 @@ sudo apt install libabsl-dev

Tried with MSVC 19.33, but it seemed like coroutines and concepts are not fully implemented yet.

#### CMakeLists.txt

To use Ichor, compile and install it in a location that cmake can find (e.g. /usr) and use the following CMakeLists.txt:

```cmake
cmake_minimum_required(VERSION 3.12)
project(my_project)
set(CMAKE_CXX_STANDARD 20)
find_package(my_exe CONFIG REQUIRED)
add_executable(my_exe main.cpp)
target_link_libraries(my_exe Ichor::ichor)
```

### CMake Options

Expand Down Expand Up @@ -134,6 +149,10 @@ Enables the use of the [sdevent event queue](../include/ichor/event_queues/Sdeve

Enables the use of the abseil containers in Ichor. Requires having abseil headers and libraries installed on your system.

#### ICHOR_DISABLE_RTTI

Disables `dynamic_cast<>()` in most cases as well as `typeid`. Ichor is an opinionated piece of software and we strongly encourage you to disable RTTI. We believe `dynamic_cast<>()` is wrong in almost all instances. Virtual methods and double dispatch should be used instead. If, however, you really want to use RTTI, use this option to re-enable it.

#### ICHOR_USE_MIMALLOC

If `ICHOR_USE_SANITIZERS` is turned OFF, Ichor by default compiles itself with mimalloc, speeding up the runtime a lot and reducing peak memory usage.
Expand Down Expand Up @@ -273,7 +292,7 @@ struct MyTimerService final : public IMyTimerService, public Ichor::Service<MyTi
return Ichor::StartBehaviour::SUCCEEDED;
}

Ichor::AsyncGenerator<void> handleEvent(Ichor::TimerEvent const * const) {
Ichor::AsyncGenerator<void> handleEvent(Ichor::TimerEvent const &) {
co_return;
}

Expand Down Expand Up @@ -339,7 +358,7 @@ struct MyTimerService final : public IMyTimerService, public Ichor::Service<MyTi
return Ichor::StartBehaviour::SUCCEEDED;
}

Ichor::AsyncGenerator<void> handleEvent(Ichor::TimerEvent const * const) {
Ichor::AsyncGenerator<void> handleEvent(Ichor::TimerEvent const &) {
getManager().pushEvent<Ichor::QuitEvent>(getServiceId()); // Add this
co_return;
}
Expand Down Expand Up @@ -409,7 +428,7 @@ Pushing an event with a priority is done with the `pushPrioritisedEvent` functio
getManager().pushPrioritisedEvent<TimerEvent>(getServiceId(), 10);
```
The default priority for events is 1000. For dependency related things (like start service, dependency online events) this is 100.
The default priority for events is 1000. For dependency related things (like start service, dependency online events) it is 100.
### Memory allocation
Expand Down
12 changes: 6 additions & 6 deletions examples/common/TestMsgJsonSerializer.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@
#include <ichor/LifecycleManager.h>
#include "TestMsg.h"

#ifdef USE_RAPIDJSON
#ifdef ICHOR_USE_RAPIDJSON
#include <rapidjson/document.h>
#include <rapidjson/writer.h>
#elif USE_BOOST_JSON
#elif ICHOR_USE_BOOST_JSON
#pragma GCC diagnostic push
#ifndef __clang__
#pragma GCC diagnostic ignored "-Wduplicated-branches"
Expand All @@ -35,7 +35,7 @@ class TestMsgJsonSerializer final : public ISerializer, public Service<TestMsgJs
std::vector<uint8_t> serialize(const void* obj) final {
auto msg = static_cast<const TestMsg*>(obj);

#ifdef USE_RAPIDJSON
#ifdef ICHOR_USE_RAPIDJSON
rapidjson::StringBuffer sb;
rapidjson::Writer<rapidjson::StringBuffer> writer(sb);

Expand All @@ -50,7 +50,7 @@ class TestMsgJsonSerializer final : public ISerializer, public Service<TestMsgJs
writer.EndObject();
auto *ret = sb.GetString();
return std::vector<uint8_t>(ret, ret + sb.GetSize() + 1);
#elif USE_BOOST_JSON
#elif ICHOR_USE_BOOST_JSON
boost::json::value jv{};
boost::json::serializer sr;
jv = {{"id", msg->id}, {"val", msg->val}};
Expand Down Expand Up @@ -84,7 +84,7 @@ class TestMsgJsonSerializer final : public ISerializer, public Service<TestMsgJs
#endif
}
void* deserialize(std::vector<uint8_t> &&stream) final {
#ifdef USE_RAPIDJSON
#ifdef ICHOR_USE_RAPIDJSON
rapidjson::Document d;
d.ParseInsitu(reinterpret_cast<char*>(stream.data()));

Expand All @@ -93,7 +93,7 @@ class TestMsgJsonSerializer final : public ISerializer, public Service<TestMsgJs
}

return new TestMsg{d["id"].GetUint64(), d["val"].GetString()};
#elif USE_BOOST_JSON
#elif ICHOR_USE_BOOST_JSON
boost::json::parser p{};

std::error_code ec;
Expand Down
12 changes: 6 additions & 6 deletions examples/http_ping_pong/PingMsgJsonSerializer.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@
#include <ichor/LifecycleManager.h>
#include "PingMsg.h"

#ifdef USE_RAPIDJSON
#ifdef ICHOR_USE_RAPIDJSON
#include <rapidjson/document.h>
#include <rapidjson/writer.h>
#elif USE_BOOST_JSON
#elif ICHOR_USE_BOOST_JSON
#pragma GCC diagnostic push
#ifndef __clang__
#pragma GCC diagnostic ignored "-Wduplicated-branches"
Expand All @@ -35,7 +35,7 @@ class PingMsgJsonSerializer final : public ISerializer, public Service<PingMsgJs
std::vector<uint8_t> serialize(const void* obj) final {
auto msg = static_cast<const PingMsg*>(obj);

#ifdef USE_RAPIDJSON
#ifdef ICHOR_USE_RAPIDJSON
rapidjson::StringBuffer sb;
rapidjson::Writer<rapidjson::StringBuffer> writer(sb);

Expand All @@ -47,7 +47,7 @@ class PingMsgJsonSerializer final : public ISerializer, public Service<PingMsgJs
writer.EndObject();
auto *ret = sb.GetString();
return std::vector<uint8_t>(ret, ret + sb.GetSize() + 1);
#elif USE_BOOST_JSON
#elif ICHOR_USE_BOOST_JSON
boost::json::value jv{};
boost::json::serializer sr;
jv = {{"sequence", msg->sequence}};
Expand Down Expand Up @@ -81,7 +81,7 @@ class PingMsgJsonSerializer final : public ISerializer, public Service<PingMsgJs
#endif
}
void* deserialize(std::vector<uint8_t> &&stream) final {
#ifdef USE_RAPIDJSON
#ifdef ICHOR_USE_RAPIDJSON
rapidjson::Document d;
d.ParseInsitu(reinterpret_cast<char*>(stream.data()));

Expand All @@ -90,7 +90,7 @@ class PingMsgJsonSerializer final : public ISerializer, public Service<PingMsgJs
}

return new PingMsg{d["sequence"].GetUint64()};
#elif USE_BOOST_JSON
#elif ICHOR_USE_BOOST_JSON
boost::json::parser p{};

std::error_code ec;
Expand Down
2 changes: 1 addition & 1 deletion include/ichor/Service.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

#include <cstdint>
#include <atomic>
#include "sole.hpp"
#include <sole/sole.h>
#include <ichor/Common.h>
#include <ichor/Concepts.h>
#include <ichor/Enums.h>
Expand Down
1 change: 1 addition & 0 deletions include/ichor/services/network/http/HttpHostService.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ namespace Ichor {
friend DependencyRegister;

std::unique_ptr<tcp::acceptor> _httpAcceptor{};
// _httpStreams should only be modified from the boost thread
unordered_map<uint64_t, std::unique_ptr<beast::tcp_stream>> _httpStreams{};
std::atomic<uint64_t> _priority{INTERNAL_EVENT_PRIORITY};
std::atomic<bool> _quit{};
Expand Down
File renamed without changes.
3 changes: 0 additions & 3 deletions sonar-project.properties

This file was deleted.

2 changes: 1 addition & 1 deletion src/services/network/http/HttpConnectionService.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
#include <ichor/DependencyManager.h>
#include <ichor/events/RunFunctionEvent.h>
#include <ichor/services/network/http/HttpConnectionService.h>
#include <ichor/services/network/http/HttpScopeGuardFinish.h>
#include <ichor/services/network/http/HttpScopeGuards.h>
#include <ichor/services/network/NetworkEvents.h>

namespace Ichor {
Expand Down
15 changes: 11 additions & 4 deletions src/services/network/http/HttpHostService.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

#include <ichor/DependencyManager.h>
#include <ichor/services/network/http/HttpHostService.h>
#include <ichor/services/network/http/HttpScopeGuardFinish.h>
#include <ichor/services/network/http/HttpScopeGuards.h>

Ichor::HttpHostService::HttpHostService(DependencyRegister &reg, Properties props, DependencyManager *mng) : Service(std::move(props), mng) {
reg.registerDependency<ILogger>(this, true);
Expand Down Expand Up @@ -41,9 +41,12 @@ Ichor::StartBehaviour Ichor::HttpHostService::stop() {
if (_httpAcceptor->is_open()) {
_httpAcceptor->close();
}
for(auto &[id, stream] : _httpStreams) {
stream->cancel();
}
net::spawn(*_httpContextService->getContext(), [this](net::yield_context _yield) {
// _httpStreams should only be modified from the boost thread
for (auto &[id, stream]: _httpStreams) {
stream->cancel();
}
});

_httpAcceptor = nullptr;
_cleanedupStream = true;
Expand All @@ -52,6 +55,7 @@ Ichor::StartBehaviour Ichor::HttpHostService::stop() {
if(_finishedListenAndRead.load(std::memory_order_acquire) != 0 || !_cleanedupStream) {
return Ichor::StartBehaviour::FAILED_AND_RETRY;
}
// _httpStreams should only be modified from the boost thread, except here where we know there are no fibers running
_httpStreams.clear();

return Ichor::StartBehaviour::SUCCEEDED;
Expand Down Expand Up @@ -182,6 +186,7 @@ void Ichor::HttpHostService::read(tcp::socket socket, net::yield_context yield)
beast::error_code ec;
auto addr = socket.remote_endpoint().address().to_string();
uint64_t streamId = _streamIdCounter++;
// _httpStreams should only be modified from the boost thread
auto *httpStream = _httpStreams.emplace(streamId, std::make_unique<beast::tcp_stream>(std::move(socket))).first->second.get();

// This buffer is required to persist across reads
Expand Down Expand Up @@ -265,6 +270,7 @@ void Ichor::HttpHostService::read(tcp::socket socket, net::yield_context yield)
co_return;
});
}
// _httpStreams should only be modified from the boost thread
_httpStreams.erase(streamId);

// At this point the connection is closed gracefully
Expand All @@ -291,6 +297,7 @@ void Ichor::HttpHostService::sendInternal(uint64_t streamId, http::response<http
while(!_outbox.empty()) {
// Move message, should be trivially copyable and prevents iterator invalidation
auto next = std::move(_outbox.front());
// _httpStreams should only be modified from the boost thread
auto streamIt = _httpStreams.find(next.streamId);

if (streamIt == end(_httpStreams)) {
Expand Down
1 change: 1 addition & 0 deletions test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ foreach(filename ${PROJECT_TEST_SOURCES})
target_link_libraries(${testname} ${CMAKE_THREAD_LIBS_INIT})
target_link_libraries(${testname} ichor)
target_link_libraries(${testname} Catch2::Catch2WithMain)
target_compile_definitions(${testname} PUBLIC CATCH_CONFIG_FAST_COMPILE)

if(ICHOR_USE_SANITIZERS)
target_link_libraries(${testname})
Expand Down

0 comments on commit 530a9b9

Please sign in to comment.