xref: /llvm-project-15.0.7/libcxx/src/thread.cpp (revision e63d087b)
1 //===------------------------- thread.cpp----------------------------------===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 
10 #include "thread"
11 #include "exception"
12 #include "vector"
13 #include "future"
14 #include <sys/types.h>
15 #include <sys/sysctl.h>
16 
17 _LIBCPP_BEGIN_NAMESPACE_STD
18 
19 thread::~thread()
20 {
21     if (__t_ != 0)
22         terminate();
23 }
24 
25 void
26 thread::join()
27 {
28     int ec = pthread_join(__t_, 0);
29 #ifndef _LIBCPP_NO_EXCEPTIONS
30     if (ec)
31         throw system_error(error_code(ec, system_category()), "thread::join failed");
32 #endif  // _LIBCPP_NO_EXCEPTIONS
33     __t_ = 0;
34 }
35 
36 void
37 thread::detach()
38 {
39     int ec = EINVAL;
40     if (__t_ != 0)
41     {
42         ec = pthread_detach(__t_);
43         if (ec == 0)
44             __t_ = 0;
45     }
46 #ifndef _LIBCPP_NO_EXCEPTIONS
47     if (ec)
48         throw system_error(error_code(ec, system_category()), "thread::detach failed");
49 #endif  // _LIBCPP_NO_EXCEPTIONS
50 }
51 
52 unsigned
53 thread::hardware_concurrency()
54 {
55 #if defined(CTL_HW) && defined(HW_NCPU)
56     int n;
57     int mib[2] = {CTL_HW, HW_NCPU};
58     std::size_t s = sizeof(n);
59     sysctl(mib, 2, &n, &s, 0, 0);
60     return n;
61 #else  // defined(CTL_HW) && defined(HW_NCPU)
62     // TODO: grovel through /proc or check cpuid on x86 and similar
63     // instructions on other architectures.
64     return 0;  // Means not computable [thread.thread.static]
65 #endif  // defined(CTL_HW) && defined(HW_NCPU)
66 }
67 
68 namespace this_thread
69 {
70 
71 void
72 sleep_for(const chrono::nanoseconds& ns)
73 {
74     using namespace chrono;
75     if (ns >= nanoseconds::zero())
76     {
77         timespec ts;
78         ts.tv_sec = static_cast<decltype(ts.tv_sec)>(duration_cast<seconds>(ns).count());
79         ts.tv_nsec = static_cast<decltype(ts.tv_nsec)>((ns - seconds(ts.tv_sec)).count());
80         nanosleep(&ts, 0);
81     }
82 }
83 
84 }  // this_thread
85 
86 __thread_specific_ptr<__thread_struct>&
87 __thread_local_data()
88 {
89     static __thread_specific_ptr<__thread_struct> __p;
90     return __p;
91 }
92 
93 // __thread_struct_imp
94 
95 class __thread_struct_imp
96 {
97     typedef vector<__assoc_sub_state*> _AsyncStates;
98     typedef vector<pair<condition_variable*, mutex*> > _Notify;
99 
100     _AsyncStates async_states_;
101     _Notify notify_;
102 
103     __thread_struct_imp(const __thread_struct_imp&);
104     __thread_struct_imp& operator=(const __thread_struct_imp&);
105 public:
106     __thread_struct_imp() {}
107     ~__thread_struct_imp();
108 
109     void notify_all_at_thread_exit(condition_variable* cv, mutex* m);
110     void __make_ready_at_thread_exit(__assoc_sub_state* __s);
111 };
112 
113 __thread_struct_imp::~__thread_struct_imp()
114 {
115     for (_Notify::iterator i = notify_.begin(), e = notify_.end();
116             i != e; ++i)
117     {
118         i->second->unlock();
119         i->first->notify_all();
120     }
121     for (_AsyncStates::iterator i = async_states_.begin(), e = async_states_.end();
122             i != e; ++i)
123     {
124         (*i)->__make_ready();
125         (*i)->__release_shared();
126     }
127 }
128 
129 void
130 __thread_struct_imp::notify_all_at_thread_exit(condition_variable* cv, mutex* m)
131 {
132     notify_.push_back(pair<condition_variable*, mutex*>(cv, m));
133 }
134 
135 void
136 __thread_struct_imp::__make_ready_at_thread_exit(__assoc_sub_state* __s)
137 {
138     async_states_.push_back(__s);
139     __s->__add_shared();
140 }
141 
142 // __thread_struct
143 
144 __thread_struct::__thread_struct()
145     : __p_(new __thread_struct_imp)
146 {
147 }
148 
149 __thread_struct::~__thread_struct()
150 {
151     delete __p_;
152 }
153 
154 void
155 __thread_struct::notify_all_at_thread_exit(condition_variable* cv, mutex* m)
156 {
157     __p_->notify_all_at_thread_exit(cv, m);
158 }
159 
160 void
161 __thread_struct::__make_ready_at_thread_exit(__assoc_sub_state* __s)
162 {
163     __p_->__make_ready_at_thread_exit(__s);
164 }
165 
166 _LIBCPP_END_NAMESPACE_STD
167