From 9714e0376a2890b850496c981694af5f91a49353 Mon Sep 17 00:00:00 2001 From: Ken Payson Date: Tue, 10 Oct 2017 11:18:49 -0700 Subject: Add thread pool reset on fork with FORKING_SUPPORT_ENABLED --- src/core/lib/support/fork.c | 62 +++++++++++++++++++++++++++++++++++++ src/core/lib/support/fork.h | 35 +++++++++++++++++++++ src/core/lib/support/thd_internal.h | 30 ++++++++++++++++++ src/core/lib/support/thd_posix.c | 56 +++++++++++++++++++++++++++++++++ src/core/lib/support/thd_windows.c | 2 ++ 5 files changed, 185 insertions(+) create mode 100644 src/core/lib/support/fork.c create mode 100644 src/core/lib/support/fork.h create mode 100644 src/core/lib/support/thd_internal.h (limited to 'src/core/lib/support') diff --git a/src/core/lib/support/fork.c b/src/core/lib/support/fork.c new file mode 100644 index 0000000000..2f29af899d --- /dev/null +++ b/src/core/lib/support/fork.c @@ -0,0 +1,62 @@ +/* + * + * Copyright 2017 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include "src/core/lib/support/fork.h" + +#include + +#include +#include + +#include "src/core/lib/support/env.h" + +/* + * NOTE: FORKING IS NOT GENERALLY SUPPORTED, THIS IS ONLY INTENDED TO WORK + * AROUND VERY SPECIFIC USE CASES. + */ + +static int override_fork_support_enabled = -1; +static int fork_support_enabled; + +void grpc_fork_support_init() { +#ifdef GRPC_ENABLE_FORK_SUPPORT + fork_support_enabled = 1; +#else + fork_support_enabled = 0; + char *env = gpr_getenv("GRPC_ENABLE_FORK_SUPPORT"); + if (env != NULL) { + static const char *truthy[] = {"yes", "Yes", "YES", "true", + "True", "TRUE", "1"}; + for (size_t i = 0; i < GPR_ARRAY_SIZE(truthy); i++) { + if (0 == strcmp(env, truthy[i])) { + fork_support_enabled = 1; + } + } + gpr_free(env); + } +#endif + if (override_fork_support_enabled != -1) { + fork_support_enabled = override_fork_support_enabled; + } +} + +int grpc_fork_support_enabled() { return fork_support_enabled; } + +void grpc_enable_fork_support(int enable) { + override_fork_support_enabled = enable; +} diff --git a/src/core/lib/support/fork.h b/src/core/lib/support/fork.h new file mode 100644 index 0000000000..215d4214a6 --- /dev/null +++ b/src/core/lib/support/fork.h @@ -0,0 +1,35 @@ +/* + * + * Copyright 2017 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#ifndef GRPC_CORE_LIB_SUPPORT_FORK_H +#define GRPC_CORE_LIB_SUPPORT_FORK_H + +/* + * NOTE: FORKING IS NOT GENERALLY SUPPORTED, THIS IS ONLY INTENDED TO WORK + * AROUND VERY SPECIFIC USE CASES. + */ + +void grpc_fork_support_init(void); + +int grpc_fork_support_enabled(void); + +// Test only: Must be called before grpc_init(), and overrides +// environment variables/compile flags +void grpc_enable_fork_support(int enable); + +#endif /* GRPC_CORE_LIB_SUPPORT_FORK_H */ diff --git a/src/core/lib/support/thd_internal.h b/src/core/lib/support/thd_internal.h new file mode 100644 index 0000000000..38bffc847d --- /dev/null +++ b/src/core/lib/support/thd_internal.h @@ -0,0 +1,30 @@ +/* + * + * Copyright 2015 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#ifndef GRPC_CORE_LIB_SUPPORT_THD_INTERNAL_H +#define GRPC_CORE_LIB_SUPPORT_THD_INTERNAL_H + +#include + +/* Internal interfaces between modules within the gpr support library. */ +void gpr_thd_init(); + +/* Wait for all outstanding threads to finish, up to deadline */ +int gpr_await_threads(gpr_timespec deadline); + +#endif /* GRPC_CORE_LIB_SUPPORT_THD_INTERNAL_H */ diff --git a/src/core/lib/support/thd_posix.c b/src/core/lib/support/thd_posix.c index 98afd10df7..219297c046 100644 --- a/src/core/lib/support/thd_posix.c +++ b/src/core/lib/support/thd_posix.c @@ -24,22 +24,34 @@ #include #include +#include #include #include #include #include #include +#include "src/core/lib/support/fork.h" + +static gpr_mu g_mu; +static gpr_cv g_cv; +static int g_thread_count; +static int g_awaiting_threads; + struct thd_arg { void (*body)(void *arg); /* body of a thread */ void *arg; /* argument to a thread */ }; +static void inc_thd_count(); +static void dec_thd_count(); + /* Body of every thread started via gpr_thd_new. */ static void *thread_body(void *v) { struct thd_arg a = *(struct thd_arg *)v; free(v); (*a.body)(a.arg); + dec_thd_count(); return NULL; } @@ -54,6 +66,7 @@ int gpr_thd_new(gpr_thd_id *t, void (*thd_body)(void *arg), void *arg, GPR_ASSERT(a != NULL); a->body = thd_body; a->arg = arg; + inc_thd_count(); GPR_ASSERT(pthread_attr_init(&attr) == 0); if (gpr_thd_options_is_detached(options)) { @@ -68,6 +81,7 @@ int gpr_thd_new(gpr_thd_id *t, void (*thd_body)(void *arg), void *arg, if (!thread_started) { /* don't use gpr_free, as this was allocated using malloc (see above) */ free(a); + dec_thd_count(); } *t = (gpr_thd_id)p; return thread_started; @@ -77,4 +91,46 @@ gpr_thd_id gpr_thd_currentid(void) { return (gpr_thd_id)pthread_self(); } void gpr_thd_join(gpr_thd_id t) { pthread_join((pthread_t)t, NULL); } +/***************************************** + * Only used when fork support is enabled + */ + +static void inc_thd_count() { + if (grpc_fork_support_enabled()) { + gpr_mu_lock(&g_mu); + g_thread_count++; + gpr_mu_unlock(&g_mu); + } +} + +static void dec_thd_count() { + if (grpc_fork_support_enabled()) { + gpr_mu_lock(&g_mu); + g_thread_count--; + if (g_awaiting_threads && g_thread_count == 0) { + gpr_cv_signal(&g_cv); + } + gpr_mu_unlock(&g_mu); + } +} + +void gpr_thd_init() { + gpr_mu_init(&g_mu); + gpr_cv_init(&g_cv); + g_thread_count = 0; + g_awaiting_threads = 0; +} + +int gpr_await_threads(gpr_timespec deadline) { + gpr_mu_lock(&g_mu); + g_awaiting_threads = 1; + int res = 0; + if (g_thread_count > 0) { + res = gpr_cv_wait(&g_cv, &g_mu, deadline); + } + g_awaiting_threads = 0; + gpr_mu_unlock(&g_mu); + return res == 0; +} + #endif /* GPR_POSIX_SYNC */ diff --git a/src/core/lib/support/thd_windows.c b/src/core/lib/support/thd_windows.c index 54533e9412..4c6013bf33 100644 --- a/src/core/lib/support/thd_windows.c +++ b/src/core/lib/support/thd_windows.c @@ -50,6 +50,8 @@ static void destroy_thread(struct thd_info *t) { gpr_free(t); } +void gpr_thd_init(void) {} + /* Body of every thread started via gpr_thd_new. */ static DWORD WINAPI thread_body(void *v) { g_thd_info = (struct thd_info *)v; -- cgit v1.2.3 From e3ee18ada980020ff718332509e0d1d33a8a0885 Mon Sep 17 00:00:00 2001 From: Nicolas Noble Date: Tue, 10 Oct 2017 09:49:10 -0700 Subject: Fix Windows's memory leak (cherry picked from commit 3290e49a1d5b896b7ce65d658ffef00bf65d35dd) clang-format. (cherry picked from commit c02dbe57c666e26f40e517b6f940f6cbd4bb43fc) --- src/core/lib/support/env_windows.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'src/core/lib/support') diff --git a/src/core/lib/support/env_windows.c b/src/core/lib/support/env_windows.c index 652eeb61c6..a6499543f8 100644 --- a/src/core/lib/support/env_windows.c +++ b/src/core/lib/support/env_windows.c @@ -43,7 +43,10 @@ char *gpr_getenv(const char *name) { DWORD ret; ret = GetEnvironmentVariable(tname, NULL, 0); - if (ret == 0) return NULL; + if (ret == 0) { + gpr_free(tname); + return NULL; + } size = ret * (DWORD)sizeof(TCHAR); tresult = gpr_malloc(size); ret = GetEnvironmentVariable(tname, tresult, size); -- cgit v1.2.3