summaryrefslogtreecommitdiffstats
path: root/src/rocksdb/port/win/win_thread.h
blob: 916033b77c8ab0a0056c1bee46f478d56ac985b7 (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
//  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

#ifndef _POSIX_THREADS

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

#include "rocksdb/rocksdb_namespace.h"

namespace ROCKSDB_NAMESPACE {
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:
  using native_handle_type = void*;

  // 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

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

#endif  // !_POSIX_THREADS