Changeset View
Changeset View
Standalone View
Standalone View
source/ps/Execution/SyncWait.h
- This file was added.
/* Copyright (C) 2022 Wildfire Games. | |||||
* This file is part of 0 A.D. | |||||
* | |||||
* 0 A.D. is free software: you can redistribute it and/or modify | |||||
* it under the terms of the GNU General Public License as published by | |||||
* the Free Software Foundation, either version 2 of the License, or | |||||
* (at your option) any later version. | |||||
* | |||||
* 0 A.D. is distributed in the hope that it will be useful, | |||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
* GNU General Public License for more details. | |||||
* | |||||
* You should have received a copy of the GNU General Public License | |||||
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#ifndef INCLUDED_EXECUTION_SYNC_WAIT | |||||
#define INCLUDED_EXECUTION_SYNC_WAIT | |||||
#include "ps/Execution/Execution.h" | |||||
#include <boost/optional.hpp> | |||||
#include <boost/variant.hpp> | |||||
#include <condition_variable> | |||||
#include <exception> | |||||
#include <mutex> | |||||
namespace PS | |||||
{ | |||||
namespace Execution | |||||
{ | |||||
namespace SyncWait | |||||
{ | |||||
template<typename Result> | |||||
class Receiver | |||||
jprahman: Receiver here looks like an internal implementation detail, do we typically hide these sorts of… | |||||
{ | |||||
public: | |||||
Receiver(std::mutex& mutex, std::condition_variable& condVar, bool& done, | |||||
boost::optional<boost::variant<HandleVoid<Wrapper<Result>>, std::exception_ptr>>& result) : | |||||
m_Mutex(mutex), | |||||
m_CondVar(condVar), | |||||
m_Done(done), | |||||
m_Result(result) | |||||
{} | |||||
template<typename... Res> | |||||
void SetValue(Res&&... res) | |||||
{ | |||||
{ | |||||
std::lock_guard lock{m_Mutex}; | |||||
jprahmanUnsubmitted Not Done Inline ActionsCouldn't the lock guard be moved down to just before line 63 since only m_Done participates in the condition_variable::wait() call? jprahman: Couldn't the lock guard be moved down to just before line 63 since only m_Done participates in… | |||||
if constexpr (sizeof...(Res) == 0) | |||||
{ | |||||
static_assert(std::is_void_v<Result>); | |||||
m_Result.emplace(VoidTag{}); | |||||
} | |||||
else | |||||
{ | |||||
static_assert(sizeof...(Res) == 1 && std::is_same_v<Res..., Result>); | |||||
m_Result.emplace(std::forward<Res...>(res...)); | |||||
} | |||||
m_Done = true; | |||||
} | |||||
m_CondVar.notify_one(); | |||||
} | |||||
void SetError(std::exception_ptr ex) | |||||
{ | |||||
{ | |||||
std::lock_guard lock{m_Mutex}; | |||||
m_Result.emplace(ex); | |||||
m_Done = true; | |||||
} | |||||
m_CondVar.notify_one(); | |||||
} | |||||
void SetDone() | |||||
{ | |||||
{ | |||||
std::lock_guard lock{m_Mutex}; | |||||
m_Done = true; | |||||
} | |||||
m_CondVar.notify_one(); | |||||
} | |||||
private: | |||||
std::mutex& m_Mutex; | |||||
std::condition_variable& m_CondVar; | |||||
bool& m_Done; | |||||
boost::optional<boost::variant<HandleVoid<Wrapper<Result>>, std::exception_ptr>>& m_Result; | |||||
}; | |||||
struct Fn : MakeSenderAdaptor<Fn> | |||||
{ | |||||
template<typename Send> | |||||
boost::optional<HandleVoid<Wrapper<ResultTypeOf<std::remove_reference_t<Send>>>>> | |||||
operator ()(Send&& send) const | |||||
{ | |||||
using ResultType = ResultTypeOf<std::remove_reference_t<Send>>; | |||||
std::mutex mutex; | |||||
std::condition_variable condVar; | |||||
bool done = false; | |||||
boost::optional<boost::variant<HandleVoid<Wrapper<ResultType>>, std::exception_ptr>> result; | |||||
auto state = std::forward<Send>(send).Connect( | |||||
SyncWait::Receiver<ResultType>{mutex, condVar, done, result}); | |||||
state.Start(); | |||||
std::unique_lock lock{mutex}; | |||||
Lint: localMutex The lock is ineffective because the mutex is locked at the same scope as the mutex itself. Lint: localMutex: The lock is ineffective because the mutex is locked at the same scope as the mutex itself. | |||||
Lint: localMutex The lock is ineffective because the mutex is locked at the same scope as the mutex itself. Lint: localMutex: The lock is ineffective because the mutex is locked at the same scope as the mutex itself. | |||||
Lint: localMutex The lock is ineffective because the mutex is locked at the same scope as the mutex itself. Lint: localMutex: The lock is ineffective because the mutex is locked at the same scope as the mutex itself. | |||||
condVar.wait(lock, [&done]{return done;}); | |||||
if (!result) | |||||
return boost::none; | |||||
if (result.get().which() == 0) | |||||
return boost::get<HandleVoid<Wrapper<ResultType>>>(result.get()); | |||||
std::rethrow_exception(boost::get<std::exception_ptr>(result.get())); | |||||
} | |||||
using MakeSenderAdaptor<Fn>::operator(); | |||||
}; | |||||
} // SyncWait | |||||
constexpr SyncWait::Fn syncWait; | |||||
} | |||||
} | |||||
#endif // INCLUDED_EXECUTION_SYNC_WAIT |
Wildfire Games · Phabricator
Receiver here looks like an internal implementation detail, do we typically hide these sorts of things inside a "namespace detail" sub-namespace?