Skip to content

Commit

Permalink
Nested exceptions.
Browse files Browse the repository at this point in the history
  • Loading branch information
jnbrq committed Oct 2, 2023
1 parent 11a5c7e commit c08cf5e
Show file tree
Hide file tree
Showing 14 changed files with 215 additions and 212 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ libcxxdes tries to provide the complete feature set of SimPy, it currently suppo
`co_await sequential(p1(), p2(), ...)`, `co_await (p1(), p2(), ...)`
- Timeouts:
`co_await delay(5)`, `co_await timeout(5_s)`
3. Interruptable coroutines which are useful for modelling preemptive resources.
3. Interruptable coroutines which are useful for modelling preemptive resources. --Not feasible to implement. Use || with a queue, same thing.
4. Priority-scheduling of events that take place at the same simulation time. `coroutine<T>` can be assigned priorities! (lower the number, higher the priority)
5. `time_unit()` and `time_precision()` functions for mapping simulation time (integer) to real-world time.
6. Synchronization primitives, such as `mutex`, `semaphore`, `queue<T>`, and `event`.
Expand Down
152 changes: 152 additions & 0 deletions examples/exceptions.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
#include <cxxdes/cxxdes.hpp>
#include <fmt/core.h>

using namespace cxxdes::core;

subroutine<> f()
{
throw std::runtime_error("f has thrown an exception!");
co_return;
}

subroutine<> g()
{
co_await f();
}

coroutine<> h()
{
try
{
co_await g();
}
catch (std::exception &ex)
{
fmt::println("[h] Exception: {}", ex.what());
}

throw std::runtime_error("h has thrown an exception!");
}

coroutine<> co_main()
{
try
{
co_await h();
}
catch (std::exception &ex)
{
fmt::println("[co_main] Exception: {}", ex.what());
}

throw std::runtime_error("[co_main] co_main has thrown an exception!");
}

void nestedExceptions()
{
fmt::println("test: nested exceptions");

environment env;
env.bind(co_main());

try
{
env.run();
}
catch (std::exception &ex)
{
fmt::println("[nestedExceptions] Exception: {}", ex.what());
}
}

void stopping()
{
fmt::println("test: stopping");

auto coro = []() -> coroutine<>
{
fmt::println("hey!");
co_await timeout(50);
// executes no more from here
co_await timeout(100);
fmt::println("should not be printed");
}();

environment env;
env.bind(coro);

env.run_for(1);
}

void asynchronous1()
{
fmt::println("test: asynchronous1");

auto coro = []() -> coroutine<>
{
auto coro2 = []() -> coroutine<>
{
co_await timeout(2);
fmt::println("coro2 $0");
throw std::runtime_error("coro2 has thrown an exception");
fmt::println("coro2 $1");
}();

co_await (timeout(1) || coro2);
fmt::println("coro done");
}();

environment env;
env.bind(coro);

try
{
env.run();
}
catch (std::exception &ex)
{
fmt::println("[asynchronous] Exception: {}", ex.what());
}
}

void asynchronous2()
{
fmt::println("test: asynchronous2");

auto coro = []() -> coroutine<>
{
auto coro2 = []() -> coroutine<>
{
co_await timeout(2);
fmt::println("coro2 $0");
throw std::runtime_error("coro2 has thrown an exception");
fmt::println("coro2 $1");
}();
co_await async(coro2);
fmt::println("coro done");

// since we did not await coro2, no completion token could
// be generated. that is, the exception is lost.
}();

environment env;
env.bind(coro);

try
{
env.run();
}
catch (std::exception &ex)
{
fmt::println("[asynchronous2] Exception: {}", ex.what());
}
}

int main()
{
nestedExceptions();
stopping();
asynchronous1();
asynchronous2();
return 0;
}
55 changes: 2 additions & 53 deletions examples/pitfall.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,48 +25,6 @@ CXXDES_SIMULATION(pitfall) {

#define _TrackLocation cxxdes::util::source_location const = cxxdes::util::source_location::current()

CXXDES_SIMULATION(interrupts) {
using simulation::simulation;

coroutine<> foo(_TrackLocation) {
try {
while (true) {
fmt::print("now: {}\n", now());
co_await delay(1);
}
}
catch (interrupted_exception &err) {
fmt::print("exception: {}\n", err.what());
co_return ;
}
}

coroutine<> bar(_TrackLocation) {
try {
co_await delay(100);
}
catch (interrupted_exception &err) {
fmt::print("exception: {}\n", err.what());
co_return ;
}
}

coroutine<> co_main(_TrackLocation) {
{
coroutine<> h = co_await async(foo());
co_await delay(5);
h.interrupt();
}

{
coroutine<> h = co_await async(bar());
co_await delay(5);
h.interrupt(interrupted_exception("interrupted!"));
// h.interrupt(std::runtime_error("what?"));
}
}
};

CXXDES_SIMULATION(subroutines) {
using simulation::simulation;

Expand Down Expand Up @@ -102,14 +60,8 @@ CXXDES_SIMULATION(subroutines2) {
using simulation::simulation;

subroutine<int> foo() {
try {
co_await delay(600);
co_await delay(600);
}
catch (cxxdes::core::stopped_exception &ex) {
fmt::print("exception: {}, now {}\n", ex.what(), now());
throw ex;
}
co_await delay(600);
co_await delay(600);
co_return 20;
}

Expand Down Expand Up @@ -165,9 +117,6 @@ int main() {
fmt::print("pitfall\n");
pitfall::run();

fmt::print("interrupts\n");
interrupts::run_for(500);

fmt::print("subroutines\n");
subroutines::run();

Expand Down
2 changes: 1 addition & 1 deletion examples/subroutine.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#include <coroutine>
#include <fmt/core.h>
#include <stack>
#include <fmt/core.h>

std::stack<std::coroutine_handle<>> call_stack;

Expand Down
5 changes: 0 additions & 5 deletions include/cxxdes/core/core.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
#include <unordered_set>
#include <cstddef>
#include <memory>
#include <stack>
#include <string>

#include <cxxdes/misc/time.hpp>
Expand Down Expand Up @@ -59,9 +58,6 @@ struct token;
template <typename T>
struct immediately_return;

struct interrupted_exception;
struct stopped_exception;

struct coroutine_data;
using coroutine_data_ptr = memory::ptr<coroutine_data>;
using const_coroutine_data_ptr = memory::ptr<const coroutine_data>;
Expand All @@ -82,7 +78,6 @@ struct subroutine;

#include "impl/token.ipp"
#include "impl/immediately_return.ipp"
#include "impl/exception_types.ipp"
#include "impl/coroutine_data.ipp"
#include "impl/environment.ipp"
#include "impl/timeout.ipp"
Expand Down
6 changes: 6 additions & 0 deletions include/cxxdes/core/impl/any_of.ipp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,12 @@ struct any_all_helper {

void invoke(token *tkn) override {
--remaining;

if (tkn->eptr) {
// in case an argument of all/any of throws an exception
// this must be handled by main.
std::rethrow_exception(tkn->eptr);
}

if (completion_tkn && Condition::operator()(total, remaining)) {
// inherit the output_event features
Expand Down
2 changes: 0 additions & 2 deletions include/cxxdes/core/impl/await_transform.ipp
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,6 @@ struct awaitable_wrapper {
}

auto await_resume() {
if (coro_data_this->interrupted())
coro_data_this->raise_interrupt_();
return a.await_resume();
}
};
Expand Down
37 changes: 16 additions & 21 deletions include/cxxdes/core/impl/coroutine.ipp
Original file line number Diff line number Diff line change
Expand Up @@ -76,16 +76,6 @@ struct coroutine:
return coro_data_->complete();
}

template <typename T = interrupted_exception>
void interrupt(T &&t = interrupted_exception{}) noexcept {
coro_data_->interrupt(std::forward<T>(t));
}

[[nodiscard]]
bool interrupted() const noexcept {
return coro_data_->interrupted();
}

[[nodiscard]]
priority_type priority() const noexcept {
return coro_data_->priority();
Expand Down Expand Up @@ -194,8 +184,17 @@ struct coroutine:
}
}

void await_resume(no_return_value_tag) noexcept {
completion_token_ = nullptr;
void await_resume(no_return_value_tag) {
if (completion_token_) {
auto tkn = completion_token_;
completion_token_ = nullptr;

/* If coro_data is missing from the following condition,
* it fails segv. But this should not be the case. */
if (tkn->coro_data && tkn->eptr) {
std::rethrow_exception(tkn->eptr);
}
}
}

private:
Expand Down Expand Up @@ -250,15 +249,11 @@ public:
auto final_suspend() noexcept -> std::suspend_never { return {}; }

auto unhandled_exception() -> void {
try {
std::rethrow_exception(std::current_exception());
}
catch (stopped_exception & /* ex */) {
do_return();
}
catch (...) {
std::rethrow_exception(std::current_exception());
}
// update completion tokens with the current exception
coro_data->propagate_exception(std::current_exception());

// schedule the completion tokens
coro_data->do_return();
}

template <typename T>
Expand Down
Loading

0 comments on commit c08cf5e

Please sign in to comment.