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:
ThreadInternalsWindows(void (* thd_body)(void * arg),void * arg,bool * success)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
~ThreadInternalsWindows()100 ~ThreadInternalsWindows() override {
101 gpr_mu_destroy(&mu_);
102 gpr_cv_destroy(&ready_);
103 }
104
Start()105 void Start() override {
106 gpr_mu_lock(&mu_);
107 started_ = true;
108 gpr_cv_signal(&ready_);
109 gpr_mu_unlock(&mu_);
110 }
111
Join()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:
destroy_thread()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
Thread(const char * thd_name,void (* thd_body)(void * arg),void * arg,bool * success)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
gpr_thd_currentid(void)153 gpr_thd_id gpr_thd_currentid(void) { return (gpr_thd_id)g_thd_info; }
154
155 #endif /* GPR_WINDOWS */
156