aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--docs/src/misc.rst16
-rw-r--r--include/uv.h2
-rw-r--r--src/threadpool.c4
-rw-r--r--src/unix/aix.c2
-rw-r--r--src/unix/bsd-proctitle.c7
-rw-r--r--src/unix/internal.h2
-rw-r--r--src/unix/no-proctitle.c3
-rw-r--r--src/unix/proctitle.c2
-rw-r--r--src/unix/signal.c4
-rw-r--r--src/uv-common.c16
-rw-r--r--src/uv-common.h4
-rw-r--r--src/win/signal.c5
-rw-r--r--src/win/util.c4
-rw-r--r--test/task.h1
14 files changed, 64 insertions, 8 deletions
diff --git a/docs/src/misc.rst b/docs/src/misc.rst
index 7640b8b0..7bf71b12 100644
--- a/docs/src/misc.rst
+++ b/docs/src/misc.rst
@@ -233,6 +233,22 @@ API
sure the allocator is changed while no memory was allocated with
the previous allocator, or that they are compatible.
+.. c:function:: void uv_library_shutdown(void);
+
+ .. versionadded:: 1.38.0
+
+ Release any global state that libuv is holding onto. Libuv will normally
+ do so automatically when it is unloaded but it can be instructed to perform
+ cleanup manually.
+
+ .. warning:: Only call :c:func:`uv_library_shutdown()` once.
+
+ .. warning:: Don't call :c:func:`uv_library_shutdown()` when there are
+ still event loops or I/O requests active.
+
+ .. warning:: Don't call libuv functions after calling
+ :c:func:`uv_library_shutdown()`.
+
.. c:function:: uv_buf_t uv_buf_init(char* base, unsigned int len)
Constructor for :c:type:`uv_buf_t`.
diff --git a/include/uv.h b/include/uv.h
index 3a2a504d..fb51dfd6 100644
--- a/include/uv.h
+++ b/include/uv.h
@@ -265,6 +265,8 @@ typedef void* (*uv_realloc_func)(void* ptr, size_t size);
typedef void* (*uv_calloc_func)(size_t count, size_t size);
typedef void (*uv_free_func)(void* ptr);
+UV_EXTERN void uv_library_shutdown(void);
+
UV_EXTERN int uv_replace_allocator(uv_malloc_func malloc_func,
uv_realloc_func realloc_func,
uv_calloc_func calloc_func,
diff --git a/src/threadpool.c b/src/threadpool.c
index a8f433f0..0998938f 100644
--- a/src/threadpool.c
+++ b/src/threadpool.c
@@ -160,8 +160,8 @@ static void post(QUEUE* q, enum uv__work_kind kind) {
}
+void uv__threadpool_cleanup(void) {
#ifndef _WIN32
-UV_DESTRUCTOR(static void cleanup(void)) {
unsigned int i;
if (nthreads == 0)
@@ -181,8 +181,8 @@ UV_DESTRUCTOR(static void cleanup(void)) {
threads = NULL;
nthreads = 0;
-}
#endif
+}
static void init_threads(void) {
diff --git a/src/unix/aix.c b/src/unix/aix.c
index 417ee551..6b4594b4 100644
--- a/src/unix/aix.c
+++ b/src/unix/aix.c
@@ -926,7 +926,7 @@ int uv_get_process_title(char* buffer, size_t size) {
}
-UV_DESTRUCTOR(static void free_args_mem(void)) {
+void uv__process_title_cleanup(void) {
uv__free(args_mem); /* Keep valgrind happy. */
args_mem = NULL;
}
diff --git a/src/unix/bsd-proctitle.c b/src/unix/bsd-proctitle.c
index 0ce47c8f..723b81c0 100644
--- a/src/unix/bsd-proctitle.c
+++ b/src/unix/bsd-proctitle.c
@@ -37,6 +37,13 @@ static void init_process_title_mutex_once(void) {
}
+void uv__process_title_cleanup(void) {
+ /* TODO(bnoordhuis) uv_mutex_destroy(&process_title_mutex)
+ * and reset process_title_mutex_once?
+ */
+}
+
+
char** uv_setup_args(int argc, char** argv) {
process_title = argc > 0 ? uv__strdup(argv[0]) : NULL;
return argv;
diff --git a/src/unix/internal.h b/src/unix/internal.h
index 598554b6..402ee877 100644
--- a/src/unix/internal.h
+++ b/src/unix/internal.h
@@ -106,10 +106,8 @@ int uv__pthread_sigmask(int how, const sigset_t* set, sigset_t* oset);
#if defined(__clang__) || \
defined(__GNUC__) || \
defined(__INTEL_COMPILER)
-# define UV_DESTRUCTOR(declaration) __attribute__((destructor)) declaration
# define UV_UNUSED(declaration) __attribute__((unused)) declaration
#else
-# define UV_DESTRUCTOR(declaration) declaration
# define UV_UNUSED(declaration) declaration
#endif
diff --git a/src/unix/no-proctitle.c b/src/unix/no-proctitle.c
index 165740ca..32aa0af1 100644
--- a/src/unix/no-proctitle.c
+++ b/src/unix/no-proctitle.c
@@ -29,6 +29,9 @@ char** uv_setup_args(int argc, char** argv) {
return argv;
}
+void uv__process_title_cleanup(void) {
+}
+
int uv_set_process_title(const char* title) {
return 0;
}
diff --git a/src/unix/proctitle.c b/src/unix/proctitle.c
index d124d3c7..4ee991fc 100644
--- a/src/unix/proctitle.c
+++ b/src/unix/proctitle.c
@@ -145,7 +145,7 @@ int uv_get_process_title(char* buffer, size_t size) {
}
-UV_DESTRUCTOR(static void free_args_mem(void)) {
+void uv__process_title_cleanup(void) {
uv__free(args_mem); /* Keep valgrind happy. */
args_mem = NULL;
}
diff --git a/src/unix/signal.c b/src/unix/signal.c
index 1e7e8ac5..1c83e095 100644
--- a/src/unix/signal.c
+++ b/src/unix/signal.c
@@ -77,7 +77,7 @@ static void uv__signal_global_init(void) {
}
-UV_DESTRUCTOR(static void uv__signal_global_fini(void)) {
+void uv__signal_cleanup(void) {
/* We can only use signal-safe functions here.
* That includes read/write and close, fortunately.
* We do all of this directly here instead of resetting
@@ -98,7 +98,7 @@ UV_DESTRUCTOR(static void uv__signal_global_fini(void)) {
static void uv__signal_global_reinit(void) {
- uv__signal_global_fini();
+ uv__signal_cleanup();
if (uv__make_pipe(uv__signal_lock_pipefd, 0))
abort();
diff --git a/src/uv-common.c b/src/uv-common.c
index 5cb1a8c8..f69a2c1d 100644
--- a/src/uv-common.c
+++ b/src/uv-common.c
@@ -821,3 +821,19 @@ void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) {
uv__free(cpu_infos);
}
+
+
+#ifdef __GNUC__ /* Also covers __clang__ and __INTEL_COMPILER. */
+__attribute__((destructor))
+#endif
+void uv_library_shutdown(void) {
+ static int was_shutdown;
+
+ if (was_shutdown)
+ return;
+
+ uv__process_title_cleanup();
+ uv__signal_cleanup();
+ uv__threadpool_cleanup();
+ was_shutdown = 1;
+}
diff --git a/src/uv-common.h b/src/uv-common.h
index f08fb8ae..28cc852c 100644
--- a/src/uv-common.h
+++ b/src/uv-common.h
@@ -201,6 +201,10 @@ int uv__next_timeout(const uv_loop_t* loop);
void uv__run_timers(uv_loop_t* loop);
void uv__timer_close(uv_timer_t* handle);
+void uv__process_title_cleanup(void);
+void uv__signal_cleanup(void);
+void uv__threadpool_cleanup(void);
+
#define uv__has_active_reqs(loop) \
((loop)->active_reqs.count > 0)
diff --git a/src/win/signal.c b/src/win/signal.c
index 276dc609..3d9f92cf 100644
--- a/src/win/signal.c
+++ b/src/win/signal.c
@@ -46,6 +46,11 @@ void uv_signals_init(void) {
}
+void uv__signal_cleanup(void) {
+ /* TODO(bnoordhuis) Undo effects of uv_signal_init()? */
+}
+
+
static int uv__signal_compare(uv_signal_t* w1, uv_signal_t* w2) {
/* Compare signums first so all watchers with the same signnum end up
* adjacent. */
diff --git a/src/win/util.c b/src/win/util.c
index aaa7ba03..ff8a28b4 100644
--- a/src/win/util.c
+++ b/src/win/util.c
@@ -361,6 +361,10 @@ char** uv_setup_args(int argc, char** argv) {
}
+void uv__process_title_cleanup(void) {
+}
+
+
int uv_set_process_title(const char* title) {
int err;
int length;
diff --git a/test/task.h b/test/task.h
index 27b73103..e95e3bde 100644
--- a/test/task.h
+++ b/test/task.h
@@ -230,6 +230,7 @@ typedef enum {
do { \
close_loop(uv_default_loop()); \
ASSERT(0 == uv_loop_close(uv_default_loop())); \
+ uv_library_shutdown(); \
} while (0)
/* Just sugar for wrapping the main() for a task or helper. */