Skip to content

Commit

Permalink
Add async_auto_reset_event.
Browse files Browse the repository at this point in the history
  • Loading branch information
lewissbaker committed Jul 21, 2017
1 parent be43f4a commit 4b20a24
Show file tree
Hide file tree
Showing 6 changed files with 596 additions and 0 deletions.
70 changes: 70 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ These include:
* `single_consumer_event`
* `async_mutex`
* `async_manual_reset_event` (coming)
* `async_auto_reset_event`
* Functions
* `when_all()` (coming)
* Cancellation
Expand Down Expand Up @@ -753,6 +754,75 @@ cppcoro::task<> add_item(std::string value)
}
```

## `async_auto_reset_event`

An auto-reset event is a coroutine/thread-synchronisation abstraction that allows one or more threads
to wait until the event is signalled by a thread by calling `set()`.

Once a coroutine that is awaiting the event is released by either a prior or subsequent call to `set()`
the event is automatically reset back to the 'not set' state.

API Summary:
```c++
// <cppcoro/async_auto_reset_event.hpp>
namespace cppcoro
{
class async_auto_reset_event_operation;

class async_auto_reset_event
{
public:

async_auto_reset_event(bool initiallySet = false) noexcept;

~async_auto_reset_event();

async_auto_reset_event(const async_auto_reset_event&) = delete;
async_auto_reset_event(async_auto_reset_event&&) = delete;
async_auto_reset_event& operator=(const async_auto_reset_event&) = delete;
async_auto_reset_event& operator=(async_auto_reset_event&&) = delete;

// Wait for the event to enter the 'set' state.
//
// If the event is already 'set' then the event is set to the 'not set'
// state and the awaiting coroutine continues without suspending.
// Otherwise, the coroutine is suspended and later resumed when some
// thread calls 'set()'.
//
// Note that the coroutine may be resumed inside a call to 'set()'
// or inside another thread's call to 'operator co_await()'.
async_auto_reset_event_operation operator co_await() const noexcept;

// Set the state of the event to 'set'.
//
// If there are pending coroutines awaiting the event then one
// pending coroutine is resumed and the state is immediately
// set back to the 'not set' state.
//
// This operation is a no-op if the event was already 'set'.
void set() noexcept;

// Set the state of the event to 'not-set'.
//
// This is a no-op if the state was already 'not set'.
void reset() noexcept;

};

class async_auto_reset_event_operation
{
public:
explicit async_auto_reset_event_operation(async_auto_reset_event& event) noexcept;
async_auto_reset_event_operation(const async_auto_reset_event_operation& other) noexcept;

bool await_ready() const noexcept;
bool await_suspend(std::experimental::coroutine_handle<> awaiter) noexcept;
void await_resume() const noexcept;

};
}
```
## `cancellation_token`
A `cancellation_token` is a value that can be passed to a function that allows the caller to subsequently communicate a request to cancel the operation to that function.
Expand Down
98 changes: 98 additions & 0 deletions include/cppcoro/async_auto_reset_event.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
///////////////////////////////////////////////////////////////////////////////
// Copyright (c) Lewis Baker
// Licenced under MIT license. See LICENSE.txt for details.
///////////////////////////////////////////////////////////////////////////////
#ifndef CPPCORO_ASYNC_AUTO_RESET_EVENT_HPP_INCLUDED
#define CPPCORO_ASYNC_AUTO_RESET_EVENT_HPP_INCLUDED

#include <experimental/coroutine>
#include <atomic>
#include <cstdint>

namespace cppcoro
{
class async_auto_reset_event_operation;

/// An async auto-reset event is a coroutine synchronisation abstraction
/// that allows one or more coroutines to wait until some thread calls
/// set() on the event.
///
/// When a coroutine awaits a 'set' event the event is automatically
/// reset back to the 'not set' state, thus the name 'auto reset' event.
class async_auto_reset_event
{
public:

/// Initialise the event to either 'set' or 'not set' state.
async_auto_reset_event(bool initiallySet = false) noexcept;

~async_auto_reset_event();

/// Wait for the event to enter the 'set' state.
///
/// If the event is already 'set' then the event is set to the 'not set'
/// state and the awaiting coroutine continues without suspending.
/// Otherwise, the coroutine is suspended and later resumed when some
/// thread calls 'set()'.
///
/// Note that the coroutine may be resumed inside a call to 'set()'
/// or inside another thread's call to 'operator co_await()'.
async_auto_reset_event_operation operator co_await() const noexcept;

/// Set the state of the event to 'set'.
///
/// If there are pending coroutines awaiting the event then one
/// pending coroutine is resumed and the state is immediately
/// set back to the 'not set' state.
///
/// This operation is a no-op if the event was already 'set'.
void set() noexcept;

/// Set the state of the event to 'not-set'.
///
/// This is a no-op if the state was already 'not set'.
void reset() noexcept;

private:

friend class async_auto_reset_event_operation;

void resume_waiters(std::uint64_t initialState) const noexcept;

// Bits 0-31 - Set count
// Bits 32-63 - Waiter count
mutable std::atomic<std::uint64_t> m_state;

mutable std::atomic<async_auto_reset_event_operation*> m_newWaiters;

mutable async_auto_reset_event_operation* m_waiters;

};

class async_auto_reset_event_operation
{
public:

async_auto_reset_event_operation() noexcept;

explicit async_auto_reset_event_operation(const async_auto_reset_event& event) noexcept;

async_auto_reset_event_operation(const async_auto_reset_event_operation& other) noexcept;

bool await_ready() const noexcept { return m_event == nullptr; }
bool await_suspend(std::experimental::coroutine_handle<> awaiter) noexcept;
void await_resume() const noexcept {}

private:

friend class async_auto_reset_event;

const async_auto_reset_event* m_event;
async_auto_reset_event_operation* m_next;
std::experimental::coroutine_handle<> m_awaiter;
std::atomic<std::uint32_t> m_refCount;

};
}

#endif
Loading

0 comments on commit 4b20a24

Please sign in to comment.