thd_posix.cc 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  1. /*
  2. *
  3. * Copyright 2015 gRPC authors.
  4. *
  5. * Licensed under the Apache License, Version 2.0 (the "License");
  6. * you may not use this file except in compliance with the License.
  7. * You may obtain a copy of the License at
  8. *
  9. * http://www.apache.org/licenses/LICENSE-2.0
  10. *
  11. * Unless required by applicable law or agreed to in writing, software
  12. * distributed under the License is distributed on an "AS IS" BASIS,
  13. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. * See the License for the specific language governing permissions and
  15. * limitations under the License.
  16. *
  17. */
  18. /* Posix implementation for gpr threads. */
  19. #include <grpc/support/port_platform.h>
  20. #ifdef GPR_POSIX_SYNC
  21. #include "src/core/lib/gpr/thd.h"
  22. #include <grpc/support/alloc.h>
  23. #include <grpc/support/log.h>
  24. #include <grpc/support/sync.h>
  25. #include <grpc/support/thd_id.h>
  26. #include <pthread.h>
  27. #include <stdlib.h>
  28. #include <string.h>
  29. #include "src/core/lib/gpr/fork.h"
  30. #include "src/core/lib/gpr/useful.h"
  31. static gpr_mu g_mu;
  32. static gpr_cv g_cv;
  33. static int g_thread_count;
  34. static int g_awaiting_threads;
  35. struct thd_arg {
  36. void (*body)(void* arg); /* body of a thread */
  37. void* arg; /* argument to a thread */
  38. const char* name; /* name of thread. Can be nullptr. */
  39. };
  40. static void inc_thd_count();
  41. static void dec_thd_count();
  42. /* Body of every thread started via gpr_thd_new. */
  43. static void* thread_body(void* v) {
  44. struct thd_arg a = *static_cast<struct thd_arg*>(v);
  45. free(v);
  46. if (a.name != nullptr) {
  47. #if GPR_APPLE_PTHREAD_NAME
  48. /* Apple supports 64 characters, and will truncate if it's longer. */
  49. pthread_setname_np(a.name);
  50. #elif GPR_LINUX_PTHREAD_NAME
  51. /* Linux supports 16 characters max, and will error if it's longer. */
  52. char buf[16];
  53. size_t buf_len = GPR_ARRAY_SIZE(buf) - 1;
  54. strncpy(buf, a.name, buf_len);
  55. buf[buf_len] = '\0';
  56. pthread_setname_np(pthread_self(), buf);
  57. #endif // GPR_APPLE_PTHREAD_NAME
  58. }
  59. (*a.body)(a.arg);
  60. dec_thd_count();
  61. return nullptr;
  62. }
  63. int gpr_thd_new(gpr_thd_id* t, const char* thd_name,
  64. void (*thd_body)(void* arg), void* arg,
  65. const gpr_thd_options* options) {
  66. int thread_started;
  67. pthread_attr_t attr;
  68. pthread_t p;
  69. /* don't use gpr_malloc as we may cause an infinite recursion with
  70. * the profiling code */
  71. struct thd_arg* a = static_cast<struct thd_arg*>(malloc(sizeof(*a)));
  72. GPR_ASSERT(a != nullptr);
  73. a->body = thd_body;
  74. a->arg = arg;
  75. a->name = thd_name;
  76. inc_thd_count();
  77. GPR_ASSERT(pthread_attr_init(&attr) == 0);
  78. if (gpr_thd_options_is_detached(options)) {
  79. GPR_ASSERT(pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED) ==
  80. 0);
  81. } else {
  82. GPR_ASSERT(pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE) ==
  83. 0);
  84. }
  85. thread_started = (pthread_create(&p, &attr, &thread_body, a) == 0);
  86. GPR_ASSERT(pthread_attr_destroy(&attr) == 0);
  87. if (!thread_started) {
  88. /* don't use gpr_free, as this was allocated using malloc (see above) */
  89. free(a);
  90. dec_thd_count();
  91. }
  92. *t = (gpr_thd_id)p;
  93. return thread_started;
  94. }
  95. gpr_thd_id gpr_thd_currentid(void) { return (gpr_thd_id)pthread_self(); }
  96. void gpr_thd_join(gpr_thd_id t) { pthread_join((pthread_t)t, nullptr); }
  97. /*****************************************
  98. * Only used when fork support is enabled
  99. */
  100. static void inc_thd_count() {
  101. if (grpc_fork_support_enabled()) {
  102. gpr_mu_lock(&g_mu);
  103. g_thread_count++;
  104. gpr_mu_unlock(&g_mu);
  105. }
  106. }
  107. static void dec_thd_count() {
  108. if (grpc_fork_support_enabled()) {
  109. gpr_mu_lock(&g_mu);
  110. g_thread_count--;
  111. if (g_awaiting_threads && g_thread_count == 0) {
  112. gpr_cv_signal(&g_cv);
  113. }
  114. gpr_mu_unlock(&g_mu);
  115. }
  116. }
  117. void gpr_thd_init() {
  118. gpr_mu_init(&g_mu);
  119. gpr_cv_init(&g_cv);
  120. g_thread_count = 0;
  121. g_awaiting_threads = 0;
  122. }
  123. int gpr_await_threads(gpr_timespec deadline) {
  124. gpr_mu_lock(&g_mu);
  125. g_awaiting_threads = 1;
  126. int res = 0;
  127. if (g_thread_count > 0) {
  128. res = gpr_cv_wait(&g_cv, &g_mu, deadline);
  129. }
  130. g_awaiting_threads = 0;
  131. gpr_mu_unlock(&g_mu);
  132. return res == 0;
  133. }
  134. #endif /* GPR_POSIX_SYNC */