Seastar
High performance C++ framework for concurrent servers
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Modules Pages
thread.hh
1/*
2 * This file is open source software, licensed to you under the terms
3 * of the Apache License, Version 2.0 (the "License"). See the NOTICE file
4 * distributed with this work for additional information regarding copyright
5 * ownership. You may not use this file except in compliance with the License.
6 *
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing,
12 * software distributed under the License is distributed on an
13 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14 * KIND, either express or implied. See the License for the
15 * specific language governing permissions and limitations
16 * under the License.
17 */
18
19/*
20 * Copyright (C) 2015 Cloudius Systems, Ltd.
21 */
22
23#pragma once
24
25#ifndef SEASTAR_MODULE
26#include <seastar/core/thread_impl.hh>
27#include <seastar/core/future.hh>
28#include <seastar/core/do_with.hh>
29#include <seastar/core/timer.hh>
31#include <memory>
32#include <type_traits>
33#include <seastar/util/std-compat.hh>
34#include <seastar/util/modules.hh>
35#include <ucontext.h>
36#include <boost/intrusive/list.hpp>
37#endif
38
68
70namespace seastar {
71
74SEASTAR_MODULE_EXPORT_BEGIN
75class thread;
76class thread_attributes;
77
80public:
81 std::optional<seastar::scheduling_group> sched_group;
82 // For stack_size 0, a default value will be used (128KiB when writing this comment)
83 size_t stack_size = 0;
84};
85SEASTAR_MODULE_EXPORT_END
86
88extern thread_local jmp_buf_link g_unthreaded_context;
89
90// Internal class holding thread state. We can't hold this in
91// \c thread itself because \c thread is movable, and we want pointers
92// to this state to be captured.
93class thread_context final : private task {
94 struct stack_deleter {
95 void operator()(char *ptr) const noexcept;
96 int valgrind_id;
97 stack_deleter(int valgrind_id);
98 };
99 using stack_holder = std::unique_ptr<char[], stack_deleter>;
100
101 stack_holder _stack;
102 noncopyable_function<void ()> _func;
103 jmp_buf_link _context;
104 promise<> _done;
105 bool _joined = false;
106
107 boost::intrusive::list_member_hook<> _all_link;
108 using all_thread_list = boost::intrusive::list<thread_context,
109 boost::intrusive::member_hook<thread_context, boost::intrusive::list_member_hook<>,
110 &thread_context::_all_link>,
111 boost::intrusive::constant_time_size<false>>;
112
113 static thread_local all_thread_list _all_threads;
114private:
115 static void s_main(int lo, int hi); // all parameters MUST be 'int' for makecontext
116 void setup(size_t stack_size);
117 void main();
118 stack_holder make_stack(size_t stack_size);
119 virtual void run_and_dispose() noexcept override; // from task class
120public:
121 thread_context(thread_attributes attr, noncopyable_function<void ()> func);
122 ~thread_context();
123 void switch_in();
124 void switch_out();
125 bool should_yield() const;
126 void reschedule();
127 void yield();
128 task* waiting_task() noexcept override { return _done.waiting_task(); }
129 friend class thread;
130 friend void thread_impl::switch_in(thread_context*);
131 friend void thread_impl::switch_out(thread_context*);
132 friend scheduling_group thread_impl::sched_group(const thread_context*);
133};
134
136
137SEASTAR_MODULE_EXPORT
144class thread {
145 std::unique_ptr<thread_context> _context;
146 static thread_local thread* _current;
147public:
150 thread() = default;
155 template <typename Func>
156 thread(Func func);
162 template <typename Func>
163 thread(thread_attributes attr, Func func);
165 thread(thread&& x) noexcept = default;
167 thread& operator=(thread&& x) noexcept = default;
171 ~thread() { assert(!_context || _context->_joined); }
176 future<> join();
181 static void yield();
186 static bool should_yield() {
187 return need_preempt();
188 }
189
194 static void maybe_yield() {
195 if (should_yield()) [[unlikely]] {
196 yield();
197 }
198 }
199
200 static bool running_in_thread() {
201 return thread_impl::get() != nullptr;
202 }
203};
204
205template <typename Func>
206inline
208 : _context(std::make_unique<thread_context>(std::move(attr), std::move(func))) {
209}
210
211template <typename Func>
212inline
214 : thread(thread_attributes(), std::move(func)) {
215}
216
217inline
220 _context->_joined = true;
221 return _context->_done.get_future();
222}
223
224SEASTAR_MODULE_EXPORT_BEGIN
248template <typename Func, typename... Args>
249inline
250futurize_t<std::invoke_result_t<Func, Args...>>
251async(thread_attributes attr, Func&& func, Args&&... args) noexcept {
252 using return_type = std::invoke_result_t<Func, Args...>;
253 struct work {
255 Func func;
256 std::tuple<Args...> args;
258 thread th{};
259 };
260
261 try {
262 auto wp = std::make_unique<work>(work{std::move(attr), std::forward<Func>(func), std::forward_as_tuple(std::forward<Args>(args)...)});
263 auto& w = *wp;
264 auto ret = w.pr.get_future();
265 w.th = thread(std::move(w.attr), [&w] {
266 futurize<return_type>::apply(std::move(w.func), std::move(w.args)).forward_to(std::move(w.pr));
267 });
268 return w.th.join().then([ret = std::move(ret)] () mutable {
269 return std::move(ret);
270 }).finally([wp = std::move(wp)] {});
271 } catch (...) {
272 return futurize<return_type>::make_exception_future(std::current_exception());
273 }
274}
275
285template <typename Func, typename... Args>
286inline
287futurize_t<std::invoke_result_t<Func, Args...>>
288async(Func&& func, Args&&... args) noexcept {
289 return async(thread_attributes{}, std::forward<Func>(func), std::forward<Args>(args)...);
290}
292
293SEASTAR_MODULE_EXPORT_END
294}
A representation of a possibly not-yet-computed value.
Definition: future.hh:1219
Definition: task.hh:34
thread - stateful thread of execution
Definition: thread.hh:144
~thread()
Destroys a thread object.
Definition: thread.hh:171
thread(thread &&x) noexcept=default
Moves a thread object.
static void maybe_yield()
Yield if this thread ought to call yield() now.
Definition: thread.hh:194
static void yield()
Voluntarily defer execution of current thread.
thread()=default
Constructs a thread object that does not represent a thread of execution.
static bool should_yield()
Checks whether this thread ought to call yield() now.
Definition: thread.hh:186
thread & operator=(thread &&x) noexcept=default
Move-assigns a thread object.
future yield() noexcept
Returns a future which is not ready but is scheduled to resolve soon.
Class that holds attributes controling the behavior of a thread.
Definition: thread.hh:79
futurize_t< std::invoke_result_t< Func, Args... > > async(thread_attributes attr, Func &&func, Args &&... args) noexcept
Definition: thread.hh:251
future join()
Waits for thread execution to terminate.
Definition: thread.hh:219
Seastar API namespace.
Definition: abort_on_ebadf.hh:26
STL namespace.
Converts a type to a future type, if it isn't already.
Definition: future.hh:1832