3 * Copyright 2015 gRPC authors.
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
9 * http://www.apache.org/licenses/LICENSE-2.0
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.
19 /* Windows implementation for gpr threads. */
21 #include <grpc/support/port_platform.h>
25 #include "src/core/lib/gprpp/thd.h"
27 #include <grpc/support/alloc.h>
28 #include <grpc/support/log.h>
29 #include <grpc/support/thd_id.h>
32 #include "src/core/lib/gprpp/memory.h"
35 #define thread_local __declspec(thread)
36 #elif defined(__GNUC__)
37 #define thread_local __thread
39 #error "Unknown compiler - please file a bug report"
43 class ThreadInternalsWindows;
45 ThreadInternalsWindows* thread;
46 void (*body)(void* arg); /* body of a thread */
47 void* arg; /* argument to a thread */
48 HANDLE join_event; /* the join event */
49 bool joinable; /* whether it is joinable */
52 thread_local struct thd_info* g_thd_info;
54 class ThreadInternalsWindows
55 : public grpc_core::internal::ThreadInternalsInterface {
57 ThreadInternalsWindows(void (*thd_body)(void* arg), void* arg, bool* success,
58 const grpc_core::Thread::Options& options)
64 info_ = (struct thd_info*)gpr_malloc(sizeof(*info_));
66 info_->body = thd_body;
68 info_->join_event = nullptr;
69 info_->joinable = options.joinable();
70 if (info_->joinable) {
71 info_->join_event = CreateEvent(nullptr, FALSE, FALSE, nullptr);
72 if (info_->join_event == nullptr) {
79 if (options.stack_size() != 0) {
80 // Windows will round up the given stack_size value to nearest page.
81 handle = CreateThread(nullptr, options.stack_size(), thread_body, info_,
84 handle = CreateThread(nullptr, 64 * 1024, thread_body, info_, 0, nullptr);
87 if (handle == nullptr) {
96 ~ThreadInternalsWindows() override {
98 gpr_cv_destroy(&ready_);
101 void Start() override {
104 gpr_cv_signal(&ready_);
108 void Join() override {
109 DWORD ret = WaitForSingleObject(info_->join_event, INFINITE);
110 GPR_ASSERT(ret == WAIT_OBJECT_0);
115 static DWORD WINAPI thread_body(void* v) {
116 g_thd_info = static_cast<thd_info*>(v);
117 gpr_mu_lock(&g_thd_info->thread->mu_);
118 while (!g_thd_info->thread->started_) {
119 gpr_cv_wait(&g_thd_info->thread->ready_, &g_thd_info->thread->mu_,
120 gpr_inf_future(GPR_CLOCK_MONOTONIC));
122 gpr_mu_unlock(&g_thd_info->thread->mu_);
123 if (!g_thd_info->joinable) {
124 grpc_core::Delete(g_thd_info->thread);
125 g_thd_info->thread = nullptr;
127 g_thd_info->body(g_thd_info->arg);
128 if (g_thd_info->joinable) {
129 BOOL ret = SetEvent(g_thd_info->join_event);
132 gpr_free(g_thd_info);
137 void destroy_thread() {
138 if (info_ != nullptr && info_->joinable) {
139 CloseHandle(info_->join_event);
152 namespace grpc_core {
154 Thread::Thread(const char* thd_name, void (*thd_body)(void* arg), void* arg,
155 bool* success, const Options& options)
156 : options_(options) {
157 bool outcome = false;
158 impl_ = New<ThreadInternalsWindows>(thd_body, arg, &outcome, options);
167 if (success != nullptr) {
172 } // namespace grpc_core
174 gpr_thd_id gpr_thd_currentid(void) { return (gpr_thd_id)g_thd_info; }
176 #endif /* GPR_WINDOWS */