Skip to content

Commit

Permalink
refactor initialization/finalization
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
gdamore committed Nov 11, 2024
1 parent cbe9a27 commit 713b80f
Show file tree
Hide file tree
Showing 40 changed files with 471 additions and 729 deletions.
106 changes: 42 additions & 64 deletions include/nng/nng.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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
Expand Down
23 changes: 6 additions & 17 deletions src/core/aio.c
Original file line number Diff line number Diff line change
Expand Up @@ -823,32 +823,21 @@ nni_aio_sys_fini(void)
}

int
nni_aio_sys_init(void)
nni_aio_sys_init(nng_init_params *params)
{
int num_thr;
int max_thr;
int16_t num_thr;
int16_t max_thr;

#ifndef NNG_MAX_EXPIRE_THREADS
#define NNG_MAX_EXPIRE_THREADS 8
#endif

#ifndef NNG_NUM_EXPIRE_THREADS
#define NNG_NUM_EXPIRE_THREADS (nni_plat_ncpu())
#endif

max_thr = (int) nni_init_get_param(
NNG_INIT_MAX_EXPIRE_THREADS, NNG_MAX_EXPIRE_THREADS);

num_thr = (int) nni_init_get_param(
NNG_INIT_NUM_EXPIRE_THREADS, NNG_NUM_EXPIRE_THREADS);
max_thr = params->max_expire_threads;
num_thr = params->num_expire_threads;

if ((max_thr > 0) && (num_thr > max_thr)) {
num_thr = max_thr;
}
if (num_thr < 1) {
num_thr = 1;
}
nni_init_set_effective(NNG_INIT_NUM_EXPIRE_THREADS, num_thr);
params->num_expire_threads = num_thr;
nni_aio_expire_q_list =
nni_zalloc(sizeof(nni_aio_expire_q *) * num_thr);
nni_aio_expire_q_cnt = num_thr;
Expand Down
2 changes: 1 addition & 1 deletion src/core/aio.h
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,7 @@ extern void nni_aio_completions_run(nni_aio_completions *);
extern void nni_aio_completions_add(
nni_aio_completions *, nni_aio *, int, size_t);

extern int nni_aio_sys_init(void);
extern int nni_aio_sys_init(nng_init_params *);
extern void nni_aio_sys_fini(void);

typedef struct nni_aio_expire_q nni_aio_expire_q;
Expand Down
5 changes: 0 additions & 5 deletions src/core/dialer.c
Original file line number Diff line number Diff line change
Expand Up @@ -285,13 +285,8 @@ nni_dialer_create(nni_dialer **dp, nni_sock *s, const char *url_str)
int
nni_dialer_find(nni_dialer **dp, uint32_t id)
{
int rv;
nni_dialer *d;

if ((rv = nni_init()) != 0) {
return (rv);
}

nni_mtx_lock(&dialers_lk);
if ((d = nni_id_get(&dialers, id)) != NULL) {
d->d_ref++;
Expand Down
Loading

0 comments on commit 713b80f

Please sign in to comment.