Răsfoiți Sursa

Merge branch 'master' of https://github.com/grpc/grpc into channel-tracing

ncteisen 7 ani în urmă
părinte
comite
94dad67f43
100 a modificat fișierele cu 1898 adăugiri și 734 ștergeri
  1. 12 21
      BUILD
  2. 52 4
      CMakeLists.txt
  3. 4 5
      Makefile
  4. 4 5
      build.yaml
  5. 3 3
      config.m4
  6. 3 3
      config.w32
  7. 1 0
      doc/g_stands_for.md
  8. 9 0
      examples/android/helloworld/.gitignore
  9. 24 0
      examples/android/helloworld/README.md
  10. 1 0
      examples/android/helloworld/app/.gitignore
  11. 123 0
      examples/android/helloworld/app/CMakeLists.txt
  12. 53 0
      examples/android/helloworld/app/build.gradle
  13. 21 0
      examples/android/helloworld/app/proguard-rules.pro
  14. 22 0
      examples/android/helloworld/app/src/main/AndroidManifest.xml
  15. 142 0
      examples/android/helloworld/app/src/main/cpp/grpc-helloworld.cc
  16. 167 0
      examples/android/helloworld/app/src/main/java/io/grpc/helloworldexample/cpp/HelloworldActivity.java
  17. 86 0
      examples/android/helloworld/app/src/main/res/layout/activity_helloworld.xml
  18. BIN
      examples/android/helloworld/app/src/main/res/mipmap-hdpi/ic_launcher.png
  19. BIN
      examples/android/helloworld/app/src/main/res/mipmap-mdpi/ic_launcher.png
  20. BIN
      examples/android/helloworld/app/src/main/res/mipmap-xhdpi/ic_launcher.png
  21. BIN
      examples/android/helloworld/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
  22. 3 0
      examples/android/helloworld/app/src/main/res/values/strings.xml
  23. 24 0
      examples/android/helloworld/build.gradle
  24. 17 0
      examples/android/helloworld/gradle.properties
  25. BIN
      examples/android/helloworld/gradle/wrapper/gradle-wrapper.jar
  26. 6 0
      examples/android/helloworld/gradle/wrapper/gradle-wrapper.properties
  27. 160 0
      examples/android/helloworld/gradlew
  28. 90 0
      examples/android/helloworld/gradlew.bat
  29. 1 0
      examples/android/helloworld/settings.gradle
  30. 2 2
      gRPC-C++.podspec
  31. 4 5
      gRPC-Core.podspec
  32. 3 4
      grpc.gemspec
  33. 2 3
      grpc.gyp
  34. 3 4
      package.xml
  35. 0 51
      src/core/lib/gpr/thd.cc
  36. 0 72
      src/core/lib/gpr/thd.h
  37. 0 154
      src/core/lib/gpr/thd_posix.cc
  38. 0 107
      src/core/lib/gpr/thd_windows.cc
  39. 135 0
      src/core/lib/gprpp/thd.h
  40. 209 0
      src/core/lib/gprpp/thd_posix.cc
  41. 162 0
      src/core/lib/gprpp/thd_windows.cc
  42. 57 9
      src/core/lib/iomgr/ev_poll_posix.cc
  43. 1 1
      src/core/lib/iomgr/exec_ctx.cc
  44. 11 11
      src/core/lib/iomgr/executor.cc
  45. 2 2
      src/core/lib/iomgr/fork_posix.cc
  46. 1 1
      src/core/lib/iomgr/iocp_windows.cc
  47. 1 1
      src/core/lib/iomgr/iomgr.cc
  48. 1 1
      src/core/lib/iomgr/pollset_windows.cc
  49. 1 1
      src/core/lib/iomgr/resolve_address_posix.cc
  50. 1 1
      src/core/lib/iomgr/resolve_address_windows.cc
  51. 10 19
      src/core/lib/iomgr/timer_manager.cc
  52. 1 1
      src/core/lib/iomgr/wakeup_fd_cv.cc
  53. 6 7
      src/core/lib/profiling/basic_timers.cc
  54. 2 2
      src/core/lib/surface/init.cc
  55. 1 1
      src/core/tsi/alts_transport_security.cc
  56. 2 2
      src/core/tsi/alts_transport_security.h
  57. 1 1
      src/cpp/client/channel_cc.cc
  58. 10 6
      src/cpp/server/dynamic_thread_pool.cc
  59. 2 2
      src/cpp/server/dynamic_thread_pool.h
  60. 10 5
      src/cpp/thread_manager/thread_manager.cc
  61. 5 5
      src/cpp/thread_manager/thread_manager.h
  62. 2 3
      src/python/grpcio/grpc_core_dependencies.py
  63. 26 0
      templates/CMakeLists.txt.template
  64. 5 3
      test/core/bad_client/bad_client.cc
  65. 11 6
      test/core/end2end/bad_server_response_test.cc
  66. 0 1
      test/core/end2end/fixtures/h2_census.cc
  67. 0 1
      test/core/end2end/fixtures/h2_compress.cc
  68. 0 1
      test/core/end2end/fixtures/h2_full+pipe.cc
  69. 0 1
      test/core/end2end/fixtures/h2_full+trace.cc
  70. 0 1
      test/core/end2end/fixtures/h2_full+workarounds.cc
  71. 0 1
      test/core/end2end/fixtures/h2_full.cc
  72. 0 1
      test/core/end2end/fixtures/h2_http_proxy.cc
  73. 0 1
      test/core/end2end/fixtures/h2_load_reporting.cc
  74. 0 1
      test/core/end2end/fixtures/h2_proxy.cc
  75. 0 1
      test/core/end2end/fixtures/h2_sockpair+trace.cc
  76. 0 1
      test/core/end2end/fixtures/h2_sockpair.cc
  77. 0 1
      test/core/end2end/fixtures/h2_sockpair_1byte.cc
  78. 0 1
      test/core/end2end/fixtures/h2_uds.cc
  79. 5 7
      test/core/end2end/fixtures/http_proxy_fixture.cc
  80. 0 1
      test/core/end2end/fixtures/inproc.cc
  81. 5 7
      test/core/end2end/fixtures/proxy.cc
  82. 0 1
      test/core/end2end/tests/bad_ping.cc
  83. 4 7
      test/core/end2end/tests/connectivity.cc
  84. 0 1
      test/core/end2end/tests/ping.cc
  85. 0 10
      test/core/gpr/BUILD
  86. 10 10
      test/core/gpr/arena_test.cc
  87. 18 8
      test/core/gpr/cpu_test.cc
  88. 16 22
      test/core/gpr/mpscq_test.cc
  89. 11 11
      test/core/gpr/spinlock_test.cc
  90. 37 24
      test/core/gpr/sync_test.cc
  91. 0 1
      test/core/gpr/time_test.cc
  92. 12 13
      test/core/gpr/tls_test.cc
  93. 19 10
      test/core/gprpp/BUILD
  94. 0 1
      test/core/gprpp/manual_constructor_test.cc
  95. 31 36
      test/core/gprpp/thd_test.cc
  96. 6 7
      test/core/handshake/client_ssl.cc
  97. 0 1
      test/core/handshake/readahead_handshaker_server_ssl.cc
  98. 0 1
      test/core/handshake/server_ssl.cc
  99. 6 7
      test/core/handshake/server_ssl_common.cc
  100. 0 1
      test/core/handshake/server_ssl_common.h

+ 12 - 21
BUILD

@@ -527,9 +527,6 @@ grpc_cc_library(
         "src/core/lib/gpr/sync.cc",
         "src/core/lib/gpr/sync_posix.cc",
         "src/core/lib/gpr/sync_windows.cc",
-        "src/core/lib/gpr/thd.cc",
-        "src/core/lib/gpr/thd_posix.cc",
-        "src/core/lib/gpr/thd_windows.cc",
         "src/core/lib/gpr/time.cc",
         "src/core/lib/gpr/time_posix.cc",
         "src/core/lib/gpr/time_precise.cc",
@@ -539,6 +536,8 @@ 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/thd_posix.cc",
+        "src/core/lib/gprpp/thd_windows.cc",
         "src/core/lib/profiling/basic_timers.cc",
         "src/core/lib/profiling/stap_timers.cc",
     ],
@@ -552,7 +551,6 @@ grpc_cc_library(
         "src/core/lib/gpr/spinlock.h",
         "src/core/lib/gpr/string.h",
         "src/core/lib/gpr/string_windows.h",
-        "src/core/lib/gpr/thd.h",
         "src/core/lib/gpr/time_precise.h",
         "src/core/lib/gpr/tls.h",
         "src/core/lib/gpr/tls_gcc.h",
@@ -560,6 +558,10 @@ grpc_cc_library(
         "src/core/lib/gpr/tls_pthread.h",
         "src/core/lib/gpr/tmpfile.h",
         "src/core/lib/gpr/useful.h",
+        "src/core/lib/gprpp/abstract.h",
+        "src/core/lib/gprpp/manual_constructor.h",
+        "src/core/lib/gprpp/memory.h",
+        "src/core/lib/gprpp/thd.h",
         "src/core/lib/profiling/timers.h",
     ],
     language = "c++",
@@ -601,16 +603,6 @@ grpc_cc_library(
     ],
 )
 
-grpc_cc_library(
-    name = "gpr++_base",
-    language = "c++",
-    public_hdrs = [
-        "src/core/lib/gprpp/abstract.h",
-        "src/core/lib/gprpp/manual_constructor.h",
-        "src/core/lib/gprpp/memory.h",
-    ],
-)
-
 grpc_cc_library(
     name = "atomic",
     hdrs = [
@@ -633,7 +625,7 @@ grpc_cc_library(
         "src/core/lib/gprpp/inlined_vector.h",
     ],
     deps = [
-        "gpr++_base",
+        "gpr_base",
     ],
 )
 
@@ -649,7 +641,7 @@ grpc_cc_library(
     public_hdrs = ["src/core/lib/gprpp/orphanable.h"],
     deps = [
         "debug_location",
-        "gpr++_base",
+        "gpr_base",
         "grpc_trace",
         "ref_counted_ptr",
     ],
@@ -661,7 +653,7 @@ grpc_cc_library(
     public_hdrs = ["src/core/lib/gprpp/ref_counted.h"],
     deps = [
         "debug_location",
-        "gpr++_base",
+        "gpr_base",
         "grpc_trace",
         "ref_counted_ptr",
     ],
@@ -672,7 +664,7 @@ grpc_cc_library(
     language = "c++",
     public_hdrs = ["src/core/lib/gprpp/ref_counted_ptr.h"],
     deps = [
-        "gpr++_base",
+        "gpr_base",
     ],
 )
 
@@ -947,13 +939,12 @@ grpc_cc_library(
     language = "c++",
     public_hdrs = GRPC_PUBLIC_HDRS,
     deps = [
-        "gpr++_base",
         "gpr_base",
         "grpc_codegen",
         "grpc_trace",
+        "inlined_vector",
         "ref_counted",
         "ref_counted_ptr",
-        "inlined_vector",
     ],
 )
 
@@ -1429,7 +1420,7 @@ grpc_cc_library(
     ],
     language = "c++",
     deps = [
-        "gpr++_base",
+        "gpr_base",
         "grpc_base",
         "grpc_http_filters",
         "grpc_transport_chttp2_alpn",

+ 52 - 4
CMakeLists.txt

@@ -37,6 +37,7 @@ set(gRPC_INSTALL_CMAKEDIR "lib/cmake/${PACKAGE_NAME}" CACHE STRING "Installation
 
 # Options
 option(gRPC_BUILD_TESTS "Build tests" OFF)
+option(gRPC_BUILD_CODEGEN "Build codegen" ON)
 
 set(gRPC_INSTALL_default ON)
 if (NOT CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR)
@@ -78,6 +79,8 @@ if(UNIX)
     set(_gRPC_PLATFORM_LINUX ON)
   elseif(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
     set(_gRPC_PLATFORM_MAC ON)
+  elseif(${CMAKE_SYSTEM_NAME} MATCHES "Android")
+    set(_gRPC_PLATFORM_ANDROID ON)
   else()
     set(_gRPC_PLATFORM_POSIX ON)
   endif()
@@ -120,6 +123,8 @@ endif()
 
 if(_gRPC_PLATFORM_MAC)
   set(_gRPC_ALLTARGETS_LIBRARIES ${CMAKE_DL_LIBS} m pthread)
+elseif(_gRPC_PLATFORM_ANDROID)
+  set(_gRPC_ALLTARGETS_LIBRARIES ${CMAKE_DL_LIBS} m)
 elseif(UNIX)
   set(_gRPC_ALLTARGETS_LIBRARIES ${CMAKE_DL_LIBS} rt m pthread)
 endif()
@@ -655,9 +660,6 @@ add_library(gpr
   src/core/lib/gpr/sync.cc
   src/core/lib/gpr/sync_posix.cc
   src/core/lib/gpr/sync_windows.cc
-  src/core/lib/gpr/thd.cc
-  src/core/lib/gpr/thd_posix.cc
-  src/core/lib/gpr/thd_windows.cc
   src/core/lib/gpr/time.cc
   src/core/lib/gpr/time_posix.cc
   src/core/lib/gpr/time_precise.cc
@@ -667,6 +669,8 @@ 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/thd_posix.cc
+  src/core/lib/gprpp/thd_windows.cc
   src/core/lib/profiling/basic_timers.cc
   src/core/lib/profiling/stap_timers.cc
 )
@@ -697,6 +701,12 @@ target_include_directories(gpr
 target_link_libraries(gpr
   ${_gRPC_ALLTARGETS_LIBRARIES}
 )
+if (_gRPC_PLATFORM_ANDROID)
+  target_link_libraries(gpr
+    android
+    log
+  )
+endif (_gRPC_PLATFORM_ANDROID)
 
 foreach(_hdr
   include/grpc/support/alloc.h
@@ -2713,6 +2723,7 @@ endif()
 
 if (gRPC_BUILD_TESTS)
 
+if (gRPC_BUILD_CODEGEN)
 add_library(grpc++_core_stats
   ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/core/stats.pb.cc
   ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/core/stats.grpc.pb.cc
@@ -2758,6 +2769,7 @@ target_link_libraries(grpc++_core_stats
   grpc++
 )
 
+endif (gRPC_BUILD_CODEGEN)
 
 endif (gRPC_BUILD_TESTS)
 
@@ -3254,6 +3266,7 @@ if (gRPC_INSTALL)
 endif()
 
 
+if (gRPC_BUILD_CODEGEN)
 add_library(grpc++_error_details
   ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/status/status.pb.cc
   ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/status/status.grpc.pb.cc
@@ -3306,6 +3319,7 @@ foreach(_hdr
     DESTINATION "${gRPC_INSTALL_INCLUDEDIR}/${_path}"
   )
 endforeach()
+endif (gRPC_BUILD_CODEGEN)
 
 
 if (gRPC_INSTALL)
@@ -3318,6 +3332,7 @@ endif()
 
 if (gRPC_BUILD_TESTS)
 
+if (gRPC_BUILD_CODEGEN)
 add_library(grpc++_proto_reflection_desc_db
   test/cpp/util/proto_reflection_descriptor_database.cc
   ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/reflection/v1alpha/reflection.pb.cc
@@ -3374,9 +3389,11 @@ foreach(_hdr
     DESTINATION "${gRPC_INSTALL_INCLUDEDIR}/${_path}"
   )
 endforeach()
+endif (gRPC_BUILD_CODEGEN)
 
 endif (gRPC_BUILD_TESTS)
 
+if (gRPC_BUILD_CODEGEN)
 add_library(grpc++_reflection
   src/cpp/ext/proto_server_reflection.cc
   src/cpp/ext/proto_server_reflection_plugin.cc
@@ -3430,6 +3447,7 @@ foreach(_hdr
     DESTINATION "${gRPC_INSTALL_INCLUDEDIR}/${_path}"
   )
 endforeach()
+endif (gRPC_BUILD_CODEGEN)
 
 
 if (gRPC_INSTALL)
@@ -3483,6 +3501,7 @@ target_link_libraries(grpc++_test_config
 endif (gRPC_BUILD_TESTS)
 if (gRPC_BUILD_TESTS)
 
+if (gRPC_BUILD_CODEGEN)
 add_library(grpc++_test_util
   ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/health/v1/health.pb.cc
   ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/health/v1/health.grpc.pb.cc
@@ -3651,10 +3670,12 @@ foreach(_hdr
     DESTINATION "${gRPC_INSTALL_INCLUDEDIR}/${_path}"
   )
 endforeach()
+endif (gRPC_BUILD_CODEGEN)
 
 endif (gRPC_BUILD_TESTS)
 if (gRPC_BUILD_TESTS)
 
+if (gRPC_BUILD_CODEGEN)
 add_library(grpc++_test_util_unsecure
   ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/health/v1/health.pb.cc
   ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/health/v1/health.grpc.pb.cc
@@ -3821,6 +3842,7 @@ foreach(_hdr
     DESTINATION "${gRPC_INSTALL_INCLUDEDIR}/${_path}"
   )
 endforeach()
+endif (gRPC_BUILD_CODEGEN)
 
 endif (gRPC_BUILD_TESTS)
 
@@ -4163,6 +4185,7 @@ target_link_libraries(grpc_benchmark
 endif (gRPC_BUILD_TESTS)
 if (gRPC_BUILD_TESTS)
 
+if (gRPC_BUILD_CODEGEN)
 add_library(grpc_cli_libs
   test/cpp/util/cli_call.cc
   test/cpp/util/cli_credentials.cc
@@ -4224,6 +4247,7 @@ foreach(_hdr
     DESTINATION "${gRPC_INSTALL_INCLUDEDIR}/${_path}"
   )
 endforeach()
+endif (gRPC_BUILD_CODEGEN)
 
 endif (gRPC_BUILD_TESTS)
 
@@ -4289,6 +4313,7 @@ endif()
 
 if (gRPC_BUILD_TESTS)
 
+if (gRPC_BUILD_CODEGEN)
 add_library(http2_client_main
   ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/empty.pb.cc
   ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/empty.grpc.pb.cc
@@ -4352,10 +4377,12 @@ target_link_libraries(http2_client_main
   grpc++_test_config
 )
 
+endif (gRPC_BUILD_CODEGEN)
 
 endif (gRPC_BUILD_TESTS)
 if (gRPC_BUILD_TESTS)
 
+if (gRPC_BUILD_CODEGEN)
 add_library(interop_client_helper
   ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/messages.pb.cc
   ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/messages.grpc.pb.cc
@@ -4405,10 +4432,12 @@ target_link_libraries(interop_client_helper
   gpr
 )
 
+endif (gRPC_BUILD_CODEGEN)
 
 endif (gRPC_BUILD_TESTS)
 if (gRPC_BUILD_TESTS)
 
+if (gRPC_BUILD_CODEGEN)
 add_library(interop_client_main
   ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/empty.pb.cc
   ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/empty.grpc.pb.cc
@@ -4476,6 +4505,7 @@ target_link_libraries(interop_client_main
   grpc++_test_config
 )
 
+endif (gRPC_BUILD_CODEGEN)
 
 endif (gRPC_BUILD_TESTS)
 if (gRPC_BUILD_TESTS)
@@ -4526,6 +4556,7 @@ target_link_libraries(interop_server_helper
 endif (gRPC_BUILD_TESTS)
 if (gRPC_BUILD_TESTS)
 
+if (gRPC_BUILD_CODEGEN)
 add_library(interop_server_lib
   ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/empty.pb.cc
   ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/empty.grpc.pb.cc
@@ -4592,6 +4623,7 @@ target_link_libraries(interop_server_lib
   grpc++_test_config
 )
 
+endif (gRPC_BUILD_CODEGEN)
 
 endif (gRPC_BUILD_TESTS)
 if (gRPC_BUILD_TESTS)
@@ -4638,6 +4670,7 @@ target_link_libraries(interop_server_main
 endif (gRPC_BUILD_TESTS)
 if (gRPC_BUILD_TESTS)
 
+if (gRPC_BUILD_CODEGEN)
 add_library(qps
   ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/messages.pb.cc
   ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/messages.grpc.pb.cc
@@ -4724,6 +4757,7 @@ target_link_libraries(qps
   grpc
 )
 
+endif (gRPC_BUILD_CODEGEN)
 
 endif (gRPC_BUILD_TESTS)
 
@@ -6264,7 +6298,7 @@ endif (gRPC_BUILD_TESTS)
 if (gRPC_BUILD_TESTS)
 
 add_executable(gpr_thd_test
-  test/core/gpr/thd_test.cc
+  test/core/gprpp/thd_test.cc
 )
 
 
@@ -10307,6 +10341,7 @@ target_link_libraries(grpc_cli
 )
 
 endif (gRPC_BUILD_TESTS)
+if (gRPC_BUILD_CODEGEN)
 
 add_executable(grpc_cpp_plugin
   src/compiler/cpp_plugin.cc
@@ -10341,6 +10376,8 @@ if (gRPC_INSTALL)
   )
 endif()
 
+endif (gRPC_BUILD_CODEGEN)
+if (gRPC_BUILD_CODEGEN)
 
 add_executable(grpc_csharp_plugin
   src/compiler/csharp_plugin.cc
@@ -10375,6 +10412,8 @@ if (gRPC_INSTALL)
   )
 endif()
 
+endif (gRPC_BUILD_CODEGEN)
+if (gRPC_BUILD_CODEGEN)
 
 add_executable(grpc_node_plugin
   src/compiler/node_plugin.cc
@@ -10409,6 +10448,8 @@ if (gRPC_INSTALL)
   )
 endif()
 
+endif (gRPC_BUILD_CODEGEN)
+if (gRPC_BUILD_CODEGEN)
 
 add_executable(grpc_objective_c_plugin
   src/compiler/objective_c_plugin.cc
@@ -10443,6 +10484,8 @@ if (gRPC_INSTALL)
   )
 endif()
 
+endif (gRPC_BUILD_CODEGEN)
+if (gRPC_BUILD_CODEGEN)
 
 add_executable(grpc_php_plugin
   src/compiler/php_plugin.cc
@@ -10477,6 +10520,8 @@ if (gRPC_INSTALL)
   )
 endif()
 
+endif (gRPC_BUILD_CODEGEN)
+if (gRPC_BUILD_CODEGEN)
 
 add_executable(grpc_python_plugin
   src/compiler/python_plugin.cc
@@ -10511,6 +10556,8 @@ if (gRPC_INSTALL)
   )
 endif()
 
+endif (gRPC_BUILD_CODEGEN)
+if (gRPC_BUILD_CODEGEN)
 
 add_executable(grpc_ruby_plugin
   src/compiler/ruby_plugin.cc
@@ -10545,6 +10592,7 @@ if (gRPC_INSTALL)
   )
 endif()
 
+endif (gRPC_BUILD_CODEGEN)
 if (gRPC_BUILD_TESTS)
 
 add_executable(grpc_tool_test

+ 4 - 5
Makefile

@@ -2924,9 +2924,6 @@ LIBGPR_SRC = \
     src/core/lib/gpr/sync.cc \
     src/core/lib/gpr/sync_posix.cc \
     src/core/lib/gpr/sync_windows.cc \
-    src/core/lib/gpr/thd.cc \
-    src/core/lib/gpr/thd_posix.cc \
-    src/core/lib/gpr/thd_windows.cc \
     src/core/lib/gpr/time.cc \
     src/core/lib/gpr/time_posix.cc \
     src/core/lib/gpr/time_precise.cc \
@@ -2936,6 +2933,8 @@ 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/thd_posix.cc \
+    src/core/lib/gprpp/thd_windows.cc \
     src/core/lib/profiling/basic_timers.cc \
     src/core/lib/profiling/stap_timers.cc \
 
@@ -11096,7 +11095,7 @@ endif
 
 
 GPR_THD_TEST_SRC = \
-    test/core/gpr/thd_test.cc \
+    test/core/gprpp/thd_test.cc \
 
 GPR_THD_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(GPR_THD_TEST_SRC))))
 ifeq ($(NO_SECURE),true)
@@ -11116,7 +11115,7 @@ $(BINDIR)/$(CONFIG)/gpr_thd_test: $(GPR_THD_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgp
 
 endif
 
-$(OBJDIR)/$(CONFIG)/test/core/gpr/thd_test.o:  $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+$(OBJDIR)/$(CONFIG)/test/core/gprpp/thd_test.o:  $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
 
 deps_gpr_thd_test: $(GPR_THD_TEST_OBJS:.o=.dep)
 

+ 4 - 5
build.yaml

@@ -59,9 +59,6 @@ filegroups:
   - src/core/lib/gpr/sync.cc
   - src/core/lib/gpr/sync_posix.cc
   - src/core/lib/gpr/sync_windows.cc
-  - src/core/lib/gpr/thd.cc
-  - src/core/lib/gpr/thd_posix.cc
-  - src/core/lib/gpr/thd_windows.cc
   - src/core/lib/gpr/time.cc
   - src/core/lib/gpr/time_posix.cc
   - src/core/lib/gpr/time_precise.cc
@@ -71,6 +68,8 @@ 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/thd_posix.cc
+  - src/core/lib/gprpp/thd_windows.cc
   - src/core/lib/profiling/basic_timers.cc
   - src/core/lib/profiling/stap_timers.cc
   uses:
@@ -104,7 +103,6 @@ filegroups:
   - src/core/lib/gpr/spinlock.h
   - src/core/lib/gpr/string.h
   - src/core/lib/gpr/string_windows.h
-  - src/core/lib/gpr/thd.h
   - src/core/lib/gpr/time_precise.h
   - src/core/lib/gpr/tls.h
   - src/core/lib/gpr/tls_gcc.h
@@ -118,6 +116,7 @@ filegroups:
   - src/core/lib/gprpp/atomic_with_std.h
   - src/core/lib/gprpp/manual_constructor.h
   - src/core/lib/gprpp/memory.h
+  - src/core/lib/gprpp/thd.h
   - src/core/lib/profiling/timers.h
   uses:
   - gpr_codegen
@@ -2336,7 +2335,7 @@ targets:
   build: test
   language: c
   src:
-  - test/core/gpr/thd_test.cc
+  - test/core/gprpp/thd_test.cc
   deps:
   - gpr_test_util
   - gpr

+ 3 - 3
config.m4

@@ -65,9 +65,6 @@ if test "$PHP_GRPC" != "no"; then
     src/core/lib/gpr/sync.cc \
     src/core/lib/gpr/sync_posix.cc \
     src/core/lib/gpr/sync_windows.cc \
-    src/core/lib/gpr/thd.cc \
-    src/core/lib/gpr/thd_posix.cc \
-    src/core/lib/gpr/thd_windows.cc \
     src/core/lib/gpr/time.cc \
     src/core/lib/gpr/time_posix.cc \
     src/core/lib/gpr/time_precise.cc \
@@ -77,6 +74,8 @@ 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/thd_posix.cc \
+    src/core/lib/gprpp/thd_windows.cc \
     src/core/lib/profiling/basic_timers.cc \
     src/core/lib/profiling/stap_timers.cc \
     src/core/lib/surface/init.cc \
@@ -631,6 +630,7 @@ if test "$PHP_GRPC" != "no"; then
   PHP_ADD_BUILD_DIR($ext_builddir/src/core/lib/compression)
   PHP_ADD_BUILD_DIR($ext_builddir/src/core/lib/debug)
   PHP_ADD_BUILD_DIR($ext_builddir/src/core/lib/gpr)
+  PHP_ADD_BUILD_DIR($ext_builddir/src/core/lib/gprpp)
   PHP_ADD_BUILD_DIR($ext_builddir/src/core/lib/http)
   PHP_ADD_BUILD_DIR($ext_builddir/src/core/lib/iomgr)
   PHP_ADD_BUILD_DIR($ext_builddir/src/core/lib/json)

+ 3 - 3
config.w32

@@ -42,9 +42,6 @@ if (PHP_GRPC != "no") {
     "src\\core\\lib\\gpr\\sync.cc " +
     "src\\core\\lib\\gpr\\sync_posix.cc " +
     "src\\core\\lib\\gpr\\sync_windows.cc " +
-    "src\\core\\lib\\gpr\\thd.cc " +
-    "src\\core\\lib\\gpr\\thd_posix.cc " +
-    "src\\core\\lib\\gpr\\thd_windows.cc " +
     "src\\core\\lib\\gpr\\time.cc " +
     "src\\core\\lib\\gpr\\time_posix.cc " +
     "src\\core\\lib\\gpr\\time_precise.cc " +
@@ -54,6 +51,8 @@ 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\\thd_posix.cc " +
+    "src\\core\\lib\\gprpp\\thd_windows.cc " +
     "src\\core\\lib\\profiling\\basic_timers.cc " +
     "src\\core\\lib\\profiling\\stap_timers.cc " +
     "src\\core\\lib\\surface\\init.cc " +
@@ -643,6 +642,7 @@ if (PHP_GRPC != "no") {
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\lib\\compression");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\lib\\debug");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\lib\\gpr");
+  FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\lib\\gprpp");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\lib\\http");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\lib\\iomgr");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\lib\\json");

+ 1 - 0
doc/g_stands_for.md

@@ -14,3 +14,4 @@ future), and the corresponding version numbers that used them:
 - 1.8 'g' stands for 'generous'
 - 1.9 'g' stands for 'glossy'
 - 1.10 'g' stands for 'glamorous'
+- 1.11 'g' stands for 'gorgeous'

+ 9 - 0
examples/android/helloworld/.gitignore

@@ -0,0 +1,9 @@
+*.iml
+.gradle
+/local.properties
+/.idea/workspace.xml
+/.idea/libraries
+.DS_Store
+/build
+/captures
+.externalNativeBuild

+ 24 - 0
examples/android/helloworld/README.md

@@ -0,0 +1,24 @@
+gRPC on Android
+==============
+
+Note: Building the protobuf dependency for Android requires
+https://github.com/google/protobuf/pull/3878. This fix will be in the next
+protobuf release, but until then must be manually patched in to
+`third_party/protobuf` to build gRPC for Android.
+
+PREREQUISITES
+-------------
+
+- Android SDK
+- Android NDK
+- `protoc` and `grpc_cpp_plugin` binaries on the host system
+
+INSTALL
+-------
+
+The example application can be built via Android Studio or on the command line
+using `gradle`:
+
+  ```sh
+  $ ./gradlew installDebug
+  ```

+ 1 - 0
examples/android/helloworld/app/.gitignore

@@ -0,0 +1 @@
+/build

+ 123 - 0
examples/android/helloworld/app/CMakeLists.txt

@@ -0,0 +1,123 @@
+cmake_minimum_required(VERSION 3.4.1)
+
+set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
+
+set(helloworld_PROTOBUF_PROTOC_EXECUTABLE "/usr/local/bin/protoc" CACHE STRING "Protoc binary on host")
+set(helloworld_GRPC_CPP_PLUGIN_EXECUTABLE "/usr/local/bin/grpc_cpp_plugin" CACHE STRING "gRPC CPP plugin binary on host")
+
+set(GRPC_SRC_DIR ../../../../)
+
+set(GRPC_BUILD_DIR ../grpc/outputs/${ANDROID_ABI})
+file(MAKE_DIRECTORY ${GRPC_BUILD_DIR})
+
+add_subdirectory(${GRPC_SRC_DIR} ${GRPC_BUILD_DIR})
+
+include_directories(${GRPC_SRC_DIR}/include)
+
+add_library(libgrpc STATIC IMPORTED)
+set_target_properties(libgrpc PROPERTIES IMPORTED_LOCATION
+  ${GRPC_BUILD_DIR}/libgrpc.a)
+
+add_library(libgrpc++ STATIC IMPORTED)
+set_target_properties(libgrpc++ PROPERTIES IMPORTED_LOCATION
+  ${GRPC_BUILD_DIR}/libgrpc++.a)
+
+add_library(libgpr STATIC IMPORTED)
+set_target_properties(libgpr PROPERTIES IMPORTED_LOCATION
+  ${GRPC_BUILD_DIR}/libgpr.a)
+
+add_library(libcares STATIC IMPORTED)
+set_target_properties(libcares PROPERTIES IMPORTED_LOCATION
+  ${GRPC_BUILD_DIR}/third_party/cares/cares/lib/libcares.a)
+
+add_library(libzlib STATIC IMPORTED)
+set_target_properties(libzlib PROPERTIES IMPORTED_LOCATION
+  ${GRPC_BUILD_DIR}/third_party/zlib/libz.a)
+
+add_library(libcrypto STATIC IMPORTED)
+set_target_properties(libcrypto PROPERTIES IMPORTED_LOCATION
+  ${GRPC_BUILD_DIR}/third_party/boringssl/crypto/libcrypto.a)
+
+add_library(libssl STATIC IMPORTED)
+set_target_properties(libssl PROPERTIES IMPORTED_LOCATION
+  ${GRPC_BUILD_DIR}/third_party/boringssl/ssl/libssl.a)
+
+set(GRPC_PROTO_GENS_DIR ${CMAKE_BINARY_DIR}/gens)
+file(MAKE_DIRECTORY ${GRPC_PROTO_GENS_DIR})
+include_directories(${GRPC_PROTO_GENS_DIR})
+
+function(android_protobuf_grpc_generate_cpp SRC_FILES HDR_FILES INCLUDE_ROOT)
+  if(NOT ARGN)
+    message(SEND_ERROR "Error: android_protobuf_grpc_generate_cpp() called without any proto files")
+    return()
+  endif()
+
+  set(${SRC_FILES})
+  set(${HDR_FILES})
+  set(PROTOBUF_INCLUDE_PATH -I ${INCLUDE_ROOT})
+  foreach(FIL ${ARGN})
+    get_filename_component(ABS_FIL ${FIL} ABSOLUTE)
+    get_filename_component(FIL_WE ${FIL} NAME_WE)
+    file(RELATIVE_PATH REL_FIL ${CMAKE_CURRENT_SOURCE_DIR}/${INCLUDE_ROOT} ${ABS_FIL})
+    get_filename_component(REL_DIR ${REL_FIL} DIRECTORY)
+    set(RELFIL_WE "${REL_DIR}/${FIL_WE}")
+
+    list(APPEND ${SRC_FILES} "${GRPC_PROTO_GENS_DIR}/${RELFIL_WE}.pb.cc")
+    list(APPEND ${HDR_FILES} "${GRPC_PROTO_GENS_DIR}/${RELFIL_WE}.pb.h")
+    list(APPEND ${SRC_FILES} "${GRPC_PROTO_GENS_DIR}/${RELFIL_WE}.grpc.pb.cc")
+    list(APPEND ${HDR_FILES} "${GRPC_PROTO_GENS_DIR}/${RELFIL_WE}.grpc.pb.h")
+
+    add_custom_command(
+      OUTPUT "${GRPC_PROTO_GENS_DIR}/${RELFIL_WE}.grpc.pb.cc"
+             "${GRPC_PROTO_GENS_DIR}/${RELFIL_WE}.grpc.pb.h"
+             "${GRPC_PROTO_GENS_DIR}/${RELFIL_WE}.pb.cc"
+             "${GRPC_PROTO_GENS_DIR}/${RELFIL_WE}.pb.h"
+      COMMAND ${helloworld_PROTOBUF_PROTOC_EXECUTABLE}
+      ARGS --grpc_out=${GRPC_PROTO_GENS_DIR}
+        --cpp_out=${GRPC_PROTO_GENS_DIR}
+        --plugin=protoc-gen-grpc=${helloworld_GRPC_CPP_PLUGIN_EXECUTABLE}
+        ${PROTOBUF_INCLUDE_PATH}
+        ${REL_FIL}
+      WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
+      DEPENDS ${helloworld_PROTOBUF_PROTOC_EXECUTABLE} ${helloworld_GRPC_CPP_PLUGIN_EXECUTABLE} ${ABS_FIL} )
+  endforeach()
+
+  set_source_files_properties(${${SRC_FILES}} ${${HDR_FILES}} PROPERTIES GENERATED TRUE)
+  set(${SRC_FILES} ${${SRC_FILES}} PARENT_SCOPE)
+  set(${HDR_FILES} ${${HDR_FILES}} PARENT_SCOPE)
+endfunction()
+
+set(PROTO_BASE_DIR ${GRPC_SRC_DIR}/examples/protos)
+
+android_protobuf_grpc_generate_cpp(
+  HELLOWORLD_PROTO_SRCS HELLOWORLD_PROTO_HDRS ${PROTO_BASE_DIR} ${PROTO_BASE_DIR}/helloworld.proto)
+
+add_library(helloworld_proto_lib
+  SHARED ${HELLOWORLD_PROTO_HDRS} ${HELLOWORLD_PROTO_SRCS})
+
+target_link_libraries(helloworld_proto_lib
+  libprotobuf
+  libgrpc++
+  android
+  log)
+
+find_library(log-lib
+ log)
+
+add_library(grpc-helloworld
+  SHARED src/main/cpp/grpc-helloworld.cc)
+
+target_include_directories(grpc-helloworld
+  PRIVATE ${HELLOWORLD_PROTO_HEADERS})
+
+target_link_libraries(grpc-helloworld
+  libgrpc++
+  libgrpc
+  libzlib
+  libcares
+  libssl
+  libcrypto
+  helloworld_proto_lib
+  libgpr
+  android
+  ${log-lib})

+ 53 - 0
examples/android/helloworld/app/build.gradle

@@ -0,0 +1,53 @@
+apply plugin: 'com.android.application'
+
+android {
+    compileSdkVersion 26
+    defaultConfig {
+        applicationId "io.grpc.android.cpp.helloworldexample"
+        minSdkVersion 14
+        targetSdkVersion 26
+        versionCode 1
+        versionName "1.0"
+        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
+        externalNativeBuild {
+            cmake {
+                cppFlags "-std=c++14 -frtti -fexceptions"
+                arguments '-DANDROID_STL=c++_static'
+                arguments '-DRUN_HAVE_POSIX_REGEX=0'
+                arguments '-DRUN_HAVE_STD_REGEX=0'
+                arguments '-DRUN_HAVE_STEADY_CLOCK=0'
+                arguments '-Dprotobuf_BUILD_PROTOC_BINARIES=off'
+                arguments '-DgRPC_BUILD_CODEGEN=off'
+                // Set this to the path to the protoc binary on the host system (codegen is not
+                // cross-compiled to Android)
+                arguments '-Dhelloworld_PROTOBUF_PROTOC_EXECUTABLE=/usr/local/bin/protoc'
+                // Set this to the path to the gRPC C++ protoc plugin binary on the host system
+                // (codegen is not cross-compiled to Android)
+                arguments '-Dhelloworld_GRPC_CPP_PLUGIN_EXECUTABLE=/usr/local/bin/grpc_cpp_plugin'
+            }
+        }
+        ndk.abiFilters 'x86'
+    }
+    buildTypes {
+        debug {
+            minifyEnabled false
+        }
+        release {
+            minifyEnabled true
+            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
+        }
+    }
+    externalNativeBuild {
+        cmake {
+            path "CMakeLists.txt"
+        }
+    }
+}
+
+dependencies {
+    implementation fileTree(dir: 'libs', include: ['*.jar'])
+    implementation 'com.android.support:appcompat-v7:26.1.0'
+    testImplementation 'junit:junit:4.12'
+    androidTestImplementation 'com.android.support.test:runner:1.0.1'
+    androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1'
+}

+ 21 - 0
examples/android/helloworld/app/proguard-rules.pro

@@ -0,0 +1,21 @@
+# Add project specific ProGuard rules here.
+# You can control the set of applied configuration files using the
+# proguardFiles setting in build.gradle.
+#
+# For more details, see
+#   http://developer.android.com/guide/developing/tools/proguard.html
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+#   public *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile

+ 22 - 0
examples/android/helloworld/app/src/main/AndroidManifest.xml

@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="io.grpc.helloworldexample.cpp" >
+
+    <uses-permission android:name="android.permission.INTERNET" />
+
+    <application
+        android:allowBackup="false"
+        android:icon="@mipmap/ic_launcher"
+        android:label="@string/app_name"
+        android:theme="@style/Base.V7.Theme.AppCompat.Light" >
+        <activity
+            android:name=".HelloworldActivity"
+            android:label="@string/app_name" >
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+    </application>
+
+</manifest>

+ 142 - 0
examples/android/helloworld/app/src/main/cpp/grpc-helloworld.cc

@@ -0,0 +1,142 @@
+/*
+ *
+ * Copyright 2018 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 <atomic>
+
+#include <grpc++/grpc++.h>
+#include <jni.h>
+
+#include "helloworld.grpc.pb.h"
+
+using grpc::Channel;
+using grpc::ClientContext;
+using grpc::Server;
+using grpc::ServerBuilder;
+using grpc::ServerContext;
+using grpc::Status;
+using helloworld::Greeter;
+using helloworld::HelloReply;
+using helloworld::HelloRequest;
+
+std::atomic<bool> stop_server(false);
+
+// Logic and data behind the server's behavior.
+class GreeterServiceImpl final : public Greeter::Service {
+  Status SayHello(ServerContext* context, const HelloRequest* request,
+                  HelloReply* reply) override {
+    std::string prefix("Hello ");
+    reply->set_message(prefix + request->name());
+    return Status::OK;
+  }
+};
+
+void StartServer(JNIEnv* env, jobject obj, jmethodID is_cancelled_mid,
+                 int port) {
+  const int host_port_buf_size = 1024;
+  char host_port[host_port_buf_size];
+  snprintf(host_port, host_port_buf_size, "0.0.0.0:%d", port);
+
+  GreeterServiceImpl service;
+  ServerBuilder builder;
+  // Listen on the given address without any authentication mechanism.
+  builder.AddListeningPort(host_port, grpc::InsecureServerCredentials());
+  // Register "service" as the instance through which we'll communicate with
+  // clients. In this case it corresponds to an *synchronous* service.
+  builder.RegisterService(&service);
+  // Finally assemble the server.
+  std::unique_ptr<Server> server(builder.BuildAndStart());
+  while (!stop_server.load()) {
+    // Check with the Java code to see if the user has requested the server stop or the app is no
+    // longer in the foreground.
+    jboolean is_cancelled = env->CallBooleanMethod(obj, is_cancelled_mid);
+    if (is_cancelled == JNI_TRUE) {
+      stop_server = true;
+    }
+  }
+}
+
+class GreeterClient {
+ public:
+  GreeterClient(std::shared_ptr<Channel> channel)
+      : stub_(Greeter::NewStub(channel)) {}
+
+  // Assembles the client's payload, sends it and presents the response back
+  // from the server.
+  std::string SayHello(const std::string& user) {
+    // Data we are sending to the server.
+    HelloRequest request;
+    request.set_name(user);
+
+    // Container for the data we expect from the server.
+    HelloReply reply;
+
+    // Context for the client. It could be used to convey extra information to
+    // the server and/or tweak certain RPC behaviors.
+    ClientContext context;
+    // The actual RPC.
+    Status status = stub_->SayHello(&context, request, &reply);
+
+    if (status.ok()) {
+      return reply.message();
+    } else {
+      return status.error_message();
+    }
+  }
+
+ private:
+  std::unique_ptr<Greeter::Stub> stub_;
+};
+
+// Send an RPC and return the response. Invoked from Java code.
+extern "C" JNIEXPORT jstring JNICALL
+Java_io_grpc_helloworldexample_cpp_HelloworldActivity_sayHello(
+    JNIEnv* env, jobject obj_unused, jstring host_raw, jint port_raw,
+    jstring message_raw) {
+  const char* host_chars = env->GetStringUTFChars(host_raw, (jboolean*)0);
+  std::string host(host_chars, env->GetStringUTFLength(host_raw));
+
+  int port = static_cast<int>(port_raw);
+
+  const char* message_chars = env->GetStringUTFChars(message_raw, (jboolean*)0);
+  std::string message(message_chars, env->GetStringUTFLength(message_raw));
+
+  const int host_port_buf_size = 1024;
+  char host_port[host_port_buf_size];
+  snprintf(host_port, host_port_buf_size, "%s:%d", host.c_str(), port);
+
+  GreeterClient greeter(
+      grpc::CreateChannel(host_port, grpc::InsecureChannelCredentials()));
+  std::string reply = greeter.SayHello(message);
+
+  return env->NewStringUTF(reply.c_str());
+}
+
+// Start the server. Invoked from Java code.
+extern "C" JNIEXPORT void JNICALL
+Java_io_grpc_helloworldexample_cpp_HelloworldActivity_startServer(
+    JNIEnv* env, jobject obj_this, jint port_raw) {
+  int port = static_cast<int>(port_raw);
+
+  jclass cls = env->GetObjectClass(obj_this);
+  jmethodID is_cancelled_mid =
+      env->GetMethodID(cls, "isRunServerTaskCancelled", "()Z");
+
+  stop_server = false;
+
+  StartServer(env, obj_this, is_cancelled_mid, port);
+}

+ 167 - 0
examples/android/helloworld/app/src/main/java/io/grpc/helloworldexample/cpp/HelloworldActivity.java

@@ -0,0 +1,167 @@
+/*
+ * Copyright 2018, gRPC Authors All rights reserved.
+ *
+ * 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.
+ */
+
+package io.grpc.helloworldexample.cpp;
+
+import android.content.Context;
+import android.os.AsyncTask;
+import android.os.Bundle;
+import android.support.v7.app.AppCompatActivity;
+import android.text.TextUtils;
+import android.text.method.ScrollingMovementMethod;
+import android.view.View;
+import android.view.inputmethod.InputMethodManager;
+import android.widget.Button;
+import android.widget.EditText;
+import android.widget.TextView;
+import android.widget.Toast;
+import java.lang.ref.WeakReference;
+
+public class HelloworldActivity extends AppCompatActivity {
+
+  static {
+    System.loadLibrary("grpc-helloworld");
+  }
+
+  private Button sendButton;
+  private Button serverButton;
+  private EditText hostEdit;
+  private EditText portEdit;
+  private EditText messageEdit;
+  private EditText serverPortEdit;
+  private TextView resultText;
+  private GrpcTask grpcTask;
+  private RunServerTask runServerTask;
+
+  @Override
+  protected void onCreate(Bundle savedInstanceState) {
+    super.onCreate(savedInstanceState);
+    setContentView(R.layout.activity_helloworld);
+    sendButton = (Button) findViewById(R.id.send_button);
+    serverButton = (Button) findViewById(R.id.server_button);
+    hostEdit = (EditText) findViewById(R.id.host_edit_text);
+    portEdit = (EditText) findViewById(R.id.port_edit_text);
+    messageEdit = (EditText) findViewById(R.id.message_edit_text);
+    serverPortEdit = (EditText) findViewById(R.id.server_port_edit_text);
+    resultText = (TextView) findViewById(R.id.grpc_response_text);
+    resultText.setMovementMethod(new ScrollingMovementMethod());
+  }
+
+  @Override
+  protected void onPause() {
+    super.onPause();
+    if (runServerTask != null) {
+      runServerTask.cancel(true);
+      runServerTask = null;
+      serverButton.setText("Start gRPC Server");
+    }
+    if (grpcTask != null) {
+      grpcTask.cancel(true);
+      grpcTask = null;
+    }
+  }
+
+  public void sendMessage(View view) {
+    ((InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE))
+        .hideSoftInputFromWindow(hostEdit.getWindowToken(), 0);
+    sendButton.setEnabled(false);
+    resultText.setText("");
+    grpcTask = new GrpcTask(this);
+    grpcTask.executeOnExecutor(
+        AsyncTask.THREAD_POOL_EXECUTOR,
+        hostEdit.getText().toString(),
+        messageEdit.getText().toString(),
+        portEdit.getText().toString());
+  }
+
+  public void startOrStopServer(View view) {
+    if (runServerTask != null) {
+      runServerTask.cancel(true);
+      runServerTask = null;
+      serverButton.setText("Start gRPC Server");
+      Toast.makeText(this, "Server stopped", Toast.LENGTH_SHORT).show();
+    } else {
+      runServerTask = new RunServerTask(this);
+      String portStr = serverPortEdit.getText().toString();
+      int port = TextUtils.isEmpty(portStr) ? 50051 : Integer.valueOf(portStr);
+      runServerTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, port);
+      serverButton.setText("Stop gRPC Server");
+      Toast.makeText(this, "Server started on port " + port, Toast.LENGTH_SHORT).show();
+    }
+  }
+
+  private static class RunServerTask extends AsyncTask<Integer, Void, Void> {
+    private final WeakReference<HelloworldActivity> activityReference;
+
+    private RunServerTask(HelloworldActivity activity) {
+      this.activityReference = new WeakReference<HelloworldActivity>(activity);
+    }
+
+    @Override
+    protected Void doInBackground(Integer... params) {
+      int port = params[0];
+      HelloworldActivity activity = activityReference.get();
+      if (activity != null) {
+        activity.startServer(port);
+      }
+      return null;
+    }
+  }
+
+  private static class GrpcTask extends AsyncTask<String, Void, String> {
+    private final WeakReference<HelloworldActivity> activityReference;
+
+    private GrpcTask(HelloworldActivity activity) {
+      this.activityReference = new WeakReference<HelloworldActivity>(activity);
+    }
+
+    @Override
+    protected String doInBackground(String... params) {
+      String host = params[0];
+      String message = params[1];
+      String portStr = params[2];
+      int port = TextUtils.isEmpty(portStr) ? 50051 : Integer.valueOf(portStr);
+      return sayHello(host, port, message);
+    }
+
+    @Override
+    protected void onPostExecute(String result) {
+      HelloworldActivity activity = activityReference.get();
+      if (activity == null || isCancelled()) {
+        return;
+      }
+      TextView resultText = (TextView) activity.findViewById(R.id.grpc_response_text);
+      Button sendButton = (Button) activity.findViewById(R.id.send_button);
+      resultText.setText(result);
+      sendButton.setEnabled(true);
+    }
+  }
+
+  /**
+   * Invoked by native code to stop server when RunServerTask has been canceled, either by user
+   * request or upon app moving to background.
+   */
+  public boolean isRunServerTaskCancelled() {
+    if (runServerTask != null) {
+      return runServerTask.isCancelled();
+    }
+    return false;
+  }
+
+  public static native String sayHello(String host, int port, String message);
+
+  public native void startServer(int port);
+}

+ 86 - 0
examples/android/helloworld/app/src/main/res/layout/activity_helloworld.xml

@@ -0,0 +1,86 @@
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+              xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
+              android:layout_height="match_parent"
+              tools:context=".HelloworldActivity"
+              android:orientation="vertical" >
+
+    <TextView
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:paddingTop="12dp"
+        android:paddingBottom="12dp"
+        android:textSize="16sp"
+        android:text="gRPC Client Configuration"
+        android:textStyle="bold" />
+
+    <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:orientation="horizontal">
+        <EditText
+                android:id="@+id/host_edit_text"
+                android:layout_weight="2"
+                android:layout_width="0dp"
+                android:layout_height="wrap_content"
+                android:hint="Enter Host" />
+        <EditText
+                android:id="@+id/port_edit_text"
+                android:layout_weight="1"
+                android:layout_width="0dp"
+                android:layout_height="wrap_content"
+                android:inputType="numberDecimal"
+                android:hint="Enter Port" />
+    </LinearLayout>
+
+
+    <EditText
+            android:id="@+id/message_edit_text"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:hint="Enter message to send" />
+
+    <Button
+            android:id="@+id/send_button"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:onClick="sendMessage"
+            android:text="Send gRPC Request" />
+
+    <TextView
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:paddingTop="12dp"
+        android:paddingBottom="12dp"
+        android:textSize="16sp"
+        android:text="Response:" />
+
+    <TextView
+        android:id="@+id/grpc_response_text"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:scrollbars = "vertical"
+        android:textSize="16sp" />
+
+    <TextView
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:paddingTop="12dp"
+        android:paddingBottom="12dp"
+        android:textSize="16sp"
+        android:text="gRPC Server Configuration"
+        android:textStyle="bold" />
+
+    <EditText
+        android:id="@+id/server_port_edit_text"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:hint="Server port" />
+
+    <Button
+        android:id="@+id/server_button"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:onClick="startOrStopServer"
+        android:text="Start gRPC Server" />
+
+</LinearLayout>

BIN
examples/android/helloworld/app/src/main/res/mipmap-hdpi/ic_launcher.png


BIN
examples/android/helloworld/app/src/main/res/mipmap-mdpi/ic_launcher.png


BIN
examples/android/helloworld/app/src/main/res/mipmap-xhdpi/ic_launcher.png


BIN
examples/android/helloworld/app/src/main/res/mipmap-xxhdpi/ic_launcher.png


+ 3 - 0
examples/android/helloworld/app/src/main/res/values/strings.xml

@@ -0,0 +1,3 @@
+<resources>
+    <string name="app_name">GrpcHelloworldCppExample</string>
+</resources>

+ 24 - 0
examples/android/helloworld/build.gradle

@@ -0,0 +1,24 @@
+// Top-level build file where you can add configuration options common to all sub-projects/modules.
+
+buildscript {
+    repositories {
+        google()
+        jcenter()
+    }
+    dependencies {
+        classpath 'com.android.tools.build:gradle:3.0.1'
+        // NOTE: Do not place your application dependencies here; they belong
+        // in the individual module build.gradle files
+    }
+}
+
+allprojects {
+    repositories {
+        google()
+        jcenter()
+    }
+}
+
+task clean(type: Delete) {
+    delete rootProject.buildDir
+}

+ 17 - 0
examples/android/helloworld/gradle.properties

@@ -0,0 +1,17 @@
+# Project-wide Gradle settings.
+
+# IDE (e.g. Android Studio) users:
+# Gradle settings configured through the IDE *will override*
+# any settings specified in this file.
+
+# For more details on how to configure your build environment visit
+# http://www.gradle.org/docs/current/userguide/build_environment.html
+
+# Specifies the JVM arguments used for the daemon process.
+# The setting is particularly useful for tweaking memory settings.
+org.gradle.jvmargs=-Xmx1536m
+
+# When configured, Gradle will run in incubating parallel mode.
+# This option should only be used with decoupled projects. More details, visit
+# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
+# org.gradle.parallel=true

BIN
examples/android/helloworld/gradle/wrapper/gradle-wrapper.jar


+ 6 - 0
examples/android/helloworld/gradle/wrapper/gradle-wrapper.properties

@@ -0,0 +1,6 @@
+#Thu Jan 25 11:45:30 PST 2018
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.1-all.zip

+ 160 - 0
examples/android/helloworld/gradlew

@@ -0,0 +1,160 @@
+#!/usr/bin/env bash
+
+##############################################################################
+##
+##  Gradle start up script for UN*X
+##
+##############################################################################
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS=""
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn ( ) {
+    echo "$*"
+}
+
+die ( ) {
+    echo
+    echo "$*"
+    echo
+    exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+case "`uname`" in
+  CYGWIN* )
+    cygwin=true
+    ;;
+  Darwin* )
+    darwin=true
+    ;;
+  MINGW* )
+    msys=true
+    ;;
+esac
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+    ls=`ls -ld "$PRG"`
+    link=`expr "$ls" : '.*-> \(.*\)$'`
+    if expr "$link" : '/.*' > /dev/null; then
+        PRG="$link"
+    else
+        PRG=`dirname "$PRG"`"/$link"
+    fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >/dev/null
+APP_HOME="`pwd -P`"
+cd "$SAVED" >/dev/null
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+    if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+        # IBM's JDK on AIX uses strange locations for the executables
+        JAVACMD="$JAVA_HOME/jre/sh/java"
+    else
+        JAVACMD="$JAVA_HOME/bin/java"
+    fi
+    if [ ! -x "$JAVACMD" ] ; then
+        die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+    fi
+else
+    JAVACMD="java"
+    which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
+    MAX_FD_LIMIT=`ulimit -H -n`
+    if [ $? -eq 0 ] ; then
+        if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+            MAX_FD="$MAX_FD_LIMIT"
+        fi
+        ulimit -n $MAX_FD
+        if [ $? -ne 0 ] ; then
+            warn "Could not set maximum file descriptor limit: $MAX_FD"
+        fi
+    else
+        warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+    fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+    GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin ; then
+    APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+    CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+    JAVACMD=`cygpath --unix "$JAVACMD"`
+
+    # We build the pattern for arguments to be converted via cygpath
+    ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+    SEP=""
+    for dir in $ROOTDIRSRAW ; do
+        ROOTDIRS="$ROOTDIRS$SEP$dir"
+        SEP="|"
+    done
+    OURCYGPATTERN="(^($ROOTDIRS))"
+    # Add a user-defined pattern to the cygpath arguments
+    if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+        OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+    fi
+    # Now convert the arguments - kludge to limit ourselves to /bin/sh
+    i=0
+    for arg in "$@" ; do
+        CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+        CHECK2=`echo "$arg"|egrep -c "^-"`                                 ### Determine if an option
+
+        if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### Added a condition
+            eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+        else
+            eval `echo args$i`="\"$arg\""
+        fi
+        i=$((i+1))
+    done
+    case $i in
+        (0) set -- ;;
+        (1) set -- "$args0" ;;
+        (2) set -- "$args0" "$args1" ;;
+        (3) set -- "$args0" "$args1" "$args2" ;;
+        (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+        (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+        (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+        (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+        (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+        (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+    esac
+fi
+
+# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
+function splitJvmOpts() {
+    JVM_OPTS=("$@")
+}
+eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
+JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
+
+exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"

+ 90 - 0
examples/android/helloworld/gradlew.bat

@@ -0,0 +1,90 @@
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem  Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS=
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto init
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto init
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:init
+@rem Get command-line arguments, handling Windowz variants
+
+if not "%OS%" == "Windows_NT" goto win9xME_args
+if "%@eval[2+2]" == "4" goto 4NT_args
+
+:win9xME_args
+@rem Slurp the command line arguments.
+set CMD_LINE_ARGS=
+set _SKIP=2
+
+:win9xME_args_slurp
+if "x%~1" == "x" goto execute
+
+set CMD_LINE_ARGS=%*
+goto execute
+
+:4NT_args
+@rem Get arguments from the 4NT Shell from JP Software
+set CMD_LINE_ARGS=%$
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if  not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega

+ 1 - 0
examples/android/helloworld/settings.gradle

@@ -0,0 +1 @@
+include ':app'

+ 2 - 2
gRPC-C++.podspec

@@ -220,7 +220,6 @@ Pod::Spec.new do |s|
                       'src/core/lib/gpr/spinlock.h',
                       'src/core/lib/gpr/string.h',
                       'src/core/lib/gpr/string_windows.h',
-                      'src/core/lib/gpr/thd.h',
                       'src/core/lib/gpr/time_precise.h',
                       'src/core/lib/gpr/tls.h',
                       'src/core/lib/gpr/tls_gcc.h',
@@ -234,6 +233,7 @@ Pod::Spec.new do |s|
                       'src/core/lib/gprpp/atomic_with_std.h',
                       'src/core/lib/gprpp/manual_constructor.h',
                       'src/core/lib/gprpp/memory.h',
+                      'src/core/lib/gprpp/thd.h',
                       'src/core/lib/profiling/timers.h',
                       'src/core/ext/transport/chttp2/transport/bin_decoder.h',
                       'src/core/ext/transport/chttp2/transport/bin_encoder.h',
@@ -477,7 +477,6 @@ Pod::Spec.new do |s|
                               'src/core/lib/gpr/spinlock.h',
                               'src/core/lib/gpr/string.h',
                               'src/core/lib/gpr/string_windows.h',
-                              'src/core/lib/gpr/thd.h',
                               'src/core/lib/gpr/time_precise.h',
                               'src/core/lib/gpr/tls.h',
                               'src/core/lib/gpr/tls_gcc.h',
@@ -491,6 +490,7 @@ Pod::Spec.new do |s|
                               'src/core/lib/gprpp/atomic_with_std.h',
                               'src/core/lib/gprpp/manual_constructor.h',
                               'src/core/lib/gprpp/memory.h',
+                              'src/core/lib/gprpp/thd.h',
                               'src/core/lib/profiling/timers.h',
                               'src/core/lib/avl/avl.h',
                               'src/core/lib/backoff/backoff.h',

+ 4 - 5
gRPC-Core.podspec

@@ -192,7 +192,6 @@ Pod::Spec.new do |s|
                       'src/core/lib/gpr/spinlock.h',
                       'src/core/lib/gpr/string.h',
                       'src/core/lib/gpr/string_windows.h',
-                      'src/core/lib/gpr/thd.h',
                       'src/core/lib/gpr/time_precise.h',
                       'src/core/lib/gpr/tls.h',
                       'src/core/lib/gpr/tls_gcc.h',
@@ -206,6 +205,7 @@ Pod::Spec.new do |s|
                       'src/core/lib/gprpp/atomic_with_std.h',
                       'src/core/lib/gprpp/manual_constructor.h',
                       'src/core/lib/gprpp/memory.h',
+                      'src/core/lib/gprpp/thd.h',
                       'src/core/lib/profiling/timers.h',
                       'src/core/lib/gpr/alloc.cc',
                       'src/core/lib/gpr/arena.cc',
@@ -233,9 +233,6 @@ Pod::Spec.new do |s|
                       'src/core/lib/gpr/sync.cc',
                       'src/core/lib/gpr/sync_posix.cc',
                       'src/core/lib/gpr/sync_windows.cc',
-                      'src/core/lib/gpr/thd.cc',
-                      'src/core/lib/gpr/thd_posix.cc',
-                      'src/core/lib/gpr/thd_windows.cc',
                       'src/core/lib/gpr/time.cc',
                       'src/core/lib/gpr/time_posix.cc',
                       'src/core/lib/gpr/time_precise.cc',
@@ -245,6 +242,8 @@ 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/thd_posix.cc',
+                      'src/core/lib/gprpp/thd_windows.cc',
                       'src/core/lib/profiling/basic_timers.cc',
                       'src/core/lib/profiling/stap_timers.cc',
                       'src/core/ext/transport/chttp2/transport/bin_decoder.h',
@@ -730,7 +729,6 @@ Pod::Spec.new do |s|
                               'src/core/lib/gpr/spinlock.h',
                               'src/core/lib/gpr/string.h',
                               'src/core/lib/gpr/string_windows.h',
-                              'src/core/lib/gpr/thd.h',
                               'src/core/lib/gpr/time_precise.h',
                               'src/core/lib/gpr/tls.h',
                               'src/core/lib/gpr/tls_gcc.h',
@@ -744,6 +742,7 @@ Pod::Spec.new do |s|
                               'src/core/lib/gprpp/atomic_with_std.h',
                               'src/core/lib/gprpp/manual_constructor.h',
                               'src/core/lib/gprpp/memory.h',
+                              'src/core/lib/gprpp/thd.h',
                               'src/core/lib/profiling/timers.h',
                               'src/core/ext/transport/chttp2/transport/bin_decoder.h',
                               'src/core/ext/transport/chttp2/transport/bin_encoder.h',

+ 3 - 4
grpc.gemspec

@@ -83,7 +83,6 @@ Gem::Specification.new do |s|
   s.files += %w( src/core/lib/gpr/spinlock.h )
   s.files += %w( src/core/lib/gpr/string.h )
   s.files += %w( src/core/lib/gpr/string_windows.h )
-  s.files += %w( src/core/lib/gpr/thd.h )
   s.files += %w( src/core/lib/gpr/time_precise.h )
   s.files += %w( src/core/lib/gpr/tls.h )
   s.files += %w( src/core/lib/gpr/tls_gcc.h )
@@ -97,6 +96,7 @@ Gem::Specification.new do |s|
   s.files += %w( src/core/lib/gprpp/atomic_with_std.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 )
   s.files += %w( src/core/lib/profiling/timers.h )
   s.files += %w( src/core/lib/gpr/alloc.cc )
   s.files += %w( src/core/lib/gpr/arena.cc )
@@ -124,9 +124,6 @@ Gem::Specification.new do |s|
   s.files += %w( src/core/lib/gpr/sync.cc )
   s.files += %w( src/core/lib/gpr/sync_posix.cc )
   s.files += %w( src/core/lib/gpr/sync_windows.cc )
-  s.files += %w( src/core/lib/gpr/thd.cc )
-  s.files += %w( src/core/lib/gpr/thd_posix.cc )
-  s.files += %w( src/core/lib/gpr/thd_windows.cc )
   s.files += %w( src/core/lib/gpr/time.cc )
   s.files += %w( src/core/lib/gpr/time_posix.cc )
   s.files += %w( src/core/lib/gpr/time_precise.cc )
@@ -136,6 +133,8 @@ 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/thd_posix.cc )
+  s.files += %w( src/core/lib/gprpp/thd_windows.cc )
   s.files += %w( src/core/lib/profiling/basic_timers.cc )
   s.files += %w( src/core/lib/profiling/stap_timers.cc )
   s.files += %w( include/grpc/impl/codegen/byte_buffer.h )

+ 2 - 3
grpc.gyp

@@ -187,9 +187,6 @@
         'src/core/lib/gpr/sync.cc',
         'src/core/lib/gpr/sync_posix.cc',
         'src/core/lib/gpr/sync_windows.cc',
-        'src/core/lib/gpr/thd.cc',
-        'src/core/lib/gpr/thd_posix.cc',
-        'src/core/lib/gpr/thd_windows.cc',
         'src/core/lib/gpr/time.cc',
         'src/core/lib/gpr/time_posix.cc',
         'src/core/lib/gpr/time_precise.cc',
@@ -199,6 +196,8 @@
         '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/thd_posix.cc',
+        'src/core/lib/gprpp/thd_windows.cc',
         'src/core/lib/profiling/basic_timers.cc',
         'src/core/lib/profiling/stap_timers.cc',
       ],

+ 3 - 4
package.xml

@@ -90,7 +90,6 @@
     <file baseinstalldir="/" name="src/core/lib/gpr/spinlock.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/gpr/string.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/gpr/string_windows.h" role="src" />
-    <file baseinstalldir="/" name="src/core/lib/gpr/thd.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/gpr/time_precise.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/gpr/tls.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/gpr/tls_gcc.h" role="src" />
@@ -104,6 +103,7 @@
     <file baseinstalldir="/" name="src/core/lib/gprpp/atomic_with_std.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" />
     <file baseinstalldir="/" name="src/core/lib/profiling/timers.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/gpr/alloc.cc" role="src" />
     <file baseinstalldir="/" name="src/core/lib/gpr/arena.cc" role="src" />
@@ -131,9 +131,6 @@
     <file baseinstalldir="/" name="src/core/lib/gpr/sync.cc" role="src" />
     <file baseinstalldir="/" name="src/core/lib/gpr/sync_posix.cc" role="src" />
     <file baseinstalldir="/" name="src/core/lib/gpr/sync_windows.cc" role="src" />
-    <file baseinstalldir="/" name="src/core/lib/gpr/thd.cc" role="src" />
-    <file baseinstalldir="/" name="src/core/lib/gpr/thd_posix.cc" role="src" />
-    <file baseinstalldir="/" name="src/core/lib/gpr/thd_windows.cc" role="src" />
     <file baseinstalldir="/" name="src/core/lib/gpr/time.cc" role="src" />
     <file baseinstalldir="/" name="src/core/lib/gpr/time_posix.cc" role="src" />
     <file baseinstalldir="/" name="src/core/lib/gpr/time_precise.cc" role="src" />
@@ -143,6 +140,8 @@
     <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/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" />
     <file baseinstalldir="/" name="src/core/lib/profiling/stap_timers.cc" role="src" />
     <file baseinstalldir="/" name="include/grpc/impl/codegen/byte_buffer.h" role="src" />

+ 0 - 51
src/core/lib/gpr/thd.cc

@@ -1,51 +0,0 @@
-/*
- *
- * 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.
- *
- */
-
-/* Platform-independent features for gpr threads. */
-
-#include <grpc/support/port_platform.h>
-
-#include "src/core/lib/gpr/thd.h"
-
-#include <string.h>
-
-enum { GPR_THD_JOINABLE = 1 };
-
-gpr_thd_options gpr_thd_options_default(void) {
-  gpr_thd_options options;
-  memset(&options, 0, sizeof(options));
-  return options;
-}
-
-void gpr_thd_options_set_detached(gpr_thd_options* options) {
-  options->flags &= ~GPR_THD_JOINABLE;
-}
-
-void gpr_thd_options_set_joinable(gpr_thd_options* options) {
-  options->flags |= GPR_THD_JOINABLE;
-}
-
-int gpr_thd_options_is_detached(const gpr_thd_options* options) {
-  if (!options) return 1;
-  return (options->flags & GPR_THD_JOINABLE) == 0;
-}
-
-int gpr_thd_options_is_joinable(const gpr_thd_options* options) {
-  if (!options) return 0;
-  return (options->flags & GPR_THD_JOINABLE) == GPR_THD_JOINABLE;
-}

+ 0 - 72
src/core/lib/gpr/thd.h

@@ -1,72 +0,0 @@
-/*
- *
- * 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_GPR_THD_H
-#define GRPC_CORE_LIB_GPR_THD_H
-/** Internal thread interface for GPR.
-
-   Types
-        gpr_thd_options   options used when creating a thread
- */
-
-#include <grpc/support/port_platform.h>
-
-#include <grpc/support/thd_id.h>
-#include <grpc/support/time.h>
-
-/** Thread creation options. */
-typedef struct {
-  int flags; /** Opaque field. Get and set with accessors below. */
-} gpr_thd_options;
-
-/** Create a new thread running (*thd_body)(arg) and place its thread identifier
-   in *t, and return true.  If there are insufficient resources, return false.
-   thd_name is the name of the thread for identification purposes on platforms
-   that support thread naming.
-   If options==NULL, default options are used.
-   The thread is immediately runnable, and exits when (*thd_body)() returns.  */
-int gpr_thd_new(gpr_thd_id* t, const char* thd_name,
-                void (*thd_body)(void* arg), void* arg,
-                const gpr_thd_options* options);
-
-/** Return a gpr_thd_options struct with all fields set to defaults. */
-gpr_thd_options gpr_thd_options_default(void);
-
-/** Set the thread to become detached on startup - this is the default. */
-void gpr_thd_options_set_detached(gpr_thd_options* options);
-
-/** Set the thread to become joinable - mutually exclusive with detached. */
-void gpr_thd_options_set_joinable(gpr_thd_options* options);
-
-/** Returns non-zero if the option detached is set. */
-int gpr_thd_options_is_detached(const gpr_thd_options* options);
-
-/** Returns non-zero if the option joinable is set. */
-int gpr_thd_options_is_joinable(const gpr_thd_options* options);
-
-/** Blocks until the specified thread properly terminates.
-   Calling this on a detached thread has unpredictable results. */
-void gpr_thd_join(gpr_thd_id t);
-
-/* 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_GPR_THD_H */

+ 0 - 154
src/core/lib/gpr/thd_posix.cc

@@ -1,154 +0,0 @@
-/*
- *
- * 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.
- *
- */
-
-/* Posix implementation for gpr threads. */
-
-#include <grpc/support/port_platform.h>
-
-#ifdef GPR_POSIX_SYNC
-
-#include "src/core/lib/gpr/thd.h"
-
-#include <grpc/support/alloc.h>
-#include <grpc/support/log.h>
-#include <grpc/support/sync.h>
-#include <grpc/support/thd_id.h>
-#include <pthread.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "src/core/lib/gpr/fork.h"
-#include "src/core/lib/gpr/useful.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 */
-  const char* name;        /* name of thread. Can be nullptr. */
-};
-
-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 = *static_cast<struct thd_arg*>(v);
-  free(v);
-  if (a.name != nullptr) {
-#if GPR_APPLE_PTHREAD_NAME
-    /* Apple supports 64 characters, and will truncate if it's longer. */
-    pthread_setname_np(a.name);
-#elif GPR_LINUX_PTHREAD_NAME
-    /* Linux supports 16 characters max, and will error if it's longer. */
-    char buf[16];
-    size_t buf_len = GPR_ARRAY_SIZE(buf) - 1;
-    strncpy(buf, a.name, buf_len);
-    buf[buf_len] = '\0';
-    pthread_setname_np(pthread_self(), buf);
-#endif  // GPR_APPLE_PTHREAD_NAME
-  }
-  (*a.body)(a.arg);
-  dec_thd_count();
-  return nullptr;
-}
-
-int gpr_thd_new(gpr_thd_id* t, const char* thd_name,
-                void (*thd_body)(void* arg), void* arg,
-                const gpr_thd_options* options) {
-  int thread_started;
-  pthread_attr_t attr;
-  pthread_t p;
-  /* don't use gpr_malloc as we may cause an infinite recursion with
-   * the profiling code */
-  struct thd_arg* a = static_cast<struct thd_arg*>(malloc(sizeof(*a)));
-  GPR_ASSERT(a != nullptr);
-  a->body = thd_body;
-  a->arg = arg;
-  a->name = thd_name;
-  inc_thd_count();
-
-  GPR_ASSERT(pthread_attr_init(&attr) == 0);
-  if (gpr_thd_options_is_detached(options)) {
-    GPR_ASSERT(pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED) ==
-               0);
-  } else {
-    GPR_ASSERT(pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE) ==
-               0);
-  }
-  thread_started = (pthread_create(&p, &attr, &thread_body, a) == 0);
-  GPR_ASSERT(pthread_attr_destroy(&attr) == 0);
-  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;
-}
-
-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, nullptr); }
-
-/*****************************************
- * 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 */

+ 0 - 107
src/core/lib/gpr/thd_windows.cc

@@ -1,107 +0,0 @@
-/*
- *
- * 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.
- *
- */
-
-/* Windows implementation for gpr threads. */
-
-#include <grpc/support/port_platform.h>
-
-#ifdef GPR_WINDOWS
-
-#include "src/core/lib/gpr/thd.h"
-
-#include <grpc/support/alloc.h>
-#include <grpc/support/log.h>
-#include <grpc/support/thd_id.h>
-#include <string.h>
-
-#if defined(_MSC_VER)
-#define thread_local __declspec(thread)
-#elif defined(__GNUC__)
-#define thread_local __thread
-#else
-#error "Unknown compiler - please file a bug report"
-#endif
-
-struct thd_info {
-  void (*body)(void* arg); /* body of a thread */
-  void* arg;               /* argument to a thread */
-  HANDLE join_event;       /* if joinable, the join event */
-  int joinable;            /* true if not detached */
-};
-
-static thread_local struct thd_info* g_thd_info;
-
-/* Destroys a thread info */
-static void destroy_thread(struct thd_info* t) {
-  if (t->joinable) CloseHandle(t->join_event);
-  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;
-  g_thd_info->body(g_thd_info->arg);
-  if (g_thd_info->joinable) {
-    BOOL ret = SetEvent(g_thd_info->join_event);
-    GPR_ASSERT(ret);
-  } else {
-    destroy_thread(g_thd_info);
-  }
-  return 0;
-}
-
-int gpr_thd_new(gpr_thd_id* t, const char* thd_name,
-                void (*thd_body)(void* arg), void* arg,
-                const gpr_thd_options* options) {
-  HANDLE handle;
-  struct thd_info* info = (struct thd_info*)gpr_malloc(sizeof(*info));
-  info->body = thd_body;
-  info->arg = arg;
-  *t = 0;
-  if (gpr_thd_options_is_joinable(options)) {
-    info->joinable = 1;
-    info->join_event = CreateEvent(NULL, FALSE, FALSE, NULL);
-    if (info->join_event == NULL) {
-      gpr_free(info);
-      return 0;
-    }
-  } else {
-    info->joinable = 0;
-  }
-  handle = CreateThread(NULL, 64 * 1024, thread_body, info, 0, NULL);
-  if (handle == NULL) {
-    destroy_thread(info);
-  } else {
-    *t = (gpr_thd_id)info;
-    CloseHandle(handle);
-  }
-  return handle != NULL;
-}
-
-gpr_thd_id gpr_thd_currentid(void) { return (gpr_thd_id)g_thd_info; }
-
-void gpr_thd_join(gpr_thd_id t) {
-  struct thd_info* info = (struct thd_info*)t;
-  DWORD ret = WaitForSingleObject(info->join_event, INFINITE);
-  GPR_ASSERT(ret == WAIT_OBJECT_0);
-  destroy_thread(info);
-}
-
-#endif /* GPR_WINDOWS */

+ 135 - 0
src/core/lib/gprpp/thd.h

@@ -0,0 +1,135 @@
+/*
+ *
+ * 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_GPRPP_THD_H
+#define GRPC_CORE_LIB_GPRPP_THD_H
+
+/** Internal thread interface. */
+
+#include <grpc/support/port_platform.h>
+
+#include <grpc/support/log.h>
+#include <grpc/support/sync.h>
+#include <grpc/support/thd_id.h>
+#include <grpc/support/time.h>
+
+#include "src/core/lib/gprpp/abstract.h"
+#include "src/core/lib/gprpp/memory.h"
+
+namespace grpc_core {
+namespace internal {
+
+/// Base class for platform-specific thread-state
+class ThreadInternalsInterface {
+ public:
+  virtual ~ThreadInternalsInterface() {}
+  virtual void Start() GRPC_ABSTRACT;
+  virtual void Join() GRPC_ABSTRACT;
+  GRPC_ABSTRACT_BASE_CLASS
+};
+
+}  // namespace internal
+
+class Thread {
+ public:
+  /// Default constructor only to allow use in structs that lack constructors
+  /// Does not produce a validly-constructed thread; must later
+  /// use placement new to construct a real thread. Does not init mu_ and cv_
+  Thread() : state_(FAKE), impl_(nullptr) {}
+
+  /// Normal constructor to create a thread with name \a thd_name,
+  /// which will execute a thread based on function \a thd_body
+  /// with argument \a arg once it is started.
+  /// The optional \a success argument indicates whether the thread
+  /// is successfully created.
+  Thread(const char* thd_name, void (*thd_body)(void* arg), void* arg,
+         bool* success = nullptr);
+
+  /// Move constructor for thread. After this is called, the other thread
+  /// no longer represents a living thread object
+  Thread(Thread&& other) : state_(other.state_), impl_(other.impl_) {
+    other.state_ = MOVED;
+    other.impl_ = nullptr;
+  }
+
+  /// Move assignment operator for thread. After this is called, the other
+  /// thread no longer represents a living thread object. Not allowed if this
+  /// thread actually exists
+  Thread& operator=(Thread&& other) {
+    if (this != &other) {
+      // TODO(vjpai): if we can be sure that all Thread's are actually
+      // constructed, then we should assert GPR_ASSERT(impl_ == nullptr) here.
+      // However, as long as threads come in structures that are
+      // allocated via gpr_malloc, this will not be the case, so we cannot
+      // assert it for the time being.
+      state_ = other.state_;
+      impl_ = other.impl_;
+      other.state_ = MOVED;
+      other.impl_ = nullptr;
+    }
+    return *this;
+  }
+
+  /// The destructor is strictly optional; either the thread never came to life
+  /// and the constructor itself killed it or it has already been joined and
+  /// the Join function kills it. The destructor shouldn't have to do anything.
+  ~Thread() { GPR_ASSERT(impl_ == nullptr); }
+
+  void Start() {
+    if (impl_ != nullptr) {
+      GPR_ASSERT(state_ == ALIVE);
+      state_ = STARTED;
+      impl_->Start();
+    } else {
+      GPR_ASSERT(state_ == FAILED);
+    }
+  };
+
+  void Join() {
+    if (impl_ != nullptr) {
+      impl_->Join();
+      grpc_core::Delete(impl_);
+      state_ = DONE;
+      impl_ = nullptr;
+    } else {
+      GPR_ASSERT(state_ == FAILED);
+    }
+  };
+
+  static void Init();
+  static bool AwaitAll(gpr_timespec deadline);
+
+ private:
+  Thread(const Thread&) = delete;
+  Thread& operator=(const Thread&) = delete;
+
+  /// The thread states are as follows:
+  /// FAKE -- just a dummy placeholder Thread created by the default constructor
+  /// ALIVE -- an actual thread of control exists associated with this thread
+  /// STARTED -- the thread of control has been started
+  /// DONE -- the thread of control has completed and been joined
+  /// FAILED -- the thread of control never came alive
+  /// MOVED -- contents were moved out and we're no longer tracking them
+  enum ThreadState { FAKE, ALIVE, STARTED, DONE, FAILED, MOVED };
+  ThreadState state_;
+  internal::ThreadInternalsInterface* impl_;
+};
+
+}  // namespace grpc_core
+
+#endif /* GRPC_CORE_LIB_GPRPP_THD_H */

+ 209 - 0
src/core/lib/gprpp/thd_posix.cc

@@ -0,0 +1,209 @@
+/*
+ *
+ * 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.
+ *
+ */
+
+/* Posix implementation for gpr threads. */
+
+#include <grpc/support/port_platform.h>
+
+#ifdef GPR_POSIX_SYNC
+
+#include "src/core/lib/gprpp/thd.h"
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/sync.h>
+#include <grpc/support/thd_id.h>
+#include <pthread.h>
+#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/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;
+  void (*body)(void* arg); /* body of a thread */
+  void* arg;               /* argument to a thread */
+  const char* name;        /* name of thread. Can be nullptr. */
+};
+
+class ThreadInternalsPosix
+    : public grpc_core::internal::ThreadInternalsInterface {
+ public:
+  ThreadInternalsPosix(const char* thd_name, void (*thd_body)(void* arg),
+                       void* arg, bool* success)
+      : started_(false) {
+    gpr_mu_init(&mu_);
+    gpr_cv_init(&ready_);
+    pthread_attr_t attr;
+    /* don't use gpr_malloc as we may cause an infinite recursion with
+     * the profiling code */
+    thd_arg* info = static_cast<thd_arg*>(malloc(sizeof(*info)));
+    GPR_ASSERT(info != nullptr);
+    info->thread = this;
+    info->body = thd_body;
+    info->arg = arg;
+    info->name = thd_name;
+    inc_thd_count();
+
+    GPR_ASSERT(pthread_attr_init(&attr) == 0);
+    GPR_ASSERT(pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE) ==
+               0);
+
+    *success =
+        (pthread_create(&pthread_id_, &attr,
+                        [](void* v) -> void* {
+                          thd_arg arg = *static_cast<thd_arg*>(v);
+                          free(v);
+                          if (arg.name != nullptr) {
+#if GPR_APPLE_PTHREAD_NAME
+                            /* Apple supports 64 characters, and will
+                             * truncate if it's longer. */
+                            pthread_setname_np(arg.name);
+#elif GPR_LINUX_PTHREAD_NAME
+                            /* Linux supports 16 characters max, and will
+                             * error if it's longer. */
+                            char buf[16];
+                            size_t buf_len = GPR_ARRAY_SIZE(buf) - 1;
+                            strncpy(buf, arg.name, buf_len);
+                            buf[buf_len] = '\0';
+                            pthread_setname_np(pthread_self(), buf);
+#endif  // GPR_APPLE_PTHREAD_NAME
+                          }
+
+                          gpr_mu_lock(&arg.thread->mu_);
+                          while (!arg.thread->started_) {
+                            gpr_cv_wait(&arg.thread->ready_, &arg.thread->mu_,
+                                        gpr_inf_future(GPR_CLOCK_MONOTONIC));
+                          }
+                          gpr_mu_unlock(&arg.thread->mu_);
+
+                          (*arg.body)(arg.arg);
+                          dec_thd_count();
+                          return nullptr;
+                        },
+                        info) == 0);
+
+    GPR_ASSERT(pthread_attr_destroy(&attr) == 0);
+
+    if (!success) {
+      /* don't use gpr_free, as this was allocated using malloc (see above) */
+      free(info);
+      dec_thd_count();
+    }
+  };
+
+  ~ThreadInternalsPosix() override {
+    gpr_mu_destroy(&mu_);
+    gpr_cv_destroy(&ready_);
+  }
+
+  void Start() override {
+    gpr_mu_lock(&mu_);
+    started_ = true;
+    gpr_cv_signal(&ready_);
+    gpr_mu_unlock(&mu_);
+  }
+
+  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_;
+  pthread_t pthread_id_;
+};
+
+}  // namespace
+
+Thread::Thread(const char* thd_name, void (*thd_body)(void* arg), void* arg,
+               bool* success) {
+  bool outcome = false;
+  impl_ =
+      grpc_core::New<ThreadInternalsPosix>(thd_name, thd_body, arg, &outcome);
+  if (outcome) {
+    state_ = ALIVE;
+  } else {
+    state_ = FAILED;
+    grpc_core::Delete(impl_);
+    impl_ = nullptr;
+  }
+
+  if (success != nullptr) {
+    *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
+gpr_thd_id gpr_thd_currentid(void) { return (gpr_thd_id)pthread_self(); }
+
+#endif /* GPR_POSIX_SYNC */

+ 162 - 0
src/core/lib/gprpp/thd_windows.cc

@@ -0,0 +1,162 @@
+/*
+ *
+ * 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.
+ *
+ */
+
+/* Windows implementation for gpr threads. */
+
+#include <grpc/support/port_platform.h>
+
+#ifdef GPR_WINDOWS
+
+#include "src/core/lib/gprpp/thd.h"
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/thd_id.h>
+#include <string.h>
+
+#include "src/core/lib/gprpp/memory.h"
+
+#if defined(_MSC_VER)
+#define thread_local __declspec(thread)
+#define WIN_LAMBDA
+#elif defined(__GNUC__)
+#define thread_local __thread
+#define WIN_LAMBDA WINAPI
+#else
+#error "Unknown compiler - please file a bug report"
+#endif
+
+namespace {
+class ThreadInternalsWindows;
+struct thd_info {
+  ThreadInternalsWindows* thread;
+  void (*body)(void* arg); /* body of a thread */
+  void* arg;               /* argument to a thread */
+  HANDLE join_event;       /* the join event */
+};
+
+thread_local struct thd_info* g_thd_info;
+
+class ThreadInternalsWindows
+    : public grpc_core::internal::ThreadInternalsInterface {
+ public:
+  ThreadInternalsWindows(void (*thd_body)(void* arg), void* arg, bool* success)
+      : started_(false) {
+    gpr_mu_init(&mu_);
+    gpr_cv_init(&ready_);
+
+    HANDLE handle;
+    info_ = (struct thd_info*)gpr_malloc(sizeof(*info_));
+    info_->thread = this;
+    info_->body = thd_body;
+    info_->arg = arg;
+
+    info_->join_event = CreateEvent(nullptr, FALSE, FALSE, nullptr);
+    if (info_->join_event == nullptr) {
+      gpr_free(info_);
+      *success = false;
+    } else {
+      handle = CreateThread(
+          nullptr, 64 * 1024,
+          [](void* v) WIN_LAMBDA -> DWORD {
+            g_thd_info = static_cast<thd_info*>(v);
+            gpr_mu_lock(&g_thd_info->thread->mu_);
+            while (!g_thd_info->thread->started_) {
+              gpr_cv_wait(&g_thd_info->thread->ready_, &g_thd_info->thread->mu_,
+                          gpr_inf_future(GPR_CLOCK_MONOTONIC));
+            }
+            gpr_mu_unlock(&g_thd_info->thread->mu_);
+            g_thd_info->body(g_thd_info->arg);
+            BOOL ret = SetEvent(g_thd_info->join_event);
+            GPR_ASSERT(ret);
+            return 0;
+          },
+          info_, 0, nullptr);
+      if (handle == nullptr) {
+        destroy_thread();
+        *success = false;
+      } else {
+        CloseHandle(handle);
+        *success = true;
+      }
+    }
+  }
+
+  ~ThreadInternalsWindows() override {
+    gpr_mu_destroy(&mu_);
+    gpr_cv_destroy(&ready_);
+  }
+
+  void Start() override {
+    gpr_mu_lock(&mu_);
+    started_ = true;
+    gpr_cv_signal(&ready_);
+    gpr_mu_unlock(&mu_);
+  }
+
+  void Join() override {
+    DWORD ret = WaitForSingleObject(info_->join_event, INFINITE);
+    GPR_ASSERT(ret == WAIT_OBJECT_0);
+    destroy_thread();
+  }
+
+ private:
+  void destroy_thread() {
+    CloseHandle(info_->join_event);
+    gpr_free(info_);
+  }
+
+  gpr_mu mu_;
+  gpr_cv ready_;
+  bool started_;
+  thd_info* info_;
+};
+
+}  // namespace
+
+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;
+  impl_ = grpc_core::New<ThreadInternalsWindows>(thd_body, arg, &outcome);
+  if (outcome) {
+    state_ = ALIVE;
+  } else {
+    state_ = FAILED;
+    grpc_core::Delete(impl_);
+    impl_ = nullptr;
+  }
+
+  if (success != nullptr) {
+    *success = outcome;
+  }
+}
+
+}  // namespace grpc_core
+
+gpr_thd_id gpr_thd_currentid(void) { return (gpr_thd_id)g_thd_info; }
+
+#endif /* GPR_WINDOWS */

+ 57 - 9
src/core/lib/iomgr/ev_poll_posix.cc

@@ -38,9 +38,9 @@
 
 #include "src/core/lib/debug/stats.h"
 #include "src/core/lib/gpr/murmur_hash.h"
-#include "src/core/lib/gpr/thd.h"
 #include "src/core/lib/gpr/tls.h"
 #include "src/core/lib/gpr/useful.h"
+#include "src/core/lib/gprpp/thd.h"
 #include "src/core/lib/iomgr/block_annotate.h"
 #include "src/core/lib/iomgr/iomgr_internal.h"
 #include "src/core/lib/iomgr/wakeup_fd_cv.h"
@@ -255,8 +255,13 @@ typedef struct poll_result {
 } poll_result;
 
 typedef struct poll_args {
+  grpc_core::Thread poller_thd;
   gpr_cv trigger;
   int trigger_set;
+  bool harvestable;
+  gpr_cv harvest;
+  bool joinable;
+  gpr_cv join;
   struct pollfd* fds;
   nfds_t nfds;
   poll_result* result;
@@ -266,15 +271,17 @@ typedef struct poll_args {
 
 // This is a 2-tiered cache, we mantain a hash table
 // of active poll calls, so we can wait on the result
-// of that call.  We also maintain a freelist of inactive
-// poll threads.
+// of that call.  We also maintain freelists of inactive
+// poll args and of dead poller threads.
 typedef struct poll_hash_table {
   poll_args* free_pollers;
   poll_args** active_pollers;
+  poll_args* dead_pollers;
   unsigned int size;
   unsigned int count;
 } poll_hash_table;
 
+// TODO(kpayson64): Eliminate use of global non-POD variables
 poll_hash_table poll_cache;
 grpc_cv_fd_table g_cvfds;
 
@@ -1301,6 +1308,7 @@ static void pollset_set_del_fd(grpc_pollset_set* pollset_set, grpc_fd* fd) {
 
 static void run_poll(void* args);
 static void cache_poller_locked(poll_args* args);
+static void cache_harvest_locked();
 
 static void cache_insert_locked(poll_args* args) {
   uint32_t key = gpr_murmur_hash3(args->fds, args->nfds * sizeof(struct pollfd),
@@ -1363,6 +1371,10 @@ static poll_args* get_poller_locked(struct pollfd* fds, nfds_t count) {
   poll_args* pargs =
       static_cast<poll_args*>(gpr_malloc(sizeof(struct poll_args)));
   gpr_cv_init(&pargs->trigger);
+  gpr_cv_init(&pargs->harvest);
+  gpr_cv_init(&pargs->join);
+  pargs->harvestable = false;
+  pargs->joinable = false;
   pargs->fds = fds;
   pargs->nfds = count;
   pargs->next = nullptr;
@@ -1370,11 +1382,9 @@ static poll_args* get_poller_locked(struct pollfd* fds, nfds_t count) {
   pargs->trigger_set = 0;
   init_result(pargs);
   cache_poller_locked(pargs);
-  gpr_thd_id t_id;
-  gpr_thd_options opt = gpr_thd_options_default();
   gpr_ref(&g_cvfds.pollcount);
-  gpr_thd_options_set_detached(&opt);
-  GPR_ASSERT(gpr_thd_new(&t_id, "grpc_poller", &run_poll, pargs, &opt));
+  pargs->poller_thd = grpc_core::Thread("grpc_poller", &run_poll, pargs);
+  pargs->poller_thd.Start();
   return pargs;
 }
 
@@ -1439,7 +1449,33 @@ static void cache_destroy_locked(poll_args* args) {
     poll_cache.free_pollers = args->next;
   }
 
-  gpr_free(args);
+  // Now move this args to the dead poller list for later join
+  if (poll_cache.dead_pollers != nullptr) {
+    poll_cache.dead_pollers->prev = args;
+  }
+  args->prev = nullptr;
+  args->next = poll_cache.dead_pollers;
+  poll_cache.dead_pollers = args;
+}
+
+static void cache_harvest_locked() {
+  while (poll_cache.dead_pollers) {
+    poll_args* args = poll_cache.dead_pollers;
+    poll_cache.dead_pollers = poll_cache.dead_pollers->next;
+    // Keep the list consistent in case new dead pollers get added when we
+    // release the lock below to wait on joining
+    if (poll_cache.dead_pollers) {
+      poll_cache.dead_pollers->prev = nullptr;
+    }
+    args->harvestable = true;
+    gpr_cv_signal(&args->harvest);
+    while (!args->joinable) {
+      gpr_cv_wait(&args->join, &g_cvfds.mu,
+                  gpr_inf_future(GPR_CLOCK_MONOTONIC));
+    }
+    args->poller_thd.Join();
+    gpr_free(args);
+  }
 }
 
 static void decref_poll_result(poll_result* res) {
@@ -1471,6 +1507,7 @@ static void run_poll(void* args) {
     poll_result* result = pargs->result;
     int retval = g_cvfds.poll(result->fds, result->nfds, CV_POLL_PERIOD_MS);
     gpr_mu_lock(&g_cvfds.mu);
+    cache_harvest_locked();
     if (retval != 0) {
       result->completed = 1;
       result->retval = retval;
@@ -1490,6 +1527,7 @@ static void run_poll(void* args) {
       deadline = gpr_time_add(deadline, thread_grace);
       pargs->trigger_set = 0;
       gpr_cv_wait(&pargs->trigger, &g_cvfds.mu, deadline);
+      cache_harvest_locked();
       if (!pargs->trigger_set) {
         cache_destroy_locked(pargs);
         break;
@@ -1498,10 +1536,15 @@ static void run_poll(void* args) {
     gpr_mu_unlock(&g_cvfds.mu);
   }
 
-  // We still have the lock here
   if (gpr_unref(&g_cvfds.pollcount)) {
     gpr_cv_signal(&g_cvfds.shutdown_cv);
   }
+  while (!pargs->harvestable) {
+    gpr_cv_wait(&pargs->harvest, &g_cvfds.mu,
+                gpr_inf_future(GPR_CLOCK_MONOTONIC));
+  }
+  pargs->joinable = true;
+  gpr_cv_signal(&pargs->join);
   gpr_mu_unlock(&g_cvfds.mu);
 }
 
@@ -1514,6 +1557,7 @@ static int cvfd_poll(struct pollfd* fds, nfds_t nfds, int timeout) {
   nfds_t nsockfds = 0;
   poll_result* result = nullptr;
   gpr_mu_lock(&g_cvfds.mu);
+  cache_harvest_locked();
   pollcv = static_cast<grpc_cv_node*>(gpr_malloc(sizeof(grpc_cv_node)));
   pollcv->next = nullptr;
   gpr_cv pollcv_cv;
@@ -1577,12 +1621,14 @@ static int cvfd_poll(struct pollfd* fds, nfds_t nfds, int timeout) {
     pargs->trigger_set = 1;
     gpr_cv_signal(&pargs->trigger);
     gpr_cv_wait(&pollcv_cv, &g_cvfds.mu, deadline);
+    cache_harvest_locked();
     res = result->retval;
     errno = result->err;
     result->watchcount--;
     remove_cvn(&result->watchers, pollcv);
   } else if (!skip_poll) {
     gpr_cv_wait(&pollcv_cv, &g_cvfds.mu, deadline);
+    cache_harvest_locked();
   }
 
   idx = 0;
@@ -1639,6 +1685,7 @@ static void global_cv_fd_table_init() {
   for (unsigned int i = 0; i < poll_cache.size; i++) {
     poll_cache.active_pollers[i] = nullptr;
   }
+  poll_cache.dead_pollers = nullptr;
 
   gpr_mu_unlock(&g_cvfds.mu);
 }
@@ -1657,6 +1704,7 @@ static void global_cv_fd_table_shutdown() {
   grpc_poll_function = g_cvfds.poll;
   gpr_free(g_cvfds.cvfds);
 
+  cache_harvest_locked();
   gpr_free(poll_cache.active_pollers);
 
   gpr_mu_unlock(&g_cvfds.mu);

+ 1 - 1
src/core/lib/iomgr/exec_ctx.cc

@@ -23,7 +23,7 @@
 #include <grpc/support/log.h>
 #include <grpc/support/sync.h>
 
-#include "src/core/lib/gpr/thd.h"
+#include "src/core/lib/gprpp/thd.h"
 #include "src/core/lib/iomgr/combiner.h"
 #include "src/core/lib/profiling/timers.h"
 

+ 11 - 11
src/core/lib/iomgr/executor.cc

@@ -29,9 +29,9 @@
 
 #include "src/core/lib/debug/stats.h"
 #include "src/core/lib/gpr/spinlock.h"
-#include "src/core/lib/gpr/thd.h"
 #include "src/core/lib/gpr/tls.h"
 #include "src/core/lib/gpr/useful.h"
+#include "src/core/lib/gprpp/thd.h"
 #include "src/core/lib/iomgr/exec_ctx.h"
 
 #define MAX_DEPTH 2
@@ -43,7 +43,7 @@ typedef struct {
   size_t depth;
   bool shutdown;
   bool queued_long_job;
-  gpr_thd_id id;
+  grpc_core::Thread thd;
 } thread_state;
 
 static thread_state* g_thread_state;
@@ -101,13 +101,13 @@ void grpc_executor_set_threading(bool threading) {
     for (size_t i = 0; i < g_max_threads; i++) {
       gpr_mu_init(&g_thread_state[i].mu);
       gpr_cv_init(&g_thread_state[i].cv);
+      g_thread_state[i].thd = grpc_core::Thread();
       g_thread_state[i].elems = GRPC_CLOSURE_LIST_INIT;
     }
 
-    gpr_thd_options opt = gpr_thd_options_default();
-    gpr_thd_options_set_joinable(&opt);
-    gpr_thd_new(&g_thread_state[0].id, "grpc_executor", executor_thread,
-                &g_thread_state[0], &opt);
+    g_thread_state[0].thd =
+        grpc_core::Thread("grpc_executor", executor_thread, &g_thread_state[0]);
+    g_thread_state[0].thd.Start();
   } else {
     if (cur_threads == 0) return;
     for (size_t i = 0; i < g_max_threads; i++) {
@@ -121,7 +121,7 @@ void grpc_executor_set_threading(bool threading) {
     gpr_spinlock_lock(&g_adding_thread_lock);
     gpr_spinlock_unlock(&g_adding_thread_lock);
     for (gpr_atm i = 0; i < g_cur_threads; i++) {
-      gpr_thd_join(g_thread_state[i].id);
+      g_thread_state[i].thd.Join();
     }
     gpr_atm_no_barrier_store(&g_cur_threads, 0);
     for (size_t i = 0; i < g_max_threads; i++) {
@@ -264,10 +264,10 @@ static void executor_push(grpc_closure* closure, grpc_error* error,
       if (cur_thread_count < g_max_threads) {
         gpr_atm_no_barrier_store(&g_cur_threads, cur_thread_count + 1);
 
-        gpr_thd_options opt = gpr_thd_options_default();
-        gpr_thd_options_set_joinable(&opt);
-        gpr_thd_new(&g_thread_state[cur_thread_count].id, "gpr_executor",
-                    executor_thread, &g_thread_state[cur_thread_count], &opt);
+        g_thread_state[cur_thread_count].thd =
+            grpc_core::Thread("grpc_executor", executor_thread,
+                              &g_thread_state[cur_thread_count]);
+        g_thread_state[cur_thread_count].thd.Start();
       }
       gpr_spinlock_unlock(&g_adding_thread_lock);
     }

+ 2 - 2
src/core/lib/iomgr/fork_posix.cc

@@ -29,7 +29,7 @@
 
 #include "src/core/lib/gpr/env.h"
 #include "src/core/lib/gpr/fork.h"
-#include "src/core/lib/gpr/thd.h"
+#include "src/core/lib/gprpp/thd.h"
 #include "src/core/lib/iomgr/ev_posix.h"
 #include "src/core/lib/iomgr/executor.h"
 #include "src/core/lib/iomgr/timer_manager.h"
@@ -53,7 +53,7 @@ void grpc_prefork() {
     grpc_timer_manager_set_threading(false);
     grpc_executor_set_threading(false);
     grpc_core::ExecCtx::Get()->Flush();
-    if (!gpr_await_threads(
+    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!");

+ 1 - 1
src/core/lib/iomgr/iocp_windows.cc

@@ -30,7 +30,7 @@
 #include <grpc/support/log_windows.h>
 
 #include "src/core/lib/debug/stats.h"
-#include "src/core/lib/gpr/thd.h"
+#include "src/core/lib/gprpp/thd.h"
 #include "src/core/lib/iomgr/iocp_windows.h"
 #include "src/core/lib/iomgr/iomgr_internal.h"
 #include "src/core/lib/iomgr/socket_windows.h"

+ 1 - 1
src/core/lib/iomgr/iomgr.cc

@@ -31,8 +31,8 @@
 
 #include "src/core/lib/gpr/env.h"
 #include "src/core/lib/gpr/string.h"
-#include "src/core/lib/gpr/thd.h"
 #include "src/core/lib/gpr/useful.h"
+#include "src/core/lib/gprpp/thd.h"
 #include "src/core/lib/iomgr/exec_ctx.h"
 #include "src/core/lib/iomgr/executor.h"
 #include "src/core/lib/iomgr/iomgr_internal.h"

+ 1 - 1
src/core/lib/iomgr/pollset_windows.cc

@@ -24,7 +24,7 @@
 
 #include <grpc/support/log.h>
 
-#include "src/core/lib/gpr/thd.h"
+#include "src/core/lib/gprpp/thd.h"
 #include "src/core/lib/iomgr/iocp_windows.h"
 #include "src/core/lib/iomgr/iomgr_internal.h"
 #include "src/core/lib/iomgr/pollset.h"

+ 1 - 1
src/core/lib/iomgr/resolve_address_posix.cc

@@ -35,8 +35,8 @@
 
 #include "src/core/lib/gpr/host_port.h"
 #include "src/core/lib/gpr/string.h"
-#include "src/core/lib/gpr/thd.h"
 #include "src/core/lib/gpr/useful.h"
+#include "src/core/lib/gprpp/thd.h"
 #include "src/core/lib/iomgr/block_annotate.h"
 #include "src/core/lib/iomgr/executor.h"
 #include "src/core/lib/iomgr/iomgr_internal.h"

+ 1 - 1
src/core/lib/iomgr/resolve_address_windows.cc

@@ -37,7 +37,7 @@
 
 #include "src/core/lib/gpr/host_port.h"
 #include "src/core/lib/gpr/string.h"
-#include "src/core/lib/gpr/thd.h"
+#include "src/core/lib/gprpp/thd.h"
 #include "src/core/lib/iomgr/block_annotate.h"
 #include "src/core/lib/iomgr/executor.h"
 #include "src/core/lib/iomgr/iomgr_internal.h"

+ 10 - 19
src/core/lib/iomgr/timer_manager.cc

@@ -18,21 +18,20 @@
 
 #include <grpc/support/port_platform.h>
 
-#include "src/core/lib/iomgr/timer_manager.h"
+#include <inttypes.h>
 
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 
-#include <inttypes.h>
-
 #include "src/core/lib/debug/trace.h"
-#include "src/core/lib/gpr/thd.h"
+#include "src/core/lib/gprpp/thd.h"
 #include "src/core/lib/iomgr/timer.h"
+#include "src/core/lib/iomgr/timer_manager.h"
 
-typedef struct completed_thread {
-  gpr_thd_id t;
-  struct completed_thread* next;
-} completed_thread;
+struct completed_thread {
+  grpc_core::Thread thd;
+  completed_thread* next;
+};
 
 extern grpc_core::TraceFlag grpc_timer_check_trace;
 
@@ -68,7 +67,7 @@ static void gc_completed_threads(void) {
     g_completed_threads = nullptr;
     gpr_mu_unlock(&g_mu);
     while (to_gc != nullptr) {
-      gpr_thd_join(to_gc->t);
+      to_gc->thd.Join();
       completed_thread* next = to_gc->next;
       gpr_free(to_gc);
       to_gc = next;
@@ -85,18 +84,10 @@ static void start_timer_thread_and_unlock(void) {
   if (grpc_timer_check_trace.enabled()) {
     gpr_log(GPR_DEBUG, "Spawn timer thread");
   }
-  gpr_thd_options opt = gpr_thd_options_default();
-  gpr_thd_options_set_joinable(&opt);
   completed_thread* ct =
       static_cast<completed_thread*>(gpr_malloc(sizeof(*ct)));
-  // The call to gpr_thd_new() has to be under the same lock used by
-  // gc_completed_threads(), particularly due to ct->t, which is written here
-  // (internally by gpr_thd_new) and read there. Otherwise it's possible for ct
-  // to leak through g_completed_threads and be freed in gc_completed_threads()
-  // before "&ct->t" is written to, causing a use-after-free.
-  gpr_mu_lock(&g_mu);
-  gpr_thd_new(&ct->t, "grpc_global_timer", timer_thread, ct, &opt);
-  gpr_mu_unlock(&g_mu);
+  ct->thd = grpc_core::Thread("grpc_global_timer", timer_thread, ct);
+  ct->thd.Start();
 }
 
 void grpc_timer_manager_tick() {

+ 1 - 1
src/core/lib/iomgr/wakeup_fd_cv.cc

@@ -32,8 +32,8 @@
 #include <grpc/support/sync.h>
 #include <grpc/support/time.h>
 
-#include "src/core/lib/gpr/thd.h"
 #include "src/core/lib/gpr/useful.h"
+#include "src/core/lib/gprpp/thd.h"
 
 #define MAX_TABLE_RESIZE 256
 

+ 6 - 7
src/core/lib/profiling/basic_timers.cc

@@ -30,7 +30,7 @@
 #include <string.h>
 
 #include "src/core/lib/gpr/env.h"
-#include "src/core/lib/gpr/thd.h"
+#include "src/core/lib/gprpp/thd.h"
 
 typedef enum { BEGIN = '{', END = '}', MARK = '.' } marker_type;
 
@@ -68,7 +68,7 @@ static pthread_cond_t g_cv;
 static gpr_timer_log_list g_in_progress_logs;
 static gpr_timer_log_list g_done_logs;
 static int g_shutdown;
-static gpr_thd_id g_writing_thread;
+static grpc_core::Thread* g_writing_thread;
 static __thread int g_thread_id;
 static int g_next_thread_id;
 static int g_writing_enabled = 1;
@@ -182,7 +182,8 @@ static void finish_writing(void) {
   g_shutdown = 1;
   pthread_cond_signal(&g_cv);
   pthread_mutex_unlock(&g_mu);
-  gpr_thd_join(g_writing_thread);
+  g_writing_thread->Join();
+  grpc_core::Delete(g_writing_thread);
 
   gpr_log(GPR_INFO, "flushing logs");
 
@@ -201,10 +202,8 @@ void gpr_timers_set_log_filename(const char* filename) {
 }
 
 static void init_output() {
-  gpr_thd_options options = gpr_thd_options_default();
-  gpr_thd_options_set_joinable(&options);
-  GPR_ASSERT(gpr_thd_new(&g_writing_thread, "timer_output_thread",
-                         writing_thread, NULL, &options));
+  g_writing_thread = grpc_core::New<grpc_core::Thread>("timer_output_thread",
+                                                       writing_thread, nullptr);
   atexit(finish_writing);
 }
 

+ 2 - 2
src/core/lib/surface/init.cc

@@ -33,7 +33,7 @@
 #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/gpr/thd.h"
+#include "src/core/lib/gprpp/thd.h"
 #include "src/core/lib/http/parser.h"
 #include "src/core/lib/iomgr/call_combiner.h"
 #include "src/core/lib/iomgr/combiner.h"
@@ -124,7 +124,7 @@ void grpc_init(void) {
   gpr_mu_lock(&g_init_mu);
   if (++g_initializations == 1) {
     gpr_time_init();
-    gpr_thd_init();
+    grpc_core::Thread::Init();
     grpc_stats_init();
     grpc_slice_intern_init();
     grpc_mdctx_global_init();

+ 1 - 1
src/core/tsi/alts_transport_security.cc

@@ -56,7 +56,7 @@ void grpc_tsi_alts_shutdown() {
     grpc_tsi_alts_wait_for_cq_drain();
     grpc_completion_queue_destroy(g_alts_resource.cq);
     grpc_channel_destroy(g_alts_resource.channel);
-    gpr_thd_join(g_alts_resource.thread_id);
+    g_alts_resource.thread.Join();
   }
   gpr_cv_destroy(&g_alts_resource.cv);
   gpr_mu_destroy(&g_alts_resource.mu);

+ 2 - 2
src/core/tsi/alts_transport_security.h

@@ -24,10 +24,10 @@
 #include <grpc/grpc.h>
 #include <grpc/support/sync.h>
 
-#include "src/core/lib/gpr/thd.h"
+#include "src/core/lib/gprpp/thd.h"
 
 typedef struct alts_shared_resource {
-  gpr_thd_id thread_id;
+  grpc_core::Thread thread;
   grpc_channel* channel;
   grpc_completion_queue* cq;
   gpr_mu mu;

+ 1 - 1
src/cpp/client/channel_cc.cc

@@ -42,7 +42,7 @@
 #include <grpcpp/support/time.h>
 #include "src/core/lib/gpr/env.h"
 #include "src/core/lib/gpr/string.h"
-#include "src/core/lib/gpr/thd.h"
+#include "src/core/lib/gprpp/thd.h"
 #include "src/core/lib/profiling/timers.h"
 
 namespace grpc {

+ 10 - 6
src/cpp/server/dynamic_thread_pool.cc

@@ -19,20 +19,24 @@
 #include "src/cpp/server/dynamic_thread_pool.h"
 
 #include <mutex>
-#include <thread>
 
 #include <grpc/support/log.h>
 
+#include "src/core/lib/gprpp/thd.h"
+
 namespace grpc {
 
 DynamicThreadPool::DynamicThread::DynamicThread(DynamicThreadPool* pool)
     : pool_(pool),
-      thd_(new std::thread(&DynamicThreadPool::DynamicThread::ThreadFunc,
-                           this)) {}
-DynamicThreadPool::DynamicThread::~DynamicThread() {
-  thd_->join();
-  thd_.reset();
+      thd_("dynamic thread pool thread",
+           [](void* th) {
+             reinterpret_cast<DynamicThreadPool::DynamicThread*>(th)
+                 ->ThreadFunc();
+           },
+           this) {
+  thd_.Start();
 }
+DynamicThreadPool::DynamicThread::~DynamicThread() { thd_.Join(); }
 
 void DynamicThreadPool::DynamicThread::ThreadFunc() {
   pool_->ThreadFunc();

+ 2 - 2
src/cpp/server/dynamic_thread_pool.h

@@ -24,10 +24,10 @@
 #include <memory>
 #include <mutex>
 #include <queue>
-#include <thread>
 
 #include <grpcpp/support/config.h>
 
+#include "src/core/lib/gprpp/thd.h"
 #include "src/cpp/server/thread_pool_interface.h"
 
 namespace grpc {
@@ -47,7 +47,7 @@ class DynamicThreadPool final : public ThreadPoolInterface {
 
    private:
     DynamicThreadPool* pool_;
-    std::unique_ptr<std::thread> thd_;
+    grpc_core::Thread thd_;
     void ThreadFunc();
   };
   std::mutex mu_;

+ 10 - 5
src/cpp/thread_manager/thread_manager.cc

@@ -20,18 +20,24 @@
 
 #include <climits>
 #include <mutex>
-#include <thread>
 
 #include <grpc/support/log.h>
 
+#include "src/core/lib/gprpp/thd.h"
+
 namespace grpc {
 
 ThreadManager::WorkerThread::WorkerThread(ThreadManager* thd_mgr)
     : thd_mgr_(thd_mgr) {
   // Make thread creation exclusive with respect to its join happening in
   // ~WorkerThread().
-  std::lock_guard<std::mutex> lock(wt_mu_);
-  thd_ = std::thread(&ThreadManager::WorkerThread::Run, this);
+  thd_ = grpc_core::Thread(
+      "sync server thread",
+      [](void* th) {
+        reinterpret_cast<ThreadManager::WorkerThread*>(th)->Run();
+      },
+      this);
+  thd_.Start();
 }
 
 void ThreadManager::WorkerThread::Run() {
@@ -41,8 +47,7 @@ void ThreadManager::WorkerThread::Run() {
 
 ThreadManager::WorkerThread::~WorkerThread() {
   // Don't join until the thread is fully constructed.
-  std::lock_guard<std::mutex> lock(wt_mu_);
-  thd_.join();
+  thd_.Join();
 }
 
 ThreadManager::ThreadManager(int min_pollers, int max_pollers)

+ 5 - 5
src/cpp/thread_manager/thread_manager.h

@@ -23,10 +23,11 @@
 #include <list>
 #include <memory>
 #include <mutex>
-#include <thread>
 
 #include <grpcpp/support/config.h>
 
+#include "src/core/lib/gprpp/thd.h"
+
 namespace grpc {
 
 class ThreadManager {
@@ -84,8 +85,8 @@ class ThreadManager {
   virtual void Wait();
 
  private:
-  // Helper wrapper class around std::thread. This takes a ThreadManager object
-  // and starts a new std::thread to calls the Run() function.
+  // Helper wrapper class around grpc_core::Thread. Takes a ThreadManager object
+  // and starts a new grpc_core::Thread to calls the Run() function.
   //
   // The Run() function calls ThreadManager::MainWorkLoop() function and once
   // that completes, it marks the WorkerThread completed by calling
@@ -101,8 +102,7 @@ class ThreadManager {
     void Run();
 
     ThreadManager* const thd_mgr_;
-    std::mutex wt_mu_;
-    std::thread thd_;
+    grpc_core::Thread thd_;
   };
 
   // The main funtion in ThreadManager

+ 2 - 3
src/python/grpcio/grpc_core_dependencies.py

@@ -41,9 +41,6 @@ CORE_SOURCE_FILES = [
     'src/core/lib/gpr/sync.cc',
     'src/core/lib/gpr/sync_posix.cc',
     'src/core/lib/gpr/sync_windows.cc',
-    'src/core/lib/gpr/thd.cc',
-    'src/core/lib/gpr/thd_posix.cc',
-    'src/core/lib/gpr/thd_windows.cc',
     'src/core/lib/gpr/time.cc',
     'src/core/lib/gpr/time_posix.cc',
     'src/core/lib/gpr/time_precise.cc',
@@ -53,6 +50,8 @@ 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/thd_posix.cc',
+    'src/core/lib/gprpp/thd_windows.cc',
     'src/core/lib/profiling/basic_timers.cc',
     'src/core/lib/profiling/stap_timers.cc',
     'src/core/lib/surface/init.cc',

+ 26 - 0
templates/CMakeLists.txt.template

@@ -84,6 +84,7 @@
 
   # Options
   option(gRPC_BUILD_TESTS "Build tests" OFF)
+  option(gRPC_BUILD_CODEGEN "Build codegen" ON)
 
   set(gRPC_INSTALL_default ON)
   if (NOT CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR)
@@ -125,6 +126,8 @@
       set(_gRPC_PLATFORM_LINUX ON)
     elseif(<%text>${CMAKE_SYSTEM_NAME}</%text> MATCHES "Darwin")
       set(_gRPC_PLATFORM_MAC ON)
+    elseif(<%text>${CMAKE_SYSTEM_NAME}</%text> MATCHES "Android")
+      set(_gRPC_PLATFORM_ANDROID ON)
     else()
       set(_gRPC_PLATFORM_POSIX ON)
     endif()
@@ -168,6 +171,8 @@
 
   if(_gRPC_PLATFORM_MAC)
     set(_gRPC_ALLTARGETS_LIBRARIES <%text>${CMAKE_DL_LIBS}</%text> m pthread)
+  elseif(_gRPC_PLATFORM_ANDROID)
+    set(_gRPC_ALLTARGETS_LIBRARIES <%text>${CMAKE_DL_LIBS}</%text> m)
   elseif(UNIX)
     set(_gRPC_ALLTARGETS_LIBRARIES <%text>${CMAKE_DL_LIBS}</%text> rt m pthread)
   endif()
@@ -304,6 +309,13 @@
   ${cc_binary(tgt)}
   ${get_platforms_condition_end(tgt.platforms)}\
   endif (gRPC_BUILD_TESTS)
+  % elif tgt.build in ["protoc"]:
+  if (gRPC_BUILD_CODEGEN)
+  ${get_platforms_condition_begin(tgt.platforms)}\
+  ${cc_binary(tgt)}
+  ${cc_install(tgt)}
+  ${get_platforms_condition_end(tgt.platforms)}\
+  endif (gRPC_BUILD_CODEGEN)
   % else:
   ${get_platforms_condition_begin(tgt.platforms)}\
   ${cc_binary(tgt)}
@@ -314,6 +326,9 @@
   % endfor
 
   <%def name="cc_library(lib)">
+  % if any(proto_re.match(src) for src in lib.src):
+  if (gRPC_BUILD_CODEGEN)
+  % endif
   add_library(${lib.name}${' SHARED' if lib.get('dll', None) == 'only' else ''}
   % for src in lib.src:
   % if not proto_re.match(src):
@@ -376,6 +391,14 @@
   % endfor
   )
   % endif
+  % if lib.name in ["gpr"]:
+  if (_gRPC_PLATFORM_ANDROID)
+    target_link_libraries(gpr
+      android
+      log
+    )
+  endif (_gRPC_PLATFORM_ANDROID)
+  % endif
 
   % if len(lib.get('public_headers', [])) > 0:
   foreach(_hdr
@@ -390,6 +413,9 @@
     )
   endforeach()
   % endif
+  % if any(proto_re.match(src) for src in lib.src):
+  endif (gRPC_BUILD_CODEGEN)
+  % endif
   </%def>
 
   <%def name="cc_binary(tgt)">

+ 5 - 3
test/core/bad_client/bad_client.cc

@@ -29,7 +29,7 @@
 #include "src/core/lib/channel/channel_stack.h"
 #include "src/core/lib/gpr/murmur_hash.h"
 #include "src/core/lib/gpr/string.h"
-#include "src/core/lib/gpr/thd.h"
+#include "src/core/lib/gprpp/thd.h"
 #include "src/core/lib/iomgr/endpoint_pair.h"
 #include "src/core/lib/slice/slice_internal.h"
 #include "src/core/lib/surface/completion_queue.h"
@@ -220,11 +220,12 @@ void grpc_run_bad_client_test(
   /* Check a ground truth */
   GPR_ASSERT(grpc_server_has_open_connections(a.server));
 
-  gpr_thd_id id;
   gpr_event_init(&a.done_thd);
   a.validator = server_validator;
   /* Start validator */
-  gpr_thd_new(&id, "grpc_bad_client", thd_func, &a, nullptr);
+
+  grpc_core::Thread server_validator_thd("grpc_bad_client", thd_func, &a);
+  server_validator_thd.Start();
   for (int i = 0; i < num_args; i++) {
     grpc_run_client_side_validator(&args[i], i == (num_args - 1) ? flags : 0,
                                    &sfd, client_cq);
@@ -234,6 +235,7 @@ void grpc_run_bad_client_test(
 
   /* Shutdown. */
   shutdown_client(&sfd.client);
+  server_validator_thd.Join();
 
   shutdown_cq = grpc_completion_queue_create_for_pluck(nullptr);
   grpc_server_shutdown_and_notify(a.server, shutdown_cq, nullptr);

+ 11 - 6
test/core/end2end/bad_server_response_test.cc

@@ -31,7 +31,8 @@
 
 #include "src/core/lib/gpr/host_port.h"
 #include "src/core/lib/gpr/string.h"
-#include "src/core/lib/gpr/thd.h"
+#include "src/core/lib/gprpp/memory.h"
+#include "src/core/lib/gprpp/thd.h"
 #include "src/core/lib/iomgr/sockaddr.h"
 #include "src/core/lib/slice/slice_internal.h"
 #include "src/core/lib/slice/slice_string_helpers.h"
@@ -253,15 +254,17 @@ static void actually_poll_server(void* arg) {
   gpr_free(pa);
 }
 
-static void poll_server_until_read_done(test_tcp_server* server,
-                                        gpr_event* signal_when_done) {
+static grpc_core::Thread* poll_server_until_read_done(
+    test_tcp_server* server, gpr_event* signal_when_done) {
   gpr_atm_rel_store(&state.done_atm, 0);
   state.write_done = 0;
-  gpr_thd_id id;
   poll_args* pa = static_cast<poll_args*>(gpr_malloc(sizeof(*pa)));
   pa->server = server;
   pa->signal_when_done = signal_when_done;
-  gpr_thd_new(&id, "grpc_poll_server", actually_poll_server, pa, nullptr);
+  auto* th = grpc_core::New<grpc_core::Thread>("grpc_poll_server",
+                                               actually_poll_server, pa);
+  th->Start();
+  return th;
 }
 
 static void run_test(const char* response_payload,
@@ -281,9 +284,11 @@ static void run_test(const char* response_payload,
   state.response_payload_length = response_payload_length;
 
   /* poll server until sending out the response */
-  poll_server_until_read_done(&test_server, &ev);
+  grpc_core::UniquePtr<grpc_core::Thread> thdptr(
+      poll_server_until_read_done(&test_server, &ev));
   start_rpc(server_port, expected_status, expected_detail);
   gpr_event_wait(&ev, gpr_inf_future(GPR_CLOCK_REALTIME));
+  thdptr->Join();
 
   /* clean up */
   grpc_endpoint_shutdown(state.tcp,

+ 0 - 1
test/core/end2end/fixtures/h2_census.cc

@@ -30,7 +30,6 @@
 #include "src/core/lib/channel/channel_args.h"
 #include "src/core/lib/channel/connected_channel.h"
 #include "src/core/lib/gpr/host_port.h"
-#include "src/core/lib/gpr/thd.h"
 #include "src/core/lib/surface/channel.h"
 #include "src/core/lib/surface/server.h"
 #include "test/core/util/port.h"

+ 0 - 1
test/core/end2end/fixtures/h2_compress.cc

@@ -30,7 +30,6 @@
 #include "src/core/lib/channel/channel_args.h"
 #include "src/core/lib/channel/connected_channel.h"
 #include "src/core/lib/gpr/host_port.h"
-#include "src/core/lib/gpr/thd.h"
 #include "src/core/lib/surface/channel.h"
 #include "src/core/lib/surface/server.h"
 #include "test/core/util/port.h"

+ 0 - 1
test/core/end2end/fixtures/h2_full+pipe.cc

@@ -34,7 +34,6 @@
 #include "src/core/ext/transport/chttp2/transport/chttp2_transport.h"
 #include "src/core/lib/channel/connected_channel.h"
 #include "src/core/lib/gpr/host_port.h"
-#include "src/core/lib/gpr/thd.h"
 #include "src/core/lib/iomgr/wakeup_fd_posix.h"
 #include "src/core/lib/surface/channel.h"
 #include "src/core/lib/surface/server.h"

+ 0 - 1
test/core/end2end/fixtures/h2_full+trace.cc

@@ -35,7 +35,6 @@
 #include "src/core/lib/channel/connected_channel.h"
 #include "src/core/lib/gpr/env.h"
 #include "src/core/lib/gpr/host_port.h"
-#include "src/core/lib/gpr/thd.h"
 #include "src/core/lib/surface/channel.h"
 #include "src/core/lib/surface/server.h"
 #include "test/core/util/port.h"

+ 0 - 1
test/core/end2end/fixtures/h2_full+workarounds.cc

@@ -31,7 +31,6 @@
 #include "src/core/ext/transport/chttp2/transport/chttp2_transport.h"
 #include "src/core/lib/channel/connected_channel.h"
 #include "src/core/lib/gpr/host_port.h"
-#include "src/core/lib/gpr/thd.h"
 #include "src/core/lib/surface/channel.h"
 #include "src/core/lib/surface/server.h"
 #include "test/core/util/port.h"

+ 0 - 1
test/core/end2end/fixtures/h2_full.cc

@@ -29,7 +29,6 @@
 #include "src/core/ext/transport/chttp2/transport/chttp2_transport.h"
 #include "src/core/lib/channel/connected_channel.h"
 #include "src/core/lib/gpr/host_port.h"
-#include "src/core/lib/gpr/thd.h"
 #include "src/core/lib/surface/channel.h"
 #include "src/core/lib/surface/server.h"
 #include "test/core/util/port.h"

+ 0 - 1
test/core/end2end/fixtures/h2_http_proxy.cc

@@ -31,7 +31,6 @@
 #include "src/core/lib/channel/connected_channel.h"
 #include "src/core/lib/gpr/env.h"
 #include "src/core/lib/gpr/host_port.h"
-#include "src/core/lib/gpr/thd.h"
 #include "src/core/lib/surface/channel.h"
 #include "src/core/lib/surface/server.h"
 #include "test/core/end2end/fixtures/http_proxy_fixture.h"

+ 0 - 1
test/core/end2end/fixtures/h2_load_reporting.cc

@@ -31,7 +31,6 @@
 #include "src/core/lib/channel/channel_args.h"
 #include "src/core/lib/channel/connected_channel.h"
 #include "src/core/lib/gpr/host_port.h"
-#include "src/core/lib/gpr/thd.h"
 #include "src/core/lib/surface/channel.h"
 #include "src/core/lib/surface/server.h"
 #include "test/core/util/port.h"

+ 0 - 1
test/core/end2end/fixtures/h2_proxy.cc

@@ -29,7 +29,6 @@
 #include "src/core/ext/transport/chttp2/transport/chttp2_transport.h"
 #include "src/core/lib/channel/connected_channel.h"
 #include "src/core/lib/gpr/host_port.h"
-#include "src/core/lib/gpr/thd.h"
 #include "src/core/lib/surface/channel.h"
 #include "src/core/lib/surface/server.h"
 #include "test/core/end2end/fixtures/proxy.h"

+ 0 - 1
test/core/end2end/fixtures/h2_sockpair+trace.cc

@@ -36,7 +36,6 @@
 #include "src/core/ext/transport/chttp2/transport/chttp2_transport.h"
 #include "src/core/lib/channel/connected_channel.h"
 #include "src/core/lib/gpr/env.h"
-#include "src/core/lib/gpr/thd.h"
 #include "src/core/lib/iomgr/endpoint_pair.h"
 #include "src/core/lib/iomgr/iomgr.h"
 #include "src/core/lib/surface/channel.h"

+ 0 - 1
test/core/end2end/fixtures/h2_sockpair.cc

@@ -30,7 +30,6 @@
 #include "src/core/ext/filters/http/server/http_server_filter.h"
 #include "src/core/ext/transport/chttp2/transport/chttp2_transport.h"
 #include "src/core/lib/channel/connected_channel.h"
-#include "src/core/lib/gpr/thd.h"
 #include "src/core/lib/iomgr/endpoint_pair.h"
 #include "src/core/lib/iomgr/iomgr.h"
 #include "src/core/lib/surface/channel.h"

+ 0 - 1
test/core/end2end/fixtures/h2_sockpair_1byte.cc

@@ -30,7 +30,6 @@
 #include "src/core/ext/filters/http/server/http_server_filter.h"
 #include "src/core/ext/transport/chttp2/transport/chttp2_transport.h"
 #include "src/core/lib/channel/connected_channel.h"
-#include "src/core/lib/gpr/thd.h"
 #include "src/core/lib/iomgr/endpoint_pair.h"
 #include "src/core/lib/iomgr/iomgr.h"
 #include "src/core/lib/surface/channel.h"

+ 0 - 1
test/core/end2end/fixtures/h2_uds.cc

@@ -33,7 +33,6 @@
 #include "src/core/lib/channel/connected_channel.h"
 #include "src/core/lib/gpr/host_port.h"
 #include "src/core/lib/gpr/string.h"
-#include "src/core/lib/gpr/thd.h"
 #include "src/core/lib/surface/channel.h"
 #include "src/core/lib/surface/server.h"
 #include "test/core/util/port.h"

+ 5 - 7
test/core/end2end/fixtures/http_proxy_fixture.cc

@@ -33,7 +33,7 @@
 #include "src/core/lib/channel/channel_args.h"
 #include "src/core/lib/gpr/host_port.h"
 #include "src/core/lib/gpr/string.h"
-#include "src/core/lib/gpr/thd.h"
+#include "src/core/lib/gprpp/thd.h"
 #include "src/core/lib/http/parser.h"
 #include "src/core/lib/iomgr/closure.h"
 #include "src/core/lib/iomgr/combiner.h"
@@ -53,7 +53,7 @@
 
 struct grpc_end2end_http_proxy {
   char* proxy_name;
-  gpr_thd_id thd;
+  grpc_core::Thread thd;
   grpc_tcp_server* server;
   grpc_channel_args* channel_args;
   gpr_mu* mu;
@@ -550,10 +550,8 @@ grpc_end2end_http_proxy* grpc_end2end_http_proxy_create(
   grpc_tcp_server_start(proxy->server, &proxy->pollset, 1, on_accept, proxy);
 
   // Start proxy thread.
-  gpr_thd_options opt = gpr_thd_options_default();
-  gpr_thd_options_set_joinable(&opt);
-  GPR_ASSERT(
-      gpr_thd_new(&proxy->thd, "grpc_http_proxy", thread_main, proxy, &opt));
+  proxy->thd = grpc_core::Thread("grpc_http_proxy", thread_main, proxy);
+  proxy->thd.Start();
   return proxy;
 }
 
@@ -566,7 +564,7 @@ static void destroy_pollset(void* arg, grpc_error* error) {
 void grpc_end2end_http_proxy_destroy(grpc_end2end_http_proxy* proxy) {
   gpr_unref(&proxy->users);  // Signal proxy thread to shutdown.
   grpc_core::ExecCtx exec_ctx;
-  gpr_thd_join(proxy->thd);
+  proxy->thd.Join();
   grpc_tcp_server_shutdown_listeners(proxy->server);
   grpc_tcp_server_unref(proxy->server);
   gpr_free(proxy->proxy_name);

+ 0 - 1
test/core/end2end/fixtures/inproc.cc

@@ -29,7 +29,6 @@
 #include "src/core/ext/transport/inproc/inproc_transport.h"
 #include "src/core/lib/channel/connected_channel.h"
 #include "src/core/lib/gpr/host_port.h"
-#include "src/core/lib/gpr/thd.h"
 #include "src/core/lib/surface/channel.h"
 #include "src/core/lib/surface/server.h"
 #include "test/core/util/port.h"

+ 5 - 7
test/core/end2end/fixtures/proxy.cc

@@ -25,12 +25,12 @@
 #include <grpc/support/sync.h>
 
 #include "src/core/lib/gpr/host_port.h"
-#include "src/core/lib/gpr/thd.h"
 #include "src/core/lib/gpr/useful.h"
+#include "src/core/lib/gprpp/thd.h"
 #include "test/core/util/port.h"
 
 struct grpc_end2end_proxy {
-  gpr_thd_id thd;
+  grpc_core::Thread thd;
   char* proxy_port;
   char* server_port;
   grpc_completion_queue* cq;
@@ -76,7 +76,6 @@ static void request_call(grpc_end2end_proxy* proxy);
 grpc_end2end_proxy* grpc_end2end_proxy_create(const grpc_end2end_proxy_def* def,
                                               grpc_channel_args* client_args,
                                               grpc_channel_args* server_args) {
-  gpr_thd_options opt = gpr_thd_options_default();
   int proxy_port = grpc_pick_unused_port_or_die();
   int server_port = grpc_pick_unused_port_or_die();
 
@@ -98,9 +97,8 @@ grpc_end2end_proxy* grpc_end2end_proxy_create(const grpc_end2end_proxy_def* def,
   grpc_server_start(proxy->server);
 
   grpc_call_details_init(&proxy->new_call_details);
-  gpr_thd_options_set_joinable(&opt);
-  GPR_ASSERT(
-      gpr_thd_new(&proxy->thd, "grpc_end2end_proxy", thread_main, proxy, &opt));
+  proxy->thd = grpc_core::Thread("grpc_end2end_proxy", thread_main, proxy);
+  proxy->thd.Start();
 
   request_call(proxy);
 
@@ -123,7 +121,7 @@ static void shutdown_complete(void* arg, int success) {
 void grpc_end2end_proxy_destroy(grpc_end2end_proxy* proxy) {
   grpc_server_shutdown_and_notify(proxy->server, proxy->cq,
                                   new_closure(shutdown_complete, proxy));
-  gpr_thd_join(proxy->thd);
+  proxy->thd.Join();
   gpr_free(proxy->proxy_port);
   gpr_free(proxy->server_port);
   grpc_server_destroy(proxy->server);

+ 0 - 1
test/core/end2end/tests/bad_ping.cc

@@ -25,7 +25,6 @@
 #include <grpc/support/sync.h>
 #include <grpc/support/time.h>
 
-#include "src/core/lib/gpr/thd.h"
 #include "src/core/lib/gpr/useful.h"
 #include "test/core/end2end/cq_verifier.h"
 

+ 4 - 7
test/core/end2end/tests/connectivity.cc

@@ -22,7 +22,7 @@
 #include <grpc/support/sync.h>
 #include <grpc/support/time.h>
 
-#include "src/core/lib/gpr/thd.h"
+#include "src/core/lib/gprpp/thd.h"
 #include "test/core/end2end/cq_verifier.h"
 
 static void* tag(intptr_t t) { return (void*)t; }
@@ -50,8 +50,6 @@ static void test_connectivity(grpc_end2end_test_config config) {
   grpc_connectivity_state state;
   cq_verifier* cqv = cq_verifier_create(f.cq);
   child_events ce;
-  gpr_thd_options thdopt = gpr_thd_options_default();
-  gpr_thd_id thdid;
 
   grpc_channel_args client_args;
   grpc_arg arg_array[1];
@@ -67,9 +65,8 @@ static void test_connectivity(grpc_end2end_test_config config) {
   ce.channel = f.client;
   ce.cq = f.cq;
   gpr_event_init(&ce.started);
-  gpr_thd_options_set_joinable(&thdopt);
-  GPR_ASSERT(
-      gpr_thd_new(&thdid, "grpc_connectivity", child_thread, &ce, &thdopt));
+  grpc_core::Thread thd("grpc_connectivity", child_thread, &ce);
+  thd.Start();
 
   gpr_event_wait(&ce.started, gpr_inf_future(GPR_CLOCK_MONOTONIC));
 
@@ -86,7 +83,7 @@ static void test_connectivity(grpc_end2end_test_config config) {
       f.client, GRPC_CHANNEL_IDLE, gpr_now(GPR_CLOCK_MONOTONIC), f.cq, tag(1));
 
   /* eventually the child thread completion should trigger */
-  gpr_thd_join(thdid);
+  thd.Join();
 
   /* check that we're still in idle, and start connecting */
   GPR_ASSERT(grpc_channel_check_connectivity_state(f.client, 1) ==

+ 0 - 1
test/core/end2end/tests/ping.cc

@@ -22,7 +22,6 @@
 #include <grpc/support/sync.h>
 #include <grpc/support/time.h>
 
-#include "src/core/lib/gpr/thd.h"
 #include "src/core/lib/gpr/useful.h"
 #include "test/core/end2end/cq_verifier.h"
 

+ 0 - 10
test/core/gpr/BUILD

@@ -128,16 +128,6 @@ grpc_cc_test(
     ],
 )
 
-grpc_cc_test(
-    name = "thd_test",
-    srcs = ["thd_test.cc"],
-    language = "C++",
-    deps = [
-        "//:gpr",
-        "//test/core/util:gpr_test_util",
-    ],
-)
-
 grpc_cc_test(
     name = "time_test",
     srcs = ["time_test.cc"],

+ 10 - 10
test/core/gpr/arena_test.cc

@@ -18,16 +18,17 @@
 
 #include "src/core/lib/gpr/arena.h"
 
+#include <inttypes.h>
+#include <string.h>
+
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 #include <grpc/support/string_util.h>
 #include <grpc/support/sync.h>
-#include <inttypes.h>
-#include <string.h>
 
 #include "src/core/lib/gpr/string.h"
-#include "src/core/lib/gpr/thd.h"
 #include "src/core/lib/gpr/useful.h"
+#include "src/core/lib/gprpp/thd.h"
 #include "test/core/util/test_config.h"
 
 static void test_noop(void) { gpr_arena_destroy(gpr_arena_create(1)); }
@@ -97,19 +98,18 @@ static void concurrent_test(void) {
   gpr_event_init(&args.ev_start);
   args.arena = gpr_arena_create(1024);
 
-  gpr_thd_id thds[CONCURRENT_TEST_THREADS];
+  grpc_core::Thread thds[CONCURRENT_TEST_THREADS];
 
   for (int i = 0; i < CONCURRENT_TEST_THREADS; i++) {
-    gpr_thd_options opt = gpr_thd_options_default();
-    gpr_thd_options_set_joinable(&opt);
-    gpr_thd_new(&thds[i], "grpc_concurrent_test", concurrent_test_body, &args,
-                &opt);
+    thds[i] =
+        grpc_core::Thread("grpc_concurrent_test", concurrent_test_body, &args);
+    thds[i].Start();
   }
 
   gpr_event_set(&args.ev_start, (void*)1);
 
-  for (int i = 0; i < CONCURRENT_TEST_THREADS; i++) {
-    gpr_thd_join(thds[i]);
+  for (auto& th : thds) {
+    th.Join();
   }
 
   gpr_arena_destroy(args.arena);

+ 18 - 8
test/core/gpr/cpu_test.cc

@@ -21,15 +21,17 @@
    gpr_cpu_current_cpu()
 */
 
-#include <grpc/support/alloc.h>
 #include <grpc/support/cpu.h>
+
+#include <stdio.h>
+#include <string.h>
+
+#include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 #include <grpc/support/sync.h>
 #include <grpc/support/time.h>
-#include <stdio.h>
-#include <string.h>
 
-#include "src/core/lib/gpr/thd.h"
+#include "src/core/lib/gprpp/thd.h"
 #include "test/core/util/test_config.h"
 
 /* Test structure is essentially:
@@ -101,7 +103,6 @@ static void cpu_test(void) {
   uint32_t i;
   int cores_seen = 0;
   struct cpu_test ct;
-  gpr_thd_id thd;
   ct.ncores = gpr_cpu_num_cores();
   GPR_ASSERT(ct.ncores > 0);
   ct.nthreads = static_cast<int>(ct.ncores) * 3;
@@ -110,15 +111,24 @@ static void cpu_test(void) {
   gpr_mu_init(&ct.mu);
   gpr_cv_init(&ct.done_cv);
   ct.is_done = 0;
-  for (i = 0; i < ct.ncores * 3; i++) {
-    GPR_ASSERT(
-        gpr_thd_new(&thd, "grpc_cpu_test", &worker_thread, &ct, nullptr));
+
+  uint32_t nthreads = ct.ncores * 3;
+  grpc_core::Thread* thd =
+      static_cast<grpc_core::Thread*>(gpr_malloc(sizeof(*thd) * nthreads));
+
+  for (i = 0; i < nthreads; i++) {
+    thd[i] = grpc_core::Thread("grpc_cpu_test", &worker_thread, &ct);
+    thd[i].Start();
   }
   gpr_mu_lock(&ct.mu);
   while (!ct.is_done) {
     gpr_cv_wait(&ct.done_cv, &ct.mu, gpr_inf_future(GPR_CLOCK_MONOTONIC));
   }
   gpr_mu_unlock(&ct.mu);
+  for (i = 0; i < nthreads; i++) {
+    thd[i].Join();
+  }
+  gpr_free(thd);
   fprintf(stderr, "Saw cores [");
   fflush(stderr);
   for (i = 0; i < ct.ncores; i++) {

+ 16 - 22
test/core/gpr/mpscq_test.cc

@@ -24,8 +24,8 @@
 #include <grpc/support/log.h>
 #include <grpc/support/sync.h>
 
-#include "src/core/lib/gpr/thd.h"
 #include "src/core/lib/gpr/useful.h"
+#include "src/core/lib/gprpp/thd.h"
 #include "test/core/util/test_config.h"
 
 typedef struct test_node {
@@ -76,18 +76,16 @@ static void test_mt(void) {
   gpr_log(GPR_DEBUG, "test_mt");
   gpr_event start;
   gpr_event_init(&start);
-  gpr_thd_id thds[100];
+  grpc_core::Thread thds[100];
   thd_args ta[GPR_ARRAY_SIZE(thds)];
   gpr_mpscq q;
   gpr_mpscq_init(&q);
   for (size_t i = 0; i < GPR_ARRAY_SIZE(thds); i++) {
-    gpr_thd_options options = gpr_thd_options_default();
-    gpr_thd_options_set_joinable(&options);
     ta[i].ctr = 0;
     ta[i].q = &q;
     ta[i].start = &start;
-    GPR_ASSERT(
-        gpr_thd_new(&thds[i], "grpc_mt_test", test_thread, &ta[i], &options));
+    thds[i] = grpc_core::Thread("grpc_mt_test", test_thread, &ta[i]);
+    thds[i].Start();
   }
   size_t num_done = 0;
   size_t spins = 0;
@@ -104,8 +102,8 @@ static void test_mt(void) {
     gpr_free(tn);
   }
   gpr_log(GPR_DEBUG, "spins: %" PRIdPTR, spins);
-  for (size_t i = 0; i < GPR_ARRAY_SIZE(thds); i++) {
-    gpr_thd_join(thds[i]);
+  for (auto& th : thds) {
+    th.Join();
   }
   gpr_mpscq_destroy(&q);
 }
@@ -147,19 +145,17 @@ static void test_mt_multipop(void) {
   gpr_log(GPR_DEBUG, "test_mt_multipop");
   gpr_event start;
   gpr_event_init(&start);
-  gpr_thd_id thds[100];
-  gpr_thd_id pull_thds[100];
+  grpc_core::Thread thds[50];
+  grpc_core::Thread pull_thds[50];
   thd_args ta[GPR_ARRAY_SIZE(thds)];
   gpr_mpscq q;
   gpr_mpscq_init(&q);
   for (size_t i = 0; i < GPR_ARRAY_SIZE(thds); i++) {
-    gpr_thd_options options = gpr_thd_options_default();
-    gpr_thd_options_set_joinable(&options);
     ta[i].ctr = 0;
     ta[i].q = &q;
     ta[i].start = &start;
-    GPR_ASSERT(gpr_thd_new(&thds[i], "grpc_multipop_test", test_thread, &ta[i],
-                           &options));
+    thds[i] = grpc_core::Thread("grpc_multipop_test", test_thread, &ta[i]);
+    thds[i].Start();
   }
   pull_args pa;
   pa.ta = ta;
@@ -170,18 +166,16 @@ static void test_mt_multipop(void) {
   pa.start = &start;
   gpr_mu_init(&pa.mu);
   for (size_t i = 0; i < GPR_ARRAY_SIZE(pull_thds); i++) {
-    gpr_thd_options options = gpr_thd_options_default();
-    gpr_thd_options_set_joinable(&options);
-    GPR_ASSERT(gpr_thd_new(&pull_thds[i], "grpc_multipop_pull", pull_thread,
-                           &pa, &options));
+    pull_thds[i] = grpc_core::Thread("grpc_multipop_pull", pull_thread, &pa);
+    pull_thds[i].Start();
   }
   gpr_event_set(&start, (void*)1);
-  for (size_t i = 0; i < GPR_ARRAY_SIZE(pull_thds); i++) {
-    gpr_thd_join(pull_thds[i]);
+  for (auto& pth : pull_thds) {
+    pth.Join();
   }
   gpr_log(GPR_DEBUG, "spins: %" PRIdPTR, pa.spins);
-  for (size_t i = 0; i < GPR_ARRAY_SIZE(thds); i++) {
-    gpr_thd_join(thds[i]);
+  for (auto& th : thds) {
+    th.Join();
   }
   gpr_mpscq_destroy(&q);
 }

+ 11 - 11
test/core/gpr/spinlock_test.cc

@@ -16,24 +16,26 @@
  *
  */
 
-/* Test of gpr synchronization support. */
+/* Test of gpr spin-lock support. */
 
 #include "src/core/lib/gpr/spinlock.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 #include <grpc/support/sync.h>
 #include <grpc/support/time.h>
-#include <stdio.h>
-#include <stdlib.h>
 
-#include "src/core/lib/gpr/thd.h"
+#include "src/core/lib/gprpp/thd.h"
 #include "test/core/util/test_config.h"
 
 /* ------------------------------------------------- */
 /* Tests for gpr_spinlock. */
 struct test {
   int thread_count; /* number of threads */
-  gpr_thd_id* threads;
+  grpc_core::Thread* threads;
 
   int64_t iterations; /* number of iterations per thread */
   int64_t counter;
@@ -46,7 +48,7 @@ struct test {
 static struct test* test_new(int threads, int64_t iterations, int incr_step) {
   struct test* m = static_cast<struct test*>(gpr_malloc(sizeof(*m)));
   m->thread_count = threads;
-  m->threads = static_cast<gpr_thd_id*>(
+  m->threads = static_cast<grpc_core::Thread*>(
       gpr_malloc(sizeof(*m->threads) * static_cast<size_t>(threads)));
   m->iterations = iterations;
   m->counter = 0;
@@ -66,10 +68,8 @@ static void test_destroy(struct test* m) {
 static void test_create_threads(struct test* m, void (*body)(void* arg)) {
   int i;
   for (i = 0; i != m->thread_count; i++) {
-    gpr_thd_options opt = gpr_thd_options_default();
-    gpr_thd_options_set_joinable(&opt);
-    GPR_ASSERT(
-        gpr_thd_new(&m->threads[i], "grpc_create_threads", body, m, &opt));
+    m->threads[i] = grpc_core::Thread("grpc_create_threads", body, m);
+    m->threads[i].Start();
   }
 }
 
@@ -77,7 +77,7 @@ static void test_create_threads(struct test* m, void (*body)(void* arg)) {
 static void test_wait(struct test* m) {
   int i;
   for (i = 0; i != m->thread_count; i++) {
-    gpr_thd_join(m->threads[i]);
+    m->threads[i].Join();
   }
 }
 

+ 37 - 24
test/core/gpr/sync_test.cc

@@ -18,14 +18,16 @@
 
 /* Test of gpr synchronization support. */
 
-#include <grpc/support/alloc.h>
-#include <grpc/support/log.h>
 #include <grpc/support/sync.h>
-#include <grpc/support/time.h>
+
 #include <stdio.h>
 #include <stdlib.h>
 
-#include "src/core/lib/gpr/thd.h"
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/time.h>
+
+#include "src/core/lib/gprpp/thd.h"
 #include "test/core/util/test_config.h"
 
 /* ==================Example use of interface===================
@@ -133,7 +135,8 @@ int queue_remove(queue* q, int* head, gpr_timespec abs_deadline) {
 /* ------------------------------------------------- */
 /* Tests for gpr_mu and gpr_cv, and the queue example. */
 struct test {
-  int threads; /* number of threads */
+  int nthreads; /* number of threads */
+  grpc_core::Thread* threads;
 
   int64_t iterations; /* number of iterations per thread */
   int64_t counter;
@@ -157,13 +160,15 @@ struct test {
 };
 
 /* Return pointer to a new struct test. */
-static struct test* test_new(int threads, int64_t iterations, int incr_step) {
+static struct test* test_new(int nthreads, int64_t iterations, int incr_step) {
   struct test* m = static_cast<struct test*>(gpr_malloc(sizeof(*m)));
-  m->threads = threads;
+  m->nthreads = nthreads;
+  m->threads = static_cast<grpc_core::Thread*>(
+      gpr_malloc(sizeof(*m->threads) * nthreads));
   m->iterations = iterations;
   m->counter = 0;
   m->thread_count = 0;
-  m->done = threads;
+  m->done = nthreads;
   m->incr_step = incr_step;
   gpr_mu_init(&m->mu);
   gpr_cv_init(&m->cv);
@@ -171,7 +176,7 @@ static struct test* test_new(int threads, int64_t iterations, int incr_step) {
   queue_init(&m->q);
   gpr_stats_init(&m->stats_counter, 0);
   gpr_ref_init(&m->refcount, 0);
-  gpr_ref_init(&m->thread_refcount, threads);
+  gpr_ref_init(&m->thread_refcount, nthreads);
   gpr_event_init(&m->event);
   return m;
 }
@@ -182,15 +187,16 @@ static void test_destroy(struct test* m) {
   gpr_cv_destroy(&m->cv);
   gpr_cv_destroy(&m->done_cv);
   queue_destroy(&m->q);
+  gpr_free(m->threads);
   gpr_free(m);
 }
 
-/* Create m->threads threads, each running (*body)(m) */
+/* Create m->nthreads threads, each running (*body)(m) */
 static void test_create_threads(struct test* m, void (*body)(void* arg)) {
-  gpr_thd_id id;
   int i;
-  for (i = 0; i != m->threads; i++) {
-    GPR_ASSERT(gpr_thd_new(&id, "grpc_create_threads", body, m, nullptr));
+  for (i = 0; i != m->nthreads; i++) {
+    m->threads[i] = grpc_core::Thread("grpc_create_threads", body, m);
+    m->threads[i].Start();
   }
 }
 
@@ -201,9 +207,12 @@ static void test_wait(struct test* m) {
     gpr_cv_wait(&m->done_cv, &m->mu, gpr_inf_future(GPR_CLOCK_MONOTONIC));
   }
   gpr_mu_unlock(&m->mu);
+  for (int i = 0; i != m->nthreads; i++) {
+    m->threads[i].Join();
+  }
 }
 
-/* Get an integer thread id in the raneg 0..threads-1 */
+/* Get an integer thread id in the raneg 0..nthreads-1 */
 static int thread_id(struct test* m) {
   int id;
   gpr_mu_lock(&m->mu);
@@ -245,16 +254,20 @@ static void test(const char* name, void (*body)(void* m),
     fprintf(stderr, " %ld", static_cast<long>(iterations));
     fflush(stderr);
     m = test_new(10, iterations, incr_step);
+    grpc_core::Thread extra_thd;
     if (extra != nullptr) {
-      gpr_thd_id id;
-      GPR_ASSERT(gpr_thd_new(&id, name, extra, m, nullptr));
+      extra_thd = grpc_core::Thread(name, extra, m);
+      extra_thd.Start();
       m->done++; /* one more thread to wait for */
     }
     test_create_threads(m, body);
     test_wait(m);
-    if (m->counter != m->threads * m->iterations * m->incr_step) {
+    if (extra != nullptr) {
+      extra_thd.Join();
+    }
+    if (m->counter != m->nthreads * m->iterations * m->incr_step) {
       fprintf(stderr, "counter %ld  threads %d  iterations %ld\n",
-              static_cast<long>(m->counter), m->threads,
+              static_cast<long>(m->counter), m->nthreads,
               static_cast<long>(m->iterations));
       fflush(stderr);
       GPR_ASSERT(0);
@@ -296,7 +309,7 @@ static void inctry(void* v /*=m*/) {
   mark_thread_done(m);
 }
 
-/* Increment counter only when (m->counter%m->threads)==m->thread_id; then mark
+/* Increment counter only when (m->counter%m->nthreads)==m->thread_id; then mark
    thread as done.  */
 static void inc_by_turns(void* v /*=m*/) {
   struct test* m = static_cast<struct test*>(v);
@@ -304,7 +317,7 @@ static void inc_by_turns(void* v /*=m*/) {
   int id = thread_id(m);
   for (i = 0; i != m->iterations; i++) {
     gpr_mu_lock(&m->mu);
-    while ((m->counter % m->threads) != id) {
+    while ((m->counter % m->nthreads) != id) {
       gpr_cv_wait(&m->cv, &m->mu, gpr_inf_future(GPR_CLOCK_MONOTONIC));
     }
     m->counter++;
@@ -369,12 +382,12 @@ static void many_producers(void* v /*=m*/) {
   mark_thread_done(m);
 }
 
-/* Consume elements from m->q until m->threads*m->iterations are seen,
+/* Consume elements from m->q until m->nthreads*m->iterations are seen,
    wait an extra second to confirm that no more elements are arriving,
    then mark thread as done. */
 static void consumer(void* v /*=m*/) {
   struct test* m = static_cast<struct test*>(v);
-  int64_t n = m->iterations * m->threads;
+  int64_t n = m->iterations * m->nthreads;
   int64_t i;
   int value;
   for (i = 0; i != n; i++) {
@@ -424,11 +437,11 @@ static void refinc(void* v /*=m*/) {
 }
 
 /* Wait until m->event is set to (void *)1, then decrement m->refcount by 1
-   (m->threads * m->iterations * m->incr_step) times, and ensure that the last
+   (m->nthreads * m->iterations * m->incr_step) times, and ensure that the last
    decrement caused the counter to reach zero, then mark thread as done.  */
 static void refcheck(void* v /*=m*/) {
   struct test* m = static_cast<struct test*>(v);
-  int64_t n = m->iterations * m->threads * m->incr_step;
+  int64_t n = m->iterations * m->nthreads * m->incr_step;
   int64_t i;
   GPR_ASSERT(gpr_event_wait(&m->event, gpr_inf_future(GPR_CLOCK_REALTIME)) ==
              (void*)1);

+ 0 - 1
test/core/gpr/time_test.cc

@@ -26,7 +26,6 @@
 #include <stdlib.h>
 #include <string.h>
 
-#include "src/core/lib/gpr/thd.h"
 #include "test/core/util/test_config.h"
 
 static void to_fp(void* arg, const char* buf, size_t len) {

+ 12 - 13
test/core/gpr/tls_test.cc

@@ -18,13 +18,15 @@
 
 /* Test of gpr thread local storage support. */
 
-#include <grpc/support/log.h>
-#include <grpc/support/sync.h>
+#include "src/core/lib/gpr/tls.h"
+
 #include <stdio.h>
 #include <stdlib.h>
 
-#include "src/core/lib/gpr/thd.h"
-#include "src/core/lib/gpr/tls.h"
+#include <grpc/support/log.h>
+#include <grpc/support/sync.h>
+
+#include "src/core/lib/gprpp/thd.h"
 #include "test/core/util/test_config.h"
 
 #define NUM_THREADS 100
@@ -46,21 +48,18 @@ static void thd_body(void* arg) {
 /* ------------------------------------------------- */
 
 int main(int argc, char* argv[]) {
-  gpr_thd_options opt = gpr_thd_options_default();
-  int i;
-  gpr_thd_id threads[NUM_THREADS];
+  grpc_core::Thread threads[NUM_THREADS];
 
   grpc_test_init(argc, argv);
 
   gpr_tls_init(&test_var);
 
-  gpr_thd_options_set_joinable(&opt);
-
-  for (i = 0; i < NUM_THREADS; i++) {
-    gpr_thd_new(&threads[i], "grpc_tls_test", thd_body, nullptr, &opt);
+  for (auto& th : threads) {
+    th = grpc_core::Thread("grpc_tls_test", thd_body, nullptr);
+    th.Start();
   }
-  for (i = 0; i < NUM_THREADS; i++) {
-    gpr_thd_join(threads[i]);
+  for (auto& th : threads) {
+    th.Join();
   }
 
   gpr_tls_destroy(&test_var);

+ 19 - 10
test/core/gprpp/BUILD

@@ -24,7 +24,6 @@ grpc_cc_test(
     language = "C++",
     deps = [
         "//:gpr",
-        "//:gpr++_base",
         "//test/core/util:gpr_test_util",
     ],
 )
@@ -37,7 +36,7 @@ grpc_cc_test(
     ],
     language = "C++",
     deps = [
-        "//:gpr++_base",
+        "//:gpr_base",
         "//test/core/util:gpr_test_util",
     ],
 )
@@ -58,39 +57,49 @@ grpc_cc_test(
 grpc_cc_test(
     name = "orphanable_test",
     srcs = ["orphanable_test.cc"],
+    external_deps = [
+        "gtest",
+    ],
     language = "C++",
     deps = [
         "//:orphanable",
         "//test/core/util:gpr_test_util",
     ],
-    external_deps = [
-        "gtest",
-    ],
 )
 
 grpc_cc_test(
     name = "ref_counted_test",
     srcs = ["ref_counted_test.cc"],
+    external_deps = [
+        "gtest",
+    ],
     language = "C++",
     deps = [
         "//:ref_counted",
         "//test/core/util:gpr_test_util",
     ],
-    external_deps = [
-        "gtest",
-    ],
 )
 
 grpc_cc_test(
     name = "ref_counted_ptr_test",
     srcs = ["ref_counted_ptr_test.cc"],
+    external_deps = [
+        "gtest",
+    ],
     language = "C++",
     deps = [
         "//:ref_counted",
         "//:ref_counted_ptr",
         "//test/core/util:gpr_test_util",
     ],
-    external_deps = [
-        "gtest",
+)
+
+grpc_cc_test(
+    name = "thd_test",
+    srcs = ["thd_test.cc"],
+    language = "C++",
+    deps = [
+        "//:gpr",
+        "//test/core/util:gpr_test_util",
     ],
 )

+ 0 - 1
test/core/gprpp/manual_constructor_test.cc

@@ -26,7 +26,6 @@
 #include <stdlib.h>
 #include <cstring>
 
-#include "src/core/lib/gpr/thd.h"
 #include "src/core/lib/gprpp/abstract.h"
 #include "test/core/util/test_config.h"
 

+ 31 - 36
test/core/gpr/thd_test.cc → test/core/gprpp/thd_test.cc

@@ -18,17 +18,18 @@
 
 /* Test of gpr thread support. */
 
-#include "src/core/lib/gpr/thd.h"
+#include "src/core/lib/gprpp/thd.h"
+
+#include <stdio.h>
+#include <stdlib.h>
 
 #include <grpc/support/log.h>
 #include <grpc/support/sync.h>
 #include <grpc/support/time.h>
-#include <stdio.h>
-#include <stdlib.h>
 
 #include "test/core/util/test_config.h"
 
-#define NUM_THREADS 300
+#define NUM_THREADS 100
 
 struct test {
   gpr_mu mu;
@@ -38,7 +39,7 @@ struct test {
 };
 
 /* A Thread body.   Decrement t->n, and if is becomes zero, set t->done. */
-static void thd_body(void* v) {
+static void thd_body1(void* v) {
   struct test* t = static_cast<struct test*>(v);
   gpr_mu_lock(&t->mu);
   t->n--;
@@ -49,48 +50,42 @@ static void thd_body(void* v) {
   gpr_mu_unlock(&t->mu);
 }
 
-static void thd_body_joinable(void* v) {}
-
-/* Test thread options work as expected */
-static void test_options(void) {
-  gpr_thd_options options = gpr_thd_options_default();
-  GPR_ASSERT(!gpr_thd_options_is_joinable(&options));
-  GPR_ASSERT(gpr_thd_options_is_detached(&options));
-  gpr_thd_options_set_joinable(&options);
-  GPR_ASSERT(gpr_thd_options_is_joinable(&options));
-  GPR_ASSERT(!gpr_thd_options_is_detached(&options));
-  gpr_thd_options_set_detached(&options);
-  GPR_ASSERT(!gpr_thd_options_is_joinable(&options));
-  GPR_ASSERT(gpr_thd_options_is_detached(&options));
-}
-
-/* Test that we can create a number of threads and wait for them. */
-static void test(void) {
-  int i;
-  gpr_thd_id thd;
-  gpr_thd_id thds[NUM_THREADS];
+/* Test that we can create a number of threads, wait for them, and join them. */
+static void test1(void) {
+  grpc_core::Thread thds[NUM_THREADS];
   struct test t;
-  gpr_thd_options options = gpr_thd_options_default();
   gpr_mu_init(&t.mu);
   gpr_cv_init(&t.done_cv);
   t.n = NUM_THREADS;
   t.is_done = 0;
-  for (i = 0; i < NUM_THREADS; i++) {
-    GPR_ASSERT(gpr_thd_new(&thd, "grpc_thread_test", &thd_body, &t, nullptr));
+  for (auto& th : thds) {
+    th = grpc_core::Thread("grpc_thread_body1_test", &thd_body1, &t);
+    th.Start();
   }
   gpr_mu_lock(&t.mu);
   while (!t.is_done) {
     gpr_cv_wait(&t.done_cv, &t.mu, gpr_inf_future(GPR_CLOCK_REALTIME));
   }
   gpr_mu_unlock(&t.mu);
+  for (auto& th : thds) {
+    th.Join();
+  }
   GPR_ASSERT(t.n == 0);
-  gpr_thd_options_set_joinable(&options);
-  for (i = 0; i < NUM_THREADS; i++) {
-    GPR_ASSERT(gpr_thd_new(&thds[i], "grpc_joinable_thread_test",
-                           &thd_body_joinable, nullptr, &options));
+}
+
+static void thd_body2(void* v) {}
+
+/* Test that we can create a number of threads and join them. */
+static void test2(void) {
+  grpc_core::Thread thds[NUM_THREADS];
+  for (auto& th : thds) {
+    bool ok;
+    th = grpc_core::Thread("grpc_thread_body2_test", &thd_body2, nullptr, &ok);
+    GPR_ASSERT(ok);
+    th.Start();
   }
-  for (i = 0; i < NUM_THREADS; i++) {
-    gpr_thd_join(thds[i]);
+  for (auto& th : thds) {
+    th.Join();
   }
 }
 
@@ -98,7 +93,7 @@ static void test(void) {
 
 int main(int argc, char* argv[]) {
   grpc_test_init(argc, argv);
-  test_options();
-  test();
+  test1();
+  test2();
   return 0;
 }

+ 6 - 7
test/core/handshake/client_ssl.cc

@@ -35,7 +35,7 @@
 #include <grpc/support/log.h>
 #include <grpc/support/string_util.h>
 
-#include "src/core/lib/gpr/thd.h"
+#include "src/core/lib/gprpp/thd.h"
 #include "src/core/lib/iomgr/load_file.h"
 #include "test/core/util/port.h"
 #include "test/core/util/test_config.h"
@@ -230,12 +230,11 @@ static bool client_ssl_test(char* server_alpn_preferred) {
   GPR_ASSERT(server_socket > 0 && port > 0);
 
   // Launch the TLS server thread.
-  gpr_thd_options thdopt = gpr_thd_options_default();
-  gpr_thd_id thdid;
-  gpr_thd_options_set_joinable(&thdopt);
   server_args args = {server_socket, server_alpn_preferred};
-  GPR_ASSERT(gpr_thd_new(&thdid, "grpc_client_ssl_test", server_thread, &args,
-                         &thdopt));
+  bool ok;
+  grpc_core::Thread thd("grpc_client_ssl_test", server_thread, &args, &ok);
+  GPR_ASSERT(ok);
+  thd.Start();
 
   // Load key pair and establish client SSL credentials.
   grpc_ssl_pem_key_cert_pair pem_key_cert_pair;
@@ -303,7 +302,7 @@ static bool client_ssl_test(char* server_alpn_preferred) {
   grpc_slice_unref(key_slice);
   grpc_slice_unref(ca_slice);
 
-  gpr_thd_join(thdid);
+  thd.Join();
 
   grpc_shutdown();
 

+ 0 - 1
test/core/handshake/readahead_handshaker_server_ssl.cc

@@ -30,7 +30,6 @@
 #include <grpc/support/string_util.h>
 #include <grpc/support/sync.h>
 
-#include "src/core/lib/gpr/thd.h"
 #include "src/core/lib/iomgr/load_file.h"
 #include "test/core/util/port.h"
 #include "test/core/util/test_config.h"

+ 0 - 1
test/core/handshake/server_ssl.cc

@@ -30,7 +30,6 @@
 #include <grpc/support/string_util.h>
 #include <grpc/support/sync.h>
 
-#include "src/core/lib/gpr/thd.h"
 #include "src/core/lib/iomgr/load_file.h"
 #include "test/core/util/port.h"
 #include "test/core/util/test_config.h"

+ 6 - 7
test/core/handshake/server_ssl_common.cc

@@ -32,7 +32,7 @@
 #include <grpc/support/string_util.h>
 #include <grpc/support/sync.h>
 
-#include "src/core/lib/gpr/thd.h"
+#include "src/core/lib/gprpp/thd.h"
 #include "src/core/lib/iomgr/load_file.h"
 #include "test/core/util/port.h"
 #include "test/core/util/test_config.h"
@@ -138,11 +138,10 @@ bool server_ssl_test(const char* alpn_list[], unsigned int alpn_list_len,
   gpr_event_init(&client_handshake_complete);
 
   // Launch the gRPC server thread.
-  gpr_thd_options thdopt = gpr_thd_options_default();
-  gpr_thd_id thdid;
-  gpr_thd_options_set_joinable(&thdopt);
-  GPR_ASSERT(
-      gpr_thd_new(&thdid, "grpc_ssl_test", server_thread, &port, &thdopt));
+  bool ok;
+  grpc_core::Thread thd("grpc_ssl_test", server_thread, &port, &ok);
+  GPR_ASSERT(ok);
+  thd.Start();
 
   SSL_load_error_strings();
   OpenSSL_add_ssl_algorithms();
@@ -235,7 +234,7 @@ bool server_ssl_test(const char* alpn_list[], unsigned int alpn_list_len,
   EVP_cleanup();
   close(sock);
 
-  gpr_thd_join(thdid);
+  thd.Join();
 
   grpc_shutdown();
 

+ 0 - 1
test/core/handshake/server_ssl_common.h

@@ -26,7 +26,6 @@
 #include <grpc/support/string_util.h>
 #include <grpc/support/sync.h>
 
-#include "src/core/lib/gpr/thd.h"
 #include "src/core/lib/iomgr/load_file.h"
 #include "test/core/util/port.h"
 #include "test/core/util/test_config.h"

Unele fișiere nu au fost afișate deoarece prea multe fișiere au fost modificate în acest diff