diff options
| author | Garrett D'Amore <garrett@damore.org> | 2020-08-08 18:25:48 -0700 |
|---|---|---|
| committer | Garrett D'Amore <garrett@damore.org> | 2020-08-08 19:30:17 -0700 |
| commit | 6c5070d9157ab0de667568655f0bbeb60780d701 (patch) | |
| tree | ab1a03e16907c97e6d76f1d95d79aea0f4a875ce | |
| parent | ddc0d044dd0fcf4aa1dc333fd5bda0de47850a64 (diff) | |
| download | nng-6c5070d9157ab0de667568655f0bbeb60780d701.tar.gz nng-6c5070d9157ab0de667568655f0bbeb60780d701.tar.bz2 nng-6c5070d9157ab0de667568655f0bbeb60780d701.zip | |
fixes #960 NNG threads inherit application thread name
This also exposes an nng_thread_set_name() function for
applications to use. All NNG thread names start with "nng:".
Note that support is highly dependent on the operating system.
| -rw-r--r-- | CMakeLists.txt | 2 | ||||
| -rw-r--r-- | docs/man/CMakeLists.txt | 1 | ||||
| -rw-r--r-- | docs/man/libnng.3.adoc | 1 | ||||
| -rw-r--r-- | docs/man/nng_thread_set_name.3supp.adoc | 48 | ||||
| -rw-r--r-- | include/nng/supplemental/util/platform.h | 5 | ||||
| -rw-r--r-- | src/core/aio.c | 2 | ||||
| -rw-r--r-- | src/core/platform.h | 4 | ||||
| -rw-r--r-- | src/core/reap.c | 6 | ||||
| -rw-r--r-- | src/core/taskq.c | 4 | ||||
| -rw-r--r-- | src/core/thread.c | 8 | ||||
| -rw-r--r-- | src/core/thread.h | 5 | ||||
| -rw-r--r-- | src/core/timer.c | 4 | ||||
| -rw-r--r-- | src/platform/posix/posix_pollq_epoll.c | 1 | ||||
| -rw-r--r-- | src/platform/posix/posix_pollq_kqueue.c | 3 | ||||
| -rw-r--r-- | src/platform/posix/posix_pollq_poll.c | 3 | ||||
| -rw-r--r-- | src/platform/posix/posix_pollq_port.c | 1 | ||||
| -rw-r--r-- | src/platform/posix/posix_resolv_gai.c | 4 | ||||
| -rw-r--r-- | src/platform/posix/posix_thread.c | 27 | ||||
| -rw-r--r-- | src/platform/windows/win_io.c | 3 | ||||
| -rw-r--r-- | src/platform/windows/win_ipcdial.c | 4 | ||||
| -rw-r--r-- | src/platform/windows/win_resolv.c | 1 | ||||
| -rw-r--r-- | src/platform/windows/win_thread.c | 53 | ||||
| -rw-r--r-- | src/supplemental/util/platform.c | 12 | ||||
| -rw-r--r-- | src/transport/zerotier/zerotier.c | 1 |
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; |
