MySQL 8.0.37
Source Code Documentation
executor.h
Go to the documentation of this file.
1/*
2 Copyright (c) 2020, 2024, Oracle and/or its affiliates.
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License, version 2.0,
6 as published by the Free Software Foundation.
7
8 This program is designed to work with certain software (including
9 but not limited to OpenSSL) that is licensed under separate terms,
10 as designated in a particular file or component or in included license
11 documentation. The authors of MySQL hereby grant you an additional
12 permission to link the program and your derivative works with the
13 separately licensed software that they have either included with
14 the program or referenced in the documentation.
15
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
20
21 You should have received a copy of the GNU General Public License
22 along with this program; if not, write to the Free Software
23 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
24*/
25
26#ifndef MYSQL_HARNESS_NET_TS_EXECUTOR_H_
27#define MYSQL_HARNESS_NET_TS_EXECUTOR_H_
28
29#include <algorithm> // for_each
30#include <condition_variable>
31#include <functional>
32#include <list>
33#include <memory> // allocator
34#include <mutex>
35#include <queue>
36#include <stdexcept> // logic_error
37#include <thread>
38#include <type_traits> // decay_t, enable_if
39#include <typeindex>
40#include <unordered_map>
41#include <utility>
42
43#include "my_compiler.h"
46
47namespace net {
48enum class fork_event { prepare, parent, child };
49
50// 13.3 [async.async.result]
51template <class CompletionToken, class Signature>
52class async_result;
53
54template <class CompletionToken, class Signature>
56 public:
57 using completion_handler_type = CompletionToken;
58 using return_type = void;
59
61 async_result(const async_result &) = delete;
63
65};
66
67// 13.4 [async.async.completion]
68template <class CompletionToken, class Signature>
69class async_completion;
70
71template <class CompletionToken, class Signature>
74
75 public:
77
78 private:
79 using handler_type = std::conditional_t<
80 std::is_same<CompletionToken, completion_handler_type>::value,
82
83 public:
84 explicit async_completion(CompletionToken &t)
85 : completion_handler{std::forward<handler_type>(t)},
89
92};
93
94// 13.5 [async.assoc.alloc]
95
97MY_COMPILER_CLANG_DIAGNOSTIC_IGNORE("-Wdeprecated-declarations")
98
99template <class T, class ProtoAllocator = std::allocator<void>>
101
102template <class T, class ProtoAllocator = std::allocator<void>>
104 typename associated_allocator<T, ProtoAllocator>::type;
105
107
108template <class T, class ProtoAllocator, typename = std::void_t<>>
110 using type = ProtoAllocator;
111
112 static type __get(const T & /* t */, const ProtoAllocator &a) noexcept {
113 return a;
114 }
115};
116
117template <class T, class ProtoAllocator>
118struct associated_allocator_impl<T, ProtoAllocator,
119 std::void_t<typename T::allocator_type>> {
120 using type = typename T::allocator_type;
121
122 static type __get(const T &t, const ProtoAllocator & /* a */) noexcept {
123 return t.get_allocator();
124 }
125};
126
127template <class T, class ProtoAllocator>
129 static auto get(const T &t,
130 const ProtoAllocator &a = ProtoAllocator()) noexcept {
132 return Impl::__get(t, a);
133 }
134};
135
136// 13.6 [async.assoc.alloc.get]
137template <class T>
140}
141
142template <class T, class ProtoAllocator>
144 const T &t, const ProtoAllocator &a) noexcept {
145 return associated_allocator<T>::get(t, a);
146}
147
148// 13.7 [async.exec.ctx]
149class service_already_exists : public std::logic_error {
150 public:
151 using std::logic_error::logic_error;
152};
153
155 public:
156 class service;
157
158 // 13.7.1 [async.exec.ctx.cons]
159 execution_context() = default;
162
163 // 13.7.2 [async.exec.ctx.dtor]
165 shutdown();
166 destroy();
167 }
168
169 // 13.7.3 [async.exec.ctx.ops]
171 // prepare is in reverse
172 if (e == fork_event::prepare) {
173 std::for_each(services_.rbegin(), services_.rend(),
174 [e](auto &svc) { svc.ptr_->notify_fork(e); });
175 } else {
176 std::for_each(services_.begin(), services_.end(),
177 [e](auto &svc) { svc.ptr_->notify_fork(e); });
178 }
179 }
180
181 protected:
182 // 13.7.4 [async.exec.ctx.protected]
183 void shutdown() noexcept {
184 // shutdown in reverse insert-order
185 std::for_each(services_.rbegin(), services_.rend(), [](auto &svc) {
186 if (svc.active_) {
187 svc.ptr_->shutdown();
188 svc.active_ = false;
189 }
190 });
191 }
192
193 void destroy() noexcept {
194 // destroy in reverse insert-order
195 while (!services_.empty()) services_.pop_back();
196
197 keys_.clear();
198 }
199
200 // as service has a protected destructor unique_ptr can't call it itself and
201 // we much provide our own deleter: service_deleter
202 template <class Service>
203 static void service_deleter(service *svc) {
204 delete static_cast<Service *>(svc);
205 }
206
207 struct ServicePtr {
208 template <class Service>
209 ServicePtr(Service *svc) : ptr_(svc, &service_deleter<Service>) {}
210
211 // each service is only shutdown once.
212 bool active_{true};
213
214 std::unique_ptr<service, void (*)(service *)> ptr_;
215 };
216
217 using service_key_type = std::type_index;
218
219 /**
220 * maps selected type to unique identifier.
221 */
222 template <class Key>
224 return std::type_index(typeid(Key));
225 }
226
227 // mutex for services_, keys_
228 mutable std::mutex services_mtx_;
229
230 // services in insertion-order
231 std::list<ServicePtr> services_;
232 std::unordered_map<service_key_type, service *> keys_;
233
234 template <typename Service, class... Args>
235 service *add_service(Args &&... args) {
236 services_.push_back(
237 ServicePtr{new Service{*this, std::forward<Args>(args)...}});
238
239 return services_.back().ptr_.get();
240 }
241
242 template <class Service>
243 friend typename Service::key_type &use_service(execution_context &ctx);
244
245 template <class Service>
246 friend bool has_service(const execution_context &ctx) noexcept;
247
248 template <class Service, class... Args>
249 friend Service &make_service(execution_context &ctx, Args &&... args);
250};
251
252// 13.7.5 [async.exec.ctx.globals]
253template <class Service>
255 using Key = typename Service::key_type;
256
257 static_assert(std::is_base_of<execution_context::service, Key>::value,
258 "Key must derive from execution_context::service");
259 static_assert(std::is_base_of<Key, Service>::value,
260 "Service must derive from Key");
261
262 auto key = execution_context::service_key<Key>();
263
264 std::lock_guard<std::mutex> lk(ctx.services_mtx_);
265
266 auto &svc = ctx.keys_[key];
267 if (svc == nullptr) {
268 // if no service registered, add one
269 svc = ctx.add_service<Service>();
270 }
271
272 return static_cast<Key &>(*svc);
273}
274
275template <class Service, class... Args>
276Service &make_service(execution_context &ctx, Args &&... args) {
277 using Key = typename Service::key_type;
278
279 static_assert(std::is_base_of<execution_context::service, Key>::value,
280 "Key must derive from execution_context::service");
281 static_assert(std::is_base_of<Key, Service>::value,
282 "Service must derive from Key");
283
284 auto key = execution_context::service_key<Key>();
285
286 std::lock_guard<std::mutex> lk(ctx.services_mtx_);
287 auto &svc = ctx.keys_[key];
288 if (svc == nullptr) {
289 // if no service registered, add one
290 svc = ctx.add_service<Service>(std::forward(args)...);
291 } else {
293 "can't make_service(), Service already exists");
294 }
295
296 return static_cast<Service &>(*svc);
297}
298
299template <class Service>
300bool has_service(const execution_context &ctx) noexcept {
301 using Key = typename Service::key_type;
302
303 std::lock_guard<std::mutex> lk(ctx.services_mtx_);
304 return ctx.keys_.count(execution_context::service_key<Key>()) > 0;
305}
306
307// 13.8 [async.exec.ctx.svc]
309 protected:
310 explicit service(execution_context &owner) : context_{owner} {}
311 service(const service &) = delete;
312 service &operator=(const service &) = delete;
313 virtual ~service() = default;
314 execution_context &context() noexcept { return context_; }
315
316 private:
317 virtual void shutdown() noexcept = 0;
318 virtual void notify_fork(fork_event) noexcept {}
319
320 friend class execution_context;
322};
323
324// 13.9 [async.is.exec]
325//
326namespace impl {
327
328template <class T, class = std::void_t<>>
329struct is_executor : std::false_type {};
330
331// checker for the requirements of a executor
332//
333// see 13.2.2 [async.reqmts.executor]
334//
335// - copy-constructible
336// - destructible
337// - ... no exceptions
338// - operator==
339// - operator!=
340// - .context()
341// - .on_work_started()
342// - .on_work_finished()
343// - .dispatch(void (*)(), allocator)
344// - .post(void (*)(), allocator)
345// - .defer(void (*)(), allocator)
346template <class T, typename U = std::remove_const_t<T>>
347auto executor_requirements(U *__x = nullptr, const U *__const_x = nullptr,
348 void (*f)() = nullptr,
349 const std::allocator<int> &a = {})
350 -> std::enable_if_t<
351 std::conjunction<
352 std::is_copy_constructible<T>,
353 // methods/operators must exist
354 std::is_same<decltype(*__const_x == *__const_x), bool>,
355 std::is_same<decltype(*__const_x != *__const_x), bool>,
356 std::is_void<decltype(__x->on_work_started())>,
357 std::is_void<decltype(__x->on_work_finished())>,
358 std::is_void<decltype(__x->dispatch(std::move(f), a))>,
359 std::is_void<decltype(__x->post(std::move(f), a))>,
360 std::is_void<decltype(__x->defer(std::move(f), a))>>::value,
361
362 // context() may either return execution_context & or E&
363 std::void_t<decltype(__x->context()), void()>>;
364
365template <class T>
366struct is_executor<T, decltype(executor_requirements<T>())> : std::true_type {};
367} // namespace impl
368
369template <class T>
371
372template <class T>
374
375// 13.10 [async.executor.arg]
377
379
380// 13.11 [async.uses.executor]
381
382namespace impl {
383
384template <class T, class Executor, typename = std::void_t<>>
385struct uses_executor : std::false_type {};
386
387template <class T, class Executor>
388struct uses_executor<T, Executor, std::void_t<typename T::executor_type>>
389 : std::is_convertible<Executor, typename T::executor_type> {};
390
391} // namespace impl
392
393template <class T, class Executor>
395
396template <class T, class Executor>
398
399// 13.12 [async.assoc.exec]
400template <class T, class Executor, typename = std::void_t<>>
402 using type = Executor;
403
404 static type __get(const T & /* t */, const Executor &ex) noexcept {
405 return ex;
406 }
407};
408
409template <class T, class Executor>
410struct associated_executor_impl<T, Executor,
411 std::void_t<typename T::executor_type>> {
412 using type = typename T::executor_type;
413
414 static type __get(const T &t, const Executor & /* a */) noexcept {
415 return t.get_executor();
416 }
417};
418
419template <class T, class Executor = system_executor>
420struct associated_executor;
421
422template <class T, class Executor = system_executor>
424
425template <class T, class Executor>
427 static auto get(const T &t, const Executor &ex = Executor()) noexcept {
429 return Impl::__get(t, ex);
430 }
431};
432
433// 13.13 [async.assoc.exec.get]
434template <class T>
435associated_executor_t<T> get_associated_executor(const T &t) noexcept;
436
437template <class T, class Executor>
438associated_executor_t<T, Executor> get_associated_executor(
439 const T &t, const Executor &ex) noexcept;
440
441template <class T, class ExecutorContext>
442associated_executor_t<T, typename ExecutorContext::executor_type>
443get_associated_executor(const T &t, const ExecutorContext &ctx) noexcept;
444
445template <class T>
448}
449
450template <class T, class Executor>
452 const T &t, const Executor &ex) noexcept {
454}
455
456template <class T, class ExecutorContext>
457associated_executor_t<T, typename ExecutorContext::executor_type>
458get_associated_executor(const T &t, const ExecutorContext &ctx) noexcept {
459 return get_associated_executor(t, ctx.get_executor());
460}
461
462// 13.14 [async.exec.binder] - not implemented
463
464// 13.15 [async.bind.executor] - not implemented
465
466// 13.16 [async.exec.work.guard]
467
468template <class Executor>
470 public:
471 using executor_type = Executor;
472
473 explicit executor_work_guard(const executor_type &ex) noexcept
474 : ex_{ex}, owns_{true} {
475 ex_.on_work_started();
476 }
478 : ex_{other.ex_}, owns_{other.owns_} {
479 if (owns_) {
480 ex_.on_work_started();
481 }
482 }
484 : ex_{std::move(other.ex_)}, owns_{std::exchange(other.owns_, false)} {}
485
487
489 if (owns_) {
490 ex_.on_work_finished();
491 }
492 }
493
494 executor_type get_executor() const noexcept { return ex_; }
495
496 bool owns_work() const noexcept { return owns_; }
497
498 void reset() noexcept {
499 if (owns_) {
500 ex_.on_work_finished();
501 }
502 owns_ = false;
503 }
504
505 private:
506 Executor ex_;
507 bool owns_;
508};
509
510// 13.17 [async.make.work.guard]
511
512// NOTE: 'is_executor_v' should be used here, but sun-cc fails with
513//
514// Error: Could not find a match for
515// net::make_work_guard<Executor>(net::io_context::executor_type)
516// needed in
517// net::executor_work_guard<net::io_context::executor_type>
518// net::make_work_guard<net::io_context>(net::io_context&).
519//
520// Using the `is_executor<...>::value` makes it work correctly with all
521// compilers
522template <class Executor>
523std::enable_if_t<is_executor<Executor>::value, executor_work_guard<Executor>>
524make_work_guard(const Executor &ex) {
526}
527
528template <class ExecutionContext>
529std::enable_if_t<
530 std::is_convertible<ExecutionContext &, execution_context &>::value,
531 executor_work_guard<typename ExecutionContext::executor_type>>
533 return make_work_guard(ctx.get_executor());
534}
535
536template <class T>
537std::enable_if_t<!is_executor<T>::value &&
538 !std::is_convertible<T &, execution_context &>::value,
539 executor_work_guard<associated_executor_t<T>>>
540make_work_guard(const T &t) {
542}
543
544template <class T, class U>
545auto make_work_guard(const T &t, U &&u)
547 std::forward<U>(u)))) {
548 return make_work_guard(get_associated_executor(t, std::forward<U>(u)));
549}
550
551class system_context;
552
553// 13.18 [async.system.exec]
555 public:
556 system_executor() = default;
557
558 system_context &context() const noexcept;
559
560 void on_work_started() const noexcept {}
561 void on_work_finished() const noexcept {}
562
563 template <class Func, class ProtoAllocator>
564 void dispatch(Func &&f, const ProtoAllocator &a) const;
565 template <class Func, class ProtoAllocator>
566 void post(Func &&f, const ProtoAllocator &a) const;
567 template <class Func, class ProtoAllocator>
568 void defer(Func &&f, const ProtoAllocator &a) const;
569};
570
571// 13.18.2 [async.system.exec.comparisons]
572inline bool operator==(const system_executor &, const system_executor &) {
573 return true;
574}
575
576inline bool operator!=(const system_executor &, const system_executor &) {
577 return false;
578}
579
580// 13.19 [async.system.context]
581//
582// just barely enough of a system_context to run everything in the
583// main-thread
585 public:
587
588 system_context() = delete;
591 ~system_context() override {
592 stop();
593 join();
594 }
595
596 executor_type get_executor() noexcept { return {}; }
597
598 void stop() {
599 std::lock_guard<std::mutex> lk(mtx_);
600 stopped_ = true;
601
602 cv_.notify_all();
603 }
604 bool stopped() const noexcept {
605 std::lock_guard<std::mutex> lk(mtx_);
606 return stopped_;
607 }
608 void join() {
609 if (thread_.joinable()) thread_.join();
610 }
611
612 private:
613 struct __tag {};
615
616 friend class system_executor;
617
618 void run_() {
619 for (;;) {
620 std::function<void()> f;
621 {
622 std::unique_lock<std::mutex> lk(mtx_);
623
624 cv_.wait(lk, [this] { return stopped_ || !tasks_.empty(); });
625
626 if (stopped_) return;
627
628 f = std::move(tasks_.front());
629 tasks_.pop();
630 }
631 f();
632 }
633 }
634
635 void post_(std::function<void()> f) {
636 std::lock_guard<std::mutex> lk(mtx_);
637 if (stopped_) return;
638
639 if (!thread_.joinable()) {
640 thread_ = std::thread(&system_context::run_, this);
641 }
642
643 tasks_.push(std::move(f));
644
645 cv_.notify_one();
646 }
647
648 static system_context &get_() noexcept {
649 static system_context sc(__tag{});
650 return sc;
651 }
652
653 std::thread thread_;
654 mutable std::mutex mtx_;
655 std::condition_variable cv_;
656 std::queue<std::function<void()>> tasks_;
657 bool stopped_{false};
658};
659
660// 13.18.1 [async.system.exec.ops]
661
662inline system_context &system_executor::context() const noexcept {
663 return system_context::get_();
664}
665
666template <class Func, class ProtoAllocator>
667void system_executor::post(Func &&f, const ProtoAllocator &) const {
668 system_context::get_().post_(std::forward<Func>(f));
669}
670
671template <class Func, class ProtoAllocator>
672void system_executor::dispatch(Func &&f, const ProtoAllocator &) const {
673 std::decay_t<Func>{std::forward<Func>(f)}();
674}
675template <class Func, class ProtoAllocator>
676void system_executor::defer(Func &&f, const ProtoAllocator &a) const {
677 post(std::forward<Func>(f), a);
678}
679
680// 13.20 [async.bad.exec] - not implemented
681
682// 13.21 [async.executor] - not implemented
683//
684//
685namespace impl {
686/**
687 * function object for net::dispatch(), net::post(), net::defer().
688 */
689template <class CompletionHandler>
691 public:
692 explicit Dispatcher(CompletionHandler &handler)
693 : handler_{std::move(handler)},
694 work_guard_{net::make_work_guard(handler_)} {}
695
696 void operator()() {
697 auto alloc = get_associated_allocator(handler_);
698
699 work_guard_.get_executor().dispatch(std::move(handler_), alloc);
700
701 work_guard_.reset();
702 }
703
704 private:
705 CompletionHandler handler_;
706 decltype(net::make_work_guard(handler_)) work_guard_;
707};
708
709template <class CompletionHandler>
712}
713} // namespace impl
714
715// 13.22 [async.dispatch]
716
717template <class CompletionToken>
718auto dispatch(CompletionToken &&token) {
719 async_completion<CompletionToken, void()> completion(token);
720
721 auto ex = get_associated_executor(completion.completion_handler);
722 auto alloc = get_associated_allocator(completion.completion_handler);
723 ex.dispatch(std::move(completion.completion_handler), alloc);
724
725 return completion.result.get();
726}
727
728/**
729 * queue a function call for later execution.
730 */
731template <class Executor, class CompletionToken>
732std::enable_if_t<
733 is_executor<Executor>::value,
734 typename async_result<std::decay_t<CompletionToken>, void()>::return_type>
735dispatch(const Executor &ex, CompletionToken &&token) {
736 async_completion<CompletionToken, void()> completion(token);
737
738 auto alloc = get_associated_allocator(completion.completion_handler);
739
740 ex.dispatch(impl::make_dispatcher(completion.completion_handler), alloc);
741
742 return completion.result.get();
743}
744
745/**
746 * queue a function call for later execution.
747 */
748template <class ExecutionContext, class CompletionToken>
749std::enable_if_t<
750 std::is_convertible<ExecutionContext &, execution_context &>::value,
751 typename async_result<std::decay_t<CompletionToken>, void()>::return_type>
752dispatch(ExecutionContext &ctx, CompletionToken &&token) {
753 return net::dispatch(ctx.get_executor(),
754 std::forward<CompletionToken>(token));
755}
756
757// 13.23 [async.post]
758
759/**
760 * queue a function call for later execution.
761 */
762template <class CompletionToken>
763auto post(CompletionToken &&token) {
764 async_completion<CompletionToken, void()> completion(token);
765
766 auto ex = get_associated_executor(completion.completion_handler);
767 auto alloc = get_associated_allocator(completion.completion_handler);
768 ex.post(std::move(completion.completion_handler), alloc);
769
770 return completion.result.get();
771}
772
773/**
774 * queue a function call for later execution.
775 */
776template <class Executor, class CompletionToken>
777std::enable_if_t<
778 is_executor<Executor>::value,
779 typename async_result<std::decay_t<CompletionToken>, void()>::return_type>
780post(const Executor &ex, CompletionToken &&token) {
781 async_completion<CompletionToken, void()> completion(token);
782
783 auto alloc = get_associated_allocator(completion.completion_handler);
784
785 ex.post(impl::make_dispatcher(completion.completion_handler), alloc);
786
787 return completion.result.get();
788}
789
790/**
791 * queue a function call for later execution.
792 */
793template <class ExecutionContext, class CompletionToken>
794std::enable_if_t<
795 std::is_convertible<ExecutionContext &, execution_context &>::value,
796 typename async_result<std::decay_t<CompletionToken>, void()>::return_type>
797post(ExecutionContext &ctx, CompletionToken &&token) {
798 return net::post(ctx.get_executor(), std::forward<CompletionToken>(token));
799}
800
801// 13.24 [async.defer]
802
803template <class CompletionToken>
804auto defer(CompletionToken &&token) {
805 async_completion<CompletionToken, void()> completion(token);
806
807 auto ex = get_associated_executor(completion.completion_handler);
808 auto alloc = get_associated_allocator(completion.completion_handler);
809 ex.defer(std::move(completion.completion_handler), alloc);
810
811 return completion.result.get();
812}
813
814/**
815 * queue a function call for later execution.
816 */
817template <class Executor, class CompletionToken>
818std::enable_if_t<
819 is_executor<Executor>::value,
820 typename async_result<std::decay_t<CompletionToken>, void()>::return_type>
821defer(const Executor &ex, CompletionToken &&token) {
822 async_completion<CompletionToken, void()> completion(token);
823
824 auto alloc = get_associated_allocator(completion.completion_handler);
825
826 ex.defer(impl::make_dispatcher(completion.completion_handler), alloc);
827
828 return completion.result.get();
829}
830
831/**
832 * queue a function call for later execution.
833 */
834template <class ExecutionContext, class CompletionToken>
835std::enable_if_t<
836 std::is_convertible<ExecutionContext &, execution_context &>::value,
837 typename async_result<std::decay_t<CompletionToken>, void()>::return_type>
838defer(ExecutionContext &ctx, CompletionToken &&token) {
839 return net::defer(ctx.get_executor(), std::forward<CompletionToken>(token));
840}
841
842// 13.25 [async.strand] - partially implemented
843
844template <class Executor>
845class strand {
846 public:
847 using inner_executor_type = Executor;
848
849 strand() = default;
850
851 explicit strand(Executor ex) : inner_ex_{ex} {}
852
853 template <class ProtoAllocator>
854 strand(std::allocator_arg_t, const ProtoAllocator & /* alloc */, Executor ex)
855 : inner_ex_{ex} {}
856
857 strand(const strand &other) noexcept : inner_ex_{other.inner_ex_} {}
858 strand(strand &&other) noexcept : inner_ex_{std::move(other.inner_ex_)} {}
859
860 template <class OtherExecutor>
861 strand(const strand<OtherExecutor> &other) noexcept
862 : inner_ex_{other.inner_ex_} {}
863 template <class OtherExecutor>
865 : inner_ex_{std::move(other.inner_ex_)} {}
866
867 strand operator=(const strand &other) noexcept {
868 inner_ex_ = other.inner_ex_;
869
870 return *this;
871 }
872
873 strand operator=(strand &&other) noexcept {
874 inner_ex_ = std::move(other.inner_ex_);
875
876 return *this;
877 }
878
879 template <class OtherExecutor>
880 strand operator=(const strand<OtherExecutor> &other) noexcept {
881 inner_ex_ = other.inner_ex_;
882
883 return *this;
884 }
885
886 template <class OtherExecutor>
888 inner_ex_ = std::move(other.inner_ex_);
889
890 return *this;
891 }
892
894
895 // strand ops
896
897 inner_executor_type get_inner_executor() const noexcept { return inner_ex_; }
898
899 bool running_in_this_thread() const noexcept {
900 return impl::Callstack<strand>::contains(this) != nullptr;
901 }
902
903 execution_context &context() const noexcept { return inner_ex_.context(); }
904
905 void on_work_started() const noexcept { inner_ex_.on_work_started(); }
906 void on_work_finished() const noexcept { inner_ex_.on_work_finished(); }
907
908 template <class Func, class ProtoAllocator>
909 void dispatch(Func &&f, const ProtoAllocator & /* a */) const {
910 if (running_in_this_thread()) {
911 std::forward<Func>(f)();
912 }
913 }
914 template <class Func, class ProtoAllocator>
915 void post(Func &&f, const ProtoAllocator &a) const;
916 template <class Func, class ProtoAllocator>
917 void defer(Func &&f, const ProtoAllocator &a) const;
918
919 private:
920 Executor inner_ex_;
921
922 bool running_{false};
923 std::queue<std::function<void()>> jobs_;
924};
925
926template <class Executor>
928
929template <class Executor>
931 return !(a == b);
932}
933
934// 13.26 [async.use.future] - not implemented
935
936// 13.27 [async.packaged.task.spec] - not implemented
937
938} // namespace net
939
940#endif
execution context for SQL.
Definition: sql_exec_context.h:43
The handler class is the interface for dynamically loadable storage engines.
Definition: handler.h:4413
Definition: executor.h:72
std::conditional_t< std::is_same< CompletionToken, completion_handler_type >::value, completion_handler_type &, completion_handler_type > handler_type
Definition: executor.h:81
async_completion & operator=(const async_completion &)=delete
handler_type completion_handler
Definition: executor.h:90
async_completion(CompletionToken &t)
Definition: executor.h:84
async_completion(const async_completion &)=delete
result_type result
Definition: executor.h:91
typename result_type::completion_handler_type completion_handler_type
Definition: executor.h:76
Definition: executor.h:55
void return_type
Definition: executor.h:58
CompletionToken completion_handler_type
Definition: executor.h:57
return_type get()
Definition: executor.h:64
async_result(const async_result &)=delete
async_result(completion_handler_type &)
Definition: executor.h:60
async_result & operator=(const async_result &)=delete
Definition: executor.h:308
virtual void shutdown() noexcept=0
service(const service &)=delete
service & operator=(const service &)=delete
service(execution_context &owner)
Definition: executor.h:310
execution_context & context_
Definition: executor.h:321
execution_context & context() noexcept
Definition: executor.h:314
Definition: executor.h:154
std::list< ServicePtr > services_
Definition: executor.h:231
execution_context(const execution_context &)=delete
void shutdown() noexcept
Definition: executor.h:183
void destroy() noexcept
Definition: executor.h:193
static void service_deleter(service *svc)
Definition: executor.h:203
void notify_fork(fork_event e)
Definition: executor.h:170
service * add_service(Args &&... args)
Definition: executor.h:235
execution_context & operator=(const execution_context &)=delete
virtual ~execution_context()
Definition: executor.h:164
static service_key_type service_key()
maps selected type to unique identifier.
Definition: executor.h:223
std::mutex services_mtx_
Definition: executor.h:228
std::type_index service_key_type
Definition: executor.h:217
std::unordered_map< service_key_type, service * > keys_
Definition: executor.h:232
Definition: executor.h:469
Executor executor_type
Definition: executor.h:471
executor_work_guard(const executor_work_guard &other) noexcept
Definition: executor.h:477
bool owns_
Definition: executor.h:507
executor_type get_executor() const noexcept
Definition: executor.h:494
executor_work_guard(executor_work_guard &&other) noexcept
Definition: executor.h:483
void reset() noexcept
Definition: executor.h:498
Executor ex_
Definition: executor.h:506
executor_work_guard(const executor_type &ex) noexcept
Definition: executor.h:473
executor_work_guard & operator=(const executor_work_guard &other)=delete
~executor_work_guard()
Definition: executor.h:488
bool owns_work() const noexcept
Definition: executor.h:496
function object for net::dispatch(), net::post(), net::defer().
Definition: executor.h:690
Dispatcher(CompletionHandler &handler)
Definition: executor.h:692
CompletionHandler handler_
Definition: executor.h:705
void operator()()
Definition: executor.h:696
Definition: executor.h:149
Definition: executor.h:845
void post(Func &&f, const ProtoAllocator &a) const
strand(Executor ex)
Definition: executor.h:851
strand()=default
strand operator=(const strand< OtherExecutor > &other) noexcept
Definition: executor.h:880
strand(strand< OtherExecutor > &&other) noexcept
Definition: executor.h:864
strand(const strand< OtherExecutor > &other) noexcept
Definition: executor.h:861
Executor inner_ex_
Definition: executor.h:920
bool running_in_this_thread() const noexcept
Definition: executor.h:899
void defer(Func &&f, const ProtoAllocator &a) const
strand operator=(strand< OtherExecutor > &&other) noexcept
Definition: executor.h:887
strand operator=(strand &&other) noexcept
Definition: executor.h:873
void on_work_started() const noexcept
Definition: executor.h:905
void on_work_finished() const noexcept
Definition: executor.h:906
void dispatch(Func &&f, const ProtoAllocator &) const
Definition: executor.h:909
execution_context & context() const noexcept
Definition: executor.h:903
Executor inner_executor_type
Definition: executor.h:847
strand(strand &&other) noexcept
Definition: executor.h:858
strand operator=(const strand &other) noexcept
Definition: executor.h:867
std::queue< std::function< void()> > jobs_
Definition: executor.h:923
strand(std::allocator_arg_t, const ProtoAllocator &, Executor ex)
Definition: executor.h:854
strand(const strand &other) noexcept
Definition: executor.h:857
inner_executor_type get_inner_executor() const noexcept
Definition: executor.h:897
Definition: executor.h:584
static system_context & get_() noexcept
Definition: executor.h:648
void join()
Definition: executor.h:608
std::condition_variable cv_
Definition: executor.h:655
std::queue< std::function< void()> > tasks_
Definition: executor.h:656
void run_()
Definition: executor.h:618
std::thread thread_
Definition: executor.h:653
system_context(const system_context &)=delete
bool stopped() const noexcept
Definition: executor.h:604
~system_context() override
Definition: executor.h:591
void post_(std::function< void()> f)
Definition: executor.h:635
std::mutex mtx_
Definition: executor.h:654
executor_type get_executor() noexcept
Definition: executor.h:596
system_context & operator=(const system_context &)=delete
void stop()
Definition: executor.h:598
system_context(__tag)
Definition: executor.h:614
Definition: executor.h:554
system_executor()=default
void on_work_finished() const noexcept
Definition: executor.h:561
static bool contains(const std::vector< std::string > &container, const std::string &file)
Definition: config_files.cc:41
Header for compiler-dependent features.
#define MY_COMPILER_DIAGNOSTIC_PUSH()
save the compiler's diagnostic (enabled warnings, errors, ...) state
Definition: my_compiler.h:296
#define MY_COMPILER_DIAGNOSTIC_POP()
restore the compiler's diagnostic (enabled warnings, errors, ...) state
Definition: my_compiler.h:297
static QUEUE queue
Definition: myisampack.cc:207
void for_each(const Shards< COUNT > &shards, Function &&f) noexcept
Iterate over the shards.
Definition: ut0counter.h:323
int key_type
Definition: http_request.h:50
std::string_view Key
The key type for the hash structure in HashJoinRowBuffer.
Definition: hash_join_buffer.h:102
Definition: authentication.cc:36
std::string join(Container cont, const std::string &delim)
join elements of an container into a string separated by a delimiter.
Definition: string.h:151
auto executor_requirements(U *__x=nullptr, const U *__const_x=nullptr, void(*f)()=nullptr, const std::allocator< int > &a={}) -> std::enable_if_t< std::conjunction< std::is_copy_constructible< T >, std::is_same< decltype(*__const_x== *__const_x), bool >, std::is_same< decltype(*__const_x != *__const_x), bool >, std::is_void< decltype(__x->on_work_started())>, std::is_void< decltype(__x->on_work_finished())>, std::is_void< decltype(__x->dispatch(std::move(f), a))>, std::is_void< decltype(__x->post(std::move(f), a))>, std::is_void< decltype(__x->defer(std::move(f), a))> >::value, std::void_t< decltype(__x->context()), void()> >
Dispatcher< CompletionHandler > make_dispatcher(CompletionHandler &handler)
Definition: executor.h:710
Definition: buffer.h:45
constexpr bool uses_executor_v
Definition: executor.h:397
bool has_service(const execution_context &ctx) noexcept
Definition: executor.h:300
Service & make_service(execution_context &ctx, Args &&... args)
Definition: executor.h:276
auto defer(CompletionToken &&token)
Definition: executor.h:804
std::enable_if_t< is_executor< Executor >::value, executor_work_guard< Executor > > make_work_guard(const Executor &ex)
Definition: executor.h:524
typename associated_executor< T, Executor >::type associated_executor_t
Definition: executor.h:423
associated_allocator_t< T > get_associated_allocator(const T &t) noexcept
Definition: executor.h:138
auto dispatch(CompletionToken &&token)
Definition: executor.h:718
auto post(CompletionToken &&token)
queue a function call for later execution.
Definition: executor.h:763
constexpr executor_arg_t executor_arg
Definition: executor.h:378
Service::key_type & use_service(execution_context &ctx)
Definition: executor.h:254
typename associated_allocator< T, ProtoAllocator >::type associated_allocator_t
Definition: executor.h:104
constexpr bool is_executor_v
Definition: executor.h:373
bool operator!=(const strand< Executor > &a, const strand< Executor > &b)
Definition: executor.h:930
std::enable_if_t< std::is_convertible< ExecutionContext &, execution_context & >::value, typename async_result< std::decay_t< CompletionToken >, void()>::return_type > post(ExecutionContext &ctx, CompletionToken &&token)
queue a function call for later execution.
Definition: executor.h:797
bool operator==(const strand< Executor > &a, const strand< Executor > &b)
fork_event
Definition: executor.h:48
std::enable_if_t< std::is_convertible< ExecutionContext &, execution_context & >::value, typename async_result< std::decay_t< CompletionToken >, void()>::return_type > defer(ExecutionContext &ctx, CompletionToken &&token)
queue a function call for later execution.
Definition: executor.h:838
associated_executor_t< T, typename ExecutorContext::executor_type > get_associated_executor(const T &t, const ExecutorContext &ctx) noexcept
Definition: executor.h:458
std::enable_if_t< std::is_convertible< ExecutionContext &, execution_context & >::value, typename async_result< std::decay_t< CompletionToken >, void()>::return_type > dispatch(ExecutionContext &ctx, CompletionToken &&token)
queue a function call for later execution.
Definition: executor.h:752
auto make_work_guard(const T &t, U &&u) -> decltype(make_work_guard(get_associated_executor(t, std::forward< U >(u))))
Definition: executor.h:545
associated_allocator_t< T > get_associated_allocator(const T &t, const ProtoAllocator &a) noexcept
Definition: executor.h:143
void get(PSI_field *, PSI_longlong *) noexcept
Definition: pfs_plugin_column_bigint_v1_all_empty.cc:32
Definition: gcs_xcom_synode.h:64
std::conditional_t< !std::is_array< T >::value, std::unique_ptr< T, detail::Deleter< T > >, std::conditional_t< detail::is_unbounded_array_v< T >, std::unique_ptr< T, detail::Array_deleter< std::remove_extent_t< T > > >, void > > unique_ptr
The following is a common type that is returned by all the ut::make_unique (non-aligned) specializati...
Definition: ut0new.h:2438
MY_COMPILER_CLANG_DIAGNOSTIC_IGNORE("-Winconsistent-missing-destructor-override") extern "C"
Definition: protobuf_plugin.cc:32
required string key
Definition: replication_asynchronous_connection_failover.proto:60
required string type
Definition: replication_group_member_actions.proto:34
static type __get(const T &t, const ProtoAllocator &) noexcept
Definition: executor.h:122
Definition: executor.h:109
static type __get(const T &, const ProtoAllocator &a) noexcept
Definition: executor.h:112
ProtoAllocator type
Definition: executor.h:110
Definition: executor.h:128
static auto get(const T &t, const ProtoAllocator &a=ProtoAllocator()) noexcept
Definition: executor.h:129
static type __get(const T &t, const Executor &) noexcept
Definition: executor.h:414
Definition: executor.h:401
static type __get(const T &, const Executor &ex) noexcept
Definition: executor.h:404
Executor type
Definition: executor.h:402
Definition: executor.h:426
static auto get(const T &t, const Executor &ex=Executor()) noexcept
Definition: executor.h:427
Definition: executor.h:207
ServicePtr(Service *svc)
Definition: executor.h:209
Definition: executor.h:376
Definition: executor.h:329
Definition: executor.h:385
Definition: executor.h:370
Definition: executor.h:613
Definition: executor.h:394
Definition: result.h:30
Definition: dtoa.cc:595