aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--docs/man/libnng.adoc1
-rw-r--r--docs/man/nng_sleep_aio.adoc49
-rw-r--r--src/core/aio.c19
-rw-r--r--src/core/aio.h2
-rw-r--r--src/nng.c6
-rw-r--r--src/nng.h5
-rw-r--r--tests/aio.c23
7 files changed, 104 insertions, 1 deletions
diff --git a/docs/man/libnng.adoc b/docs/man/libnng.adoc
index 8c18c8ff..68cbdcf4 100644
--- a/docs/man/libnng.adoc
+++ b/docs/man/libnng.adoc
@@ -157,6 +157,7 @@ The following functions are used in the asynchronous model:
|<<nng_aio_wait#,nng_aio_wait(3)>>|wait for asynchronous I/O operation
|<<nng_recv_aio#,nng_recv_aio(3)>>|receive message asynchronously
|<<nng_send_aio#,nng_send_aio(3)>>|send message asynchronously
+|<<nng_sleep_aio#,nng_sleep_aio(3)>>|sleep asynchronously
|===
=== Protocols
diff --git a/docs/man/nng_sleep_aio.adoc b/docs/man/nng_sleep_aio.adoc
new file mode 100644
index 00000000..dff00219
--- /dev/null
+++ b/docs/man/nng_sleep_aio.adoc
@@ -0,0 +1,49 @@
+= nng_sleep_aio(3)
+//
+// Copyright 2018 Staysail Systems, Inc. <info@staysail.tech>
+// Copyright 2018 Capitar IT Group BV <info@capitar.com>
+//
+// This document is supplied under the terms of the MIT License, a
+// copy of which should be located in the distribution where this
+// file was obtained (LICENSE.txt). A copy of the license may also be
+// found online at https://opensource.org/licenses/MIT.
+//
+
+== NAME
+
+nng_sleep_aio - sleep asynchronously
+
+== SYNOPSIS
+
+[source, c]
+-----------
+#include <nng/nng.h>
+
+void nng_sleep_aio(nng_duration msec, nng_aio *aio);
+-----------
+
+== DESCRIPTION
+
+The `nng_sleep_aio()` function performs an asynchronous "`sleep``",
+causing the callback for _aio_ to be executed after _msec_ milliseconds.
+This is logically the equivalent of starting an asynchronous operation
+that does nothing at all, but expires after _msec_ duration, _except_ that
+the completion result will be zero rather `NNG_ETIMEDOUT`.
+
+NOTE: This overrides and replaces any timeout on the _aio_ set with
+<<nng_aio_set_timeout#,nng_aio_set_timeout(3)>>.
+
+== RETURN VALUES
+
+None.
+
+== ERRORS
+
+None.
+
+== SEE ALSO
+
+<<nng_aio_abort#,nng_aio_abort(3)>>,
+<<nng_aio_alloc#,nng_aio_alloc(3)>>,
+<<nng_aio_set_timeout#,nng_aio_set_timeout(3)>>,
+<<nng#,nng(7)>>
diff --git a/src/core/aio.c b/src/core/aio.c
index dd5edf0e..e0206830 100644
--- a/src/core/aio.c
+++ b/src/core/aio.c
@@ -70,6 +70,7 @@ struct nng_aio {
unsigned a_expiring : 1; // expiration callback in progress
unsigned a_waiting : 1; // a thread is waiting for this to finish
unsigned a_synch : 1; // run completion synchronously
+ unsigned a_sleep : 1; // sleeping with no action
nni_task a_task;
// Read/write operations.
@@ -375,6 +376,7 @@ nni_aio_finish_impl(nni_aio *aio, int rv, size_t count, nni_msg *msg)
}
aio->a_expire = NNI_TIME_NEVER;
+ aio->a_sleep = 0;
// If we are expiring, then we rely on the expiration thread to
// complete this; we must not because the expiration thread is
@@ -471,6 +473,7 @@ nni_aio_expire_loop(void *arg)
nni_aio * aio;
nni_time now;
nni_aio_cancelfn cancelfn;
+ int rv;
NNI_ARG_UNUSED(arg);
@@ -506,14 +509,18 @@ nni_aio_expire_loop(void *arg)
// and the done flag won't be set either.
aio->a_expiring = 1;
cancelfn = aio->a_prov_cancel;
+ rv = aio->a_sleep ? 0 : NNG_ETIMEDOUT;
+ aio->a_sleep = 0;
// Cancel any outstanding activity. This is always non-NULL
// for a valid aio, and becomes NULL only when an AIO is
// already being canceled or finished.
if (cancelfn != NULL) {
nni_mtx_unlock(&nni_aio_lk);
- cancelfn(aio, NNG_ETIMEDOUT);
+ cancelfn(aio, aio->a_sleep ? 0 : NNG_ETIMEDOUT);
nni_mtx_lock(&nni_aio_lk);
+ } else {
+ aio->a_pend = 1;
}
NNI_ASSERT(aio->a_pend); // nni_aio_finish was run
@@ -612,6 +619,16 @@ nni_aio_iov_advance(nni_aio *aio, size_t n)
}
void
+nni_sleep_aio(nng_duration ms, nng_aio *aio)
+{
+ nni_aio_set_timeout(aio, ms);
+ aio->a_sleep = 1;
+ if (nni_aio_start(aio, NULL, NULL)) {
+ return;
+ }
+}
+
+void
nni_aio_sys_fini(void)
{
nni_mtx *mtx = &nni_aio_lk;
diff --git a/src/core/aio.h b/src/core/aio.h
index 141248b8..49ef5298 100644
--- a/src/core/aio.h
+++ b/src/core/aio.h
@@ -151,6 +151,8 @@ extern void nni_aio_get_iov(nni_aio *, unsigned *, nni_iov **);
extern void nni_aio_normalize_timeout(nni_aio *, nng_duration);
extern void nni_aio_bump_count(nni_aio *, size_t);
+extern void nni_sleep_aio(nni_duration, nni_aio *);
+
extern int nni_aio_sys_init(void);
extern void nni_aio_sys_fini(void);
#endif // CORE_AIO_H
diff --git a/src/nng.c b/src/nng.c
index 19b33220..4c2a58db 100644
--- a/src/nng.c
+++ b/src/nng.c
@@ -1039,6 +1039,12 @@ nng_aio_free(nng_aio *aio)
nni_aio_fini(aio);
}
+void
+nng_sleep_aio(nng_duration ms, nng_aio *aio)
+{
+ nni_sleep_aio(ms, aio);
+}
+
int
nng_aio_result(nng_aio *aio)
{
diff --git a/src/nng.h b/src/nng.h
index 7615785d..b7adee93 100644
--- a/src/nng.h
+++ b/src/nng.h
@@ -352,6 +352,11 @@ NNG_DECL int nng_aio_set_iov(nng_aio *, unsigned, const nng_iov *);
// given aio.
NNG_DECL void nng_aio_finish(nng_aio *, int);
+// nng_aio_sleep does a "sleeping" operation, basically does nothing
+// but wait for the specified number of milliseconds to expire, then
+// calls the callback. This returns 0, rather than NNG_ETIMEDOUT.
+NNG_DECL void nng_sleep_aio(nng_duration, nng_aio *);
+
// Message API.
NNG_DECL int nng_msg_alloc(nng_msg **, size_t);
NNG_DECL void nng_msg_free(nng_msg *);
diff --git a/tests/aio.c b/tests/aio.c
index 8af5dbc7..b57c5a69 100644
--- a/tests/aio.c
+++ b/tests/aio.c
@@ -12,6 +12,7 @@
#include "nng.h"
#include "protocol/pair1/pair.h"
+#include "supplemental/util/platform.h"
#include "stubs.h"
@@ -28,11 +29,33 @@ cbdone(void *p)
(*(int *) p)++;
}
+void
+sleepdone(void *arg)
+{
+ *(nng_time *) arg = nng_clock();
+}
+
Main({
Test("AIO operations", {
const char *addr = "inproc://aio";
+ Convey("Sleep works", {
+ nng_time start = 0;
+ nng_time end = 0;
+ nng_aio *saio;
+ So(nng_aio_alloc(&saio, sleepdone, &end) == 0);
+ start = nng_clock();
+ nng_sleep_aio(200, saio);
+ nng_aio_wait(saio);
+ So(nng_aio_result(saio) == 0);
+ So(end != 0);
+ So((end - start) >= 200);
+ So((end - start) <= 1000);
+ So((nng_clock() - start) >= 200);
+ So((nng_clock() - start) <= 1000);
+ nng_aio_free(saio);
+ });
Convey("Given a connected pair of sockets", {
nng_socket s1;
nng_socket s2;