File indexing completed on 2025-09-14 08:27:40
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011 #ifndef BOOST_ASIO_SPAWN_HPP
0012 #define BOOST_ASIO_SPAWN_HPP
0013
0014 #if defined(_MSC_VER) && (_MSC_VER >= 1200)
0015 # pragma once
0016 #endif
0017
0018 #include <boost/asio/detail/config.hpp>
0019 #include <boost/asio/any_io_executor.hpp>
0020 #include <boost/asio/cancellation_signal.hpp>
0021 #include <boost/asio/cancellation_state.hpp>
0022 #include <boost/asio/detail/exception.hpp>
0023 #include <boost/asio/detail/memory.hpp>
0024 #include <boost/asio/detail/type_traits.hpp>
0025 #include <boost/asio/io_context.hpp>
0026 #include <boost/asio/is_executor.hpp>
0027 #include <boost/asio/strand.hpp>
0028
0029 #include <boost/asio/detail/push_options.hpp>
0030
0031 namespace boost {
0032 namespace asio {
0033 namespace detail {
0034
0035
0036 class spawned_thread_base
0037 {
0038 public:
0039 spawned_thread_base()
0040 : owner_(0),
0041 has_context_switched_(false),
0042 throw_if_cancelled_(false),
0043 terminal_(false)
0044 {
0045 }
0046
0047 virtual ~spawned_thread_base() {}
0048 virtual void resume() = 0;
0049 virtual void suspend_with(void (*fn)(void*), void* arg) = 0;
0050 virtual void destroy() = 0;
0051
0052 void attach(spawned_thread_base** owner)
0053 {
0054 owner_ = owner;
0055 *owner_ = this;
0056 }
0057
0058 void detach()
0059 {
0060 if (owner_)
0061 *owner_ = 0;
0062 owner_ = 0;
0063 }
0064
0065 void suspend()
0066 {
0067 suspend_with(0, 0);
0068 }
0069
0070 template <typename F>
0071 void suspend_with(F f)
0072 {
0073 suspend_with(&spawned_thread_base::call<F>, &f);
0074 }
0075
0076 cancellation_slot get_cancellation_slot() const noexcept
0077 {
0078 return cancellation_state_.slot();
0079 }
0080
0081 cancellation_state get_cancellation_state() const noexcept
0082 {
0083 return cancellation_state_;
0084 }
0085
0086 void reset_cancellation_state()
0087 {
0088 cancellation_state_ = cancellation_state(parent_cancellation_slot_);
0089 }
0090
0091 template <typename Filter>
0092 void reset_cancellation_state(Filter filter)
0093 {
0094 cancellation_state_ = cancellation_state(
0095 parent_cancellation_slot_, filter, filter);
0096 }
0097
0098 template <typename InFilter, typename OutFilter>
0099 void reset_cancellation_state(InFilter in_filter, OutFilter out_filter)
0100 {
0101 cancellation_state_ = cancellation_state(
0102 parent_cancellation_slot_, in_filter, out_filter);
0103 }
0104
0105 cancellation_type_t cancelled() const noexcept
0106 {
0107 return cancellation_state_.cancelled();
0108 }
0109
0110 bool has_context_switched() const noexcept
0111 {
0112 return has_context_switched_;
0113 }
0114
0115 bool throw_if_cancelled() const noexcept
0116 {
0117 return throw_if_cancelled_;
0118 }
0119
0120 void throw_if_cancelled(bool value) noexcept
0121 {
0122 throw_if_cancelled_ = value;
0123 }
0124
0125 protected:
0126 spawned_thread_base** owner_;
0127 boost::asio::cancellation_slot parent_cancellation_slot_;
0128 boost::asio::cancellation_state cancellation_state_;
0129 bool has_context_switched_;
0130 bool throw_if_cancelled_;
0131 bool terminal_;
0132
0133 private:
0134
0135 spawned_thread_base(const spawned_thread_base&) = delete;
0136 spawned_thread_base& operator=(const spawned_thread_base&) = delete;
0137
0138 template <typename F>
0139 static void call(void* f)
0140 {
0141 (*static_cast<F*>(f))();
0142 }
0143 };
0144
0145 template <typename T>
0146 struct spawn_signature
0147 {
0148 typedef void type(exception_ptr, T);
0149 };
0150
0151 template <>
0152 struct spawn_signature<void>
0153 {
0154 typedef void type(exception_ptr);
0155 };
0156
0157 template <typename Executor>
0158 class initiate_spawn;
0159
0160 }
0161
0162
0163
0164
0165
0166
0167
0168
0169
0170
0171
0172
0173
0174
0175
0176
0177
0178
0179
0180
0181 template <typename Executor>
0182 class basic_yield_context
0183 {
0184 public:
0185
0186 typedef Executor executor_type;
0187
0188
0189 typedef cancellation_slot cancellation_slot_type;
0190
0191
0192
0193
0194
0195 template <typename OtherExecutor>
0196 basic_yield_context(const basic_yield_context<OtherExecutor>& other,
0197 constraint_t<
0198 is_convertible<OtherExecutor, Executor>::value
0199 > = 0)
0200 : spawned_thread_(other.spawned_thread_),
0201 executor_(other.executor_),
0202 ec_(other.ec_)
0203 {
0204 }
0205
0206
0207 executor_type get_executor() const noexcept
0208 {
0209 return executor_;
0210 }
0211
0212
0213 cancellation_slot_type get_cancellation_slot() const noexcept
0214 {
0215 return spawned_thread_->get_cancellation_slot();
0216 }
0217
0218
0219 cancellation_state get_cancellation_state() const noexcept
0220 {
0221 return spawned_thread_->get_cancellation_state();
0222 }
0223
0224
0225
0226
0227
0228
0229
0230
0231 void reset_cancellation_state() const
0232 {
0233 spawned_thread_->reset_cancellation_state();
0234 }
0235
0236
0237
0238
0239
0240
0241
0242
0243
0244 template <typename Filter>
0245 void reset_cancellation_state(Filter&& filter) const
0246 {
0247 spawned_thread_->reset_cancellation_state(
0248 static_cast<Filter&&>(filter));
0249 }
0250
0251
0252
0253
0254
0255
0256
0257
0258
0259
0260 template <typename InFilter, typename OutFilter>
0261 void reset_cancellation_state(InFilter&& in_filter,
0262 OutFilter&& out_filter) const
0263 {
0264 spawned_thread_->reset_cancellation_state(
0265 static_cast<InFilter&&>(in_filter),
0266 static_cast<OutFilter&&>(out_filter));
0267 }
0268
0269
0270 cancellation_type_t cancelled() const noexcept
0271 {
0272 return spawned_thread_->cancelled();
0273 }
0274
0275
0276
0277 bool throw_if_cancelled() const noexcept
0278 {
0279 return spawned_thread_->throw_if_cancelled();
0280 }
0281
0282
0283
0284 void throw_if_cancelled(bool value) const noexcept
0285 {
0286 spawned_thread_->throw_if_cancelled(value);
0287 }
0288
0289
0290
0291
0292
0293
0294
0295
0296
0297
0298
0299
0300
0301
0302
0303
0304
0305
0306
0307
0308 basic_yield_context operator[](boost::system::error_code& ec) const
0309 {
0310 basic_yield_context tmp(*this);
0311 tmp.ec_ = &ec;
0312 return tmp;
0313 }
0314
0315 #if !defined(GENERATING_DOCUMENTATION)
0316
0317 basic_yield_context(detail::spawned_thread_base* spawned_thread,
0318 const Executor& ex)
0319 : spawned_thread_(spawned_thread),
0320 executor_(ex),
0321 ec_(0)
0322 {
0323 }
0324
0325 detail::spawned_thread_base* spawned_thread_;
0326 Executor executor_;
0327 boost::system::error_code* ec_;
0328 #endif
0329 };
0330
0331
0332
0333 typedef basic_yield_context<any_io_executor> yield_context;
0334
0335
0336
0337
0338
0339
0340
0341
0342
0343
0344
0345
0346
0347
0348
0349
0350
0351
0352
0353
0354
0355
0356
0357
0358
0359
0360
0361
0362
0363
0364
0365
0366
0367
0368
0369
0370
0371
0372
0373
0374
0375
0376
0377
0378
0379
0380
0381
0382
0383
0384
0385
0386
0387
0388
0389
0390
0391
0392
0393
0394
0395
0396
0397
0398
0399 template <typename Executor, typename F,
0400 BOOST_ASIO_COMPLETION_TOKEN_FOR(typename detail::spawn_signature<
0401 result_of_t<F(basic_yield_context<Executor>)>>::type)
0402 CompletionToken = default_completion_token_t<Executor>>
0403 auto spawn(const Executor& ex, F&& function,
0404 CompletionToken&& token = default_completion_token_t<Executor>(),
0405 constraint_t<
0406 is_executor<Executor>::value || execution::is_executor<Executor>::value
0407 > = 0)
0408 -> decltype(
0409 async_initiate<CompletionToken,
0410 typename detail::spawn_signature<
0411 result_of_t<F(basic_yield_context<Executor>)>>::type>(
0412 declval<detail::initiate_spawn<Executor>>(),
0413 token, static_cast<F&&>(function)));
0414
0415
0416
0417
0418
0419
0420
0421
0422
0423
0424
0425
0426
0427
0428
0429
0430
0431
0432
0433
0434
0435
0436
0437
0438
0439
0440
0441
0442
0443
0444 template <typename ExecutionContext, typename F,
0445 BOOST_ASIO_COMPLETION_TOKEN_FOR(typename detail::spawn_signature<
0446 result_of_t<F(basic_yield_context<
0447 typename ExecutionContext::executor_type>)>>::type)
0448 CompletionToken = default_completion_token_t<
0449 typename ExecutionContext::executor_type>>
0450 auto spawn(ExecutionContext& ctx, F&& function,
0451 CompletionToken&& token
0452 = default_completion_token_t<typename ExecutionContext::executor_type>(),
0453 constraint_t<
0454 is_convertible<ExecutionContext&, execution_context&>::value
0455 > = 0)
0456 -> decltype(
0457 async_initiate<CompletionToken,
0458 typename detail::spawn_signature<
0459 result_of_t<F(basic_yield_context<
0460 typename ExecutionContext::executor_type>)>>::type>(
0461 declval<detail::initiate_spawn<
0462 typename ExecutionContext::executor_type>>(),
0463 token, static_cast<F&&>(function)));
0464
0465
0466
0467
0468
0469
0470
0471
0472
0473
0474
0475
0476
0477
0478
0479
0480
0481
0482
0483
0484
0485
0486
0487
0488
0489
0490
0491
0492
0493
0494
0495
0496 template <typename Executor, typename F,
0497 BOOST_ASIO_COMPLETION_TOKEN_FOR(typename detail::spawn_signature<
0498 result_of_t<F(basic_yield_context<Executor>)>>::type)
0499 CompletionToken = default_completion_token_t<Executor>>
0500 auto spawn(const basic_yield_context<Executor>& ctx, F&& function,
0501 CompletionToken&& token = default_completion_token_t<Executor>(),
0502 constraint_t<
0503 is_executor<Executor>::value || execution::is_executor<Executor>::value
0504 > = 0)
0505 -> decltype(
0506 async_initiate<CompletionToken,
0507 typename detail::spawn_signature<
0508 result_of_t<F(basic_yield_context<Executor>)>>::type>(
0509 declval<detail::initiate_spawn<Executor>>(),
0510 token, static_cast<F&&>(function)));
0511
0512 #if defined(BOOST_ASIO_HAS_BOOST_CONTEXT_FIBER) \
0513 || defined(GENERATING_DOCUMENTATION)
0514
0515
0516
0517
0518
0519
0520
0521
0522
0523
0524
0525
0526
0527
0528
0529
0530
0531
0532
0533
0534
0535
0536
0537
0538
0539
0540
0541
0542
0543
0544
0545
0546
0547
0548 template <typename Executor, typename StackAllocator, typename F,
0549 BOOST_ASIO_COMPLETION_TOKEN_FOR(typename detail::spawn_signature<
0550 result_of_t<F(basic_yield_context<Executor>)>>::type)
0551 CompletionToken = default_completion_token_t<Executor>>
0552 auto spawn(const Executor& ex, allocator_arg_t,
0553 StackAllocator&& stack_allocator, F&& function,
0554 CompletionToken&& token = default_completion_token_t<Executor>(),
0555 constraint_t<
0556 is_executor<Executor>::value || execution::is_executor<Executor>::value
0557 > = 0)
0558 -> decltype(
0559 async_initiate<CompletionToken,
0560 typename detail::spawn_signature<
0561 result_of_t<F(basic_yield_context<Executor>)>>::type>(
0562 declval<detail::initiate_spawn<Executor>>(),
0563 token, allocator_arg_t(),
0564 static_cast<StackAllocator&&>(stack_allocator),
0565 static_cast<F&&>(function)));
0566
0567
0568
0569
0570
0571
0572
0573
0574
0575
0576
0577
0578
0579
0580
0581
0582
0583
0584
0585
0586
0587
0588
0589
0590
0591
0592
0593
0594
0595
0596
0597
0598
0599
0600 template <typename ExecutionContext, typename StackAllocator, typename F,
0601 BOOST_ASIO_COMPLETION_TOKEN_FOR(typename detail::spawn_signature<
0602 result_of_t<F(basic_yield_context<
0603 typename ExecutionContext::executor_type>)>>::type)
0604 CompletionToken = default_completion_token_t<
0605 typename ExecutionContext::executor_type>>
0606 auto spawn(ExecutionContext& ctx, allocator_arg_t,
0607 StackAllocator&& stack_allocator, F&& function,
0608 CompletionToken&& token
0609 = default_completion_token_t<typename ExecutionContext::executor_type>(),
0610 constraint_t<
0611 is_convertible<ExecutionContext&, execution_context&>::value
0612 > = 0)
0613 -> decltype(
0614 async_initiate<CompletionToken,
0615 typename detail::spawn_signature<
0616 result_of_t<F(basic_yield_context<
0617 typename ExecutionContext::executor_type>)>>::type>(
0618 declval<detail::initiate_spawn<
0619 typename ExecutionContext::executor_type>>(),
0620 token, allocator_arg_t(),
0621 static_cast<StackAllocator&&>(stack_allocator),
0622 static_cast<F&&>(function)));
0623
0624
0625
0626
0627
0628
0629
0630
0631
0632
0633
0634
0635
0636
0637
0638
0639
0640
0641
0642
0643
0644
0645
0646
0647
0648
0649
0650
0651
0652
0653
0654
0655
0656
0657
0658
0659
0660
0661 template <typename Executor, typename StackAllocator, typename F,
0662 BOOST_ASIO_COMPLETION_TOKEN_FOR(typename detail::spawn_signature<
0663 result_of_t<F(basic_yield_context<Executor>)>>::type)
0664 CompletionToken = default_completion_token_t<Executor>>
0665 auto spawn(const basic_yield_context<Executor>& ctx, allocator_arg_t,
0666 StackAllocator&& stack_allocator, F&& function,
0667 CompletionToken&& token = default_completion_token_t<Executor>(),
0668 constraint_t<
0669 is_executor<Executor>::value || execution::is_executor<Executor>::value
0670 > = 0)
0671 -> decltype(
0672 async_initiate<CompletionToken,
0673 typename detail::spawn_signature<
0674 result_of_t<F(basic_yield_context<Executor>)>>::type>(
0675 declval<detail::initiate_spawn<Executor>>(),
0676 token, allocator_arg_t(),
0677 static_cast<StackAllocator&&>(stack_allocator),
0678 static_cast<F&&>(function)));
0679
0680 #endif
0681
0682
0683
0684
0685 }
0686 }
0687
0688 #include <boost/asio/detail/pop_options.hpp>
0689
0690 #include <boost/asio/impl/spawn.hpp>
0691
0692 #endif