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