1 //  Copyright (c) 2011-present, Facebook, Inc.  All rights reserved.
2 //  This source code is licensed under both the GPLv2 (found in the
3 //  COPYING file in the root directory) and Apache 2.0 License
4 //  (found in the LICENSE.Apache file in the root directory).
5 //
6 // Copyright (c) 2011 The LevelDB Authors. All rights reserved.
7 // Use of this source code is governed by a BSD-style license that can be
8 // found in the LICENSE file. See the AUTHORS file for names of contributors.
9 
10 #pragma once
11 
12 #ifndef _POSIX_THREADS
13 
14 #include <memory>
15 #include <functional>
16 #include <type_traits>
17 
18 #include "rocksdb/rocksdb_namespace.h"
19 
20 namespace ROCKSDB_NAMESPACE {
21 namespace port {
22 
23 // This class is a replacement for std::thread
24 // 2 reasons we do not like std::thread:
25 //  -- is that it dynamically allocates its internals that are automatically
26 //     freed when  the thread terminates and not on the destruction of the
27 //     object. This makes it difficult to control the source of memory
28 //     allocation
29 //  -  This implements Pimpl so we can easily replace the guts of the
30 //      object in our private version if necessary.
31 class WindowsThread {
32   struct Data;
33 
34   std::shared_ptr<Data>  data_;
35   unsigned int           th_id_;
36 
37   void Init(std::function<void()>&&);
38 
39  public:
40   using native_handle_type = void*;
41 
42   // Construct with no thread
43   WindowsThread();
44 
45   // Template constructor
46   //
47   // This templated constructor accomplishes several things
48   //
49   // - Allows the class as whole to be not a template
50   //
51   // - take "universal" references to support both _lvalues and _rvalues
52   //
53   // -  because this constructor is a catchall case in many respects it
54   //    may prevent us from using both the default __ctor, the move __ctor.
55   //    Also it may circumvent copy __ctor deletion. To work around this
56   //    we make sure this one has at least one argument and eliminate
57   //    it from the overload  selection when WindowsThread is the first
58   //    argument.
59   //
60   // - construct with Fx(Ax...) with a variable number of types/arguments.
61   //
62   // - Gathers together the callable object with its arguments and constructs
63   //   a single callable entity
64   //
65   // - Makes use of std::function to convert it to a specification-template
66   //   dependent type that both checks the signature conformance to ensure
67   //   that all of the necessary arguments are provided and allows pimpl
68   //   implementation.
69   template <class Fn, class... Args,
70             class = typename std::enable_if<!std::is_same<
71                 typename std::decay<Fn>::type, WindowsThread>::value>::type>
WindowsThread(Fn && fx,Args &&...ax)72   explicit WindowsThread(Fn&& fx, Args&&... ax) : WindowsThread() {
73     // Use binder to create a single callable entity
74     auto binder = std::bind(std::forward<Fn>(fx), std::forward<Args>(ax)...);
75     // Use std::function to take advantage of the type erasure
76     // so we can still hide implementation within pimpl
77     // This also makes sure that the binder signature is compliant
78     std::function<void()> target = binder;
79 
80     Init(std::move(target));
81   }
82 
83   ~WindowsThread();
84 
85   WindowsThread(const WindowsThread&) = delete;
86 
87   WindowsThread& operator=(const WindowsThread&) = delete;
88 
89   WindowsThread(WindowsThread&&) noexcept;
90 
91   WindowsThread& operator=(WindowsThread&&) noexcept;
92 
93   bool joinable() const;
94 
get_id()95   unsigned int get_id() const { return th_id_; }
96 
97   native_handle_type native_handle() const;
98 
99   static unsigned hardware_concurrency();
100 
101   void join();
102 
103   bool detach();
104 
105   void swap(WindowsThread&);
106 };
107 } // namespace port
108 }  // namespace ROCKSDB_NAMESPACE
109 
110 namespace std {
swap(ROCKSDB_NAMESPACE::port::WindowsThread & th1,ROCKSDB_NAMESPACE::port::WindowsThread & th2)111 inline void swap(ROCKSDB_NAMESPACE::port::WindowsThread& th1,
112                  ROCKSDB_NAMESPACE::port::WindowsThread& th2) {
113   th1.swap(th2);
114 }
115 } // namespace std
116 
117 #endif  // !_POSIX_THREADS
118