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