Home | History | Annotate | Download | only in gprpp
      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