]> git.proxmox.com Git - ceph.git/blame - ceph/src/boost/boost/fiber/context.hpp
import quincy beta 17.1.0
[ceph.git] / ceph / src / boost / boost / fiber / context.hpp
CommitLineData
7c673cae
FG
1
2// Copyright Oliver Kowalke 2013.
3// Distributed under the Boost Software License, Version 1.0.
4// (See accompanying file LICENSE_1_0.txt or copy at
5// http://www.boost.org/LICENSE_1_0.txt)
6
7#ifndef BOOST_FIBERS_CONTEXT_H
8#define BOOST_FIBERS_CONTEXT_H
9
10#include <atomic>
11#include <chrono>
b32b8144 12#include <cstdint>
7c673cae
FG
13#include <exception>
14#include <functional>
b32b8144 15#include <iostream>
7c673cae
FG
16#include <map>
17#include <memory>
b32b8144 18#include <tuple>
7c673cae 19#include <type_traits>
f67539c2 20#include <utility>
7c673cae
FG
21
22#include <boost/assert.hpp>
23#include <boost/config.hpp>
92f5a8d4 24#include <boost/core/ignore_unused.hpp>
b32b8144 25#if defined(BOOST_NO_CXX17_STD_APPLY)
7c673cae 26#include <boost/context/detail/apply.hpp>
b32b8144 27#endif
11fdf7f2 28#include <boost/context/fiber.hpp>
7c673cae
FG
29#include <boost/context/stack_context.hpp>
30#include <boost/intrusive/list.hpp>
31#include <boost/intrusive/parent_from_member.hpp>
32#include <boost/intrusive_ptr.hpp>
33#include <boost/intrusive/set.hpp>
b32b8144 34#include <boost/intrusive/slist.hpp>
7c673cae
FG
35
36#include <boost/fiber/detail/config.hpp>
37#include <boost/fiber/detail/data.hpp>
38#include <boost/fiber/detail/decay_copy.hpp>
39#include <boost/fiber/detail/fss.hpp>
40#include <boost/fiber/detail/spinlock.hpp>
7c673cae
FG
41#include <boost/fiber/exceptions.hpp>
42#include <boost/fiber/fixedsize_stack.hpp>
43#include <boost/fiber/policy.hpp>
44#include <boost/fiber/properties.hpp>
45#include <boost/fiber/segmented_stack.hpp>
46#include <boost/fiber/type.hpp>
20effc67 47#include <boost/fiber/waker.hpp>
7c673cae
FG
48
49#ifdef BOOST_HAS_ABI_HEADERS
50# include BOOST_ABI_PREFIX
51#endif
52
53#ifdef _MSC_VER
54# pragma warning(push)
55# pragma warning(disable:4251)
56#endif
57
58namespace boost {
59namespace fibers {
60
61class context;
62class fiber;
63class scheduler;
64
65namespace detail {
66
7c673cae
FG
67struct ready_tag;
68typedef intrusive::list_member_hook<
69 intrusive::tag< ready_tag >,
70 intrusive::link_mode<
71 intrusive::auto_unlink
72 >
73> ready_hook;
74
75struct sleep_tag;
76typedef intrusive::set_member_hook<
77 intrusive::tag< sleep_tag >,
78 intrusive::link_mode<
79 intrusive::auto_unlink
80 >
81> sleep_hook;
82
7c673cae
FG
83struct worker_tag;
84typedef intrusive::list_member_hook<
85 intrusive::tag< worker_tag >,
86 intrusive::link_mode<
87 intrusive::auto_unlink
88 >
89> worker_hook;
90
b32b8144
FG
91struct terminated_tag;
92typedef intrusive::slist_member_hook<
93 intrusive::tag< terminated_tag >,
94 intrusive::link_mode<
95 intrusive::safe_link
96 >
97> terminated_hook;
7c673cae 98
b32b8144
FG
99struct remote_ready_tag;
100typedef intrusive::slist_member_hook<
101 intrusive::tag< remote_ready_tag >,
102 intrusive::link_mode<
103 intrusive::safe_link
104 >
105> remote_ready_hook;
7c673cae 106
b32b8144 107}
7c673cae
FG
108
109class BOOST_FIBERS_DECL context {
110private:
b32b8144
FG
111 friend class dispatcher_context;
112 friend class main_context;
113 template< typename Fn, typename ... Arg > friend class worker_context;
7c673cae
FG
114 friend class scheduler;
115
7c673cae
FG
116 struct fss_data {
117 void * vp{ nullptr };
118 detail::fss_cleanup_function::ptr_t cleanup_function{};
119
f67539c2 120 fss_data() noexcept = default;
7c673cae
FG
121
122 fss_data( void * vp_,
f67539c2 123 detail::fss_cleanup_function::ptr_t fn) noexcept :
7c673cae 124 vp( vp_),
f67539c2 125 cleanup_function(std::move( fn)) {
7c673cae
FG
126 BOOST_ASSERT( cleanup_function);
127 }
128
129 void do_cleanup() {
130 ( * cleanup_function)( vp);
131 }
132 };
133
b32b8144 134 typedef std::map< uintptr_t, fss_data > fss_data_t;
7c673cae
FG
135
136#if ! defined(BOOST_FIBERS_NO_ATOMICS)
b32b8144 137 std::atomic< std::size_t > use_count_;
7c673cae 138#else
b32b8144 139 std::size_t use_count_;
7c673cae 140#endif
b32b8144
FG
141#if ! defined(BOOST_FIBERS_NO_ATOMICS)
142 detail::remote_ready_hook remote_ready_hook_{};
7c673cae 143#endif
b32b8144
FG
144 detail::spinlock splk_{};
145 bool terminated_{ false };
20effc67 146 wait_queue wait_queue_{};
7c673cae 147public:
b32b8144 148#if ! defined(BOOST_FIBERS_NO_ATOMICS)
20effc67 149 std::atomic<size_t> waker_epoch_{ 0 };
b32b8144 150#endif
7c673cae 151private:
b32b8144
FG
152 scheduler * scheduler_{ nullptr };
153 fss_data_t fss_data_{};
154 detail::sleep_hook sleep_hook_{};
20effc67 155 waker sleep_waker_{};
b32b8144
FG
156 detail::ready_hook ready_hook_{};
157 detail::terminated_hook terminated_hook_{};
158 detail::worker_hook worker_hook_{};
159 fiber_properties * properties_{ nullptr };
11fdf7f2 160 boost::context::fiber c_{};
b32b8144
FG
161 std::chrono::steady_clock::time_point tp_;
162 type type_;
163 launch policy_;
164
165 context( std::size_t initial_count, type t, launch policy) noexcept :
166 use_count_{ initial_count },
167 tp_{ (std::chrono::steady_clock::time_point::max)() },
168 type_{ t },
169 policy_{ policy } {
170 }
7c673cae
FG
171
172public:
173 class id {
174 private:
175 context * impl_{ nullptr };
176
177 public:
b32b8144 178 id() = default;
7c673cae
FG
179
180 explicit id( context * impl) noexcept :
b32b8144 181 impl_{ impl } {
7c673cae
FG
182 }
183
184 bool operator==( id const& other) const noexcept {
185 return impl_ == other.impl_;
186 }
187
188 bool operator!=( id const& other) const noexcept {
189 return impl_ != other.impl_;
190 }
191
192 bool operator<( id const& other) const noexcept {
193 return impl_ < other.impl_;
194 }
195
196 bool operator>( id const& other) const noexcept {
197 return other.impl_ < impl_;
198 }
199
200 bool operator<=( id const& other) const noexcept {
201 return ! ( * this > other);
202 }
203
204 bool operator>=( id const& other) const noexcept {
205 return ! ( * this < other);
206 }
207
208 template< typename charT, class traitsT >
209 friend std::basic_ostream< charT, traitsT > &
210 operator<<( std::basic_ostream< charT, traitsT > & os, id const& other) {
211 if ( nullptr != other.impl_) {
212 return os << other.impl_;
7c673cae 213 }
f67539c2 214 return os << "{not-valid}";
7c673cae
FG
215 }
216
217 explicit operator bool() const noexcept {
218 return nullptr != impl_;
219 }
220
221 bool operator!() const noexcept {
222 return nullptr == impl_;
223 }
224 };
225
226 static context * active() noexcept;
227
228 static void reset_active() noexcept;
229
7c673cae 230 context( context const&) = delete;
11fdf7f2 231 context( context &&) = delete;
7c673cae 232 context & operator=( context const&) = delete;
11fdf7f2 233 context & operator=( context &&) = delete;
7c673cae 234
20effc67
TL
235 #if !defined(BOOST_EMBTC)
236
b32b8144
FG
237 friend bool
238 operator==( context const& lhs, context const& rhs) noexcept {
239 return & lhs == & rhs;
240 }
241
20effc67
TL
242 #else
243
244 friend bool
245 operator==( context const& lhs, context const& rhs) noexcept;
246
247 #endif
248
7c673cae
FG
249 virtual ~context();
250
b32b8144
FG
251 scheduler * get_scheduler() const noexcept {
252 return scheduler_;
253 }
7c673cae
FG
254
255 id get_id() const noexcept;
256
b32b8144 257 bool is_resumable() const noexcept {
f67539c2 258 return static_cast<bool>(c_);
b32b8144
FG
259 }
260
7c673cae
FG
261 void resume() noexcept;
262 void resume( detail::spinlock_lock &) noexcept;
263 void resume( context *) noexcept;
264
265 void suspend() noexcept;
266 void suspend( detail::spinlock_lock &) noexcept;
267
11fdf7f2
TL
268 boost::context::fiber suspend_with_cc() noexcept;
269 boost::context::fiber terminate() noexcept;
b32b8144 270
7c673cae
FG
271 void join();
272
273 void yield() noexcept;
274
275 bool wait_until( std::chrono::steady_clock::time_point const&) noexcept;
276 bool wait_until( std::chrono::steady_clock::time_point const&,
20effc67
TL
277 detail::spinlock_lock &,
278 waker &&) noexcept;
279
280 bool wake(const size_t) noexcept;
281
282 waker create_waker() noexcept {
283 // this operation makes all previously created wakers to be outdated
284 return { this, ++waker_epoch_ };
285 }
7c673cae 286
b32b8144 287 void schedule( context *) noexcept;
7c673cae
FG
288
289 bool is_context( type t) const noexcept {
290 return type::none != ( type_ & t);
291 }
292
7c673cae
FG
293 void * get_fss_data( void const * vp) const;
294
295 void set_fss_data(
296 void const * vp,
297 detail::fss_cleanup_function::ptr_t const& cleanup_fn,
298 void * data,
299 bool cleanup_existing);
300
301 void set_properties( fiber_properties * props) noexcept;
302
303 fiber_properties * get_properties() const noexcept {
304 return properties_;
305 }
306
307 launch get_policy() const noexcept {
308 return policy_;
309 }
310
b32b8144
FG
311 bool worker_is_linked() const noexcept;
312
7c673cae
FG
313 bool ready_is_linked() const noexcept;
314
b32b8144
FG
315 bool remote_ready_is_linked() const noexcept;
316
7c673cae
FG
317 bool sleep_is_linked() const noexcept;
318
319 bool terminated_is_linked() const noexcept;
320
b32b8144
FG
321 template< typename List >
322 void worker_link( List & lst) noexcept {
323 static_assert( std::is_same< typename List::value_traits::hook_type, detail::worker_hook >::value, "not a worker-queue");
324 BOOST_ASSERT( ! worker_is_linked() );
325 lst.push_back( * this);
326 }
7c673cae
FG
327
328 template< typename List >
329 void ready_link( List & lst) noexcept {
330 static_assert( std::is_same< typename List::value_traits::hook_type, detail::ready_hook >::value, "not a ready-queue");
b32b8144
FG
331 BOOST_ASSERT( ! ready_is_linked() );
332 lst.push_back( * this);
333 }
334
335 template< typename List >
336 void remote_ready_link( List & lst) noexcept {
337 static_assert( std::is_same< typename List::value_traits::hook_type, detail::remote_ready_hook >::value, "not a remote-ready-queue");
338 BOOST_ASSERT( ! remote_ready_is_linked() );
7c673cae
FG
339 lst.push_back( * this);
340 }
341
342 template< typename Set >
343 void sleep_link( Set & set) noexcept {
344 static_assert( std::is_same< typename Set::value_traits::hook_type,detail::sleep_hook >::value, "not a sleep-queue");
b32b8144 345 BOOST_ASSERT( ! sleep_is_linked() );
7c673cae
FG
346 set.insert( * this);
347 }
348
349 template< typename List >
350 void terminated_link( List & lst) noexcept {
351 static_assert( std::is_same< typename List::value_traits::hook_type, detail::terminated_hook >::value, "not a terminated-queue");
b32b8144 352 BOOST_ASSERT( ! terminated_is_linked() );
7c673cae
FG
353 lst.push_back( * this);
354 }
355
b32b8144 356 void worker_unlink() noexcept;
7c673cae
FG
357
358 void ready_unlink() noexcept;
359
360 void sleep_unlink() noexcept;
361
7c673cae
FG
362 void detach() noexcept;
363
364 void attach( context *) noexcept;
365
20effc67
TL
366 #if !defined(BOOST_EMBTC)
367
7c673cae
FG
368 friend void intrusive_ptr_add_ref( context * ctx) noexcept {
369 BOOST_ASSERT( nullptr != ctx);
b32b8144 370 ctx->use_count_.fetch_add( 1, std::memory_order_relaxed);
7c673cae
FG
371 }
372
373 friend void intrusive_ptr_release( context * ctx) noexcept {
374 BOOST_ASSERT( nullptr != ctx);
b32b8144
FG
375 if ( 1 == ctx->use_count_.fetch_sub( 1, std::memory_order_release) ) {
376 std::atomic_thread_fence( std::memory_order_acquire);
11fdf7f2 377 boost::context::fiber c = std::move( ctx->c_);
7c673cae
FG
378 // destruct context
379 ctx->~context();
380 // deallocated stack
11fdf7f2 381 std::move( c).resume();
7c673cae
FG
382 }
383 }
20effc67
TL
384
385 #else
386
387 friend void intrusive_ptr_add_ref( context * ctx) noexcept;
388 friend void intrusive_ptr_release( context * ctx) noexcept;
389
390 #endif
391
7c673cae
FG
392};
393
20effc67
TL
394#if defined(BOOST_EMBTC)
395
396 inline bool
397 operator==( context const& lhs, context const& rhs) noexcept {
398 return & lhs == & rhs;
399 }
400
401 inline void intrusive_ptr_add_ref( context * ctx) noexcept {
402 BOOST_ASSERT( nullptr != ctx);
403 ctx->use_count_.fetch_add( 1, std::memory_order_relaxed);
404 }
405
406 inline void intrusive_ptr_release( context * ctx) noexcept {
407 BOOST_ASSERT( nullptr != ctx);
408 if ( 1 == ctx->use_count_.fetch_sub( 1, std::memory_order_release) ) {
409 std::atomic_thread_fence( std::memory_order_acquire);
410 boost::context::fiber c = std::move( ctx->c_);
411 // destruct context
412 ctx->~context();
413 // deallocated stack
414 std::move( c).resume();
415 }
416 }
417
418#endif
419
7c673cae
FG
420inline
421bool operator<( context const& l, context const& r) noexcept {
422 return l.get_id() < r.get_id();
423}
424
b32b8144
FG
425template< typename Fn, typename ... Arg >
426class worker_context final : public context {
427private:
428 typename std::decay< Fn >::type fn_;
429 std::tuple< Arg ... > arg_;
430
11fdf7f2
TL
431 boost::context::fiber
432 run_( boost::context::fiber && c) {
b32b8144
FG
433 {
434 // fn and tpl must be destroyed before calling terminate()
435 auto fn = std::move( fn_);
436 auto arg = std::move( arg_);
11fdf7f2
TL
437#if (defined(BOOST_USE_UCONTEXT)||defined(BOOST_USE_WINFIB))
438 std::move( c).resume();
92f5a8d4
TL
439#else
440 boost::ignore_unused(c);
11fdf7f2 441#endif
b32b8144
FG
442#if defined(BOOST_NO_CXX17_STD_APPLY)
443 boost::context::detail::apply( std::move( fn), std::move( arg) );
444#else
445 std::apply( std::move( fn), std::move( arg) );
446#endif
447 }
448 // terminate context
449 return terminate();
450 }
451
452public:
453 template< typename StackAlloc >
454 worker_context( launch policy,
11fdf7f2 455 boost::context::preallocated const& palloc, StackAlloc && salloc,
b32b8144
FG
456 Fn && fn, Arg ... arg) :
457 context{ 1, type::worker_context, policy },
458 fn_( std::forward< Fn >( fn) ),
459 arg_( std::forward< Arg >( arg) ... ) {
11fdf7f2
TL
460 c_ = boost::context::fiber{ std::allocator_arg, palloc, std::forward< StackAlloc >( salloc),
461 std::bind( & worker_context::run_, this, std::placeholders::_1) };
462#if (defined(BOOST_USE_UCONTEXT)||defined(BOOST_USE_WINFIB))
463 c_ = std::move( c_).resume();
464#endif
b32b8144
FG
465 }
466};
467
468
469template< typename StackAlloc, typename Fn, typename ... Arg >
7c673cae 470static intrusive_ptr< context > make_worker_context( launch policy,
11fdf7f2 471 StackAlloc && salloc,
b32b8144
FG
472 Fn && fn, Arg ... arg) {
473 typedef worker_context< Fn, Arg ... > context_t;
474
475 auto sctx = salloc.allocate();
7c673cae 476 // reserve space for control structure
b32b8144
FG
477 void * storage = reinterpret_cast< void * >(
478 ( reinterpret_cast< uintptr_t >( sctx.sp) - static_cast< uintptr_t >( sizeof( context_t) ) )
479 & ~ static_cast< uintptr_t >( 0xff) );
480 void * stack_bottom = reinterpret_cast< void * >(
481 reinterpret_cast< uintptr_t >( sctx.sp) - static_cast< uintptr_t >( sctx.size) );
482 const std::size_t size = reinterpret_cast< uintptr_t >( storage) - reinterpret_cast< uintptr_t >( stack_bottom);
7c673cae 483 // placement new of context on top of fiber's stack
b32b8144
FG
484 return intrusive_ptr< context >{
485 new ( storage) context_t{
7c673cae 486 policy,
b32b8144 487 boost::context::preallocated{ storage, size, sctx },
11fdf7f2 488 std::forward< StackAlloc >( salloc),
7c673cae 489 std::forward< Fn >( fn),
b32b8144 490 std::forward< Arg >( arg) ... } };
7c673cae
FG
491}
492
20effc67 493}}
7c673cae
FG
494
495#ifdef _MSC_VER
496# pragma warning(pop)
497#endif
498
499#ifdef BOOST_HAS_ABI_HEADERS
500# include BOOST_ABI_SUFFIX
501#endif
502
503#endif // BOOST_FIBERS_CONTEXT_H