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
19 #include <grpc/support/port_platform.h>
20
21 #include "src/core/lib/iomgr/executor.h"
22
23 #include <string.h>
24
25 #include <grpc/support/alloc.h>
26 #include <grpc/support/cpu.h>
27 #include <grpc/support/log.h>
28 #include <grpc/support/sync.h>
29
30 #include "src/core/lib/gpr/useful.h"
31 #include "src/core/lib/gprpp/crash.h"
32 #include "src/core/lib/gprpp/memory.h"
33 #include "src/core/lib/iomgr/exec_ctx.h"
34 #include "src/core/lib/iomgr/iomgr_internal.h"
35
36 #define MAX_DEPTH 2
37
38 #define EXECUTOR_TRACE(format, ...) \
39 do { \
40 if (GRPC_TRACE_FLAG_ENABLED(executor_trace)) { \
41 gpr_log(GPR_INFO, "EXECUTOR " format, __VA_ARGS__); \
42 } \
43 } while (0)
44
45 #define EXECUTOR_TRACE0(str) \
46 do { \
47 if (GRPC_TRACE_FLAG_ENABLED(executor_trace)) { \
48 gpr_log(GPR_INFO, "EXECUTOR " str); \
49 } \
50 } while (0)
51
52 namespace grpc_core {
53 namespace {
54
55 thread_local ThreadState* g_this_thread_state;
56
57 Executor* executors[static_cast<size_t>(ExecutorType::NUM_EXECUTORS)];
58
default_enqueue_short(grpc_closure * closure,grpc_error_handle error)59 void default_enqueue_short(grpc_closure* closure, grpc_error_handle error) {
60 executors[static_cast<size_t>(ExecutorType::DEFAULT)]->Enqueue(
61 closure, error, true /* is_short */);
62 }
63
default_enqueue_long(grpc_closure * closure,grpc_error_handle error)64 void default_enqueue_long(grpc_closure* closure, grpc_error_handle error) {
65 executors[static_cast<size_t>(ExecutorType::DEFAULT)]->Enqueue(
66 closure, error, false /* is_short */);
67 }
68
resolver_enqueue_short(grpc_closure * closure,grpc_error_handle error)69 void resolver_enqueue_short(grpc_closure* closure, grpc_error_handle error) {
70 executors[static_cast<size_t>(ExecutorType::RESOLVER)]->Enqueue(
71 closure, error, true /* is_short */);
72 }
73
resolver_enqueue_long(grpc_closure * closure,grpc_error_handle error)74 void resolver_enqueue_long(grpc_closure* closure, grpc_error_handle error) {
75 executors[static_cast<size_t>(ExecutorType::RESOLVER)]->Enqueue(
76 closure, error, false /* is_short */);
77 }
78
79 using EnqueueFunc = void (*)(grpc_closure* closure, grpc_error_handle error);
80
81 const EnqueueFunc
82 executor_enqueue_fns_[static_cast<size_t>(ExecutorType::NUM_EXECUTORS)]
83 [static_cast<size_t>(ExecutorJobType::NUM_JOB_TYPES)] =
84 {{default_enqueue_short, default_enqueue_long},
85 {resolver_enqueue_short, resolver_enqueue_long}};
86
87 } // namespace
88
89 TraceFlag executor_trace(false, "executor");
90
Executor(const char * name)91 Executor::Executor(const char* name) : name_(name) {
92 adding_thread_lock_ = GPR_SPINLOCK_STATIC_INITIALIZER;
93 gpr_atm_rel_store(&num_threads_, 0);
94 max_threads_ = std::max(1u, 2 * gpr_cpu_num_cores());
95 }
96
Init()97 void Executor::Init() { SetThreading(true); }
98
RunClosures(const char * executor_name,grpc_closure_list list)99 size_t Executor::RunClosures(const char* executor_name,
100 grpc_closure_list list) {
101 size_t n = 0;
102
103 // In the executor, the ExecCtx for the thread is declared in the executor
104 // thread itself, but this is the point where we could start seeing
105 // application-level callbacks. No need to create a new ExecCtx, though,
106 // since there already is one and it is flushed (but not destructed) in this
107 // function itself. The ApplicationCallbackExecCtx will have its callbacks
108 // invoked on its destruction, which will be after completing any closures in
109 // the executor's closure list (which were explicitly scheduled onto the
110 // executor).
111 ApplicationCallbackExecCtx callback_exec_ctx(
112 GRPC_APP_CALLBACK_EXEC_CTX_FLAG_IS_INTERNAL_THREAD);
113
114 grpc_closure* c = list.head;
115 while (c != nullptr) {
116 grpc_closure* next = c->next_data.next;
117 #ifndef NDEBUG
118 EXECUTOR_TRACE("(%s) run %p [created by %s:%d]", executor_name, c,
119 c->file_created, c->line_created);
120 c->scheduled = false;
121 #else
122 EXECUTOR_TRACE("(%s) run %p", executor_name, c);
123 #endif
124 grpc_error_handle error =
125 internal::StatusMoveFromHeapPtr(c->error_data.error);
126 c->error_data.error = 0;
127 c->cb(c->cb_arg, std::move(error));
128 c = next;
129 n++;
130 ExecCtx::Get()->Flush();
131 }
132
133 return n;
134 }
135
IsThreaded() const136 bool Executor::IsThreaded() const {
137 return gpr_atm_acq_load(&num_threads_) > 0;
138 }
139
SetThreading(bool threading)140 void Executor::SetThreading(bool threading) {
141 gpr_atm curr_num_threads = gpr_atm_acq_load(&num_threads_);
142 EXECUTOR_TRACE("(%s) SetThreading(%d) begin", name_, threading);
143
144 if (threading) {
145 if (curr_num_threads > 0) {
146 EXECUTOR_TRACE("(%s) SetThreading(true). curr_num_threads > 0", name_);
147 return;
148 }
149
150 GPR_ASSERT(num_threads_ == 0);
151 gpr_atm_rel_store(&num_threads_, 1);
152 thd_state_ = static_cast<ThreadState*>(
153 gpr_zalloc(sizeof(ThreadState) * max_threads_));
154
155 for (size_t i = 0; i < max_threads_; i++) {
156 gpr_mu_init(&thd_state_[i].mu);
157 gpr_cv_init(&thd_state_[i].cv);
158 thd_state_[i].id = i;
159 thd_state_[i].name = name_;
160 thd_state_[i].thd = Thread();
161 thd_state_[i].elems = GRPC_CLOSURE_LIST_INIT;
162 }
163
164 thd_state_[0].thd = Thread(name_, &Executor::ThreadMain, &thd_state_[0]);
165 thd_state_[0].thd.Start();
166 } else { // !threading
167 if (curr_num_threads == 0) {
168 EXECUTOR_TRACE("(%s) SetThreading(false). curr_num_threads == 0", name_);
169 return;
170 }
171
172 for (size_t i = 0; i < max_threads_; i++) {
173 gpr_mu_lock(&thd_state_[i].mu);
174 thd_state_[i].shutdown = true;
175 gpr_cv_signal(&thd_state_[i].cv);
176 gpr_mu_unlock(&thd_state_[i].mu);
177 }
178
179 // Ensure no thread is adding a new thread. Once this is past, then no
180 // thread will try to add a new one either (since shutdown is true)
181 gpr_spinlock_lock(&adding_thread_lock_);
182 gpr_spinlock_unlock(&adding_thread_lock_);
183
184 curr_num_threads = gpr_atm_no_barrier_load(&num_threads_);
185 for (gpr_atm i = 0; i < curr_num_threads; i++) {
186 thd_state_[i].thd.Join();
187 EXECUTOR_TRACE("(%s) Thread %" PRIdPTR " of %" PRIdPTR " joined", name_,
188 i + 1, curr_num_threads);
189 }
190
191 gpr_atm_rel_store(&num_threads_, 0);
192 for (size_t i = 0; i < max_threads_; i++) {
193 gpr_mu_destroy(&thd_state_[i].mu);
194 gpr_cv_destroy(&thd_state_[i].cv);
195 RunClosures(thd_state_[i].name, thd_state_[i].elems);
196 }
197
198 gpr_free(thd_state_);
199
200 // grpc_iomgr_shutdown_background_closure() will close all the registered
201 // fds in the background poller, and wait for all pending closures to
202 // finish. Thus, never call Executor::SetThreading(false) in the middle of
203 // an application.
204 // TODO(guantaol): create another method to finish all the pending closures
205 // registered in the background poller by Executor.
206 grpc_iomgr_platform_shutdown_background_closure();
207 }
208
209 EXECUTOR_TRACE("(%s) SetThreading(%d) done", name_, threading);
210 }
211
Shutdown()212 void Executor::Shutdown() { SetThreading(false); }
213
ThreadMain(void * arg)214 void Executor::ThreadMain(void* arg) {
215 ThreadState* ts = static_cast<ThreadState*>(arg);
216 g_this_thread_state = ts;
217
218 ExecCtx exec_ctx(GRPC_EXEC_CTX_FLAG_IS_INTERNAL_THREAD);
219
220 size_t subtract_depth = 0;
221 for (;;) {
222 EXECUTOR_TRACE("(%s) [%" PRIdPTR "]: step (sub_depth=%" PRIdPTR ")",
223 ts->name, ts->id, subtract_depth);
224
225 gpr_mu_lock(&ts->mu);
226 ts->depth -= subtract_depth;
227 // Wait for closures to be enqueued or for the executor to be shutdown
228 while (grpc_closure_list_empty(ts->elems) && !ts->shutdown) {
229 ts->queued_long_job = false;
230 gpr_cv_wait(&ts->cv, &ts->mu, gpr_inf_future(GPR_CLOCK_MONOTONIC));
231 }
232
233 if (ts->shutdown) {
234 EXECUTOR_TRACE("(%s) [%" PRIdPTR "]: shutdown", ts->name, ts->id);
235 gpr_mu_unlock(&ts->mu);
236 break;
237 }
238
239 grpc_closure_list closures = ts->elems;
240 ts->elems = GRPC_CLOSURE_LIST_INIT;
241 gpr_mu_unlock(&ts->mu);
242
243 EXECUTOR_TRACE("(%s) [%" PRIdPTR "]: execute", ts->name, ts->id);
244
245 ExecCtx::Get()->InvalidateNow();
246 subtract_depth = RunClosures(ts->name, closures);
247 }
248
249 g_this_thread_state = nullptr;
250 }
251
Enqueue(grpc_closure * closure,grpc_error_handle error,bool is_short)252 void Executor::Enqueue(grpc_closure* closure, grpc_error_handle error,
253 bool is_short) {
254 bool retry_push;
255
256 do {
257 retry_push = false;
258 size_t cur_thread_count =
259 static_cast<size_t>(gpr_atm_acq_load(&num_threads_));
260
261 // If the number of threads is zero(i.e either the executor is not threaded
262 // or already shutdown), then queue the closure on the exec context itself
263 if (cur_thread_count == 0) {
264 #ifndef NDEBUG
265 EXECUTOR_TRACE("(%s) schedule %p (created %s:%d) inline", name_, closure,
266 closure->file_created, closure->line_created);
267 #else
268 EXECUTOR_TRACE("(%s) schedule %p inline", name_, closure);
269 #endif
270 grpc_closure_list_append(ExecCtx::Get()->closure_list(), closure, error);
271 return;
272 }
273
274 if (grpc_iomgr_platform_add_closure_to_background_poller(closure, error)) {
275 return;
276 }
277
278 ThreadState* ts = g_this_thread_state;
279 if (ts == nullptr) {
280 ts = &thd_state_[HashPointer(ExecCtx::Get(), cur_thread_count)];
281 }
282
283 ThreadState* orig_ts = ts;
284 bool try_new_thread = false;
285
286 for (;;) {
287 #ifndef NDEBUG
288 EXECUTOR_TRACE(
289 "(%s) try to schedule %p (%s) (created %s:%d) to thread "
290 "%" PRIdPTR,
291 name_, closure, is_short ? "short" : "long", closure->file_created,
292 closure->line_created, ts->id);
293 #else
294 EXECUTOR_TRACE("(%s) try to schedule %p (%s) to thread %" PRIdPTR, name_,
295 closure, is_short ? "short" : "long", ts->id);
296 #endif
297
298 gpr_mu_lock(&ts->mu);
299 if (ts->queued_long_job) {
300 // if there's a long job queued, we never queue anything else to this
301 // queue (since long jobs can take 'infinite' time and we need to
302 // guarantee no starvation). Spin through queues and try again
303 gpr_mu_unlock(&ts->mu);
304 size_t idx = ts->id;
305 ts = &thd_state_[(idx + 1) % cur_thread_count];
306 if (ts == orig_ts) {
307 // We cycled through all the threads. Retry enqueue again by creating
308 // a new thread
309 //
310 // TODO (sreek): There is a potential issue here. We are
311 // unconditionally setting try_new_thread to true here. What if the
312 // executor is shutdown OR if cur_thread_count is already equal to
313 // max_threads ?
314 // (Fortunately, this is not an issue yet (as of july 2018) because
315 // there is only one instance of long job in gRPC and hence we will
316 // not hit this code path)
317 retry_push = true;
318 try_new_thread = true;
319 break;
320 }
321
322 continue; // Try the next thread-state
323 }
324
325 // == Found the thread state (i.e thread) to enqueue this closure! ==
326
327 // Also, if this thread has been waiting for closures, wake it up.
328 // - If grpc_closure_list_empty() is true and the Executor is not
329 // shutdown, it means that the thread must be waiting in ThreadMain()
330 // - Note that gpr_cv_signal() won't immediately wakeup the thread. That
331 // happens after we release the mutex &ts->mu a few lines below
332 if (grpc_closure_list_empty(ts->elems) && !ts->shutdown) {
333 gpr_cv_signal(&ts->cv);
334 }
335
336 grpc_closure_list_append(&ts->elems, closure, error);
337
338 // If we already queued more than MAX_DEPTH number of closures on this
339 // thread, use this as a hint to create more threads
340 ts->depth++;
341 try_new_thread = ts->depth > MAX_DEPTH &&
342 cur_thread_count < max_threads_ && !ts->shutdown;
343
344 ts->queued_long_job = !is_short;
345
346 gpr_mu_unlock(&ts->mu);
347 break;
348 }
349
350 if (try_new_thread && gpr_spinlock_trylock(&adding_thread_lock_)) {
351 cur_thread_count = static_cast<size_t>(gpr_atm_acq_load(&num_threads_));
352 if (cur_thread_count < max_threads_) {
353 // Increment num_threads (safe to do a store instead of a cas because we
354 // always increment num_threads under the 'adding_thread_lock')
355 gpr_atm_rel_store(&num_threads_, cur_thread_count + 1);
356
357 thd_state_[cur_thread_count].thd =
358 Thread(name_, &Executor::ThreadMain, &thd_state_[cur_thread_count]);
359 thd_state_[cur_thread_count].thd.Start();
360 }
361 gpr_spinlock_unlock(&adding_thread_lock_);
362 }
363 } while (retry_push);
364 }
365
366 // Executor::InitAll() and Executor::ShutdownAll() functions are called in the
367 // the grpc_init() and grpc_shutdown() code paths which are protected by a
368 // global mutex. So it is okay to assume that these functions are thread-safe
InitAll()369 void Executor::InitAll() {
370 EXECUTOR_TRACE0("Executor::InitAll() enter");
371
372 // Return if Executor::InitAll() is already called earlier
373 if (executors[static_cast<size_t>(ExecutorType::DEFAULT)] != nullptr) {
374 GPR_ASSERT(executors[static_cast<size_t>(ExecutorType::RESOLVER)] !=
375 nullptr);
376 return;
377 }
378
379 executors[static_cast<size_t>(ExecutorType::DEFAULT)] =
380 new Executor("default-executor");
381 executors[static_cast<size_t>(ExecutorType::RESOLVER)] =
382 new Executor("resolver-executor");
383
384 executors[static_cast<size_t>(ExecutorType::DEFAULT)]->Init();
385 executors[static_cast<size_t>(ExecutorType::RESOLVER)]->Init();
386
387 EXECUTOR_TRACE0("Executor::InitAll() done");
388 }
389
Run(grpc_closure * closure,grpc_error_handle error,ExecutorType executor_type,ExecutorJobType job_type)390 void Executor::Run(grpc_closure* closure, grpc_error_handle error,
391 ExecutorType executor_type, ExecutorJobType job_type) {
392 executor_enqueue_fns_[static_cast<size_t>(executor_type)]
393 [static_cast<size_t>(job_type)](closure, error);
394 }
395
ShutdownAll()396 void Executor::ShutdownAll() {
397 EXECUTOR_TRACE0("Executor::ShutdownAll() enter");
398
399 // Return if Executor:SshutdownAll() is already called earlier
400 if (executors[static_cast<size_t>(ExecutorType::DEFAULT)] == nullptr) {
401 GPR_ASSERT(executors[static_cast<size_t>(ExecutorType::RESOLVER)] ==
402 nullptr);
403 return;
404 }
405
406 executors[static_cast<size_t>(ExecutorType::DEFAULT)]->Shutdown();
407 executors[static_cast<size_t>(ExecutorType::RESOLVER)]->Shutdown();
408
409 // Delete the executor objects.
410 //
411 // NOTE: It is important to call Shutdown() on all executors first before
412 // calling delete because it is possible for one executor (that is not
413 // shutdown yet) to call Enqueue() on a different executor which is already
414 // shutdown. This is legal and in such cases, the Enqueue() operation
415 // effectively "fails" and enqueues that closure on the calling thread's
416 // exec_ctx.
417 //
418 // By ensuring that all executors are shutdown first, we are also ensuring
419 // that no thread is active across all executors.
420
421 delete executors[static_cast<size_t>(ExecutorType::DEFAULT)];
422 delete executors[static_cast<size_t>(ExecutorType::RESOLVER)];
423 executors[static_cast<size_t>(ExecutorType::DEFAULT)] = nullptr;
424 executors[static_cast<size_t>(ExecutorType::RESOLVER)] = nullptr;
425
426 EXECUTOR_TRACE0("Executor::ShutdownAll() done");
427 }
428
IsThreaded(ExecutorType executor_type)429 bool Executor::IsThreaded(ExecutorType executor_type) {
430 GPR_ASSERT(executor_type < ExecutorType::NUM_EXECUTORS);
431 return executors[static_cast<size_t>(executor_type)]->IsThreaded();
432 }
433
IsThreadedDefault()434 bool Executor::IsThreadedDefault() {
435 return Executor::IsThreaded(ExecutorType::DEFAULT);
436 }
437
SetThreadingAll(bool enable)438 void Executor::SetThreadingAll(bool enable) {
439 EXECUTOR_TRACE("Executor::SetThreadingAll(%d) called", enable);
440 for (size_t i = 0; i < static_cast<size_t>(ExecutorType::NUM_EXECUTORS);
441 i++) {
442 executors[i]->SetThreading(enable);
443 }
444 }
445
SetThreadingDefault(bool enable)446 void Executor::SetThreadingDefault(bool enable) {
447 EXECUTOR_TRACE("Executor::SetThreadingDefault(%d) called", enable);
448 executors[static_cast<size_t>(ExecutorType::DEFAULT)]->SetThreading(enable);
449 }
450
451 } // namespace grpc_core
452