Skip to content

Commit

Permalink
task_detach_start (#24)
Browse files Browse the repository at this point in the history
* task_detach_start
  • Loading branch information
kelbon authored Aug 9, 2024
1 parent b3fc8d8 commit b440bde
Show file tree
Hide file tree
Showing 4 changed files with 63 additions and 2 deletions.
10 changes: 9 additions & 1 deletion include/kelcoro/common.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,15 @@ struct [[nodiscard("co_await it!")]] transfer_control_to {
assert(who_waits != nullptr);
return false;
}
KELCORO_ASSUME_NOONE_SEES std::coroutine_handle<> await_suspend(std::coroutine_handle<>) noexcept {
KELCORO_ASSUME_NOONE_SEES std::coroutine_handle<> await_suspend(std::coroutine_handle<> h) noexcept {
if (who_waits.done()) [[unlikely]] {
(void)h;
assert(h == who_waits);
// only possible on gcc/clang when compiler passes handle on final suspend point
// standard says it should be legal to just return handle to continue coroutine and free memory
who_waits.destroy();
return std::noop_coroutine();
}
return who_waits; // symmetric transfer here
}
static constexpr void await_resume() noexcept {
Expand Down
15 changes: 14 additions & 1 deletion include/kelcoro/noexcept_task.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,20 @@ struct noexcept_task : enable_resource_deduction {
[[nodiscard]] handle_type release() noexcept {
return std::exchange(handle_, nullptr);
}

#if defined(__GNUC__) || defined(__clang__)
// postcondition: empty(), task result ignored
// returns released task handle
// if stop_at_end is false, then task will delete itself at end, otherwise handle.destroy() should be called
handle_type start_and_detach(bool stop_at_end = false) {
if (!handle_)
return nullptr;
handle_type h = std::exchange(handle_, nullptr);
// task resumes itself at end and destroys itself or just stops with noop_coroutine
h.promise().who_waits = stop_at_end ? std::noop_coroutine() : std::coroutine_handle<>(h);
h.resume();
return h;
}
#endif
// blocking
result_type get() noexcept {
assert(!empty());
Expand Down
14 changes: 14 additions & 0 deletions include/kelcoro/task.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,20 @@ struct task : enable_resource_deduction {
return std::exchange(handle_, nullptr);
}

#if defined(__GNUC__) || defined(__clang__)
// postcondition: empty(), task result ignored
// returns released task handle
// if stop_at_end is false, then task will delete itself at end, otherwise handle.destroy() should be called
handle_type start_and_detach(bool stop_at_end = false) {
if (!handle_)
return nullptr;
handle_type h = std::exchange(handle_, nullptr);
// task resumes itself at end and destroys itself or just stops with noop_coroutine
h.promise().who_waits = stop_at_end ? std::noop_coroutine() : std::coroutine_handle<>(h);
h.resume();
return h;
}
#endif
// blocking
result_type get() {
assert(!empty());
Expand Down
26 changes: 26 additions & 0 deletions tests/test_coroutines.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -458,6 +458,31 @@ TEST(task_blocking_wait_noexcept) {
return error_count;
}

TEST(task_start_and_detach) {
std::atomic_bool flag = false;
dd::task task = [](std::atomic_bool& flag) -> dd::task<void> {
(void)co_await dd::jump_on(dd::new_thread_executor);
flag.exchange(true);
(void)co_await dd::jump_on(dd::new_thread_executor);
dd::scope_exit e = [&] { flag.notify_one(); };
}(flag);
task.start_and_detach();
error_if(!task.empty());
flag.wait(false);
int x = 0;
dd::task task2 = [](int& x) -> dd::task<void> {
x = 42;
co_return;
}(x);
error_if(x != 0);
std::coroutine_handle h = task2.start_and_detach(/*stop_at_end=*/true);
error_if(!task2.empty());
error_if(x != 42);
error_if(!h.done());
h.destroy();
return error_count;
}

TEST(task_blocking_wait) {
error_if(do_smth().get() != "hello from task");
return error_count;
Expand Down Expand Up @@ -554,6 +579,7 @@ int main() {
ec += TESTtask_blocking_wait();
ec += TESTtask_with_exception();
ec += TESTtask_blocking_wait_noexcept();
ec += TESTtask_start_and_detach();
return ec;
}
#else
Expand Down

0 comments on commit b440bde

Please sign in to comment.