Built motion from commit 6a09e18b.|2.6.11
[motion2.git] / legacy-libs / grpc-cloned / deps / grpc / src / core / lib / gprpp / thd_windows.cc
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 #elif defined(__GNUC__)
37 #define thread_local __thread
38 #else
39 #error "Unknown compiler - please file a bug report"
40 #endif
41
42 namespace {
43 class ThreadInternalsWindows;
44 struct thd_info {
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 */
50 };
51
52 thread_local struct thd_info* g_thd_info;
53
54 class ThreadInternalsWindows
55     : public grpc_core::internal::ThreadInternalsInterface {
56  public:
57   ThreadInternalsWindows(void (*thd_body)(void* arg), void* arg, bool* success,
58                          const grpc_core::Thread::Options& options)
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     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) {
73         gpr_free(info_);
74         *success = false;
75         return;
76       }
77     }
78
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_,
82                             0, nullptr);
83     } else {
84       handle = CreateThread(nullptr, 64 * 1024, thread_body, info_, 0, nullptr);
85     }
86
87     if (handle == nullptr) {
88       destroy_thread();
89       *success = false;
90     } else {
91       CloseHandle(handle);
92       *success = true;
93     }
94   }
95
96   ~ThreadInternalsWindows() override {
97     gpr_mu_destroy(&mu_);
98     gpr_cv_destroy(&ready_);
99   }
100
101   void Start() override {
102     gpr_mu_lock(&mu_);
103     started_ = true;
104     gpr_cv_signal(&ready_);
105     gpr_mu_unlock(&mu_);
106   }
107
108   void Join() override {
109     DWORD ret = WaitForSingleObject(info_->join_event, INFINITE);
110     GPR_ASSERT(ret == WAIT_OBJECT_0);
111     destroy_thread();
112   }
113
114  private:
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));
121     }
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;
126     }
127     g_thd_info->body(g_thd_info->arg);
128     if (g_thd_info->joinable) {
129       BOOL ret = SetEvent(g_thd_info->join_event);
130       GPR_ASSERT(ret);
131     } else {
132       gpr_free(g_thd_info);
133     }
134     return 0;
135   }
136
137   void destroy_thread() {
138     if (info_ != nullptr && info_->joinable) {
139       CloseHandle(info_->join_event);
140     }
141     gpr_free(info_);
142   }
143
144   gpr_mu mu_;
145   gpr_cv ready_;
146   bool started_;
147   thd_info* info_;
148 };
149
150 }  // namespace
151
152 namespace grpc_core {
153
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);
159   if (outcome) {
160     state_ = ALIVE;
161   } else {
162     state_ = FAILED;
163     Delete(impl_);
164     impl_ = nullptr;
165   }
166
167   if (success != nullptr) {
168     *success = outcome;
169   }
170 }
171
172 }  // namespace grpc_core
173
174 gpr_thd_id gpr_thd_currentid(void) { return (gpr_thd_id)g_thd_info; }
175
176 #endif /* GPR_WINDOWS */