source: mainline/uspace/lib/cpp/include/__bits/thread/thread.hpp@ 1621f91

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 1621f91 was b251af5a, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 6 years ago

Remove <lib/cpp/include/bits/common.hpp>, which is no longer necessary

  • Property mode set to 100644
File size: 8.5 KB
Line 
1/*
2 * Copyright (c) 2018 Jaroslav Jindrak
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29#ifndef LIBCPP_BITS_THREAD
30#define LIBCPP_BITS_THREAD
31
32#include <__bits/thread/threading.hpp>
33#include <chrono>
34#include <ostream>
35
36namespace std
37{
38 namespace aux
39 {
40 template<class Callable>
41 int thread_main(void*);
42
43 /**
44 * Fibrils in HelenOS are not joinable. They were
45 * in the past, but that functionality was removed from them
46 * so we created a workaround using a conditional variable that
47 * comprises the following two wrapper classes.
48 */
49 class joinable_wrapper
50 {
51 public:
52 joinable_wrapper()
53 : join_mtx_{}, join_cv_{},
54 finished_{false}, detached_{false}
55 {
56 aux::threading::mutex::init(join_mtx_);
57 aux::threading::condvar::init(join_cv_);
58 }
59
60 void join()
61 {
62 aux::threading::mutex::lock(join_mtx_);
63 while (!finished_)
64 aux::threading::condvar::wait(join_cv_, join_mtx_);
65 aux::threading::mutex::unlock(join_mtx_);
66 }
67
68 bool finished() const
69 {
70 return finished_;
71 }
72
73 void detach()
74 {
75 detached_ = true;
76 }
77
78 bool detached() const
79 {
80 return detached_;
81 }
82
83 protected:
84 aux::mutex_t join_mtx_;
85 aux::condvar_t join_cv_;
86 bool finished_;
87 bool detached_;
88 };
89
90 template<class Callable>
91 class callable_wrapper: public joinable_wrapper
92 {
93 public:
94 callable_wrapper(Callable&& clbl)
95 : joinable_wrapper{}, callable_{forward<Callable>(clbl)}
96 { /* DUMMY BODY */ }
97
98 void operator()()
99 {
100 callable_();
101
102 aux::threading::mutex::lock(join_mtx_);
103 finished_ = true;
104 aux::threading::mutex::unlock(join_mtx_);
105
106 aux::threading::condvar::broadcast(join_cv_);
107 }
108
109 private:
110 Callable callable_;
111 };
112 }
113
114 /**
115 * 30.3.1, class thread:
116 */
117
118 class thread
119 {
120 public:
121 class id;
122
123 using native_handle_type = aux::thread_t*;
124
125 /**
126 * 30.3.1.2, thread constructors:
127 * 30.3.1.3, thread destructor:
128 * 30.3.1.4, thread assignment:
129 */
130
131 thread() noexcept;
132
133 ~thread();
134
135 // TODO: check the remark in the standard
136 template<class F, class... Args>
137 explicit thread(F&& f, Args&&... args)
138 : id_{}
139 {
140 auto callable = [=](){
141 return f(forward<Args>(args)...);
142 };
143
144 auto callable_wrapper = new aux::callable_wrapper<decltype(callable)>{move(callable)};
145 joinable_wrapper_ = static_cast<aux::joinable_wrapper*>(callable_wrapper);
146
147 id_ = aux::threading::thread::create(
148 aux::thread_main<decltype(callable_wrapper)>,
149 *callable_wrapper
150 );
151
152 aux::threading::thread::start(id_);
153 // TODO: fibrils are weird here, 2 returns with same thread ids
154 }
155
156 thread(const thread&) = delete;
157 thread& operator=(const thread&) = delete;
158
159 thread(thread&& other) noexcept;
160 thread& operator=(thread&& other) noexcept;
161
162 /**
163 * 30.3.1.5, thread members:
164 */
165
166 void swap(thread& other) noexcept;
167
168 bool joinable() const noexcept;
169
170 void join();
171
172 void detach();
173
174 id get_id() const noexcept;
175
176 native_handle_type native_handle();
177
178 static unsigned hardware_concurrency() noexcept;
179
180 private:
181 aux::thread_t id_;
182 aux::joinable_wrapper* joinable_wrapper_{nullptr};
183
184 template<class Callable>
185 friend int aux::thread_main(void*);
186 };
187
188 namespace aux
189 {
190 template<class CallablePtr>
191 int thread_main(void* clbl)
192 {
193 if (!clbl)
194 return 1;
195
196 auto callable = static_cast<CallablePtr>(clbl);
197 (*callable)();
198
199 if (callable->detached())
200 delete callable;
201
202 return 0;
203 }
204 }
205
206 void swap(thread& x, thread& y) noexcept;
207
208 /**
209 * 30.3.2, namespace this_thread:
210 */
211
212 namespace this_thread
213 {
214 thread::id get_id() noexcept;
215
216 void yield() noexcept;
217
218 template<class Clock, class Duration>
219 void sleep_until(const chrono::time_point<Clock, Duration>& abs_time)
220 {
221 auto now = Clock::now();
222
223 auto time = aux::threading::time::convert(abs_time - now);
224 aux::threading::time::sleep(time);
225 }
226
227 template<class Rep, class Period>
228 void sleep_for(const chrono::duration<Rep, Period>& rel_time)
229 {
230 if (rel_time <= chrono::duration<Rep, Period>::zero())
231 return;
232
233 // TODO: timeouts?
234 auto time = aux::threading::time::convert(rel_time);
235 aux::threading::time::sleep(time);
236 }
237 }
238
239 template<class T>
240 struct hash;
241
242 class thread::id
243 {
244 public:
245 constexpr id() noexcept
246 : id_{}
247 { /* DUMMY BODY */ }
248
249 private:
250 aux::thread_t id_;
251
252 id(aux::thread_t id)
253 : id_{id}
254 { /* DUMMY BODY */ }
255
256 friend class thread;
257
258 friend bool operator==(thread::id, thread::id) noexcept;
259 friend bool operator!=(thread::id, thread::id) noexcept;
260 friend bool operator<(thread::id, thread::id) noexcept;
261 friend bool operator<=(thread::id, thread::id) noexcept;
262 friend bool operator>(thread::id, thread::id) noexcept;
263 friend bool operator>=(thread::id, thread::id) noexcept;
264
265 template<class Char, class Traits>
266 friend basic_ostream<Char, Traits>& operator<<(
267 basic_ostream<Char, Traits>&, thread::id);
268
269 friend struct hash<id>;
270
271 friend id this_thread::get_id() noexcept;
272 };
273
274 bool operator==(thread::id lhs, thread::id rhs) noexcept;
275 bool operator!=(thread::id lhs, thread::id rhs) noexcept;
276 bool operator<(thread::id lhs, thread::id rhs) noexcept;
277 bool operator<=(thread::id lhs, thread::id rhs) noexcept;
278 bool operator>(thread::id lhs, thread::id rhs) noexcept;
279 bool operator>=(thread::id lhs, thread::id rhs) noexcept;
280
281 template<class Char, class Traits>
282 basic_ostream<Char, Traits>& operator<<(basic_ostream<Char, Traits>& out, thread::id id)
283 {
284 out << id.id_;
285
286 return out;
287 }
288
289 template<> // TODO: implement
290 struct hash<thread::id>;
291}
292
293#endif
Note: See TracBrowser for help on using the repository browser.