diff --git a/emper/io/Future.cpp b/emper/io/Future.cpp index 50870da12840b081c539b263cf88ca3dd9d95bfc..71a6dab8e053b1745028ffecc0afd53fa7b05959 100644 --- a/emper/io/Future.cpp +++ b/emper/io/Future.cpp @@ -88,7 +88,7 @@ auto Future::cancel() -> int32_t { state.cancelled = true; if (!isSubmitted() || isForgotten()) { - LOGW("Cancelling unsubmitted or forgotten " << this); + LOGW("Cancelling " << (isForgotten() ? "forgotten " : "unsubmitted ") << this); return -ENOENT; } diff --git a/emper/io/Future.hpp b/emper/io/Future.hpp index d0978de740cc9c636b812765ef2cb6d3fa76d723..c559ba996e9e7b57ac5f6dd30f3cbd34b2a91822 100644 --- a/emper/io/Future.hpp +++ b/emper/io/Future.hpp @@ -137,12 +137,12 @@ class Future : public Logger<LogSubsystem::IO> { // only if callback is set and if callback is set ~Future does not call cancel. // NOLINTNEXTLINE(bugprone-exception-escape) virtual ~Future() { - if (isForgotten() || callback) { + if (isForgotten() || isRetrieved() || isCancelled() || callback) { return; } if constexpr (emper::DEBUG) { - if (!isRetrieved() && !isDependency() && !isCancelled()) { + if (!isDependency()) { LOGE(this << " created but never awaited"); abort(); } diff --git a/tests/io/CancelFutureTest.cpp b/tests/io/CancelFutureTest.cpp index 0ff9b09f38367b7a8b37a2ebd9662472847fb371..829a8a9f3ff2e3fa27f98d33c0a1b6797973100f 100644 --- a/tests/io/CancelFutureTest.cpp +++ b/tests/io/CancelFutureTest.cpp @@ -12,44 +12,55 @@ using emper::io::ReadFuture; using emper::io::WriteFuture; -void emperTest() { - int efd = eventfd(0, 0); - if (efd == -1) { - DIE_MSG_ERRNO("eventfd failed"); - } +int efd; +uint64_t read_buf; +uint64_t write_buf = 42; - uint64_t read_buf; - uint64_t write_buf = 42; - // cancel not submitted Future +void cancelNotSubmitted() { ReadFuture readFuture(efd, &read_buf, sizeof(read_buf), 0); assert(readFuture.cancel() == -ENOENT); +} - // cancel submitted non-completed Future +void cancelSubmittedNotCompleted() { + ReadFuture readFuture(efd, &read_buf, sizeof(read_buf), 0); readFuture.submit(); assert(readFuture.cancel() == -ECANCELED); +} - readFuture.reset(); - +void cancelCompleted() { + ReadFuture readFuture(efd, &read_buf, sizeof(read_buf), 0); readFuture.submit(); WriteFuture writeFuture(efd, &write_buf, sizeof(write_buf), 0); assert(writeFuture.submitAndWait() == sizeof(write_buf)); assert(readFuture.cancel() == sizeof(write_buf) && read_buf == write_buf); +} + +void cancelNotCompletedChain() { + ReadFuture readFuture(efd, &read_buf, sizeof(read_buf), 0); + ReadFuture readFuture2(efd, &read_buf, sizeof(read_buf), 0); + readFuture2.setDependency(readFuture); - writeFuture.reset(); - read_buf = 0; - readFuture.reset(); + readFuture2.submit(); + assert(readFuture2.cancel() == -ECANCELED); + assert(readFuture.wait() == -ECANCELED); +} - // cancel a chain +void cancelPartialCompletedChain() { + ReadFuture readFuture(efd, &read_buf, sizeof(read_buf), 0); ReadFuture readFuture2(efd, &read_buf, sizeof(read_buf), 0); readFuture2.setDependency(readFuture); + readFuture2.submit(); assert(readFuture2.cancel() == -ECANCELED); assert(readFuture.wait() == -ECANCELED); +} - readFuture2.reset(); - readFuture.reset(); +void cancelNotCompletedFutureChain() { + ReadFuture readFuture(efd, &read_buf, sizeof(read_buf), 0); + WriteFuture writeFuture(efd, &write_buf, sizeof(write_buf), 0); + ReadFuture readFuture2(efd, &read_buf, sizeof(read_buf), 0); + readFuture2.setDependency(readFuture); - // cancel partial completed chain readFuture2.submit(); assert(writeFuture.submitAndWait() == sizeof(write_buf)); // TODO: investigate why this read is completed with -EINTR most of the time @@ -57,3 +68,16 @@ void emperTest() { assert(r == -EINTR || r == -ECANCELED); assert(readFuture.wait() == sizeof(write_buf) && read_buf == write_buf); } + +void emperTest() { + efd = eventfd(0, 0); + if (efd == -1) { + DIE_MSG_ERRNO("eventfd failed"); + } + + cancelNotSubmitted(); + cancelSubmittedNotCompleted(); + cancelCompleted(); + cancelNotCompletedChain(); + cancelPartialCompletedChain(); +}