Merge pull request #14647 from kpayson64/fork_exec_ctx_check

Add exec_ctx check to fork handlers
pull/15360/head
kpayson64 7 years ago committed by GitHub
commit 5fc081acd1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 4
      BUILD
  2. 33
      CMakeLists.txt
  3. 38
      Makefile
  4. 16
      build.yaml
  5. 2
      config.m4
  6. 2
      config.w32
  7. 4
      gRPC-C++.podspec
  8. 6
      gRPC-Core.podspec
  9. 4
      grpc.gemspec
  10. 2
      grpc.gyp
  11. 4
      package.xml
  12. 78
      src/core/lib/gpr/fork.cc
  13. 35
      src/core/lib/gpr/fork.h
  14. 260
      src/core/lib/gprpp/fork.cc
  15. 79
      src/core/lib/gprpp/fork.h
  16. 3
      src/core/lib/gprpp/thd.h
  17. 57
      src/core/lib/gprpp/thd_posix.cc
  18. 7
      src/core/lib/gprpp/thd_windows.cc
  19. 12
      src/core/lib/iomgr/exec_ctx.h
  20. 47
      src/core/lib/iomgr/fork_posix.cc
  21. 9
      src/core/lib/surface/init.cc
  22. 2
      src/python/grpcio/grpc_core_dependencies.py
  23. 10
      test/core/gprpp/BUILD
  24. 135
      test/core/gprpp/fork_test.cc
  25. 2
      tools/doxygen/Doxyfile.c++.internal
  26. 4
      tools/doxygen/Doxyfile.core.internal
  27. 21
      tools/run_tests/generated/sources_and_headers.json
  28. 20
      tools/run_tests/generated/tests.json

@ -512,7 +512,6 @@ grpc_cc_library(
"src/core/lib/gpr/env_linux.cc",
"src/core/lib/gpr/env_posix.cc",
"src/core/lib/gpr/env_windows.cc",
"src/core/lib/gpr/fork.cc",
"src/core/lib/gpr/host_port.cc",
"src/core/lib/gpr/log.cc",
"src/core/lib/gpr/log_android.cc",
@ -537,6 +536,7 @@ grpc_cc_library(
"src/core/lib/gpr/tmpfile_posix.cc",
"src/core/lib/gpr/tmpfile_windows.cc",
"src/core/lib/gpr/wrap_memcpy.cc",
"src/core/lib/gprpp/fork.cc",
"src/core/lib/gprpp/thd_posix.cc",
"src/core/lib/gprpp/thd_windows.cc",
"src/core/lib/profiling/basic_timers.cc",
@ -545,7 +545,6 @@ grpc_cc_library(
hdrs = [
"src/core/lib/gpr/arena.h",
"src/core/lib/gpr/env.h",
"src/core/lib/gpr/fork.h",
"src/core/lib/gpr/host_port.h",
"src/core/lib/gpr/mpscq.h",
"src/core/lib/gpr/murmur_hash.h",
@ -560,6 +559,7 @@ grpc_cc_library(
"src/core/lib/gpr/tmpfile.h",
"src/core/lib/gpr/useful.h",
"src/core/lib/gprpp/abstract.h",
"src/core/lib/gprpp/fork.h",
"src/core/lib/gprpp/manual_constructor.h",
"src/core/lib/gprpp/memory.h",
"src/core/lib/gprpp/thd.h",

@ -264,6 +264,9 @@ endif()
if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
add_dependencies(buildtests_c fling_test)
endif()
if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC)
add_dependencies(buildtests_c fork_test)
endif()
if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
add_dependencies(buildtests_c goaway_server_test)
endif()
@ -760,7 +763,6 @@ add_library(gpr
src/core/lib/gpr/env_linux.cc
src/core/lib/gpr/env_posix.cc
src/core/lib/gpr/env_windows.cc
src/core/lib/gpr/fork.cc
src/core/lib/gpr/host_port.cc
src/core/lib/gpr/log.cc
src/core/lib/gpr/log_android.cc
@ -785,6 +787,7 @@ add_library(gpr
src/core/lib/gpr/tmpfile_posix.cc
src/core/lib/gpr/tmpfile_windows.cc
src/core/lib/gpr/wrap_memcpy.cc
src/core/lib/gprpp/fork.cc
src/core/lib/gprpp/thd_posix.cc
src/core/lib/gprpp/thd_windows.cc
src/core/lib/profiling/basic_timers.cc
@ -6412,6 +6415,34 @@ target_link_libraries(fling_test
gpr
)
endif()
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC)
add_executable(fork_test
test/core/gprpp/fork_test.cc
)
target_include_directories(fork_test
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include
PRIVATE ${_gRPC_SSL_INCLUDE_DIR}
PRIVATE ${_gRPC_PROTOBUF_INCLUDE_DIR}
PRIVATE ${_gRPC_ZLIB_INCLUDE_DIR}
PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
)
target_link_libraries(fork_test
${_gRPC_ALLTARGETS_LIBRARIES}
gpr_test_util
gpr
)
endif()
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)

@ -993,6 +993,7 @@ fling_client: $(BINDIR)/$(CONFIG)/fling_client
fling_server: $(BINDIR)/$(CONFIG)/fling_server
fling_stream_test: $(BINDIR)/$(CONFIG)/fling_stream_test
fling_test: $(BINDIR)/$(CONFIG)/fling_test
fork_test: $(BINDIR)/$(CONFIG)/fork_test
goaway_server_test: $(BINDIR)/$(CONFIG)/goaway_server_test
gpr_cpu_test: $(BINDIR)/$(CONFIG)/gpr_cpu_test
gpr_env_test: $(BINDIR)/$(CONFIG)/gpr_env_test
@ -1435,6 +1436,7 @@ buildtests_c: privatelibs_c \
$(BINDIR)/$(CONFIG)/fling_server \
$(BINDIR)/$(CONFIG)/fling_stream_test \
$(BINDIR)/$(CONFIG)/fling_test \
$(BINDIR)/$(CONFIG)/fork_test \
$(BINDIR)/$(CONFIG)/goaway_server_test \
$(BINDIR)/$(CONFIG)/gpr_cpu_test \
$(BINDIR)/$(CONFIG)/gpr_env_test \
@ -1954,6 +1956,8 @@ test_c: buildtests_c
$(Q) $(BINDIR)/$(CONFIG)/fling_stream_test || ( echo test fling_stream_test failed ; exit 1 )
$(E) "[RUN] Testing fling_test"
$(Q) $(BINDIR)/$(CONFIG)/fling_test || ( echo test fling_test failed ; exit 1 )
$(E) "[RUN] Testing fork_test"
$(Q) $(BINDIR)/$(CONFIG)/fork_test || ( echo test fork_test failed ; exit 1 )
$(E) "[RUN] Testing goaway_server_test"
$(Q) $(BINDIR)/$(CONFIG)/goaway_server_test || ( echo test goaway_server_test failed ; exit 1 )
$(E) "[RUN] Testing gpr_cpu_test"
@ -3176,7 +3180,6 @@ LIBGPR_SRC = \
src/core/lib/gpr/env_linux.cc \
src/core/lib/gpr/env_posix.cc \
src/core/lib/gpr/env_windows.cc \
src/core/lib/gpr/fork.cc \
src/core/lib/gpr/host_port.cc \
src/core/lib/gpr/log.cc \
src/core/lib/gpr/log_android.cc \
@ -3201,6 +3204,7 @@ LIBGPR_SRC = \
src/core/lib/gpr/tmpfile_posix.cc \
src/core/lib/gpr/tmpfile_windows.cc \
src/core/lib/gpr/wrap_memcpy.cc \
src/core/lib/gprpp/fork.cc \
src/core/lib/gprpp/thd_posix.cc \
src/core/lib/gprpp/thd_windows.cc \
src/core/lib/profiling/basic_timers.cc \
@ -11293,6 +11297,38 @@ endif
endif
FORK_TEST_SRC = \
test/core/gprpp/fork_test.cc \
FORK_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(FORK_TEST_SRC))))
ifeq ($(NO_SECURE),true)
# You can't build secure targets if you don't have OpenSSL.
$(BINDIR)/$(CONFIG)/fork_test: openssl_dep_error
else
$(BINDIR)/$(CONFIG)/fork_test: $(FORK_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
$(E) "[LD] Linking $@"
$(Q) mkdir -p `dirname $@`
$(Q) $(LD) $(LDFLAGS) $(FORK_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBS) $(LDLIBS_SECURE) -o $(BINDIR)/$(CONFIG)/fork_test
endif
$(OBJDIR)/$(CONFIG)/test/core/gprpp/fork_test.o: $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
deps_fork_test: $(FORK_TEST_OBJS:.o=.dep)
ifneq ($(NO_SECURE),true)
ifneq ($(NO_DEPS),true)
-include $(FORK_TEST_OBJS:.o=.dep)
endif
endif
GOAWAY_SERVER_TEST_SRC = \
test/core/end2end/goaway_server_test.cc \

@ -123,7 +123,6 @@ filegroups:
- src/core/lib/gpr/env_linux.cc
- src/core/lib/gpr/env_posix.cc
- src/core/lib/gpr/env_windows.cc
- src/core/lib/gpr/fork.cc
- src/core/lib/gpr/host_port.cc
- src/core/lib/gpr/log.cc
- src/core/lib/gpr/log_android.cc
@ -148,6 +147,7 @@ filegroups:
- src/core/lib/gpr/tmpfile_posix.cc
- src/core/lib/gpr/tmpfile_windows.cc
- src/core/lib/gpr/wrap_memcpy.cc
- src/core/lib/gprpp/fork.cc
- src/core/lib/gprpp/thd_posix.cc
- src/core/lib/gprpp/thd_windows.cc
- src/core/lib/profiling/basic_timers.cc
@ -176,7 +176,6 @@ filegroups:
headers:
- src/core/lib/gpr/arena.h
- src/core/lib/gpr/env.h
- src/core/lib/gpr/fork.h
- src/core/lib/gpr/host_port.h
- src/core/lib/gpr/mpscq.h
- src/core/lib/gpr/murmur_hash.h
@ -194,6 +193,7 @@ filegroups:
- src/core/lib/gprpp/atomic.h
- src/core/lib/gprpp/atomic_with_atm.h
- src/core/lib/gprpp/atomic_with_std.h
- src/core/lib/gprpp/fork.h
- src/core/lib/gprpp/manual_constructor.h
- src/core/lib/gprpp/memory.h
- src/core/lib/gprpp/thd.h
@ -2387,6 +2387,18 @@ targets:
- mac
- linux
- posix
- name: fork_test
build: test
language: c
src:
- test/core/gprpp/fork_test.cc
deps:
- gpr_test_util
- gpr
platforms:
- mac
- linux
uses_polling: false
- name: goaway_server_test
cpu_cost: 0.1
build: test

@ -53,7 +53,6 @@ if test "$PHP_GRPC" != "no"; then
src/core/lib/gpr/env_linux.cc \
src/core/lib/gpr/env_posix.cc \
src/core/lib/gpr/env_windows.cc \
src/core/lib/gpr/fork.cc \
src/core/lib/gpr/host_port.cc \
src/core/lib/gpr/log.cc \
src/core/lib/gpr/log_android.cc \
@ -78,6 +77,7 @@ if test "$PHP_GRPC" != "no"; then
src/core/lib/gpr/tmpfile_posix.cc \
src/core/lib/gpr/tmpfile_windows.cc \
src/core/lib/gpr/wrap_memcpy.cc \
src/core/lib/gprpp/fork.cc \
src/core/lib/gprpp/thd_posix.cc \
src/core/lib/gprpp/thd_windows.cc \
src/core/lib/profiling/basic_timers.cc \

@ -29,7 +29,6 @@ if (PHP_GRPC != "no") {
"src\\core\\lib\\gpr\\env_linux.cc " +
"src\\core\\lib\\gpr\\env_posix.cc " +
"src\\core\\lib\\gpr\\env_windows.cc " +
"src\\core\\lib\\gpr\\fork.cc " +
"src\\core\\lib\\gpr\\host_port.cc " +
"src\\core\\lib\\gpr\\log.cc " +
"src\\core\\lib\\gpr\\log_android.cc " +
@ -54,6 +53,7 @@ if (PHP_GRPC != "no") {
"src\\core\\lib\\gpr\\tmpfile_posix.cc " +
"src\\core\\lib\\gpr\\tmpfile_windows.cc " +
"src\\core\\lib\\gpr\\wrap_memcpy.cc " +
"src\\core\\lib\\gprpp\\fork.cc " +
"src\\core\\lib\\gprpp\\thd_posix.cc " +
"src\\core\\lib\\gprpp\\thd_windows.cc " +
"src\\core\\lib\\profiling\\basic_timers.cc " +

@ -214,7 +214,6 @@ Pod::Spec.new do |s|
'src/cpp/codegen/codegen_init.cc',
'src/core/lib/gpr/arena.h',
'src/core/lib/gpr/env.h',
'src/core/lib/gpr/fork.h',
'src/core/lib/gpr/host_port.h',
'src/core/lib/gpr/mpscq.h',
'src/core/lib/gpr/murmur_hash.h',
@ -232,6 +231,7 @@ Pod::Spec.new do |s|
'src/core/lib/gprpp/atomic.h',
'src/core/lib/gprpp/atomic_with_atm.h',
'src/core/lib/gprpp/atomic_with_std.h',
'src/core/lib/gprpp/fork.h',
'src/core/lib/gprpp/manual_constructor.h',
'src/core/lib/gprpp/memory.h',
'src/core/lib/gprpp/thd.h',
@ -504,7 +504,6 @@ Pod::Spec.new do |s|
'src/cpp/thread_manager/thread_manager.h',
'src/core/lib/gpr/arena.h',
'src/core/lib/gpr/env.h',
'src/core/lib/gpr/fork.h',
'src/core/lib/gpr/host_port.h',
'src/core/lib/gpr/mpscq.h',
'src/core/lib/gpr/murmur_hash.h',
@ -522,6 +521,7 @@ Pod::Spec.new do |s|
'src/core/lib/gprpp/atomic.h',
'src/core/lib/gprpp/atomic_with_atm.h',
'src/core/lib/gprpp/atomic_with_std.h',
'src/core/lib/gprpp/fork.h',
'src/core/lib/gprpp/manual_constructor.h',
'src/core/lib/gprpp/memory.h',
'src/core/lib/gprpp/thd.h',

@ -185,7 +185,6 @@ Pod::Spec.new do |s|
# To save you from scrolling, this is the last part of the podspec.
ss.source_files = 'src/core/lib/gpr/arena.h',
'src/core/lib/gpr/env.h',
'src/core/lib/gpr/fork.h',
'src/core/lib/gpr/host_port.h',
'src/core/lib/gpr/mpscq.h',
'src/core/lib/gpr/murmur_hash.h',
@ -203,6 +202,7 @@ Pod::Spec.new do |s|
'src/core/lib/gprpp/atomic.h',
'src/core/lib/gprpp/atomic_with_atm.h',
'src/core/lib/gprpp/atomic_with_std.h',
'src/core/lib/gprpp/fork.h',
'src/core/lib/gprpp/manual_constructor.h',
'src/core/lib/gprpp/memory.h',
'src/core/lib/gprpp/thd.h',
@ -217,7 +217,6 @@ Pod::Spec.new do |s|
'src/core/lib/gpr/env_linux.cc',
'src/core/lib/gpr/env_posix.cc',
'src/core/lib/gpr/env_windows.cc',
'src/core/lib/gpr/fork.cc',
'src/core/lib/gpr/host_port.cc',
'src/core/lib/gpr/log.cc',
'src/core/lib/gpr/log_android.cc',
@ -242,6 +241,7 @@ Pod::Spec.new do |s|
'src/core/lib/gpr/tmpfile_posix.cc',
'src/core/lib/gpr/tmpfile_windows.cc',
'src/core/lib/gpr/wrap_memcpy.cc',
'src/core/lib/gprpp/fork.cc',
'src/core/lib/gprpp/thd_posix.cc',
'src/core/lib/gprpp/thd_windows.cc',
'src/core/lib/profiling/basic_timers.cc',
@ -802,7 +802,6 @@ Pod::Spec.new do |s|
ss.private_header_files = 'src/core/lib/gpr/arena.h',
'src/core/lib/gpr/env.h',
'src/core/lib/gpr/fork.h',
'src/core/lib/gpr/host_port.h',
'src/core/lib/gpr/mpscq.h',
'src/core/lib/gpr/murmur_hash.h',
@ -820,6 +819,7 @@ Pod::Spec.new do |s|
'src/core/lib/gprpp/atomic.h',
'src/core/lib/gprpp/atomic_with_atm.h',
'src/core/lib/gprpp/atomic_with_std.h',
'src/core/lib/gprpp/fork.h',
'src/core/lib/gprpp/manual_constructor.h',
'src/core/lib/gprpp/memory.h',
'src/core/lib/gprpp/thd.h',

@ -81,7 +81,6 @@ Gem::Specification.new do |s|
s.files += %w( include/grpc/impl/codegen/sync_windows.h )
s.files += %w( src/core/lib/gpr/arena.h )
s.files += %w( src/core/lib/gpr/env.h )
s.files += %w( src/core/lib/gpr/fork.h )
s.files += %w( src/core/lib/gpr/host_port.h )
s.files += %w( src/core/lib/gpr/mpscq.h )
s.files += %w( src/core/lib/gpr/murmur_hash.h )
@ -99,6 +98,7 @@ Gem::Specification.new do |s|
s.files += %w( src/core/lib/gprpp/atomic.h )
s.files += %w( src/core/lib/gprpp/atomic_with_atm.h )
s.files += %w( src/core/lib/gprpp/atomic_with_std.h )
s.files += %w( src/core/lib/gprpp/fork.h )
s.files += %w( src/core/lib/gprpp/manual_constructor.h )
s.files += %w( src/core/lib/gprpp/memory.h )
s.files += %w( src/core/lib/gprpp/thd.h )
@ -113,7 +113,6 @@ Gem::Specification.new do |s|
s.files += %w( src/core/lib/gpr/env_linux.cc )
s.files += %w( src/core/lib/gpr/env_posix.cc )
s.files += %w( src/core/lib/gpr/env_windows.cc )
s.files += %w( src/core/lib/gpr/fork.cc )
s.files += %w( src/core/lib/gpr/host_port.cc )
s.files += %w( src/core/lib/gpr/log.cc )
s.files += %w( src/core/lib/gpr/log_android.cc )
@ -138,6 +137,7 @@ Gem::Specification.new do |s|
s.files += %w( src/core/lib/gpr/tmpfile_posix.cc )
s.files += %w( src/core/lib/gpr/tmpfile_windows.cc )
s.files += %w( src/core/lib/gpr/wrap_memcpy.cc )
s.files += %w( src/core/lib/gprpp/fork.cc )
s.files += %w( src/core/lib/gprpp/thd_posix.cc )
s.files += %w( src/core/lib/gprpp/thd_windows.cc )
s.files += %w( src/core/lib/profiling/basic_timers.cc )

@ -194,7 +194,6 @@
'src/core/lib/gpr/env_linux.cc',
'src/core/lib/gpr/env_posix.cc',
'src/core/lib/gpr/env_windows.cc',
'src/core/lib/gpr/fork.cc',
'src/core/lib/gpr/host_port.cc',
'src/core/lib/gpr/log.cc',
'src/core/lib/gpr/log_android.cc',
@ -219,6 +218,7 @@
'src/core/lib/gpr/tmpfile_posix.cc',
'src/core/lib/gpr/tmpfile_windows.cc',
'src/core/lib/gpr/wrap_memcpy.cc',
'src/core/lib/gprpp/fork.cc',
'src/core/lib/gprpp/thd_posix.cc',
'src/core/lib/gprpp/thd_windows.cc',
'src/core/lib/profiling/basic_timers.cc',

@ -88,7 +88,6 @@
<file baseinstalldir="/" name="include/grpc/impl/codegen/sync_windows.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/gpr/arena.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/gpr/env.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/gpr/fork.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/gpr/host_port.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/gpr/mpscq.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/gpr/murmur_hash.h" role="src" />
@ -106,6 +105,7 @@
<file baseinstalldir="/" name="src/core/lib/gprpp/atomic.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/gprpp/atomic_with_atm.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/gprpp/atomic_with_std.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/gprpp/fork.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/gprpp/manual_constructor.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/gprpp/memory.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/gprpp/thd.h" role="src" />
@ -120,7 +120,6 @@
<file baseinstalldir="/" name="src/core/lib/gpr/env_linux.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/gpr/env_posix.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/gpr/env_windows.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/gpr/fork.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/gpr/host_port.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/gpr/log.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/gpr/log_android.cc" role="src" />
@ -145,6 +144,7 @@
<file baseinstalldir="/" name="src/core/lib/gpr/tmpfile_posix.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/gpr/tmpfile_windows.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/gpr/wrap_memcpy.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/gprpp/fork.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/gprpp/thd_posix.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/gprpp/thd_windows.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/profiling/basic_timers.cc" role="src" />

@ -1,78 +0,0 @@
/*
*
* 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 <grpc/support/port_platform.h>
#include "src/core/lib/gpr/fork.h"
#include <string.h>
#include <grpc/support/alloc.h>
#include "src/core/lib/gpr/env.h"
#include "src/core/lib/gpr/useful.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;
#endif
bool env_var_set = false;
char* env = gpr_getenv("GRPC_ENABLE_FORK_SUPPORT");
if (env != nullptr) {
static const char* truthy[] = {"yes", "Yes", "YES", "true",
"True", "TRUE", "1"};
static const char* falsey[] = {"no", "No", "NO", "false",
"False", "FALSE", "0"};
for (size_t i = 0; i < GPR_ARRAY_SIZE(truthy); i++) {
if (0 == strcmp(env, truthy[i])) {
fork_support_enabled = 1;
env_var_set = true;
break;
}
}
if (!env_var_set) {
for (size_t i = 0; i < GPR_ARRAY_SIZE(falsey); i++) {
if (0 == strcmp(env, falsey[i])) {
fork_support_enabled = 0;
env_var_set = true;
break;
}
}
}
gpr_free(env);
}
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;
}

@ -1,35 +0,0 @@
/*
*
* 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_GPR_FORK_H
#define GRPC_CORE_LIB_GPR_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_GPR_FORK_H */

@ -0,0 +1,260 @@
/*
*
* 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 <grpc/support/port_platform.h>
#include "src/core/lib/gprpp/fork.h"
#include <string.h>
#include <grpc/support/alloc.h>
#include <grpc/support/sync.h>
#include <grpc/support/time.h>
#include "src/core/lib/gpr/env.h"
#include "src/core/lib/gpr/useful.h"
#include "src/core/lib/gprpp/memory.h"
/*
* NOTE: FORKING IS NOT GENERALLY SUPPORTED, THIS IS ONLY INTENDED TO WORK
* AROUND VERY SPECIFIC USE CASES.
*/
namespace grpc_core {
namespace internal {
// The exec_ctx_count has 2 modes, blocked and unblocked.
// When unblocked, the count is 2-indexed; exec_ctx_count=2 indicates
// 0 active ExecCtxs, exex_ctx_count=3 indicates 1 active ExecCtxs...
// When blocked, the exec_ctx_count is 0-indexed. Note that ExecCtx
// creation can only be blocked if there is exactly 1 outstanding ExecCtx,
// meaning that BLOCKED and UNBLOCKED counts partition the integers
#define UNBLOCKED(n) (n + 2)
#define BLOCKED(n) (n)
class ExecCtxState {
public:
ExecCtxState() : fork_complete_(true) {
gpr_mu_init(&mu_);
gpr_cv_init(&cv_);
gpr_atm_no_barrier_store(&count_, UNBLOCKED(0));
}
void IncExecCtxCount() {
gpr_atm count = gpr_atm_no_barrier_load(&count_);
while (true) {
if (count <= BLOCKED(1)) {
// This only occurs if we are trying to fork. Wait until the fork()
// operation completes before allowing new ExecCtxs.
gpr_mu_lock(&mu_);
if (gpr_atm_no_barrier_load(&count_) <= BLOCKED(1)) {
while (!fork_complete_) {
gpr_cv_wait(&cv_, &mu_, gpr_inf_future(GPR_CLOCK_REALTIME));
}
}
gpr_mu_unlock(&mu_);
} else if (gpr_atm_no_barrier_cas(&count_, count, count + 1)) {
break;
}
count = gpr_atm_no_barrier_load(&count_);
}
}
void DecExecCtxCount() { gpr_atm_no_barrier_fetch_add(&count_, -1); }
bool BlockExecCtx() {
// Assumes there is an active ExecCtx when this function is called
if (gpr_atm_no_barrier_cas(&count_, UNBLOCKED(1), BLOCKED(1))) {
gpr_mu_lock(&mu_);
fork_complete_ = false;
gpr_mu_unlock(&mu_);
return true;
}
return false;
}
void AllowExecCtx() {
gpr_mu_lock(&mu_);
gpr_atm_no_barrier_store(&count_, UNBLOCKED(0));
fork_complete_ = true;
gpr_cv_broadcast(&cv_);
gpr_mu_unlock(&mu_);
}
~ExecCtxState() {
gpr_mu_destroy(&mu_);
gpr_cv_destroy(&cv_);
}
private:
bool fork_complete_;
gpr_mu mu_;
gpr_cv cv_;
gpr_atm count_;
};
class ThreadState {
public:
ThreadState() : awaiting_threads_(false), threads_done_(false), count_(0) {
gpr_mu_init(&mu_);
gpr_cv_init(&cv_);
}
void IncThreadCount() {
gpr_mu_lock(&mu_);
count_++;
gpr_mu_unlock(&mu_);
}
void DecThreadCount() {
gpr_mu_lock(&mu_);
count_--;
if (awaiting_threads_ && count_ == 0) {
threads_done_ = true;
gpr_cv_signal(&cv_);
}
gpr_mu_unlock(&mu_);
}
void AwaitThreads() {
gpr_mu_lock(&mu_);
awaiting_threads_ = true;
threads_done_ = (count_ == 0);
while (!threads_done_) {
gpr_cv_wait(&cv_, &mu_, gpr_inf_future(GPR_CLOCK_REALTIME));
}
awaiting_threads_ = true;
gpr_mu_unlock(&mu_);
}
~ThreadState() {
gpr_mu_destroy(&mu_);
gpr_cv_destroy(&cv_);
}
private:
bool awaiting_threads_;
bool threads_done_;
gpr_mu mu_;
gpr_cv cv_;
int count_;
};
} // namespace
void Fork::GlobalInit() {
if (!overrideEnabled_) {
#ifdef GRPC_ENABLE_FORK_SUPPORT
supportEnabled_ = true;
#else
supportEnabled_ = false;
#endif
bool env_var_set = false;
char* env = gpr_getenv("GRPC_ENABLE_FORK_SUPPORT");
if (env != nullptr) {
static const char* truthy[] = {"yes", "Yes", "YES", "true",
"True", "TRUE", "1"};
static const char* falsey[] = {"no", "No", "NO", "false",
"False", "FALSE", "0"};
for (size_t i = 0; i < GPR_ARRAY_SIZE(truthy); i++) {
if (0 == strcmp(env, truthy[i])) {
supportEnabled_ = true;
env_var_set = true;
break;
}
}
if (!env_var_set) {
for (size_t i = 0; i < GPR_ARRAY_SIZE(falsey); i++) {
if (0 == strcmp(env, falsey[i])) {
supportEnabled_ = false;
env_var_set = true;
break;
}
}
}
gpr_free(env);
}
}
if (supportEnabled_) {
execCtxState_ = grpc_core::New<internal::ExecCtxState>();
threadState_ = grpc_core::New<internal::ThreadState>();
}
}
void Fork::GlobalShutdown() {
if (supportEnabled_) {
grpc_core::Delete(execCtxState_);
grpc_core::Delete(threadState_);
}
}
bool Fork::Enabled() { return supportEnabled_; }
// Testing Only
void Fork::Enable(bool enable) {
overrideEnabled_ = true;
supportEnabled_ = enable;
}
void Fork::IncExecCtxCount() {
if (supportEnabled_) {
execCtxState_->IncExecCtxCount();
}
}
void Fork::DecExecCtxCount() {
if (supportEnabled_) {
execCtxState_->DecExecCtxCount();
}
}
bool Fork::BlockExecCtx() {
if (supportEnabled_) {
return execCtxState_->BlockExecCtx();
}
return false;
}
void Fork::AllowExecCtx() {
if (supportEnabled_) {
execCtxState_->AllowExecCtx();
}
}
void Fork::IncThreadCount() {
if (supportEnabled_) {
threadState_->IncThreadCount();
}
}
void Fork::DecThreadCount() {
if (supportEnabled_) {
threadState_->DecThreadCount();
}
}
void Fork::AwaitThreads() {
if (supportEnabled_) {
threadState_->AwaitThreads();
}
}
internal::ExecCtxState* Fork::execCtxState_ = nullptr;
internal::ThreadState* Fork::threadState_ = nullptr;
bool Fork::supportEnabled_ = false;
bool Fork::overrideEnabled_ = false;
} // namespace grpc_core

@ -0,0 +1,79 @@
/*
*
* 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_GPRPP_FORK_H
#define GRPC_CORE_LIB_GPRPP_FORK_H
/*
* NOTE: FORKING IS NOT GENERALLY SUPPORTED, THIS IS ONLY INTENDED TO WORK
* AROUND VERY SPECIFIC USE CASES.
*/
namespace grpc_core {
namespace internal {
class ExecCtxState;
class ThreadState;
} // namespace internal
class Fork {
public:
static void GlobalInit();
static void GlobalShutdown();
// Returns true if fork suppport is enabled, false otherwise
static bool Enabled();
// Increment the count of active ExecCtxs.
// Will block until a pending fork is complete if one is in progress.
static void IncExecCtxCount();
// Decrement the count of active ExecCtxs
static void DecExecCtxCount();
// Check if there is a single active ExecCtx
// (the one used to invoke this function). If there are more,
// return false. Otherwise, return true and block creation of
// more ExecCtx s until AlloWExecCtx() is called
//
static bool BlockExecCtx();
static void AllowExecCtx();
// Increment the count of active threads.
static void IncThreadCount();
// Decrement the count of active threads.
static void DecThreadCount();
// Await all core threads to be joined.
static void AwaitThreads();
// Test only: overrides environment variables/compile flags
// Must be called before grpc_init()
static void Enable(bool enable);
private:
static internal::ExecCtxState* execCtxState_;
static internal::ThreadState* threadState_;
static bool supportEnabled_;
static bool overrideEnabled_;
};
} // namespace grpc_core
#endif /* GRPC_CORE_LIB_GPRPP_FORK_H */

@ -111,9 +111,6 @@ class Thread {
}
};
static void Init();
static bool AwaitAll(gpr_timespec deadline);
private:
Thread(const Thread&) = delete;
Thread& operator=(const Thread&) = delete;

@ -32,17 +32,12 @@
#include <stdlib.h>
#include <string.h>
#include "src/core/lib/gpr/fork.h"
#include "src/core/lib/gpr/useful.h"
#include "src/core/lib/gprpp/fork.h"
#include "src/core/lib/gprpp/memory.h"
namespace grpc_core {
namespace {
gpr_mu g_mu;
gpr_cv g_cv;
int g_thread_count;
int g_awaiting_threads;
class ThreadInternalsPosix;
struct thd_arg {
ThreadInternalsPosix* thread;
@ -68,7 +63,7 @@ class ThreadInternalsPosix
info->body = thd_body;
info->arg = arg;
info->name = thd_name;
inc_thd_count();
grpc_core::Fork::IncThreadCount();
GPR_ASSERT(pthread_attr_init(&attr) == 0);
GPR_ASSERT(pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE) ==
@ -103,7 +98,7 @@ class ThreadInternalsPosix
gpr_mu_unlock(&arg.thread->mu_);
(*arg.body)(arg.arg);
dec_thd_count();
grpc_core::Fork::DecThreadCount();
return nullptr;
},
info) == 0);
@ -113,7 +108,7 @@ class ThreadInternalsPosix
if (!success) {
/* don't use gpr_free, as this was allocated using malloc (see above) */
free(info);
dec_thd_count();
grpc_core::Fork::DecThreadCount();
}
};
@ -132,29 +127,6 @@ class ThreadInternalsPosix
void Join() override { pthread_join(pthread_id_, nullptr); }
private:
/*****************************************
* 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);
}
}
gpr_mu mu_;
gpr_cv ready_;
bool started_;
@ -180,27 +152,6 @@ Thread::Thread(const char* thd_name, void (*thd_body)(void* arg), void* arg,
*success = outcome;
}
}
void Thread::Init() {
gpr_mu_init(&g_mu);
gpr_cv_init(&g_cv);
g_thread_count = 0;
g_awaiting_threads = 0;
}
bool Thread::AwaitAll(gpr_timespec deadline) {
gpr_mu_lock(&g_mu);
g_awaiting_threads = 1;
int res = 0;
while ((g_thread_count > 0) &&
(gpr_time_cmp(gpr_now(GPR_CLOCK_REALTIME), deadline) < 0)) {
res = gpr_cv_wait(&g_cv, &g_mu, deadline);
}
g_awaiting_threads = 0;
gpr_mu_unlock(&g_mu);
return res == 0;
}
} // namespace grpc_core
// The following is in the external namespace as it is exposed as C89 API

@ -131,13 +131,6 @@ class ThreadInternalsWindows
namespace grpc_core {
void Thread::Init() {}
bool Thread::AwaitAll(gpr_timespec deadline) {
// TODO: Consider adding this if needed
return false;
}
Thread::Thread(const char* thd_name, void (*thd_body)(void* arg), void* arg,
bool* success) {
bool outcome = false;

@ -26,6 +26,7 @@
#include <grpc/support/log.h>
#include "src/core/lib/gpr/tls.h"
#include "src/core/lib/gprpp/fork.h"
#include "src/core/lib/iomgr/closure.h"
typedef gpr_atm grpc_millis;
@ -85,16 +86,23 @@ class ExecCtx {
public:
/** Default Constructor */
ExecCtx() : flags_(GRPC_EXEC_CTX_FLAG_IS_FINISHED) { Set(this); }
ExecCtx() : flags_(GRPC_EXEC_CTX_FLAG_IS_FINISHED) {
grpc_core::Fork::IncExecCtxCount();
Set(this);
}
/** Parameterised Constructor */
ExecCtx(uintptr_t fl) : flags_(fl) { Set(this); }
ExecCtx(uintptr_t fl) : flags_(fl) {
grpc_core::Fork::IncExecCtxCount();
Set(this);
}
/** Destructor */
virtual ~ExecCtx() {
flags_ |= GRPC_EXEC_CTX_FLAG_IS_FINISHED;
Flush();
Set(last_exec_ctx_);
grpc_core::Fork::DecExecCtxCount();
}
/** Disallow copy and assignment operators */

@ -28,7 +28,7 @@
#include <grpc/support/log.h>
#include "src/core/lib/gpr/env.h"
#include "src/core/lib/gpr/fork.h"
#include "src/core/lib/gprpp/fork.h"
#include "src/core/lib/gprpp/thd.h"
#include "src/core/lib/iomgr/ev_posix.h"
#include "src/core/lib/iomgr/executor.h"
@ -41,46 +41,59 @@
* AROUND VERY SPECIFIC USE CASES.
*/
namespace {
bool skipped_handler = true;
bool registered_handlers = false;
} // namespace
void grpc_prefork() {
if (!grpc_fork_support_enabled()) {
grpc_core::ExecCtx exec_ctx;
skipped_handler = true;
if (!grpc_is_initialized()) {
return;
}
if (!grpc_core::Fork::Enabled()) {
gpr_log(GPR_ERROR,
"Fork support not enabled; try running with the "
"environment variable GRPC_ENABLE_FORK_SUPPORT=1");
return;
}
if (grpc_is_initialized()) {
grpc_core::ExecCtx exec_ctx;
grpc_timer_manager_set_threading(false);
grpc_executor_set_threading(false);
grpc_core::ExecCtx::Get()->Flush();
if (!grpc_core::Thread::AwaitAll(
gpr_time_add(gpr_now(GPR_CLOCK_REALTIME),
gpr_time_from_seconds(3, GPR_TIMESPAN)))) {
gpr_log(GPR_ERROR, "gRPC thread still active! Cannot fork!");
}
if (!grpc_core::Fork::BlockExecCtx()) {
gpr_log(GPR_INFO,
"Other threads are currently calling into gRPC, skipping fork() "
"handlers");
return;
}
grpc_timer_manager_set_threading(false);
grpc_executor_set_threading(false);
grpc_core::ExecCtx::Get()->Flush();
grpc_core::Fork::AwaitThreads();
skipped_handler = false;
}
void grpc_postfork_parent() {
if (grpc_is_initialized()) {
grpc_timer_manager_set_threading(true);
if (!skipped_handler) {
grpc_core::Fork::AllowExecCtx();
grpc_core::ExecCtx exec_ctx;
grpc_timer_manager_set_threading(true);
grpc_executor_set_threading(true);
}
}
void grpc_postfork_child() {
if (grpc_is_initialized()) {
grpc_timer_manager_set_threading(true);
if (!skipped_handler) {
grpc_core::Fork::AllowExecCtx();
grpc_core::ExecCtx exec_ctx;
grpc_timer_manager_set_threading(true);
grpc_executor_set_threading(true);
}
}
void grpc_fork_handlers_auto_register() {
if (grpc_fork_support_enabled()) {
if (grpc_core::Fork::Enabled() & !registered_handlers) {
#ifdef GRPC_POSIX_FORK_ALLOW_PTHREAD_ATFORK
pthread_atfork(grpc_prefork, grpc_postfork_parent, grpc_postfork_child);
registered_handlers = true;
#endif // GRPC_POSIX_FORK_ALLOW_PTHREAD_ATFORK
}
}

@ -32,8 +32,7 @@
#include "src/core/lib/channel/handshaker_registry.h"
#include "src/core/lib/debug/stats.h"
#include "src/core/lib/debug/trace.h"
#include "src/core/lib/gpr/fork.h"
#include "src/core/lib/gprpp/thd.h"
#include "src/core/lib/gprpp/fork.h"
#include "src/core/lib/http/parser.h"
#include "src/core/lib/iomgr/call_combiner.h"
#include "src/core/lib/iomgr/combiner.h"
@ -65,12 +64,10 @@ static int g_initializations;
static void do_basic_init(void) {
gpr_log_verbosity_init();
grpc_fork_support_init();
gpr_mu_init(&g_init_mu);
grpc_register_built_in_plugins();
grpc_cq_global_init();
g_initializations = 0;
grpc_fork_handlers_auto_register();
}
static bool append_filter(grpc_channel_stack_builder* builder, void* arg) {
@ -123,8 +120,9 @@ void grpc_init(void) {
gpr_mu_lock(&g_init_mu);
if (++g_initializations == 1) {
grpc_core::Fork::GlobalInit();
grpc_fork_handlers_auto_register();
gpr_time_init();
grpc_core::Thread::Init();
grpc_stats_init();
grpc_slice_intern_init();
grpc_mdctx_global_init();
@ -180,6 +178,7 @@ void grpc_shutdown(void) {
grpc_slice_intern_shutdown();
grpc_channel_trace_registry_shutdown();
grpc_stats_shutdown();
grpc_core::Fork::GlobalShutdown();
}
grpc_core::ExecCtx::GlobalShutdown();
}

@ -28,7 +28,6 @@ CORE_SOURCE_FILES = [
'src/core/lib/gpr/env_linux.cc',
'src/core/lib/gpr/env_posix.cc',
'src/core/lib/gpr/env_windows.cc',
'src/core/lib/gpr/fork.cc',
'src/core/lib/gpr/host_port.cc',
'src/core/lib/gpr/log.cc',
'src/core/lib/gpr/log_android.cc',
@ -53,6 +52,7 @@ CORE_SOURCE_FILES = [
'src/core/lib/gpr/tmpfile_posix.cc',
'src/core/lib/gpr/tmpfile_windows.cc',
'src/core/lib/gpr/wrap_memcpy.cc',
'src/core/lib/gprpp/fork.cc',
'src/core/lib/gprpp/thd_posix.cc',
'src/core/lib/gprpp/thd_windows.cc',
'src/core/lib/profiling/basic_timers.cc',

@ -18,6 +18,16 @@ licenses(["notice"]) # Apache v2
grpc_package(name = "test/core/gprpp")
grpc_cc_test(
name = "fork_test",
srcs = ["fork_test.cc"],
language = "C++",
deps = [
"//:gpr",
"//test/core/util:gpr_test_util",
],
)
grpc_cc_test(
name = "manual_constructor_test",
srcs = ["manual_constructor_test.cc"],

@ -0,0 +1,135 @@
/*
*
* 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/gprpp/fork.h"
#include "src/core/lib/gprpp/thd.h"
#include "test/core/util/test_config.h"
static void test_init() {
GPR_ASSERT(!grpc_core::Fork::Enabled());
// Default fork support (disabled)
grpc_core::Fork::GlobalInit();
GPR_ASSERT(!grpc_core::Fork::Enabled());
grpc_core::Fork::GlobalShutdown();
// Explicitly disabled fork support
grpc_core::Fork::Enable(false);
grpc_core::Fork::GlobalInit();
GPR_ASSERT(!grpc_core::Fork::Enabled());
grpc_core::Fork::GlobalShutdown();
// Explicitly enabled fork support
grpc_core::Fork::Enable(true);
grpc_core::Fork::GlobalInit();
GPR_ASSERT(grpc_core::Fork::Enabled());
grpc_core::Fork::GlobalShutdown();
}
#define THREAD_DELAY_MS 3000
#define THREAD_DELAY_EPSILON 500
#define CONCURRENT_TEST_THREADS 100
static void sleeping_thd(void* arg) {
int64_t sleep_ms = (int64_t)arg;
gpr_sleep_until(gpr_time_add(gpr_now(GPR_CLOCK_REALTIME),
gpr_time_from_millis(sleep_ms, GPR_TIMESPAN)));
}
static void test_thd_count() {
// Test no active threads
grpc_core::Fork::Enable(true);
grpc_core::Fork::GlobalInit();
grpc_core::Fork::AwaitThreads();
grpc_core::Fork::GlobalShutdown();
grpc_core::Fork::Enable(true);
grpc_core::Fork::GlobalInit();
grpc_core::Thread thds[CONCURRENT_TEST_THREADS];
gpr_timespec est_end_time =
gpr_time_add(gpr_now(GPR_CLOCK_REALTIME),
gpr_time_from_millis(THREAD_DELAY_MS, GPR_TIMESPAN));
gpr_timespec tolerance =
gpr_time_from_millis(THREAD_DELAY_EPSILON, GPR_TIMESPAN);
for (int i = 0; i < CONCURRENT_TEST_THREADS; i++) {
intptr_t sleep_time_ms =
(i * THREAD_DELAY_MS) / (CONCURRENT_TEST_THREADS - 1);
thds[i] =
grpc_core::Thread("grpc_fork_test", sleeping_thd, (void*)sleep_time_ms);
thds[i].Start();
}
grpc_core::Fork::AwaitThreads();
gpr_timespec end_time = gpr_now(GPR_CLOCK_REALTIME);
for (auto& thd : thds) {
thd.Join();
}
GPR_ASSERT(gpr_time_similar(end_time, est_end_time, tolerance));
grpc_core::Fork::GlobalShutdown();
}
static void exec_ctx_thread(void* arg) {
bool* exec_ctx_created = (bool*)arg;
grpc_core::Fork::IncExecCtxCount();
*exec_ctx_created = true;
}
static void test_exec_count() {
grpc_core::Fork::Enable(true);
grpc_core::Fork::GlobalInit();
grpc_core::Fork::IncExecCtxCount();
GPR_ASSERT(grpc_core::Fork::BlockExecCtx());
grpc_core::Fork::DecExecCtxCount();
grpc_core::Fork::AllowExecCtx();
grpc_core::Fork::IncExecCtxCount();
grpc_core::Fork::IncExecCtxCount();
GPR_ASSERT(!grpc_core::Fork::BlockExecCtx());
grpc_core::Fork::DecExecCtxCount();
grpc_core::Fork::DecExecCtxCount();
grpc_core::Fork::IncExecCtxCount();
GPR_ASSERT(grpc_core::Fork::BlockExecCtx());
grpc_core::Fork::DecExecCtxCount();
grpc_core::Fork::AllowExecCtx();
// Test that block_exec_ctx() blocks grpc_core::Fork::IncExecCtxCount
bool exec_ctx_created = false;
grpc_core::Thread thd =
grpc_core::Thread("grpc_fork_test", exec_ctx_thread, &exec_ctx_created);
grpc_core::Fork::IncExecCtxCount();
GPR_ASSERT(grpc_core::Fork::BlockExecCtx());
grpc_core::Fork::DecExecCtxCount();
thd.Start();
gpr_sleep_until(gpr_time_add(gpr_now(GPR_CLOCK_REALTIME),
gpr_time_from_seconds(1, GPR_TIMESPAN)));
GPR_ASSERT(!exec_ctx_created);
grpc_core::Fork::AllowExecCtx();
thd.Join(); // This ensure that the call got un-blocked
grpc_core::Fork::GlobalShutdown();
}
int main(int argc, char* argv[]) {
grpc_test_init(argc, argv);
test_init();
test_thd_count();
test_exec_count();
return 0;
}

@ -1031,7 +1031,6 @@ src/core/lib/debug/stats_data.h \
src/core/lib/debug/trace.h \
src/core/lib/gpr/arena.h \
src/core/lib/gpr/env.h \
src/core/lib/gpr/fork.h \
src/core/lib/gpr/host_port.h \
src/core/lib/gpr/mpscq.h \
src/core/lib/gpr/murmur_hash.h \
@ -1050,6 +1049,7 @@ src/core/lib/gprpp/atomic.h \
src/core/lib/gprpp/atomic_with_atm.h \
src/core/lib/gprpp/atomic_with_std.h \
src/core/lib/gprpp/debug_location.h \
src/core/lib/gprpp/fork.h \
src/core/lib/gprpp/inlined_vector.h \
src/core/lib/gprpp/manual_constructor.h \
src/core/lib/gprpp/memory.h \

@ -1083,8 +1083,6 @@ src/core/lib/gpr/env.h \
src/core/lib/gpr/env_linux.cc \
src/core/lib/gpr/env_posix.cc \
src/core/lib/gpr/env_windows.cc \
src/core/lib/gpr/fork.cc \
src/core/lib/gpr/fork.h \
src/core/lib/gpr/host_port.cc \
src/core/lib/gpr/host_port.h \
src/core/lib/gpr/log.cc \
@ -1128,6 +1126,8 @@ src/core/lib/gprpp/atomic.h \
src/core/lib/gprpp/atomic_with_atm.h \
src/core/lib/gprpp/atomic_with_std.h \
src/core/lib/gprpp/debug_location.h \
src/core/lib/gprpp/fork.cc \
src/core/lib/gprpp/fork.h \
src/core/lib/gprpp/inlined_vector.h \
src/core/lib/gprpp/manual_constructor.h \
src/core/lib/gprpp/memory.h \

@ -602,6 +602,21 @@
"third_party": false,
"type": "target"
},
{
"deps": [
"gpr",
"gpr_test_util"
],
"headers": [],
"is_filegroup": false,
"language": "c",
"name": "fork_test",
"src": [
"test/core/gprpp/fork_test.cc"
],
"third_party": false,
"type": "target"
},
{
"deps": [
"gpr",
@ -9012,7 +9027,6 @@
"src/core/lib/gpr/env_linux.cc",
"src/core/lib/gpr/env_posix.cc",
"src/core/lib/gpr/env_windows.cc",
"src/core/lib/gpr/fork.cc",
"src/core/lib/gpr/host_port.cc",
"src/core/lib/gpr/log.cc",
"src/core/lib/gpr/log_android.cc",
@ -9037,6 +9051,7 @@
"src/core/lib/gpr/tmpfile_posix.cc",
"src/core/lib/gpr/tmpfile_windows.cc",
"src/core/lib/gpr/wrap_memcpy.cc",
"src/core/lib/gprpp/fork.cc",
"src/core/lib/gprpp/thd_posix.cc",
"src/core/lib/gprpp/thd_windows.cc",
"src/core/lib/profiling/basic_timers.cc",
@ -9069,7 +9084,6 @@
"include/grpc/support/time.h",
"src/core/lib/gpr/arena.h",
"src/core/lib/gpr/env.h",
"src/core/lib/gpr/fork.h",
"src/core/lib/gpr/host_port.h",
"src/core/lib/gpr/mpscq.h",
"src/core/lib/gpr/murmur_hash.h",
@ -9087,6 +9101,7 @@
"src/core/lib/gprpp/atomic.h",
"src/core/lib/gprpp/atomic_with_atm.h",
"src/core/lib/gprpp/atomic_with_std.h",
"src/core/lib/gprpp/fork.h",
"src/core/lib/gprpp/manual_constructor.h",
"src/core/lib/gprpp/memory.h",
"src/core/lib/gprpp/thd.h",
@ -9115,7 +9130,6 @@
"include/grpc/support/time.h",
"src/core/lib/gpr/arena.h",
"src/core/lib/gpr/env.h",
"src/core/lib/gpr/fork.h",
"src/core/lib/gpr/host_port.h",
"src/core/lib/gpr/mpscq.h",
"src/core/lib/gpr/murmur_hash.h",
@ -9133,6 +9147,7 @@
"src/core/lib/gprpp/atomic.h",
"src/core/lib/gprpp/atomic_with_atm.h",
"src/core/lib/gprpp/atomic_with_std.h",
"src/core/lib/gprpp/fork.h",
"src/core/lib/gprpp/manual_constructor.h",
"src/core/lib/gprpp/memory.h",
"src/core/lib/gprpp/thd.h",

@ -719,6 +719,26 @@
],
"uses_polling": true
},
{
"args": [],
"benchmark": false,
"ci_platforms": [
"linux",
"mac"
],
"cpu_cost": 1.0,
"exclude_configs": [],
"exclude_iomgrs": [],
"flaky": false,
"gtest": false,
"language": "c",
"name": "fork_test",
"platforms": [
"linux",
"mac"
],
"uses_polling": false
},
{
"args": [],
"benchmark": false,

Loading…
Cancel
Save