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