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 /* Windows implementation for gpr threads. */ 20 21 #include <grpc/support/port_platform.h> 22 23 #ifdef GPR_WINDOWS 24 25 #include "src/core/lib/gprpp/thd.h" 26 27 #include <grpc/support/alloc.h> 28 #include <grpc/support/log.h> 29 #include <grpc/support/thd_id.h> 30 #include <string.h> 31 32 #include "src/core/lib/gprpp/memory.h" 33 34 #if defined(_MSC_VER) 35 #define thread_local __declspec(thread) 36 #define WIN_LAMBDA 37 #elif defined(__GNUC__) 38 #define thread_local __thread 39 #define WIN_LAMBDA WINAPI 40 #else 41 #error "Unknown compiler - please file a bug report" 42 #endif 43 44 namespace { 45 class ThreadInternalsWindows; 46 struct thd_info { 47 ThreadInternalsWindows* thread; 48 void (*body)(void* arg); /* body of a thread */ 49 void* arg; /* argument to a thread */ 50 HANDLE join_event; /* the join event */ 51 }; 52 53 thread_local struct thd_info* g_thd_info; 54 55 class ThreadInternalsWindows 56 : public grpc_core::internal::ThreadInternalsInterface { 57 public: 58 ThreadInternalsWindows(void (*thd_body)(void* arg), void* arg, bool* success) 59 : started_(false) { 60 gpr_mu_init(&mu_); 61 gpr_cv_init(&ready_); 62 63 HANDLE handle; 64 info_ = (struct thd_info*)gpr_malloc(sizeof(*info_)); 65 info_->thread = this; 66 info_->body = thd_body; 67 info_->arg = arg; 68 69 info_->join_event = CreateEvent(nullptr, FALSE, FALSE, nullptr); 70 if (info_->join_event == nullptr) { 71 gpr_free(info_); 72 *success = false; 73 } else { 74 handle = CreateThread( 75 nullptr, 64 * 1024, 76 [](void* v) WIN_LAMBDA -> DWORD { 77 g_thd_info = static_cast<thd_info*>(v); 78 gpr_mu_lock(&g_thd_info->thread->mu_); 79 while (!g_thd_info->thread->started_) { 80 gpr_cv_wait(&g_thd_info->thread->ready_, &g_thd_info->thread->mu_, 81 gpr_inf_future(GPR_CLOCK_MONOTONIC)); 82 } 83 gpr_mu_unlock(&g_thd_info->thread->mu_); 84 g_thd_info->body(g_thd_info->arg); 85 BOOL ret = SetEvent(g_thd_info->join_event); 86 GPR_ASSERT(ret); 87 return 0; 88 }, 89 info_, 0, nullptr); 90 if (handle == nullptr) { 91 destroy_thread(); 92 *success = false; 93 } else { 94 CloseHandle(handle); 95 *success = true; 96 } 97 } 98 } 99 100 ~ThreadInternalsWindows() override { 101 gpr_mu_destroy(&mu_); 102 gpr_cv_destroy(&ready_); 103 } 104 105 void Start() override { 106 gpr_mu_lock(&mu_); 107 started_ = true; 108 gpr_cv_signal(&ready_); 109 gpr_mu_unlock(&mu_); 110 } 111 112 void Join() override { 113 DWORD ret = WaitForSingleObject(info_->join_event, INFINITE); 114 GPR_ASSERT(ret == WAIT_OBJECT_0); 115 destroy_thread(); 116 } 117 118 private: 119 void destroy_thread() { 120 CloseHandle(info_->join_event); 121 gpr_free(info_); 122 } 123 124 gpr_mu mu_; 125 gpr_cv ready_; 126 bool started_; 127 thd_info* info_; 128 }; 129 130 } // namespace 131 132 namespace grpc_core { 133 134 Thread::Thread(const char* thd_name, void (*thd_body)(void* arg), void* arg, 135 bool* success) { 136 bool outcome = false; 137 impl_ = grpc_core::New<ThreadInternalsWindows>(thd_body, arg, &outcome); 138 if (outcome) { 139 state_ = ALIVE; 140 } else { 141 state_ = FAILED; 142 grpc_core::Delete(impl_); 143 impl_ = nullptr; 144 } 145 146 if (success != nullptr) { 147 *success = outcome; 148 } 149 } 150 151 } // namespace grpc_core 152 153 gpr_thd_id gpr_thd_currentid(void) { return (gpr_thd_id)g_thd_info; } 154 155 #endif /* GPR_WINDOWS */ 156