diff options
| -rw-r--r-- | docs/man/libnng.adoc | 1 | ||||
| -rw-r--r-- | docs/man/nng_sleep_aio.adoc | 49 | ||||
| -rw-r--r-- | src/core/aio.c | 19 | ||||
| -rw-r--r-- | src/core/aio.h | 2 | ||||
| -rw-r--r-- | src/nng.c | 6 | ||||
| -rw-r--r-- | src/nng.h | 5 | ||||
| -rw-r--r-- | tests/aio.c | 23 |
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 @@ -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) { @@ -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; |
