executor.c 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  1. /*
  2. *
  3. * Copyright 2015, Google Inc.
  4. * All rights reserved.
  5. *
  6. * Redistribution and use in source and binary forms, with or without
  7. * modification, are permitted provided that the following conditions are
  8. * met:
  9. *
  10. * * Redistributions of source code must retain the above copyright
  11. * notice, this list of conditions and the following disclaimer.
  12. * * Redistributions in binary form must reproduce the above
  13. * copyright notice, this list of conditions and the following disclaimer
  14. * in the documentation and/or other materials provided with the
  15. * distribution.
  16. * * Neither the name of Google Inc. nor the names of its
  17. * contributors may be used to endorse or promote products derived from
  18. * this software without specific prior written permission.
  19. *
  20. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  21. * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  22. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  23. * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  24. * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  25. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  26. * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  27. * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  28. * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  29. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  30. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  31. *
  32. */
  33. #include "src/core/lib/iomgr/executor.h"
  34. #include <string.h>
  35. #include <grpc/support/alloc.h>
  36. #include <grpc/support/log.h>
  37. #include <grpc/support/sync.h>
  38. #include <grpc/support/thd.h>
  39. #include "src/core/lib/iomgr/exec_ctx.h"
  40. typedef struct grpc_executor_data {
  41. int busy; /**< is the thread currently running? */
  42. int shutting_down; /**< has \a grpc_shutdown() been invoked? */
  43. int pending_join; /**< has the thread finished but not been joined? */
  44. grpc_closure_list closures; /**< collection of pending work */
  45. gpr_thd_id tid; /**< thread id of the thread, only valid if \a busy or \a
  46. pending_join are true */
  47. gpr_thd_options options;
  48. gpr_mu mu;
  49. } grpc_executor;
  50. static grpc_executor g_executor;
  51. void grpc_executor_init() {
  52. memset(&g_executor, 0, sizeof(grpc_executor));
  53. gpr_mu_init(&g_executor.mu);
  54. g_executor.options = gpr_thd_options_default();
  55. gpr_thd_options_set_joinable(&g_executor.options);
  56. }
  57. /* thread body */
  58. static void closure_exec_thread_func(void *ignored) {
  59. grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
  60. while (1) {
  61. gpr_mu_lock(&g_executor.mu);
  62. if (g_executor.shutting_down != 0) {
  63. gpr_mu_unlock(&g_executor.mu);
  64. break;
  65. }
  66. if (grpc_closure_list_empty(g_executor.closures)) {
  67. /* no more work, time to die */
  68. GPR_ASSERT(g_executor.busy == 1);
  69. g_executor.busy = 0;
  70. gpr_mu_unlock(&g_executor.mu);
  71. break;
  72. } else {
  73. grpc_closure *c = g_executor.closures.head;
  74. grpc_closure_list_init(&g_executor.closures);
  75. gpr_mu_unlock(&g_executor.mu);
  76. while (c != NULL) {
  77. grpc_closure *next = c->next_data.next;
  78. grpc_error *error = c->error_data.error;
  79. c->cb(&exec_ctx, c->cb_arg, error);
  80. GRPC_ERROR_UNREF(error);
  81. c = next;
  82. }
  83. grpc_exec_ctx_flush(&exec_ctx);
  84. }
  85. }
  86. grpc_exec_ctx_finish(&exec_ctx);
  87. }
  88. /* Spawn the thread if new work has arrived a no thread is up */
  89. static void maybe_spawn_locked() {
  90. if (grpc_closure_list_empty(g_executor.closures) == 1) {
  91. return;
  92. }
  93. if (g_executor.shutting_down == 1) {
  94. return;
  95. }
  96. if (g_executor.busy != 0) {
  97. /* Thread still working. New work will be picked up by already running
  98. * thread. Not spawning anything. */
  99. return;
  100. } else if (g_executor.pending_join != 0) {
  101. /* Pickup the remains of the previous incarnations of the thread. */
  102. gpr_thd_join(g_executor.tid);
  103. g_executor.pending_join = 0;
  104. }
  105. /* All previous instances of the thread should have been joined at this point.
  106. * Spawn time! */
  107. g_executor.busy = 1;
  108. gpr_thd_new(&g_executor.tid, closure_exec_thread_func, NULL,
  109. &g_executor.options);
  110. g_executor.pending_join = 1;
  111. }
  112. static void executor_push(grpc_exec_ctx *exec_ctx, grpc_closure *closure,
  113. grpc_error *error) {
  114. gpr_mu_lock(&g_executor.mu);
  115. if (g_executor.shutting_down == 0) {
  116. grpc_closure_list_append(&g_executor.closures, closure, error);
  117. maybe_spawn_locked();
  118. }
  119. gpr_mu_unlock(&g_executor.mu);
  120. }
  121. void grpc_executor_shutdown(grpc_exec_ctx *exec_ctx) {
  122. int pending_join;
  123. gpr_mu_lock(&g_executor.mu);
  124. pending_join = g_executor.pending_join;
  125. g_executor.shutting_down = 1;
  126. gpr_mu_unlock(&g_executor.mu);
  127. /* we can release the lock at this point despite the access to the closure
  128. * list below because we aren't accepting new work */
  129. /* Execute pending callbacks, some may be performing cleanups */
  130. grpc_closure *c = g_executor.closures.head;
  131. grpc_closure_list_init(&g_executor.closures);
  132. while (c != NULL) {
  133. grpc_closure *next = c->next_data.next;
  134. grpc_error *error = c->error_data.error;
  135. c->cb(exec_ctx, c->cb_arg, error);
  136. GRPC_ERROR_UNREF(error);
  137. c = next;
  138. }
  139. grpc_exec_ctx_flush(exec_ctx);
  140. GPR_ASSERT(grpc_closure_list_empty(g_executor.closures));
  141. if (pending_join) {
  142. gpr_thd_join(g_executor.tid);
  143. }
  144. gpr_mu_destroy(&g_executor.mu);
  145. }
  146. static const grpc_closure_scheduler_vtable executor_vtable = {executor_push,
  147. executor_push};
  148. static grpc_closure_scheduler executor_scheduler = {&executor_vtable};
  149. grpc_closure_scheduler *grpc_executor_scheduler = &executor_scheduler;