2 #include "prepared_coro.h"
65 operator bool()
const {
return _inst !=
nullptr;}
69 mutex *_inst =
nullptr;
100 return std::move(
lock().get());
104 class awaiter :
public future<ownership> {
108 return static_cast<awaiter *
>(x);
113 static awaiter *
locked() {
return reinterpret_cast<awaiter *
>(0x1);}
119 std::atomic<awaiter *>
_req = {
nullptr};
132 awaiter *need =
nullptr;
133 return _req.compare_exchange_strong(need,
locked(), std::memory_order_acquire);
147 awaiter *awt = awaiter::from_future(fut_awt);
148 awaiter *nx =
nullptr;
149 while (!
_req.compare_exchange_weak(nx, awt, std::memory_order_relaxed)) {
174 r = awaiter::from_future(n);
190 if (
_req.compare_exchange_strong(need,
nullptr, std::memory_order_release))
return {};
194 _que =
static_cast<awaiter *
>(
_que->_chain);
205 template<
typename T,
typename Tuple>
struct tuple_add;
206 template<
typename T,
typename ... Us>
struct tuple_add<T, std::tuple<Us...> > {
207 using type = std::tuple<T, Us...>;
210 template <
typename Tuple>
struct make_unique_types;
211 template <
typename T,
typename... Us>
struct make_unique_types<std::tuple<T, Us...> > {
212 using type = std::conditional_t<
213 (std::is_same_v<T, Us> || ...),
214 typename make_unique_types<std::tuple<Us ...> >::type,
215 typename tuple_add<T,
typename make_unique_types<std::tuple<Us...> >::type>::type>;
218 template <>
struct make_unique_types< std::tuple<> > {
219 using type = std::tuple<>;
222 template<
typename Tuple>
struct make_variant_from_tuple;
223 template<
typename ... Ts>
struct make_variant_from_tuple<std::tuple<Ts...> > {
224 using type = std::variant<Ts...>;
226 template<
typename ... Ts>
using variant_of_t =
typename make_variant_from_tuple<
227 typename make_unique_types<std::tuple<Ts...> >::type>::type;
231 template<
typename ... Mutexes>
232 class lock:
public future<std::tuple<decltype(std::declval<Mutexes>().try_lock())...> > {
235 using ownership = std::tuple<decltype(std::declval<Mutexes>().try_lock())...>;
236 using future_variant = _details::variant_of_t<std::monostate,
237 decltype(std::declval<Mutexes>().lock())...>;
239 lock(Mutexes & ... lst):_mxlist(lst...),_prom(this->
get_promise()) {
241 if (finish_lock(-1, ownlist)) {
242 _prom(std::move(ownlist));
248 std::tuple<Mutexes &...> _mxlist;
249 promise<ownership> _prom;
258 auto &mx = std::get<idx>(_mxlist);
259 using LkType = decltype(mx.lock());
261 std::get<idx>(ownlist) = std::get<LkType>(_fut).await_resume();
262 if (finish_lock(idx,ownlist)) {
263 _prom(std::move(ownlist));
275 template<
int idx = 0>
276 bool finish_lock(
int skip, ownership &ownlist) {
278 if constexpr(idx >= std::tuple_size_v<ownership>) {
283 return finish_lock<idx+1>(skip,ownlist);
286 auto &own = std::get<idx>(ownlist);
288 auto &mx = std::get<idx>(_mxlist);
290 own = std::get<idx>(_mxlist).try_lock();
294 return finish_lock<idx+1>(skip,ownlist);
297 using LkType = decltype(mx.lock());
299 _fut.template emplace<LkType>();
300 LkType &fut = std::get<LkType>(_fut);
302 fut << [&]{
return mx.lock();};
304 if (fut.set_callback([
this]{ on_lock<idx>();}) ==
false) {
308 return finish_lock<idx+1>(skip,ownlist);
promise_t get_promise()
Retrieve promise and begin evaluation.
~ownership()
dtor releases ownership
ownership()=default
ownership can be default constructed
void release()
releases ownership explicitly (unlock)
ownership(ownership &&x)
ownership can be moved
ownership & operator=(ownership &&x)
ownership can be assigned by move
ownership lock_sync()
lock synchronously
future< ownership > lock()
lock the mutex, retrieve future ownership
ownership try_lock()
try to lock
awaiter * _que
contains queue of requests already registered by the lock
promise< ownership >::notify do_lock(future< ownership > *fut_awt)
initiate lock operation
void build_queue(awaiter *r, awaiter *stop)
builds internal queue
std::atomic< awaiter * > _req
static awaiter * locked()
generates special pointer, which is used as locked flag (value 0x00000001)
promise< ownership >::notify unlock()
unlock the lock
ownership make_ownership()
creates ownership object
bool try_acquire()
tries to acquire
Mutex which allows locking across co_await and co_yield suspend points.
FutureType * release()
Release the future pointer from the promise object.
Carries reference to future<T>, callable, sets value of an associated future<T>