aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt2
-rw-r--r--docs/man/CMakeLists.txt1
-rw-r--r--docs/man/libnng.3.adoc1
-rw-r--r--docs/man/nng_thread_set_name.3supp.adoc48
-rw-r--r--include/nng/supplemental/util/platform.h5
-rw-r--r--src/core/aio.c2
-rw-r--r--src/core/platform.h4
-rw-r--r--src/core/reap.c6
-rw-r--r--src/core/taskq.c4
-rw-r--r--src/core/thread.c8
-rw-r--r--src/core/thread.h5
-rw-r--r--src/core/timer.c4
-rw-r--r--src/platform/posix/posix_pollq_epoll.c1
-rw-r--r--src/platform/posix/posix_pollq_kqueue.c3
-rw-r--r--src/platform/posix/posix_pollq_poll.c3
-rw-r--r--src/platform/posix/posix_pollq_port.c1
-rw-r--r--src/platform/posix/posix_resolv_gai.c4
-rw-r--r--src/platform/posix/posix_thread.c27
-rw-r--r--src/platform/windows/win_io.c3
-rw-r--r--src/platform/windows/win_ipcdial.c4
-rw-r--r--src/platform/windows/win_resolv.c1
-rw-r--r--src/platform/windows/win_thread.c53
-rw-r--r--src/supplemental/util/platform.c12
-rw-r--r--src/transport/zerotier/zerotier.c1
24 files changed, 179 insertions, 24 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 0aecbd8e..77233435 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -317,6 +317,8 @@ else ()
nng_check_lib(rt clock_gettime NNG_HAVE_CLOCK_GETTIME)
nng_check_lib(pthread sem_wait NNG_HAVE_SEMAPHORE_PTHREAD)
nng_check_lib(pthread pthread_atfork NNG_HAVE_PTHREAD_ATFORK_PTHREAD)
+ nng_check_lib(pthread pthread_set_name_np NNG_HAVE_PTHREAD_SET_NAME_NP)
+ nng_check_lib(pthread pthread_setname_np NNG_HAVE_PTHREAD_SETNAME_NP)
nng_check_lib(nsl gethostbyname NNG_HAVE_LIBNSL)
nng_check_lib(socket socket NNG_HAVE_LIBSOCKET)
diff --git a/docs/man/CMakeLists.txt b/docs/man/CMakeLists.txt
index d17a1cfe..0f175195 100644
--- a/docs/man/CMakeLists.txt
+++ b/docs/man/CMakeLists.txt
@@ -303,6 +303,7 @@ if (NNG_ENABLE_DOC)
nng_random
nng_thread_create
nng_thread_destroy
+ nng_thread_set_name
)
set(NNG_MAN3STR
diff --git a/docs/man/libnng.3.adoc b/docs/man/libnng.3.adoc
index 6107da99..ab1a6b11 100644
--- a/docs/man/libnng.3.adoc
+++ b/docs/man/libnng.3.adoc
@@ -291,6 +291,7 @@ as a convenience to aid in creating portable applications.
|xref:nng_random.3supp.adoc[nng_random()]|get random number
|xref:nng_thread_create.3supp.adoc[nng_thread_create()]|create thread
|xref:nng_thread_destroy.3supp.adoc[nng_thread_destroy()]|reap thread
+|xref:nng_thread_set_name.3supp.adoc[nng_thread_set_name()]|set thread name
|===
=== Byte Streams
diff --git a/docs/man/nng_thread_set_name.3supp.adoc b/docs/man/nng_thread_set_name.3supp.adoc
new file mode 100644
index 00000000..385d2727
--- /dev/null
+++ b/docs/man/nng_thread_set_name.3supp.adoc
@@ -0,0 +1,48 @@
+= nng_thread_set_name(3supp)
+//
+// Copyright 2020 Staysail Systems, Inc. <info@staysail.tech>
+//
+// 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_thread_set_name - set thread name
+
+== SYNOPSIS
+
+[source, c]
+----
+#include <nng/nng.h>
+#include <nng/supplemental/util/platform.h>
+
+void nng_set_thread_name(nng_thread *thread, const char *name);
+----
+
+== DESCRIPTION
+
+The `nng_thread_set_name()` function attempts to set the name for the _thread_ to _name_.
+
+If _thread_ is `NULL`, then the name is set for the current thread.
+
+Support for this, and how names are exposed, varies between platform implementations.
+This function is intended to facilitate debugging applications that may have many threads.
+
+TIP: Internal threads created by _NNG_ will have names beginning with `nng:`.
+
+== RETURN VALUES
+
+None.
+
+== ERRORS
+
+None.
+
+== SEE ALSO
+
+[.text-left]
+xref:nng_thread_create.3supp.adoc[nng_thread_create(3supp)],
+xref:nng.7.adoc[nng(7)]
diff --git a/include/nng/supplemental/util/platform.h b/include/nng/supplemental/util/platform.h
index 87e0305f..feca858a 100644
--- a/include/nng/supplemental/util/platform.h
+++ b/include/nng/supplemental/util/platform.h
@@ -49,6 +49,11 @@ typedef struct nng_thread nng_thread;
// I/O APIs provided by nng. The thread runs until completion.
NNG_DECL int nng_thread_create(nng_thread **, void (*)(void *), void *);
+// Set the thread name. Support for this is platform specific and varies.
+// It is intended to provide information for use when debugging applications,
+// and not for programmatic use beyond that.
+NNG_DECL void nng_thread_set_name(nng_thread *, const char *);
+
// Destroy a thread (waiting for it to complete.) When this function
// returns all resources for the thread are cleaned up.
NNG_DECL void nng_thread_destroy(nng_thread *);
diff --git a/src/core/aio.c b/src/core/aio.c
index ea2203f2..97bb9153 100644
--- a/src/core/aio.c
+++ b/src/core/aio.c
@@ -488,6 +488,8 @@ nni_aio_expire_loop(void *unused)
NNI_ARG_UNUSED(unused);
+ nni_thr_set_name(NULL, "nng:aio:expire");
+
for (;;) {
nni_aio_cancelfn fn;
nni_time now;
diff --git a/src/core/platform.h b/src/core/platform.h
index c6f4ef30..6eff2f7d 100644
--- a/src/core/platform.h
+++ b/src/core/platform.h
@@ -157,6 +157,10 @@ extern void nni_plat_thr_fini(nni_plat_thr *);
// prevention in callbacks, for example.)
extern bool nni_plat_thr_is_self(nni_plat_thr *);
+// nni_plat_thr_set_name is used to set the thread name, which
+// should be a short ASCII string. It may or may not be supported --
+// this is intended to facilitate debugging.
+extern void nni_plat_thr_set_name(nni_plat_thr *, const char *);
//
// Atomics support. This will evolve over time.
//
diff --git a/src/core/reap.c b/src/core/reap.c
index bfad6c32..ddd2a06e 100644
--- a/src/core/reap.c
+++ b/src/core/reap.c
@@ -1,5 +1,5 @@
//
-// Copyright 2017 Garrett D'Amore <garrett@damore.org>
+// Copyright 2020 Staysail Systems, Inc. <info@staysail.tech>
// Copyright 2017 Capitar IT Group BV <info@capitar.com>
//
// This software is supplied under the terms of the MIT License, a
@@ -27,7 +27,9 @@ reap_worker(void *notused)
{
NNI_ARG_UNUSED(notused);
- nni_mtx_lock(&reap_mtx);
+ nni_thr_set_name(NULL, "nng:reap");
+
+ nni_mtx_lock(&reap_mtx);
for (;;) {
nni_reap_item *item;
while ((item = nni_list_first(&reap_list)) != NULL) {
diff --git a/src/core/taskq.c b/src/core/taskq.c
index fbd93ebe..9ccd5845 100644
--- a/src/core/taskq.c
+++ b/src/core/taskq.c
@@ -34,7 +34,9 @@ nni_taskq_thread(void *self)
nni_taskq * tq = thr->tqt_tq;
nni_task * task;
- nni_mtx_lock(&tq->tq_mtx);
+ nni_thr_set_name(NULL, "nng:task");
+
+ nni_mtx_lock(&tq->tq_mtx);
for (;;) {
if ((task = nni_list_first(&tq->tq_tasks)) != NULL) {
diff --git a/src/core/thread.c b/src/core/thread.c
index adc35542..986ff331 100644
--- a/src/core/thread.c
+++ b/src/core/thread.c
@@ -1,5 +1,5 @@
//
-// Copyright 2017 Garrett D'Amore <garrett@damore.org>
+// Copyright 2020 Staysail Systems, Inc. <info@staysail.tech>
//
// This software is supplied under the terms of the MIT License, a
// copy of which should be located in the distribution where this
@@ -182,3 +182,9 @@ nni_thr_is_self(nni_thr *thr)
}
return (nni_plat_thr_is_self(&thr->thr));
}
+
+void
+nni_thr_set_name(nni_thr *thr, const char *name)
+{
+ nni_plat_thr_set_name(&thr->thr, name);
+} \ No newline at end of file
diff --git a/src/core/thread.h b/src/core/thread.h
index c3d5531e..154b4616 100644
--- a/src/core/thread.h
+++ b/src/core/thread.h
@@ -1,5 +1,5 @@
//
-// Copyright 2017 Garrett D'Amore <garrett@damore.org>
+// Copyright 2020 Staysail Systems, Inc. <info@staysail.tech>
// Copyright 2017 Capitar IT Group BV <info@capitar.com>
//
// This software is supplied under the terms of the MIT License, a
@@ -85,4 +85,7 @@ extern void nni_thr_wait(nni_thr *thr);
// nni_thr_is_self returns true if the caller is the named thread.
extern bool nni_thr_is_self(nni_thr *thr);
+// nni_thr_set_name is used to set a short name for the thread.
+extern void nni_thr_set_name(nni_thr *thr, const char *);
+
#endif // CORE_THREAD_H
diff --git a/src/core/timer.c b/src/core/timer.c
index ad47ae33..36024817 100644
--- a/src/core/timer.c
+++ b/src/core/timer.c
@@ -1,5 +1,5 @@
//
-// Copyright 2018 Staysail Systems, Inc. <info@staysail.tech>
+// Copyright 2020 Staysail Systems, Inc. <info@staysail.tech>
// Copyright 2018 Capitar IT Group BV <info@capitar.com>
//
// This software is supplied under the terms of the MIT License, a
@@ -136,6 +136,8 @@ nni_timer_loop(void *arg)
nni_time now;
nni_timer_node *node;
+ nni_thr_set_name(NULL, "nng:timer");
+
for (;;) {
nni_mtx_lock(&timer->t_mx);
timer->t_active = NULL;
diff --git a/src/platform/posix/posix_pollq_epoll.c b/src/platform/posix/posix_pollq_epoll.c
index d7a2c70f..bbfa9f6e 100644
--- a/src/platform/posix/posix_pollq_epoll.c
+++ b/src/platform/posix/posix_pollq_epoll.c
@@ -377,6 +377,7 @@ nni_posix_pollq_create(nni_posix_pollq *pq)
nni_mtx_fini(&pq->mtx);
return (rv);
}
+ nni_thr_set_name(&pq->thr, "nng:poll:epoll");
nni_thr_run(&pq->thr);
return (0);
}
diff --git a/src/platform/posix/posix_pollq_kqueue.c b/src/platform/posix/posix_pollq_kqueue.c
index 7d827d7d..dda81be4 100644
--- a/src/platform/posix/posix_pollq_kqueue.c
+++ b/src/platform/posix/posix_pollq_kqueue.c
@@ -229,6 +229,8 @@ nni_posix_poll_thr(void *arg)
{
nni_posix_pollq *pq = arg;
+ nni_thr_set_name(NULL, "nng:poll:kqueue");
+
for (;;) {
int n;
struct kevent evs[NNI_MAX_KQUEUE_EVENTS];
@@ -335,7 +337,6 @@ nni_posix_pollq_create(nni_posix_pollq *pq)
int
nni_posix_pollq_sysinit(void)
{
-
return (nni_posix_pollq_create(&nni_posix_global_pollq));
}
diff --git a/src/platform/posix/posix_pollq_poll.c b/src/platform/posix/posix_pollq_poll.c
index 12c5e541..f6f81703 100644
--- a/src/platform/posix/posix_pollq_poll.c
+++ b/src/platform/posix/posix_pollq_poll.c
@@ -1,5 +1,5 @@
//
-// Copyright 2019 Staysail Systems, Inc. <info@staysail.tech>
+// Copyright 2020 Staysail Systems, Inc. <info@staysail.tech>
// Copyright 2018 Capitar IT Group BV <info@capitar.com>
//
// This software is supplied under the terms of the MIT License, a
@@ -329,6 +329,7 @@ nni_posix_pollq_create(nni_posix_pollq *pq)
nni_plat_pipe_close(pq->wakewfd, pq->wakerfd);
return (rv);
}
+ nni_thr_set_name(&pq->thr, "nng:poll:poll");
nni_mtx_init(&pq->mtx);
nni_thr_run(&pq->thr);
return (0);
diff --git a/src/platform/posix/posix_pollq_port.c b/src/platform/posix/posix_pollq_port.c
index bf628e47..7ce96f68 100644
--- a/src/platform/posix/posix_pollq_port.c
+++ b/src/platform/posix/posix_pollq_port.c
@@ -228,6 +228,7 @@ nni_posix_pollq_create(nni_posix_pollq *pq)
nni_posix_pollq_destroy(pq);
return (rv);
}
+ nni_thr_set_name(&pq->thr, "nng:poll:port");
nni_thr_run(&pq->thr);
return (0);
diff --git a/src/platform/posix/posix_resolv_gai.c b/src/platform/posix/posix_resolv_gai.c
index 88313045..1799935e 100644
--- a/src/platform/posix/posix_resolv_gai.c
+++ b/src/platform/posix/posix_resolv_gai.c
@@ -318,7 +318,9 @@ resolv_worker(void *unused)
NNI_ARG_UNUSED(unused);
- nni_mtx_lock(&resolv_mtx);
+ nni_thr_set_name(NULL, "nng:resolver");
+
+ nni_mtx_lock(&resolv_mtx);
for (;;) {
nni_aio * aio;
resolv_item *item;
diff --git a/src/platform/posix/posix_thread.c b/src/platform/posix/posix_thread.c
index b8fa814e..0178455f 100644
--- a/src/platform/posix/posix_thread.c
+++ b/src/platform/posix/posix_thread.c
@@ -1,5 +1,5 @@
//
-// Copyright 2018 Staysail Systems, Inc. <info@staysail.tech>
+// Copyright 2020 Staysail Systems, Inc. <info@staysail.tech>
// Copyright 2018 Capitar IT Group BV <info@capitar.com>
//
// This software is supplied under the terms of the MIT License, a
@@ -254,6 +254,31 @@ nni_plat_thr_is_self(nni_plat_thr *thr)
}
void
+nni_plat_thr_set_name(nni_plat_thr *thr, const char *name)
+{
+#if defined(NNG_HAVE_PTHREAD_SET_NAME_NP)
+ if (thr == NULL) {
+ pthread_set_name_np(pthread_self(), name);
+ } else {
+ pthread_set_name_np(thr->tid, name);
+ }
+#elif defined(NNG_HAVE_PTHREAD_SETNAME_NP)
+#if defined(__APPLE__)
+ // Darwin is weird, it can only set the name of pthread_self.
+ if ((thr == NULL) || (pthread_self() == thr->tid)) {
+ pthread_setname_np(name);
+ }
+#else
+ if (thr == NULL) {
+ pthread_setname_np(pthread_self(), name);
+ } else {
+ pthread_setname_np(thr->tid, name);
+ }
+#endif
+#endif
+}
+
+void
nni_atfork_child(void)
{
nni_plat_forked = 1;
diff --git a/src/platform/windows/win_io.c b/src/platform/windows/win_io.c
index 81214498..489dc01a 100644
--- a/src/platform/windows/win_io.c
+++ b/src/platform/windows/win_io.c
@@ -1,5 +1,5 @@
//
-// Copyright 2018 Staysail Systems, Inc. <info@staysail.tech>
+// Copyright 2020 Staysail Systems, Inc. <info@staysail.tech>
// Copyright 2018 Capitar IT Group BV <info@capitar.com>
//
// This software is supplied under the terms of the MIT License, a
@@ -114,6 +114,7 @@ nni_win_io_sysinit(void)
if (rv != 0) {
goto fail;
}
+ nni_thr_set_name(&win_io_thrs[i], "nng:iocp");
}
for (i = 0; i < win_io_nthr; i++) {
nni_thr_run(&win_io_thrs[i]);
diff --git a/src/platform/windows/win_ipcdial.c b/src/platform/windows/win_ipcdial.c
index 5deebc01..65d1b544 100644
--- a/src/platform/windows/win_ipcdial.c
+++ b/src/platform/windows/win_ipcdial.c
@@ -1,5 +1,5 @@
//
-// Copyright 2019 Staysail Systems, Inc. <info@staysail.tech>
+// Copyright 2020 Staysail Systems, Inc. <info@staysail.tech>
// Copyright 2018 Capitar IT Group BV <info@capitar.com>
// Copyright 2019 Devolutions <info@devolutions.net>
//
@@ -269,7 +269,7 @@ nni_win_ipc_sysinit(void)
if (rv != 0) {
return (rv);
}
-
+ nni_thr_set_name(&worker->thr, "nng:ipc:dial");
nni_thr_run(&worker->thr);
return (0);
diff --git a/src/platform/windows/win_resolv.c b/src/platform/windows/win_resolv.c
index d80b5ddf..d1cc058e 100644
--- a/src/platform/windows/win_resolv.c
+++ b/src/platform/windows/win_resolv.c
@@ -432,6 +432,7 @@ nni_win_resolv_sysinit(void)
nni_win_resolv_sysfini();
return (rv);
}
+ nni_thr_set_name(&resolv_thrs[i], "nng:resolver");
}
for (int i = 0; i < NNG_RESOLV_CONCURRENCY; i++) {
nni_thr_run(&resolv_thrs[i]);
diff --git a/src/platform/windows/win_thread.c b/src/platform/windows/win_thread.c
index 785376df..7cc87eb3 100644
--- a/src/platform/windows/win_thread.c
+++ b/src/platform/windows/win_thread.c
@@ -14,10 +14,14 @@
#ifdef NNG_PLATFORM_WINDOWS
+typedef HRESULT(WINAPI *pfnSetThreadDescription)(HANDLE, PCWSTR);
+static HMODULE hKernel32;
+
+static pfnSetThreadDescription set_thread_desc;
+
// mingw does not define InterlockedAddNoFence64, use the mingw equivalent
#if defined(__MINGW32__) || defined(__MINGW64__)
-#define InterlockedAddNoFence(a, b) \
- __atomic_add_fetch(a, b, __ATOMIC_RELAXED)
+#define InterlockedAddNoFence(a, b) __atomic_add_fetch(a, b, __ATOMIC_RELAXED)
#define InterlockedAddNoFence64(a, b) \
__atomic_add_fetch(a, b, __ATOMIC_RELAXED)
#define InterlockedIncrementAcquire64(a) \
@@ -219,11 +223,10 @@ bool
nni_atomic_cas64(nni_atomic_u64 *v, uint64_t comp, uint64_t new)
{
uint64_t old;
- old = InterlockedCompareExchange64(&v->v, (LONG64)new, (LONG64)comp);
+ old = InterlockedCompareExchange64(&v->v, (LONG64) new, (LONG64) comp);
return (old == comp);
}
-
void
nni_atomic_add(nni_atomic_int *v, int bump)
{
@@ -278,11 +281,10 @@ bool
nni_atomic_cas(nni_atomic_int *v, int comp, int new)
{
int old;
- old = InterlockedCompareExchange(&v->v, (LONG)new, (LONG)comp);
+ old = InterlockedCompareExchange(&v->v, (LONG) new, (LONG) comp);
return (old == comp);
}
-
static unsigned int __stdcall nni_plat_thr_main(void *arg)
{
nni_plat_thr *thr = arg;
@@ -325,6 +327,30 @@ nni_plat_thr_is_self(nni_plat_thr *thr)
return (GetCurrentThreadId() == thr->id);
}
+void
+nni_plat_thr_set_name(nni_plat_thr *thr, const char *name)
+{
+ if (set_thread_desc != NULL) {
+ wchar_t *wcs;
+ size_t len;
+ HANDLE h;
+
+ if (thr == NULL) {
+ h = GetCurrentThread();
+ } else {
+ h = thr->handle;
+ }
+
+ len = strlen(name) + 1;
+ if ((wcs = nni_alloc(len * 2)) == NULL) {
+ return;
+ }
+ (void) MultiByteToWideChar(CP_UTF8, 0, name, len, wcs, len);
+ set_thread_desc(h, wcs);
+ nni_free(wcs, len * 2);
+ }
+}
+
static LONG plat_inited = 0;
int
@@ -346,10 +372,18 @@ nni_plat_init(int (*helper)(void))
return (0); // fast path
}
- AcquireSRWLockExclusive(&lock);
+
+ AcquireSRWLockExclusive(&lock);
if (!plat_inited) {
- if (((rv = nni_win_io_sysinit()) != 0) ||
+ // Let's look up the function to set thread descriptions.
+ hKernel32 = LoadLibrary(TEXT("kernel32.dll"));
+ if (hKernel32 != NULL) {
+ set_thread_desc = (pfnSetThreadDescription)
+ GetProcAddress(hKernel32, "SetThreadDescription");
+ }
+
+ if (((rv = nni_win_io_sysinit()) != 0) ||
((rv = nni_win_ipc_sysinit()) != 0) ||
((rv = nni_win_tcp_sysinit()) != 0) ||
((rv = nni_win_udp_sysinit()) != 0) ||
@@ -376,6 +410,9 @@ nni_plat_fini(void)
nni_win_tcp_sysfini();
nni_win_io_sysfini();
WSACleanup();
+ if (hKernel32 != NULL) {
+ FreeLibrary(hKernel32);
+ }
plat_inited = 0;
}
diff --git a/src/supplemental/util/platform.c b/src/supplemental/util/platform.c
index 468582bd..8898b680 100644
--- a/src/supplemental/util/platform.c
+++ b/src/supplemental/util/platform.c
@@ -1,5 +1,5 @@
//
-// Copyright 2018 Staysail Systems, Inc. <info@staysail.tech>
+// Copyright 2020 Staysail Systems, Inc. <info@staysail.tech>
// Copyright 2018 Capitar IT Group BV <info@capitar.com>
//
// This software is supplied under the terms of the MIT License, a
@@ -52,12 +52,18 @@ nng_thread_create(nng_thread **thrp, void (*func)(void *), void *arg)
return (0);
}
+void
+nng_thread_set_name(nng_thread *thr, const char *name)
+{
+ nni_thr_set_name((void *)thr, name);
+}
+
// Destroy a thread (waiting for it to complete.) When this function
// returns all resources for the thread are cleaned up.
void
-nng_thread_destroy(nng_thread *thrp)
+nng_thread_destroy(nng_thread *thr)
{
- nni_thr *t = (void *) thrp;
+ nni_thr *t = (void *) thr;
nni_thr_fini(t);
NNI_FREE_STRUCT(t);
}
diff --git a/src/transport/zerotier/zerotier.c b/src/transport/zerotier/zerotier.c
index 64fdad87..e4cddb20 100644
--- a/src/transport/zerotier/zerotier.c
+++ b/src/transport/zerotier/zerotier.c
@@ -1458,6 +1458,7 @@ zt_node_create(zt_node **ztnp, const char *path)
zt_node_destroy(ztn);
return (rv);
}
+ nni_thr_set_name(&ztn->zn_bgthr, "nng:zt");
if (strlen(path) > 0) {
char *lkfile;