From 713b80f440cb414cd0b856bde0ea1b31f939777f Mon Sep 17 00:00:00 2001 From: Garrett D'Amore Date: Sat, 9 Nov 2024 23:45:21 -0800 Subject: refactor initialization/finalization Applications must now call nng_init(), but they can supply a set of parameters optionally. The code is now safe for multiple libraries to do this concurrently, meaning nng_fini no longer can race against another instance starting up. The nni_init checks on all public APIs are removed now. --- include/nng/nng.h | 106 ++++++++++++++++++++++-------------------------------- 1 file changed, 42 insertions(+), 64 deletions(-) (limited to 'include') diff --git a/include/nng/nng.h b/include/nng/nng.h index aebed4b9..a265bcf1 100644 --- a/include/nng/nng.h +++ b/include/nng/nng.h @@ -214,17 +214,6 @@ typedef struct nng_iov { #define NNG_DURATION_DEFAULT (-2) #define NNG_DURATION_ZERO (0) -// nng_fini is used to terminate the library, freeing certain global resources. -// This should only be called during atexit() or just before dlclose(). -// THIS FUNCTION MUST NOT BE CALLED CONCURRENTLY WITH ANY OTHER FUNCTION -// IN THIS LIBRARY; IT IS NOT REENTRANT OR THREADSAFE. -// -// For most cases, this call is unnecessary, but it is provided to assist -// when debugging with memory checkers (e.g. valgrind). Calling this -// function prevents global library resources from being reported incorrectly -// as memory leaks. In those cases, we recommend doing this with atexit(). -NNG_DECL void nng_fini(void); - // nng_close closes the socket, terminating all activity and // closing any underlying connections and releasing any associated // resources. @@ -1268,78 +1257,67 @@ NNG_DECL void nng_udp_recv(nng_udp *udp, nng_aio *aio); NNG_DECL int nng_udp_multicast_membership( nng_udp *udp, nng_sockaddr *sa, bool join); -// nng_init_parameter is used by applications to change a tunable setting. -// This function must be called before any other NNG function for the setting -// to have any effect. This function is also not thread-safe! -// -// The list of parameters supported is *not* documented, and subject to change. -// -// We try to provide sane defaults, so the use here is intended to provide -// more control for applications that cannot use compile-time configuration. -// -// Applications should not depend on this API for correct operation. -// -// This API is intentionally undocumented. -// -// Parameter settings are lost after nng_fini() is called. -typedef int nng_init_parameter; -NNG_DECL void nng_init_set_parameter(nng_init_parameter, uint64_t); - -// The following list of parameters is not part of our API stability promise. -// In particular the set of parameters that are supported, the default values, -// the range of valid values, and semantics associated therein are subject to -// change at any time. We won't go out of our way to break these, and we will -// try to prevent changes here from breaking working applications, but this is -// on a best effort basis only. -// -// NOTE: When removing a value, please leave the enumeration in place and add -// a suffix _RETIRED ... this will preserve the binary values for binary -// compatibility. -enum { - NNG_INIT_PARAMETER_NONE = 0, // ensure values start at 1. - +// Initialization parameters. +// Applications can tweak behavior by passing a non-empty set +// values here, but only the first caller to nng_init may supply +// values. +typedef struct { // Fix the number of threads used for tasks (callbacks), - // Default is 2 threads per core, capped to NNG_INIT_MAX_TASK_THREADS. - // At least 2 threads will be created in any case. - NNG_INIT_NUM_TASK_THREADS, + // Default is 2 threads per core, capped to max_task_threads below. + // At least 2 threads will be created in any case. 0 leaves this at + // the default. + int16_t num_task_threads; + + // Limit the number of threads of created for tasks. + // NNG will always create at least 2 of these in order to prevent + // deadlocks. -1 means no limit. Default is determined by + // NNG_MAX_TASKQ_THREADS compile time variable. + int16_t max_task_threads; // Fix the number of threads used for expiration. Default is one - // thread per core, capped to NNG_INIT_MAX_EXPIRE_THREADS. At least + // thread per core, capped to max_expires_threads below. At least // one thread will be created. - NNG_INIT_NUM_EXPIRE_THREADS, + int16_t num_expire_threads; + + // Limit the number of threads created for expiration. -1 means no + // limit. Default is determined by the NNG_MAX_EXPIRE_THREADS compile + // time variable. + int16_t max_expire_threads; // Fix the number of poller threads (used for I/O). Support varies // by platform (many platforms only support a single poller thread.) - NNG_INIT_NUM_POLLER_THREADS, + int16_t num_poller_threads; + + // Limit the number of poller/IO threads created. -1 means no limit. + // Default is determined by NNG_MAX_POLLER_THREADS compile time + // variable. + int16_t max_poller_threads; // Fix the number of threads used for DNS resolution. At least one // will be used. Default is controlled by NNG_RESOLV_CONCURRENCY // compile time variable. - NNG_INIT_NUM_RESOLVER_THREADS, - - // Limit the number of threads of created for tasks. - // NNG will always create at least 2 of these in order to prevent - // deadlocks. Zero means no limit. Default is determined by - // NNG_MAX_TASKQ_THREADS compile time variable. - NNG_INIT_MAX_TASK_THREADS, + int16_t num_resolver_threads; +} nng_init_params; - // Limit the number of threads created for expiration. Zero means no - // limit. Default is determined by the NNG_MAX_EXPIRE_THREADS compile - // time variable. - NNG_INIT_MAX_EXPIRE_THREADS, +// Initialize the library. May be called multiple times, but +// only the first call can contain a non-NULL params. If already +// initialized with non-NULL params, will return NNG_EALREADY. +// Applications should *not* call a matching nng_fini() in that case. +NNG_DECL int nng_init(nng_init_params *parms); - // Limit the number of poller/IO threads created. Zero means no limit. - // Default is determined by NNG_MAX_POLLER_THREADS compile time - // variable. - NNG_INIT_MAX_POLLER_THREADS, -}; +// nng_fini is used to terminate the library, freeing certain global resources. +// Each call to nng_fini is paired to a call to nng_init. The last such +// call will tear down any resources associated with the library. Thus, +// applications must not call other functions in the library after calling +// this. +NNG_DECL void nng_fini(void); // Logging support. // Log levels. These correspond to RFC 5424 (syslog) levels. // NNG never only uses priorities 3 - 7. // -// Note that LOG_EMER is 0, but we don't let applications submit' +// Note that LOG_EMERG is 0, but we don't let applications submit' // such messages, so this is a useful value to prevent logging altogether. typedef enum nng_log_level { NNG_LOG_NONE = 0, // used for filters only, NNG suppresses these -- cgit v1.2.3-70-g09d2