From 838c9eab97c9d954354db711faae8a1fa6c12d38 Mon Sep 17 00:00:00 2001 From: Garrett D'Amore Date: Sat, 30 Dec 2023 19:35:24 -0800 Subject: [PATCH] fixes #1751 Support nng_aio_set_expire(). While here fixed a number of nits in comments. --- docs/man/nng_aio_set_timeout.3.adoc | 11 +++++++- docs/man/nng_clock.3supp.adoc | 2 +- include/nng/nng.h | 32 +++++++++++++++--------- include/nng/supplemental/util/platform.h | 8 ++---- src/core/aio_test.c | 24 +++++++++++++++++- src/nng.c | 6 +++++ 6 files changed, 62 insertions(+), 21 deletions(-) diff --git a/docs/man/nng_aio_set_timeout.3.adoc b/docs/man/nng_aio_set_timeout.3.adoc index 0d544d592..a82b0c838 100644 --- a/docs/man/nng_aio_set_timeout.3.adoc +++ b/docs/man/nng_aio_set_timeout.3.adoc @@ -1,6 +1,6 @@ = nng_aio_set_timeout(3) // -// Copyright 2018 Staysail Systems, Inc. +// Copyright 2023 Staysail Systems, Inc. // Copyright 2018 Capitar IT Group BV // // This document is supplied under the terms of the MIT License, a @@ -21,6 +21,9 @@ nng_aio_set_timeout - set asynchronous I/O timeout typedef int nng_duration; void nng_aio_set_timeout(nng_aio *aio, nng_duration timeout); + +typedef uint64_t nng_time; +void nng_aio_set_expire(nng_aio *aio, nng_time expiration); ---- == DESCRIPTION @@ -37,6 +40,12 @@ If the timeout is `NNG_DURATION_DEFAULT`, then a "default" or socket-specific timeout is used. (This is frequently the same as `NNG_DURATION_INFINITE`.) +The `nng_aio_set_expire()` function is similar to `nng_aio_set_timeout()`, but sets +an absolute expiration time based on the system clock. The _expiration_ +is expressed as a number of milliseconds since some point in the past. +The xref:nng_clock.3supp.adoc[`nng_clock()`] function can be used to determine +the current value of the clock. + TIP: As most operations involve some context switching, it is usually a good idea to allow at least a few tens of milliseconds before timing them out -- a too small timeout might not allow the operation to properly begin before diff --git a/docs/man/nng_clock.3supp.adoc b/docs/man/nng_clock.3supp.adoc index 500134c59..d413f1b29 100644 --- a/docs/man/nng_clock.3supp.adoc +++ b/docs/man/nng_clock.3supp.adoc @@ -32,7 +32,7 @@ arbitrary time in the past. The resolution of the clock depends on the underlying timing facilities of the system. This function may be used for timing, but applications should not expect -very fine grained values. +very fine-grained values. IMPORTANT: The reference time will be the same for a given program, but different programs may have different references. diff --git a/include/nng/nng.h b/include/nng/nng.h index 06733d775..98a9a8438 100644 --- a/include/nng/nng.h +++ b/include/nng/nng.h @@ -102,6 +102,11 @@ typedef struct nng_socket_s { } nng_socket; typedef int32_t nng_duration; // in milliseconds + +// nng_time represents an absolute time since some arbitrary point in the +// past, measured in milliseconds. The values are always positive. +typedef uint64_t nng_time; + typedef struct nng_msg nng_msg; typedef struct nng_stat nng_stat; typedef struct nng_aio nng_aio; @@ -154,7 +159,7 @@ struct nng_sockaddr_abstract { uint8_t sa_name[107]; // 108 linux/windows, without leading NUL }; -// nng_sockaddr_storage is the the size required to store any nng_sockaddr. +// nng_sockaddr_storage is the size required to store any nng_sockaddr. // This size must not change, and no individual nng_sockaddr type may grow // larger than this without breaking binary compatibility. struct nng_sockaddr_storage { @@ -354,7 +359,7 @@ NNG_DECL int nng_listener_get_ptr(nng_listener, const char *, void **); NNG_DECL int nng_listener_get_ms(nng_listener, const char *, nng_duration *); NNG_DECL int nng_listener_get_addr(nng_listener, const char *, nng_sockaddr *); -// nng_strerror returns a human readable string associated with the error +// nng_strerror returns a human-readable string associated with the error // code supplied. NNG_DECL const char *nng_strerror(int); @@ -380,7 +385,7 @@ NNG_DECL int nng_recv(nng_socket, void *, size_t *, int); // nng_sendmsg is like nng_send, but offers up a message structure, which // gives the ability to provide more control over the message, including // providing backtrace information. It also can take a message that was -// obtain via nn_recvmsg, allowing for zero copy forwarding. +// obtained via nn_recvmsg, allowing for zero copy forwarding. NNG_DECL int nng_sendmsg(nng_socket, nng_msg *, int); // nng_recvmsg is like nng_recv, but is used to obtain a message structure @@ -393,7 +398,7 @@ NNG_DECL int nng_recvmsg(nng_socket, nng_msg **, int); // the completion may be executed before the data has actually been delivered, // but only when it is accepted for delivery. The supplied AIO must have // been initialized, and have an associated message. The message will be -// "owned" by the socket if the operation completes successfully. Otherwise +// "owned" by the socket if the operation completes successfully. Otherwise, // the caller is responsible for freeing it. NNG_DECL void nng_send_aio(nng_socket, nng_aio *); @@ -429,7 +434,7 @@ NNG_DECL int nng_ctx_id(nng_ctx); // uses a local context instead of the socket global context. NNG_DECL void nng_ctx_recv(nng_ctx, nng_aio *); -// nng_ctx_recvmsg is allows for receiving a message synchronously using +// nng_ctx_recvmsg allows for receiving a message synchronously using // a context. It has the same semantics as nng_recvmsg, but operates // on a context instead of a socket. NNG_DECL int nng_ctx_recvmsg(nng_ctx, nng_msg **, int); @@ -515,7 +520,7 @@ NNG_DECL void nng_aio_reap(nng_aio *); // nng_aio_stop stops any outstanding operation, and waits for the // AIO to be free, including for the callback to have completed -// execution. Therefore the caller must NOT hold any locks that +// execution. Therefore, the caller must NOT hold any locks that // are acquired in the callback, or deadlock will occur. NNG_DECL void nng_aio_stop(nng_aio *); @@ -578,6 +583,11 @@ NNG_DECL void *nng_aio_get_output(nng_aio *, unsigned); // that any socket specific timeout should be used. NNG_DECL void nng_aio_set_timeout(nng_aio *, nng_duration); +// nng_aio_set_expire is like nng_aio_set_timeout, except it sets an absolute +// expiration time. This is useful when chaining actions on a single aio +// as part of a state machine. +NNG_DECL void nng_aio_set_expire(nng_aio *, nng_time); + // nng_aio_set_iov sets a scatter/gather vector on the aio. The iov array // itself is copied. Data members (the memory regions referenced) *may* be // copied as well, depending on the operation. This operation is guaranteed @@ -943,7 +953,7 @@ NNG_DECL nng_stat *nng_stat_next(nng_stat *); NNG_DECL nng_stat *nng_stat_child(nng_stat *); // nng_stat_name is used to determine the name of the statistic. -// This is a human readable name. Statistic names, as well as the presence +// This is a human-readable name. Statistic names, as well as the presence // or absence or semantic of any particular statistic are not part of any // stable API, and may be changed without notice in future updates. NNG_DECL const char *nng_stat_name(nng_stat *); @@ -990,14 +1000,12 @@ enum nng_unit_enum { NNG_UNIT_EVENTS = 4 // Some other type of event }; -// nng_stat_value returns returns the actual value of the statistic. +// nng_stat_value returns the actual value of the statistic. // Statistic values reflect their value at the time that the corresponding // snapshot was updated, and are undefined until an update is performed. NNG_DECL uint64_t nng_stat_value(nng_stat *); -// nng_stat_value returns returns the actual value of the statistic. -// Statistic values reflect their value at the time that the corresponding -// snapshot was updated, and are undefined until an update is performed. +// nng_stat_bool returns the boolean value of the statistic. NNG_DECL bool nng_stat_bool(nng_stat *); // nng_stat_string returns the string associated with a string statistic, @@ -1005,7 +1013,7 @@ NNG_DECL bool nng_stat_bool(nng_stat *); // is valid until the associated statistic is freed. NNG_DECL const char *nng_stat_string(nng_stat *); -// nng_stat_desc returns a human readable description of the statistic. +// nng_stat_desc returns a human-readable description of the statistic. // This may be useful for display in diagnostic interfaces, etc. NNG_DECL const char *nng_stat_desc(nng_stat *); diff --git a/include/nng/supplemental/util/platform.h b/include/nng/supplemental/util/platform.h index dc3c47ddd..26f910a3e 100644 --- a/include/nng/supplemental/util/platform.h +++ b/include/nng/supplemental/util/platform.h @@ -1,5 +1,5 @@ // -// Copyright 2018 Staysail Systems, Inc. +// Copyright 2023 Staysail Systems, Inc. // Copyright 2018 Capitar IT Group BV // // This software is supplied under the terms of the MIT License, a @@ -27,13 +27,9 @@ extern "C" { #endif -// nng_time represents an absolute time since some arbitrary point in the -// past, measured in milliseconds. The values are always positive. -typedef uint64_t nng_time; - // Return an absolute time from some arbitrary point. The value is // provided in milliseconds, and is of limited resolution based on the -// system clock. (Do not use it for fine grained performance measurements.) +// system clock. (Do not use it for fine-grained performance measurements.) NNG_DECL nng_time nng_clock(void); // Sleep for specified msecs. diff --git a/src/core/aio_test.c b/src/core/aio_test.c index bbc997b5c..fb0f5c34f 100644 --- a/src/core/aio_test.c +++ b/src/core/aio_test.c @@ -1,5 +1,5 @@ // -// Copyright 2022 Staysail Systems, Inc. +// Copyright 2023 Staysail Systems, Inc. // Copyright 2018 Capitar IT Group BV // // This software is supplied under the terms of the MIT License, a @@ -190,6 +190,27 @@ test_explicit_timeout(void) NUTS_PASS(nng_close(s)); } +void +test_explicit_expiration(void) +{ + nng_socket s; + nng_aio * a; + int done = 0; + nng_time now; + + NUTS_PASS(nng_pair1_open(&s)); + NUTS_PASS(nng_aio_alloc(&a, cb_done, &done)); + now = nng_clock(); + now += 40; + nng_aio_set_expire(a, now); + nng_recv_aio(s, a); + nng_aio_wait(a); + NUTS_TRUE(done == 1); + NUTS_FAIL(nng_aio_result(a), NNG_ETIMEDOUT); + nng_aio_free(a); + NUTS_PASS(nng_close(s)); +} + void test_inherited_timeout(void) { @@ -384,6 +405,7 @@ NUTS_TESTS = { { "consumer cancel", test_consumer_cancel }, { "traffic", test_traffic }, { "explicit timeout", test_explicit_timeout }, + { "explicit expire", test_explicit_expiration }, { "inherited timeout", test_inherited_timeout }, { "zero timeout", test_zero_timeout }, { "aio reap", test_aio_reap }, diff --git a/src/nng.c b/src/nng.c index 792595682..ce75d8325 100644 --- a/src/nng.c +++ b/src/nng.c @@ -1919,6 +1919,12 @@ nng_aio_set_timeout(nng_aio *aio, nni_duration when) nni_aio_set_timeout(aio, when); } +void +nng_aio_set_expire(nng_aio *aio, nng_time when) +{ + nni_aio_set_expire(aio, when); +} + int nng_aio_set_iov(nng_aio *aio, unsigned niov, const nng_iov *iov) {