master
  1//===------------------------- thread.cpp----------------------------------===//
  2//
  3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
  4// See https://llvm.org/LICENSE.txt for license information.
  5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  6//
  7//===----------------------------------------------------------------------===//
  8
  9#include <__system_error/throw_system_error.h>
 10#include <__thread/poll_with_backoff.h>
 11#include <__thread/timed_backoff_policy.h>
 12#include <__utility/pair.h>
 13#include <exception>
 14#include <future>
 15#include <limits>
 16#include <thread>
 17#include <vector>
 18
 19#if __has_include(<unistd.h>)
 20#  include <unistd.h> // for sysconf
 21#endif
 22
 23#if defined(__NetBSD__)
 24#  pragma weak pthread_create // Do not create libpthread dependency
 25#endif
 26
 27#if defined(_LIBCPP_WIN32API)
 28#  include <windows.h>
 29#endif
 30
 31#if defined(__ELF__) && defined(_LIBCPP_LINK_PTHREAD_LIB)
 32#  pragma comment(lib, "pthread")
 33#endif
 34
 35_LIBCPP_BEGIN_NAMESPACE_STD
 36
 37thread::~thread() {
 38  if (!__libcpp_thread_isnull(&__t_))
 39    terminate();
 40}
 41
 42void thread::join() {
 43  int ec = EINVAL;
 44  if (!__libcpp_thread_isnull(&__t_)) {
 45    ec = __libcpp_thread_join(&__t_);
 46    if (ec == 0)
 47      __t_ = _LIBCPP_NULL_THREAD;
 48  }
 49
 50  if (ec)
 51    std::__throw_system_error(ec, "thread::join failed");
 52}
 53
 54void thread::detach() {
 55  int ec = EINVAL;
 56  if (!__libcpp_thread_isnull(&__t_)) {
 57    ec = __libcpp_thread_detach(&__t_);
 58    if (ec == 0)
 59      __t_ = _LIBCPP_NULL_THREAD;
 60  }
 61
 62  if (ec)
 63    std::__throw_system_error(ec, "thread::detach failed");
 64}
 65
 66unsigned thread::hardware_concurrency() noexcept {
 67#if defined(_SC_NPROCESSORS_ONLN)
 68  long result = sysconf(_SC_NPROCESSORS_ONLN);
 69  // sysconf returns -1 if the name is invalid, the option does not exist or
 70  // does not have a definite limit.
 71  // if sysconf returns some other negative number, we have no idea
 72  // what is going on. Default to something safe.
 73  if (result < 0)
 74    return 0;
 75  return static_cast<unsigned>(result);
 76#elif defined(_LIBCPP_WIN32API)
 77  SYSTEM_INFO info;
 78  GetSystemInfo(&info);
 79  return info.dwNumberOfProcessors;
 80#else // defined(CTL_HW) && defined(HW_NCPU)
 81  // TODO: grovel through /proc or check cpuid on x86 and similar
 82  // instructions on other architectures.
 83#  if defined(_LIBCPP_WARNING)
 84  _LIBCPP_WARNING("hardware_concurrency not yet implemented")
 85#  else
 86#    warning hardware_concurrency not yet implemented
 87#  endif
 88  return 0; // Means not computable [thread.thread.static]
 89#endif // defined(CTL_HW) && defined(HW_NCPU)
 90}
 91
 92namespace this_thread {
 93
 94void sleep_for(const chrono::nanoseconds& ns) {
 95  if (ns > chrono::nanoseconds::zero()) {
 96    __libcpp_thread_sleep_for(ns);
 97  }
 98}
 99
100} // namespace this_thread
101
102__thread_specific_ptr<__thread_struct>& __thread_local_data() {
103  // Even though __thread_specific_ptr's destructor doesn't actually destroy
104  // anything (see comments there), we can't call it at all because threads may
105  // outlive the static variable and calling its destructor means accessing an
106  // object outside of its lifetime, which is UB.
107  alignas(__thread_specific_ptr<__thread_struct>) static char __b[sizeof(__thread_specific_ptr<__thread_struct>)];
108  static __thread_specific_ptr<__thread_struct>* __p = new (__b) __thread_specific_ptr<__thread_struct>();
109  return *__p;
110}
111
112// __thread_struct_imp
113
114template <class T>
115class _LIBCPP_HIDDEN __hidden_allocator {
116public:
117  typedef T value_type;
118
119  T* allocate(size_t __n) { return static_cast<T*>(::operator new(__n * sizeof(T))); }
120  void deallocate(T* __p, size_t) { ::operator delete(static_cast<void*>(__p)); }
121
122  size_t max_size() const { return size_t(~0) / sizeof(T); }
123};
124
125class _LIBCPP_HIDDEN __thread_struct_imp {
126  typedef vector<__assoc_sub_state*, __hidden_allocator<__assoc_sub_state*> > _AsyncStates;
127  typedef vector<pair<condition_variable*, mutex*>, __hidden_allocator<pair<condition_variable*, mutex*> > > _Notify;
128
129  _AsyncStates async_states_;
130  _Notify notify_;
131
132  __thread_struct_imp(const __thread_struct_imp&);
133  __thread_struct_imp& operator=(const __thread_struct_imp&);
134
135public:
136  __thread_struct_imp() {}
137  ~__thread_struct_imp();
138
139  void notify_all_at_thread_exit(condition_variable* cv, mutex* m);
140  void __make_ready_at_thread_exit(__assoc_sub_state* __s);
141};
142
143__thread_struct_imp::~__thread_struct_imp() {
144  for (_Notify::iterator i = notify_.begin(), e = notify_.end(); i != e; ++i) {
145    i->first->notify_all();
146    i->second->unlock();
147  }
148  for (_AsyncStates::iterator i = async_states_.begin(), e = async_states_.end(); i != e; ++i) {
149    (*i)->__make_ready();
150    (*i)->__release_shared();
151  }
152}
153
154void __thread_struct_imp::notify_all_at_thread_exit(condition_variable* cv, mutex* m) {
155  notify_.push_back(pair<condition_variable*, mutex*>(cv, m));
156}
157
158void __thread_struct_imp::__make_ready_at_thread_exit(__assoc_sub_state* __s) {
159  async_states_.push_back(__s);
160  __s->__add_shared();
161}
162
163// __thread_struct
164
165__thread_struct::__thread_struct() : __p_(new __thread_struct_imp) {}
166
167__thread_struct::~__thread_struct() { delete __p_; }
168
169void __thread_struct::notify_all_at_thread_exit(condition_variable* cv, mutex* m) {
170  __p_->notify_all_at_thread_exit(cv, m);
171}
172
173void __thread_struct::__make_ready_at_thread_exit(__assoc_sub_state* __s) { __p_->__make_ready_at_thread_exit(__s); }
174
175_LIBCPP_END_NAMESPACE_STD