From 5f7289e1f8e1427c9214c8e3e96ad56b1f868d53 Mon Sep 17 00:00:00 2001 From: Garrett D'Amore Date: Wed, 4 Apr 2018 13:36:54 -0700 Subject: fixes #334 Separate context for state machines from sockets This provides context support for REQ and REP sockets. More discussion around this is in the issue itself. Optionally we would like to extend this to the surveyor pattern. Note that we specifically do not support pollable descriptors for non-default contexts, and the results of using file descriptors for polling (NNG_OPT_SENDFD and NNG_OPT_RECVFD) is undefined. In the future, it might be nice to figure out how to factor in optional use of a message queue for users who want more buffering, but we think there is little need for this with cooked mode. --- docs/man/nng_ctx.5.adoc | 161 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 161 insertions(+) create mode 100644 docs/man/nng_ctx.5.adoc (limited to 'docs/man/nng_ctx.5.adoc') diff --git a/docs/man/nng_ctx.5.adoc b/docs/man/nng_ctx.5.adoc new file mode 100644 index 00000000..c59a4a4c --- /dev/null +++ b/docs/man/nng_ctx.5.adoc @@ -0,0 +1,161 @@ += nng_ctx(5) +// +// Copyright 2018 Staysail Systems, Inc. +// Copyright 2018 Capitar IT Group BV +// +// 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_ctx - protocol context + +== SYNOPSIS + +[source, c] +---- +#include + +typedef uint32_t nng_ctx +---- + +== DESCRIPTION + +An `nng_ctx`(((context))) is a handle to an underlying "`context`" object, +which keeps the protocol state for some stateful protocols. +The purpose of a separate context object is to permit applications to +share a single socket, with its various underlying +<>, +<>, +and <>, +while still benefiting from separate state tracking. + +For example, a <> context will contain the request ID +of any sent request, a timer to retry the request on failure, and so forth. +A separate context on the same socket can have similar data, but corresponding +to a completely different request. + +All contexts share the same socket, and so some options, as well as the +underlying transport details, will be common to all contexts on that socket. + +NOTE: Not every protocol supports separate contexts. +See the protocol-specific documentation for further details about whether +contexts are supported, and details about what options are supported for +contexts. + +Protocols that make use of contexts will also have a "`default`" context +that is used when the socket global operations are used. +Operations using the global context will generally not interfere with +any other contexts, except that certain socket options may affect socket +global behavior. + +(((concurrent)))(((raw mode))) +Historically, applications wanting to use a stateful protocol concurrently +would have to resort to <> sockets, which bypasses +much of the various protocol handling, leaving it to up to the application +to do so. +Contexts make it possible to still benefit from advanced protocol handling, +including timeouts, retries, and matching requests to responses, while doing so +concurrently. + +NOTE: <> sockets do not support contexts, since +there is generally no state tracked for them, and thus contexts make no sense. + +TIP: Contexts are an excellent mechanism to use when building concurrent +applications, and should be used in lieu of +<> sockets when possible. + +WARNING: Use of file descriptor polling (with descriptors +obtained using the +<> or +<> options) while contexts +are in use on the same socket is not supported, and may lead to unpredictable +behavior. +These asynchronous methods should not be mixed on the same socket. + +== EXAMPLE + +The following program fragment demonstrates the use of contexts to implement +a concurrent <> service that simply echos messages back +to the sender. + +[source, c] +---- + +struct echo_context { + nng_ctx *ctx; + nng_aio *aio; + enum { INIT, RECV, SEND } state; +}; + +void +echo(void *arg) +{ + struct echo_context *ec = arg; + + switch (ec->state) { + case INIT: + ec->state = RECV; + nng_ctx_recv(ec->ctx, ec->aio); + return; + case RECV: + if (nng_aio_result(ec->aio) != 0) { + // ... handle error + } + // We reuse the message on the ec->aio + ec->state = SEND; + nng_ctx_send(ec->ctx, ec->aio); + return; + case SEND: + if (nng_aio_result(ec->aio) != 0) { + // ... handle error + } + ec->state = RECV; + nng_ctx_recv(ec->ctx, ec->aio); + return; + } +} +---- + +Given the above fragment, the following example shows setting up the +service. It assumes that the <> has already been +created and any transports set up as well with functions such as +<> +or <>. + +[source,c] +---- +#define CONCURRENCY 1024 + +echo_context ecs[CONCURRENCY]; + +void +start_echo_service(nng_socket rep_socket) +{ + for (int i = 0; i < CONCURRENCY; i++) { + // error checks elided for clarity + nng_ctx_open(ec[i].ctx, rep_socket) + nng_aio_alloc(ec[i].aio, echo, &e[i]); + ec[i].state = INIT; + echo(&ec[i]); // start it running + } +} +---- + +== SEE ALSO + +<>, +<>, +<>, +<>, +<>, +<>, +<>, +<>, +<>, +<>, +<>, +<> -- cgit v1.2.3-70-g09d2