summaryrefslogtreecommitdiffstats
path: root/src/rocksdb/port/win/win_thread.h
blob: 1d5b225e6ce4ef99f61872c77c7ff45cfaccf1e0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
//  Copyright (c) 2011-present, Facebook, Inc.  All rights reserved.
//  This source code is licensed under both the GPLv2 (found in the
//  COPYING file in the root directory) and Apache 2.0 License
//  (found in the LICENSE.Apache file in the root directory).
//
// Copyright (c) 2011 The LevelDB Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. See the AUTHORS file for names of contributors.

#pragma once

#include <memory>
#include <functional>
#include <type_traits>

namespace rocksdb {
namespace port {

// This class is a replacement for std::thread
// 2 reasons we do not like std::thread:
//  -- is that it dynamically allocates its internals that are automatically
//     freed when  the thread terminates and not on the destruction of the
//     object. This makes it difficult to control the source of memory
//     allocation 
//  -  This implements Pimpl so we can easily replace the guts of the
//      object in our private version if necessary.
class WindowsThread {

  struct Data;

  std::shared_ptr<Data>  data_;
  unsigned int           th_id_;

  void Init(std::function<void()>&&);

public:

  typedef void* native_handle_type;

  // Construct with no thread
  WindowsThread();

  // Template constructor
  // 
  // This templated constructor accomplishes several things
  //
  // - Allows the class as whole to be not a template
  //
  // - take "universal" references to support both _lvalues and _rvalues
  //
  // -  because this constructor is a catchall case in many respects it
  //    may prevent us from using both the default __ctor, the move __ctor.
  //    Also it may circumvent copy __ctor deletion. To work around this
  //    we make sure this one has at least one argument and eliminate
  //    it from the overload  selection when WindowsThread is the first
  //    argument.
  //
  // - construct with Fx(Ax...) with a variable number of types/arguments.
  //
  // - Gathers together the callable object with its arguments and constructs
  //   a single callable entity
  //
  // - Makes use of std::function to convert it to a specification-template
  //   dependent type that both checks the signature conformance to ensure
  //   that all of the necessary arguments are provided and allows pimpl
  //   implementation.
  template<class Fn,
    class... Args,
    class = typename std::enable_if<
      !std::is_same<typename std::decay<Fn>::type,
                    WindowsThread>::value>::type>
  explicit WindowsThread(Fn&& fx, Args&&... ax) :
      WindowsThread() {

    // Use binder to create a single callable entity
    auto binder = std::bind(std::forward<Fn>(fx),
      std::forward<Args>(ax)...);
    // Use std::function to take advantage of the type erasure
    // so we can still hide implementation within pimpl
    // This also makes sure that the binder signature is compliant
    std::function<void()> target = binder;

    Init(std::move(target));
  }


  ~WindowsThread();

  WindowsThread(const WindowsThread&) = delete;

  WindowsThread& operator=(const WindowsThread&) = delete;

  WindowsThread(WindowsThread&&) noexcept;

  WindowsThread& operator=(WindowsThread&&) noexcept;

  bool joinable() const;

  unsigned int get_id() const { return th_id_; }

  native_handle_type native_handle() const;

  static unsigned hardware_concurrency();

  void join();

  bool detach();

  void swap(WindowsThread&);
};
} // namespace port
} // namespace rocksdb

namespace std {
  inline
  void swap(rocksdb::port::WindowsThread& th1, 
    rocksdb::port::WindowsThread& th2) {
    th1.swap(th2);
  }
} // namespace std