Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 10 additions & 10 deletions include/dpp/coro/awaitable.h
Original file line number Diff line number Diff line change
Expand Up @@ -461,7 +461,7 @@ class promise_base {
void set_exception(std::exception_ptr ptr) {
throw_if_not_empty();
value.template emplace<2>(std::move(ptr));
[[maybe_unused]] auto previous_value = this->state.fetch_or(sf_ready, std::memory_order::acq_rel);
[[maybe_unused]] auto previous_value = this->state.fetch_or(sf_ready, std::memory_order_acq_rel);
if constexpr (Notify) {
if ((previous_value & sf_awaited) != 0) {
this->awaiter.resume();
Expand All @@ -476,7 +476,7 @@ class promise_base {
* @throws ? Any exception thrown by the coroutine if resumed will propagate
*/
void notify_awaiter() {
if ((state.load(std::memory_order::acquire) & sf_awaited) != 0) {
if ((state.load(std::memory_order_acquire) & sf_awaited) != 0) {
awaiter.resume();
}
}
Expand All @@ -488,11 +488,11 @@ class promise_base {
* @return awaitable<T> An object that can be co_await-ed to retrieve the value of this promise.
*/
awaitable<T> get_awaitable() {
uint8_t previous_flags = state.fetch_or(sf_has_awaitable, std::memory_order::relaxed);
uint8_t previous_flags = state.fetch_or(sf_has_awaitable, std::memory_order_relaxed);
if (previous_flags & sf_has_awaitable) [[unlikely]] {
throw dpp::logic_exception{"an awaitable was already created from this promise"};
}
return {this};
return { this };
}
};

Expand Down Expand Up @@ -528,7 +528,7 @@ class basic_promise : public detail::promise::promise_base<T> {
} catch (...) {
this->value.template emplace<2>(std::current_exception());
}
[[maybe_unused]] auto previous_value = this->state.fetch_or(detail::promise::sf_ready, std::memory_order::acq_rel);
[[maybe_unused]] auto previous_value = this->state.fetch_or(detail::promise::sf_ready, std::memory_order_acq_rel);
if constexpr (Notify) {
if (previous_value & detail::promise::sf_awaited) {
this->awaiter.resume();
Expand Down Expand Up @@ -559,7 +559,7 @@ class basic_promise : public detail::promise::promise_base<T> {
void set_value() {
this->throw_if_not_empty();
this->value.template emplace<1>();
[[maybe_unused]] auto previous_value = this->state.fetch_or(detail::promise::sf_ready, std::memory_order::acq_rel);
[[maybe_unused]] auto previous_value = this->state.fetch_or(detail::promise::sf_ready, std::memory_order_acq_rel);
if constexpr (Notify) {
if (previous_value & detail::promise::sf_awaited) {
this->awaiter.resume();
Expand Down Expand Up @@ -641,7 +641,7 @@ template <typename T>
auto awaitable<T>::abandon() -> uint8_t {
uint8_t previous_state = state_flags::sf_broken;
if (state_ptr) {
previous_state = state_ptr->state.fetch_or(state_flags::sf_broken, std::memory_order::acq_rel);
previous_state = state_ptr->state.fetch_or(state_flags::sf_broken, std::memory_order_acq_rel);
state_ptr = nullptr;
}
return previous_state;
Expand All @@ -662,7 +662,7 @@ bool awaitable<T>::await_ready() const {
if (!this->valid()) {
throw dpp::logic_exception("cannot co_await an empty awaitable");
}
uint8_t state = this->state_ptr->state.load(std::memory_order::relaxed);
uint8_t state = this->state_ptr->state.load(std::memory_order_relaxed);
return state & detail::promise::sf_ready;
}

Expand All @@ -672,7 +672,7 @@ bool awaitable<T>::awaiter<Derived>::await_suspend(detail::std_coroutine::corout
auto &promise = *awaitable_obj.state_ptr;

promise.awaiter = handle;
auto previous_flags = promise.state.fetch_or(detail::promise::sf_awaited, std::memory_order::relaxed);
auto previous_flags = promise.state.fetch_or(detail::promise::sf_awaited, std::memory_order_relaxed);
if (previous_flags & detail::promise::sf_awaited) {
throw dpp::logic_exception("awaitable is already being awaited");
}
Expand All @@ -684,7 +684,7 @@ template <typename Derived>
T awaitable<T>::awaiter<Derived>::await_resume() {
auto &promise = *awaitable_obj.state_ptr;

promise.state.fetch_and(static_cast<uint8_t>(~detail::promise::sf_awaited), std::memory_order::acq_rel);
promise.state.fetch_and(static_cast<uint8_t>(~detail::promise::sf_awaited), std::memory_order_acq_rel);
if (std::holds_alternative<std::exception_ptr>(promise.value)) {
std::rethrow_exception(std::get<2>(promise.value));
}
Expand Down
4 changes: 2 additions & 2 deletions include/dpp/coro/task.h
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ class [[nodiscard("dpp::task cancels itself on destruction. use co_await on it,
* @return bool Whether the task is finished.
*/
[[nodiscard]] bool done() const noexcept {
return handle && (!this->valid() || handle.promise().state.load(std::memory_order_relaxed) == state_flags::sf_done);
return handle && (!this->valid() || handle.promise().state.load(std::memory_order_acq_rel) == state_flags::sf_done);
}

/**
Expand Down Expand Up @@ -246,7 +246,7 @@ struct promise_base : basic_promise<R> {
*
* @return <a href="https://en.cppreference.com/w/cpp/coroutine/suspend_never">std::suspend_never</a> Don't suspend, the coroutine starts immediately.
*/
[[nodiscard]] std_coroutine::suspend_never initial_suspend() const noexcept {
std_coroutine::suspend_never initial_suspend() const noexcept {
return {};
}

Expand Down
62 changes: 33 additions & 29 deletions include/dpp/coro/when_any.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,23 +53,23 @@ namespace when_any {
/**
* @brief Current state of a when_any object
*/
enum class await_state {
/**
* @brief Object was started but not awaited
*/
started,
enum await_state : uint8_t {
/**
* @brief Object is being awaited
*/
waiting,
waiting = 1 << 0,
/**
* @brief Object was resumed
*/
done,
done = 1 << 1,
/**
* @brief Result is ready to retrieve
*/
ready = 1 << 2,
/**
* @brief Object was destroyed
*/
dangling
dangling = 1 << 3
};

/**
Expand Down Expand Up @@ -197,7 +197,7 @@ class when_any {
*
* @see detail::when_any::await_state
*/
std::atomic<detail::when_any::await_state> owner_state{detail::when_any::await_state::started};
std::atomic<uint8_t> owner_state{};
};

/**
Expand All @@ -212,15 +212,17 @@ class when_any {
* @return dpp::job Job handling the Nth argument
*/
template <size_t N>
static dpp::job make_job(std::shared_ptr<state_t> shared_state) {
static job make_job(std::shared_ptr<state_t> shared_state) {
using namespace detail::when_any;

/**
* Any exceptions from the awaitable's await_suspend should be thrown to the caller (the coroutine creating the when_any object)
* If the co_await passes, and it is the first one to complete, try construct the result, catch any exceptions to rethrow at resumption, and resume.
*/
if constexpr (!std::same_as<result_t<N>, detail::when_any::empty>) {
if constexpr (!std::same_as<result_t<N>, empty>) {
decltype(auto) result = co_await std::get<N>(shared_state->awaitables);

if (auto s = shared_state->owner_state.load(std::memory_order_relaxed); s == detail::when_any::await_state::dangling || s == detail::when_any::await_state::done) {
if (auto s = shared_state->owner_state.fetch_or(await_state::done, std::memory_order_relaxed); (s & (await_state::done | await_state::dangling)) != 0) {
co_return;
}

Expand All @@ -238,20 +240,17 @@ class when_any {
}
} else {
co_await std::get<N>(shared_state->awaitables);

if (auto s = shared_state->owner_state.load(std::memory_order_relaxed); s == detail::when_any::await_state::dangling || s == detail::when_any::await_state::done) {
if (auto s = shared_state->owner_state.fetch_or(await_state::done, std::memory_order_relaxed); (s & (await_state::done | await_state::dangling)) != 0) {
co_return;
}

shared_state->result.template emplace<N + 1>();
}

if (shared_state->owner_state.exchange(detail::when_any::await_state::done) != detail::when_any::await_state::waiting) {
co_return;
}

if (auto handle = shared_state->handle; handle) {
shared_state->index_finished = N;
shared_state->index_finished = N;
if (auto s = shared_state->owner_state.fetch_or(await_state::ready, std::memory_order_acq_rel); (s & (await_state::waiting)) != 0) {
assert(shared_state->handle);
shared_state->handle.resume();
}
}
Expand All @@ -261,9 +260,12 @@ class when_any {
* Each of them will co_await the awaitable and set the result if they are the first to finish
*/
void make_jobs() {
[]<size_t... Ns>(when_any *self, std::index_sequence<Ns...>) {
(make_job<Ns>(self->my_state), ...);
}(this, std::index_sequence_for<Args...>{});
constexpr auto impl = []<size_t... Ns>(when_any *self, std::index_sequence<Ns...>) {
// We create an array to guarantee evaluation order here
// https://eel.is/c++draft/dcl.init.aggr#7
[[maybe_unused]] dpp::job jobs[] = { make_job<Ns>(self->my_state)... };
};
impl(this, std::index_sequence_for<Args...>{});
}

public:
Expand Down Expand Up @@ -417,9 +419,11 @@ class when_any {
* @return bool Returns false if we want to resume immediately.
*/
bool await_suspend(detail::std_coroutine::coroutine_handle<> caller) noexcept {
auto sent = detail::when_any::await_state::started;
using namespace detail::when_any;

self->my_state->handle = caller;
return self->my_state->owner_state.compare_exchange_strong(sent, detail::when_any::await_state::waiting); // true (suspend) if `started` was replaced with `waiting` -- false (resume) if the value was not `started` (`done` is the only other option)
auto prev = self->my_state->owner_state.fetch_or(await_state::waiting, std::memory_order_acq_rel);
return (prev & await_state::ready) == 0; // true (suspend) if the state was not `ready` -- false (resume) if it was
}

/**
Expand All @@ -428,7 +432,7 @@ class when_any {
* @see result
*/
result await_resume() const noexcept {
return {self->my_state};
return { self->my_state };
}
};

Expand All @@ -448,7 +452,7 @@ class when_any {
#ifndef _DOXYGEN_
requires (sizeof...(Args_) == sizeof...(Args))
#endif /* _DOXYGEN_ */
when_any(Args_&&... args) : my_state{std::make_shared<state_t>(detail::when_any::arg_helper<Args_>::get(std::forward<Args_>(args))...)} {
when_any(Args_&&... args) : my_state{ std::make_shared<state_t>(detail::when_any::arg_helper<Args_>::get(std::forward<Args_>(args))...) } {
make_jobs();
}

Expand Down Expand Up @@ -506,7 +510,7 @@ class when_any {
* @return bool Whether co_await would suspend
*/
[[nodiscard]] bool await_ready() const noexcept {
return my_state->owner_state == detail::when_any::await_state::done;
return (my_state->owner_state.load(std::memory_order_acquire) & detail::when_any::await_state::ready) != 0;
}

/**
Expand All @@ -517,7 +521,7 @@ class when_any {
* @return result On resumption, this object returns an object that allows to retrieve the index and result of the awaitable.
*/
[[nodiscard]] awaiter operator co_await() noexcept {
return {this};
return { this };
}
};

Expand Down
2 changes: 1 addition & 1 deletion include/dpp/http_server.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ namespace dpp {
* plaintext or SSL incoming request, and passes that request to a callback
* to generate the response.
*/
struct http_server : public socket_listener<http_server_request> {
struct DPP_EXPORT http_server : public socket_listener<http_server_request> {

/**
* @brief Request handler callback to use for all incoming HTTP(S) requests
Expand Down
2 changes: 2 additions & 0 deletions include/dpp/socket.h
Original file line number Diff line number Diff line change
Expand Up @@ -190,5 +190,7 @@ struct DPP_EXPORT raii_socket {
~raii_socket();
};

extern template DPP_EXPORT bool raii_socket::set_option<int>(int level, int name, int value);


}
5 changes: 3 additions & 2 deletions include/dpp/ssl_context.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
*
************************************************************************************/
#pragma once
#include <dpp/export.h>

Check notice on line 23 in include/dpp/ssl_context.h

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

include/dpp/ssl_context.h#L23

Include file: <dpp/export.h> not found. Please note: Cppcheck does not need standard library headers to get proper results.
#include <string>
#include <cstdint>

Expand All @@ -39,14 +40,14 @@
* @param public_key Public key PEM pathname for server contexts
* @return wrapped SSL context
*/
wrapped_ssl_ctx* generate_ssl_context(uint16_t port = 0, const std::string &private_key = "", const std::string &public_key = "");
DPP_EXPORT wrapped_ssl_ctx* generate_ssl_context(uint16_t port = 0, const std::string &private_key = "", const std::string &public_key = "");

/**
* @brief Release an SSL context
* @warning Only do this if you are certain no SSL connections remain that use this context.
* As OpenSSL is a C library it is impossible for us to track this on its behalf. Be careful!
* @param port port number to release
*/
void release_ssl_context(uint16_t port = 0);
DPP_EXPORT void release_ssl_context(uint16_t port = 0);

};
Loading