1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104
|
From 5566ee8d2e5688d36b6d6702447386cc579e2a05 Mon Sep 17 00:00:00 2001
From: Garrett D'Amore <garrett@damore.org>
Date: Fri, 30 Jan 2026 22:36:52 -0800
Subject: [PATCH] aio: task_abort was a mistake (fixes #2208)
The use of task_abort to prematurely fail an aio at scheduling
time was a mistake, because it could have led to duplicate calls
to nng_aio_finish(). We do need to ensure that we leave an indicator
so that nni_aio_schedule can return the abort status to caller,
in the case that abort is called between the nni_aio_begin and
nni_aio_schedule calls.
This is more or less the same changes for main in commit 3ca7bcc0edd0f26c33264d32e7b6f07276e72e3c
but backported to stable. (A hand backport was needed.)
---
src/core/aio.c | 21 +++++++++++++--------
src/core/aio.h | 1 +
2 files changed, 14 insertions(+), 8 deletions(-)
diff --git a/src/core/aio.c b/src/core/aio.c
index 83f22a9f5..40a84b120 100644
--- a/src/core/aio.c
+++ b/src/core/aio.c
@@ -201,8 +201,6 @@ nni_aio_stop(nni_aio *aio)
if (fn != NULL) {
fn(aio, arg, NNG_ECANCELED);
- } else {
- nni_task_abort(&aio->a_task);
}
nni_aio_wait(aio);
@@ -228,8 +226,6 @@ nni_aio_close(nni_aio *aio)
if (fn != NULL) {
fn(aio, arg, NNG_ECLOSED);
- } else {
- nni_task_abort(&aio->a_task);
}
}
}
@@ -347,6 +343,7 @@ nni_aio_begin(nni_aio *aio)
aio->a_result = 0;
aio->a_count = 0;
aio->a_cancel_fn = NULL;
+ aio->a_abort = false;
// We should not reschedule anything at this point.
if (aio->a_stop) {
@@ -373,7 +370,6 @@ nni_aio_schedule(nni_aio *aio, nni_aio_cancel_fn cancel, void *data)
// Convert the relative timeout to an absolute timeout.
switch (aio->a_timeout) {
case NNG_DURATION_ZERO:
- nni_task_abort(&aio->a_task);
return (NNG_ETIMEDOUT);
case NNG_DURATION_INFINITE:
case NNG_DURATION_DEFAULT:
@@ -386,8 +382,13 @@ nni_aio_schedule(nni_aio *aio, nni_aio_cancel_fn cancel, void *data)
}
nni_mtx_lock(&eq->eq_mtx);
+ if (aio->a_abort) {
+ int rv = aio->a_result;
+ nni_mtx_unlock(&eq->eq_mtx);
+ return (rv);
+ }
+
if (aio->a_stop) {
- nni_task_abort(&aio->a_task);
nni_mtx_unlock(&eq->eq_mtx);
return (NNG_ECLOSED);
}
@@ -420,13 +421,17 @@ nni_aio_abort(nni_aio *aio, int rv)
arg = aio->a_cancel_arg;
aio->a_cancel_fn = NULL;
aio->a_cancel_arg = NULL;
+ if (fn == NULL) {
+ // We haven't been scheduled yet,
+ // so make sure that the schedule will abort.
+ aio->a_abort = true;
+ aio->a_result = rv;
+ }
nni_mtx_unlock(&eq->eq_mtx);
// Stop any I/O at the provider level.
if (fn != NULL) {
fn(aio, arg, rv);
- } else {
- nni_task_abort(&aio->a_task);
}
}
diff --git a/src/core/aio.h b/src/core/aio.h
index 04fcafe3b..1aa5c6b11 100644
--- a/src/core/aio.h
+++ b/src/core/aio.h
@@ -214,6 +214,7 @@ struct nng_aio {
bool a_expire_ok; // Expire from sleep is ok
bool a_expiring; // Expiration in progress
bool a_use_expire; // Use expire instead of timeout
+ bool a_abort; // Abort the operation.
nni_task a_task;
// Read/write operations.
|