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 #include <memory>
13 #include <functional>
14 #include <type_traits>
15
16 #include "rocksdb/rocksdb_namespace.h"
17
18 namespace ROCKSDB_NAMESPACE {
19 namespace port {
20
21 // This class is a replacement for std::thread
22 // 2 reasons we do not like std::thread:
23 // -- is that it dynamically allocates its internals that are automatically
24 // freed when the thread terminates and not on the destruction of the
25 // object. This makes it difficult to control the source of memory
26 // allocation
27 // - This implements Pimpl so we can easily replace the guts of the
28 // object in our private version if necessary.
29 class WindowsThread {
30
31 struct Data;
32
33 std::shared_ptr<Data> data_;
34 unsigned int th_id_;
35
36 void Init(std::function<void()>&&);
37
38 public:
39
40 typedef void* native_handle_type;
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,
70 class... Args,
71 class = typename std::enable_if<
72 !std::is_same<typename std::decay<Fn>::type,
73 WindowsThread>::value>::type>
WindowsThread(Fn && fx,Args &&...ax)74 explicit WindowsThread(Fn&& fx, Args&&... ax) :
75 WindowsThread() {
76
77 // Use binder to create a single callable entity
78 auto binder = std::bind(std::forward<Fn>(fx),
79 std::forward<Args>(ax)...);
80 // Use std::function to take advantage of the type erasure
81 // so we can still hide implementation within pimpl
82 // This also makes sure that the binder signature is compliant
83 std::function<void()> target = binder;
84
85 Init(std::move(target));
86 }
87
88
89 ~WindowsThread();
90
91 WindowsThread(const WindowsThread&) = delete;
92
93 WindowsThread& operator=(const WindowsThread&) = delete;
94
95 WindowsThread(WindowsThread&&) noexcept;
96
97 WindowsThread& operator=(WindowsThread&&) noexcept;
98
99 bool joinable() const;
100
get_id()101 unsigned int get_id() const { return th_id_; }
102
103 native_handle_type native_handle() const;
104
105 static unsigned hardware_concurrency();
106
107 void join();
108
109 bool detach();
110
111 void swap(WindowsThread&);
112 };
113 } // namespace port
114 } // namespace ROCKSDB_NAMESPACE
115
116 namespace std {
swap(ROCKSDB_NAMESPACE::port::WindowsThread & th1,ROCKSDB_NAMESPACE::port::WindowsThread & th2)117 inline void swap(ROCKSDB_NAMESPACE::port::WindowsThread& th1,
118 ROCKSDB_NAMESPACE::port::WindowsThread& th2) {
119 th1.swap(th2);
120 }
121 } // namespace std
122
123