MySQL 8.4.0
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]
170 void notify_fork(fork_event e);
171
172 protected:
173 // 13.7.4 [async.exec.ctx.protected]
174 void shutdown() noexcept;
175
176 void destroy() noexcept {
177 // destroy in reverse insert-order
178 while (!services_.empty()) services_.pop_back();
179
180 keys_.clear();
181 }
182
183 // as service has a protected destructor unique_ptr can't call it itself and
184 // we much provide our own deleter: service_deleter
185 template <class Service>
186 static void service_deleter(service *svc) {
187 delete static_cast<Service *>(svc);
188 }
189
190 struct ServicePtr {
191 template <class Service>
192 ServicePtr(Service *svc) : ptr_(svc, &service_deleter<Service>) {}
193
194 // each service is only shutdown once.
195 bool active_{true};
196
198 };
199
200 using service_key_type = std::type_index;
201
202 /**
203 * maps selected type to unique identifier.
204 */
205 template <class Key>
207 return std::type_index(typeid(Key));
208 }
209
210 // mutex for services_, keys_
211 mutable std::mutex services_mtx_;
212
213 // services in insertion-order
214 std::list<ServicePtr> services_;
215 std::unordered_map<service_key_type, service *> keys_;
216
217 template <typename Service, class... Args>
218 service *add_service(Args &&... args) {
219 services_.push_back(
220 ServicePtr{new Service{*this, std::forward<Args>(args)...}});
221
222 return services_.back().ptr_.get();
223 }
224
225 template <class Service>
226 friend typename Service::key_type &use_service(execution_context &ctx);
227
228 template <class Service>
229 friend bool has_service(const execution_context &ctx) noexcept;
230
231 template <class Service, class... Args>
232 friend Service &make_service(execution_context &ctx, Args &&... args);
233};
234
235// 13.7.5 [async.exec.ctx.globals]
236template <class Service>
238 using Key = typename Service::key_type;
239
240 static_assert(std::is_base_of<execution_context::service, Key>::value,
241 "Key must derive from execution_context::service");
242 static_assert(std::is_base_of<Key, Service>::value,
243 "Service must derive from Key");
244
245 auto key = execution_context::service_key<Key>();
246
247 std::lock_guard<std::mutex> lk(ctx.services_mtx_);
248
249 auto &svc = ctx.keys_[key];
250 if (svc == nullptr) {
251 // if no service registered, add one
252 svc = ctx.add_service<Service>();
253 }
254
255 return static_cast<Key &>(*svc);
256}
257
258template <class Service, class... Args>
259Service &make_service(execution_context &ctx, Args &&... args) {
260 using Key = typename Service::key_type;
261
262 static_assert(std::is_base_of<execution_context::service, Key>::value,
263 "Key must derive from execution_context::service");
264 static_assert(std::is_base_of<Key, Service>::value,
265 "Service must derive from Key");
266
267 auto key = execution_context::service_key<Key>();
268
269 std::lock_guard<std::mutex> lk(ctx.services_mtx_);
270 auto &svc = ctx.keys_[key];
271 if (svc == nullptr) {
272 // if no service registered, add one
273 svc = ctx.add_service<Service>(std::forward(args)...);
274 } else {
276 "can't make_service(), Service already exists");
277 }
278
279 return static_cast<Service &>(*svc);
280}
281
282template <class Service>
283bool has_service(const execution_context &ctx) noexcept {
284 using Key = typename Service::key_type;
285
286 std::lock_guard<std::mutex> lk(ctx.services_mtx_);
287 return ctx.keys_.count(execution_context::service_key<Key>()) > 0;
288}
289
290// 13.8 [async.exec.ctx.svc]
292 protected:
293 explicit service(execution_context &owner) : context_{owner} {}
294 service(const service &) = delete;
295 service &operator=(const service &) = delete;
296 virtual ~service() = default;
297 execution_context &context() noexcept { return context_; }
298
299 private:
300 virtual void shutdown() noexcept = 0;
301 virtual void notify_fork(fork_event) noexcept {}
302
303 friend class execution_context;
305};
306
307// 13.9 [async.is.exec]
308//
309namespace impl {
310
311template <class T, class = std::void_t<>>
312struct is_executor : std::false_type {};
313
314// checker for the requirements of a executor
315//
316// see 13.2.2 [async.reqmts.executor]
317//
318// - copy-constructible
319// - destructible
320// - ... no exceptions
321// - operator==
322// - operator!=
323// - .context()
324// - .on_work_started()
325// - .on_work_finished()
326// - .dispatch(void (*)(), allocator)
327// - .post(void (*)(), allocator)
328// - .defer(void (*)(), allocator)
329template <class T, typename U = std::remove_const_t<T>>
330auto executor_requirements(U *__x = nullptr, const U *__const_x = nullptr,
331 void (*f)() = nullptr,
332 const std::allocator<int> &a = {})
333 -> std::enable_if_t<
334 std::conjunction<
335 std::is_copy_constructible<T>,
336 // methods/operators must exist
337 std::is_same<decltype(*__const_x == *__const_x), bool>,
338 std::is_same<decltype(*__const_x != *__const_x), bool>,
339 std::is_void<decltype(__x->on_work_started())>,
340 std::is_void<decltype(__x->on_work_finished())>,
341 std::is_void<decltype(__x->dispatch(std::move(f), a))>,
342 std::is_void<decltype(__x->post(std::move(f), a))>,
343 std::is_void<decltype(__x->defer(std::move(f), a))>>::value,
344
345 // context() may either return execution_context & or E&
346 std::void_t<decltype(__x->context()), void()>>;
347
348template <class T>
349struct is_executor<T, decltype(executor_requirements<T>())> : std::true_type {};
350} // namespace impl
351
352template <class T>
354
355template <class T>
357
358// 13.10 [async.executor.arg]
360
362
363// 13.11 [async.uses.executor]
364
365namespace impl {
366
367template <class T, class Executor, typename = std::void_t<>>
368struct uses_executor : std::false_type {};
369
370template <class T, class Executor>
371struct uses_executor<T, Executor, std::void_t<typename T::executor_type>>
372 : std::is_convertible<Executor, typename T::executor_type> {};
373
374} // namespace impl
375
376template <class T, class Executor>
378
379template <class T, class Executor>
381
382// 13.12 [async.assoc.exec]
383template <class T, class Executor, typename = std::void_t<>>
385 using type = Executor;
386
387 static type __get(const T & /* t */, const Executor &ex) noexcept {
388 return ex;
389 }
390};
391
392template <class T, class Executor>
393struct associated_executor_impl<T, Executor,
394 std::void_t<typename T::executor_type>> {
395 using type = typename T::executor_type;
396
397 static type __get(const T &t, const Executor & /* a */) noexcept {
398 return t.get_executor();
399 }
400};
401
402template <class T, class Executor = system_executor>
403struct associated_executor;
404
405template <class T, class Executor = system_executor>
407
408template <class T, class Executor>
410 static auto get(const T &t, const Executor &ex = Executor()) noexcept {
412 return Impl::__get(t, ex);
413 }
414};
415
416// 13.13 [async.assoc.exec.get]
417template <class T>
418associated_executor_t<T> get_associated_executor(const T &t) noexcept;
419
420template <class T, class Executor>
421associated_executor_t<T, Executor> get_associated_executor(
422 const T &t, const Executor &ex) noexcept;
423
424template <class T, class ExecutorContext>
425associated_executor_t<T, typename ExecutorContext::executor_type>
426get_associated_executor(const T &t, const ExecutorContext &ctx) noexcept;
427
428template <class T>
431}
432
433template <class T, class Executor>
435 const T &t, const Executor &ex) noexcept {
437}
438
439template <class T, class ExecutorContext>
440associated_executor_t<T, typename ExecutorContext::executor_type>
441get_associated_executor(const T &t, const ExecutorContext &ctx) noexcept {
442 return get_associated_executor(t, ctx.get_executor());
443}
444
445// 13.14 [async.exec.binder] - not implemented
446
447// 13.15 [async.bind.executor] - not implemented
448
449// 13.16 [async.exec.work.guard]
450
451template <class Executor>
453 public:
454 using executor_type = Executor;
455
456 explicit executor_work_guard(const executor_type &ex) noexcept
457 : ex_{ex}, owns_{true} {
458 ex_.on_work_started();
459 }
461 : ex_{other.ex_}, owns_{other.owns_} {
462 if (owns_) {
463 ex_.on_work_started();
464 }
465 }
467 : ex_{std::move(other.ex_)}, owns_{std::exchange(other.owns_, false)} {}
468
470
472 if (owns_) {
473 ex_.on_work_finished();
474 }
475 }
476
477 executor_type get_executor() const noexcept { return ex_; }
478
479 bool owns_work() const noexcept { return owns_; }
480
481 void reset() noexcept {
482 if (owns_) {
483 ex_.on_work_finished();
484 }
485 owns_ = false;
486 }
487
488 private:
489 Executor ex_;
490 bool owns_;
491};
492
493// 13.17 [async.make.work.guard]
494
495// NOTE: 'is_executor_v' should be used here, but sun-cc fails with
496//
497// Error: Could not find a match for
498// net::make_work_guard<Executor>(net::io_context::executor_type)
499// needed in
500// net::executor_work_guard<net::io_context::executor_type>
501// net::make_work_guard<net::io_context>(net::io_context&).
502//
503// Using the `is_executor<...>::value` makes it work correctly with all
504// compilers
505template <class Executor>
506std::enable_if_t<is_executor<Executor>::value, executor_work_guard<Executor>>
507make_work_guard(const Executor &ex) {
509}
510
511template <class ExecutionContext>
512std::enable_if_t<
513 std::is_convertible<ExecutionContext &, execution_context &>::value,
514 executor_work_guard<typename ExecutionContext::executor_type>>
516 return make_work_guard(ctx.get_executor());
517}
518
519template <class T>
520std::enable_if_t<!is_executor<T>::value &&
521 !std::is_convertible<T &, execution_context &>::value,
522 executor_work_guard<associated_executor_t<T>>>
523make_work_guard(const T &t) {
525}
526
527template <class T, class U>
528auto make_work_guard(const T &t, U &&u)
530 std::forward<U>(u)))) {
531 return make_work_guard(get_associated_executor(t, std::forward<U>(u)));
532}
533
534class system_context;
535
536// 13.18 [async.system.exec]
538 public:
539 system_executor() = default;
540
541 system_context &context() const noexcept;
542
543 void on_work_started() const noexcept {}
544 void on_work_finished() const noexcept {}
545
546 template <class Func, class ProtoAllocator>
547 void dispatch(Func &&f, const ProtoAllocator &a) const;
548 template <class Func, class ProtoAllocator>
549 void post(Func &&f, const ProtoAllocator &a) const;
550 template <class Func, class ProtoAllocator>
551 void defer(Func &&f, const ProtoAllocator &a) const;
552};
553
554// 13.18.2 [async.system.exec.comparisons]
555inline bool operator==(const system_executor &, const system_executor &) {
556 return true;
557}
558
559inline bool operator!=(const system_executor &, const system_executor &) {
560 return false;
561}
562
563// 13.19 [async.system.context]
564//
565// just barely enough of a system_context to run everything in the
566// main-thread
568 public:
570
571 system_context() = delete;
574 ~system_context() override {
575 stop();
576 join();
577 }
578
579 executor_type get_executor() noexcept { return {}; }
580
581 void stop() {
582 std::lock_guard<std::mutex> lk(mtx_);
583 stopped_ = true;
584
585 cv_.notify_all();
586 }
587 bool stopped() const noexcept {
588 std::lock_guard<std::mutex> lk(mtx_);
589 return stopped_;
590 }
591 void join() {
592 if (thread_.joinable()) thread_.join();
593 }
594
595 private:
596 struct __tag {};
598
599 friend class system_executor;
600
601 void run_() {
602 for (;;) {
603 std::function<void()> f;
604 {
605 std::unique_lock<std::mutex> lk(mtx_);
606
607 cv_.wait(lk, [this] { return stopped_ || !tasks_.empty(); });
608
609 if (stopped_) return;
610
611 f = std::move(tasks_.front());
612 tasks_.pop();
613 }
614 f();
615 }
616 }
617
618 void post_(std::function<void()> f) {
619 std::lock_guard<std::mutex> lk(mtx_);
620 if (stopped_) return;
621
622 if (!thread_.joinable()) {
623 thread_ = std::thread(&system_context::run_, this);
624 }
625
626 tasks_.push(std::move(f));
627
628 cv_.notify_one();
629 }
630
631 static system_context &get_() noexcept {
632 static system_context sc(__tag{});
633 return sc;
634 }
635
636 std::thread thread_;
637 mutable std::mutex mtx_;
638 std::condition_variable cv_;
639 std::queue<std::function<void()>> tasks_;
640 bool stopped_{false};
641};
642
643// 13.18.1 [async.system.exec.ops]
644
645inline system_context &system_executor::context() const noexcept {
646 return system_context::get_();
647}
648
649template <class Func, class ProtoAllocator>
650void system_executor::post(Func &&f, const ProtoAllocator &) const {
651 system_context::get_().post_(std::forward<Func>(f));
652}
653
654template <class Func, class ProtoAllocator>
655void system_executor::dispatch(Func &&f, const ProtoAllocator &) const {
656 std::decay_t<Func>{std::forward<Func>(f)}();
657}
658template <class Func, class ProtoAllocator>
659void system_executor::defer(Func &&f, const ProtoAllocator &a) const {
660 post(std::forward<Func>(f), a);
661}
662
663// 13.20 [async.bad.exec] - not implemented
664
665// 13.21 [async.executor] - not implemented
666//
667//
668namespace impl {
669/**
670 * function object for net::dispatch(), net::post(), net::defer().
671 */
672template <class CompletionHandler>
674 public:
675 explicit Dispatcher(CompletionHandler &handler)
676 : handler_{std::move(handler)},
678
679 void operator()() {
681
682 work_guard_.get_executor().dispatch(std::move(handler_), alloc);
683
684 work_guard_.reset();
685 }
686
687 private:
688 CompletionHandler handler_;
690};
691
692template <class CompletionHandler>
695}
696} // namespace impl
697
698// 13.22 [async.dispatch]
699
700template <class CompletionToken>
701auto dispatch(CompletionToken &&token) {
702 async_completion<CompletionToken, void()> completion(token);
703
704 auto ex = get_associated_executor(completion.completion_handler);
705 auto alloc = get_associated_allocator(completion.completion_handler);
706 ex.dispatch(std::move(completion.completion_handler), alloc);
707
708 return completion.result.get();
709}
710
711/**
712 * queue a function call for later execution.
713 */
714template <class Executor, class CompletionToken>
715std::enable_if_t<
716 is_executor<Executor>::value,
717 typename async_result<std::decay_t<CompletionToken>, void()>::return_type>
718dispatch(const Executor &ex, CompletionToken &&token) {
719 async_completion<CompletionToken, void()> completion(token);
720
721 auto alloc = get_associated_allocator(completion.completion_handler);
722
723 ex.dispatch(impl::make_dispatcher(completion.completion_handler), alloc);
724
725 return completion.result.get();
726}
727
728/**
729 * queue a function call for later execution.
730 */
731template <class ExecutionContext, class CompletionToken>
732std::enable_if_t<
733 std::is_convertible<ExecutionContext &, execution_context &>::value,
734 typename async_result<std::decay_t<CompletionToken>, void()>::return_type>
735dispatch(ExecutionContext &ctx, CompletionToken &&token) {
736 return net::dispatch(ctx.get_executor(),
737 std::forward<CompletionToken>(token));
738}
739
740// 13.23 [async.post]
741
742/**
743 * queue a function call for later execution.
744 */
745template <class CompletionToken>
746auto post(CompletionToken &&token) {
747 async_completion<CompletionToken, void()> completion(token);
748
749 auto ex = get_associated_executor(completion.completion_handler);
750 auto alloc = get_associated_allocator(completion.completion_handler);
751 ex.post(std::move(completion.completion_handler), alloc);
752
753 return completion.result.get();
754}
755
756/**
757 * queue a function call for later execution.
758 */
759template <class Executor, class CompletionToken>
760std::enable_if_t<
761 is_executor<Executor>::value,
762 typename async_result<std::decay_t<CompletionToken>, void()>::return_type>
763post(const Executor &ex, CompletionToken &&token) {
764 async_completion<CompletionToken, void()> completion(token);
765
766 auto alloc = get_associated_allocator(completion.completion_handler);
767
768 ex.post(impl::make_dispatcher(completion.completion_handler), alloc);
769
770 return completion.result.get();
771}
772
773/**
774 * queue a function call for later execution.
775 */
776template <class ExecutionContext, class CompletionToken>
777std::enable_if_t<
778 std::is_convertible<ExecutionContext &, execution_context &>::value,
779 typename async_result<std::decay_t<CompletionToken>, void()>::return_type>
780post(ExecutionContext &ctx, CompletionToken &&token) {
781 return net::post(ctx.get_executor(), std::forward<CompletionToken>(token));
782}
783
784// 13.24 [async.defer]
785
786template <class CompletionToken>
787auto defer(CompletionToken &&token) {
788 async_completion<CompletionToken, void()> completion(token);
789
790 auto ex = get_associated_executor(completion.completion_handler);
791 auto alloc = get_associated_allocator(completion.completion_handler);
792 ex.defer(std::move(completion.completion_handler), alloc);
793
794 return completion.result.get();
795}
796
797/**
798 * queue a function call for later execution.
799 */
800template <class Executor, class CompletionToken>
801std::enable_if_t<
802 is_executor<Executor>::value,
803 typename async_result<std::decay_t<CompletionToken>, void()>::return_type>
804defer(const Executor &ex, CompletionToken &&token) {
805 async_completion<CompletionToken, void()> completion(token);
806
807 auto alloc = get_associated_allocator(completion.completion_handler);
808
809 ex.defer(impl::make_dispatcher(completion.completion_handler), alloc);
810
811 return completion.result.get();
812}
813
814/**
815 * queue a function call for later execution.
816 */
817template <class ExecutionContext, class CompletionToken>
818std::enable_if_t<
819 std::is_convertible<ExecutionContext &, execution_context &>::value,
820 typename async_result<std::decay_t<CompletionToken>, void()>::return_type>
821defer(ExecutionContext &ctx, CompletionToken &&token) {
822 return net::defer(ctx.get_executor(), std::forward<CompletionToken>(token));
823}
824
825// 13.25 [async.strand] - partially implemented
826
827template <class Executor>
828class strand {
829 public:
830 using inner_executor_type = Executor;
831
832 strand() = default;
833
834 explicit strand(Executor ex) : inner_ex_{ex} {}
835
836 template <class ProtoAllocator>
837 strand(std::allocator_arg_t, const ProtoAllocator & /* alloc */, Executor ex)
838 : inner_ex_{ex} {}
839
840 strand(const strand &other) noexcept : inner_ex_{other.inner_ex_} {}
841 strand(strand &&other) noexcept : inner_ex_{std::move(other.inner_ex_)} {}
842
843 template <class OtherExecutor>
844 strand(const strand<OtherExecutor> &other) noexcept
845 : inner_ex_{other.inner_ex_} {}
846 template <class OtherExecutor>
848 : inner_ex_{std::move(other.inner_ex_)} {}
849
850 strand operator=(const strand &other) noexcept {
851 inner_ex_ = other.inner_ex_;
852
853 return *this;
854 }
855
856 strand operator=(strand &&other) noexcept {
857 inner_ex_ = std::move(other.inner_ex_);
858
859 return *this;
860 }
861
862 template <class OtherExecutor>
863 strand operator=(const strand<OtherExecutor> &other) noexcept {
864 inner_ex_ = other.inner_ex_;
865
866 return *this;
867 }
868
869 template <class OtherExecutor>
871 inner_ex_ = std::move(other.inner_ex_);
872
873 return *this;
874 }
875
877
878 // strand ops
879
881
882 bool running_in_this_thread() const noexcept {
883 return impl::Callstack<strand>::contains(this) != nullptr;
884 }
885
886 execution_context &context() const noexcept { return inner_ex_.context(); }
887
888 void on_work_started() const noexcept { inner_ex_.on_work_started(); }
889 void on_work_finished() const noexcept { inner_ex_.on_work_finished(); }
890
891 template <class Func, class ProtoAllocator>
892 void dispatch(Func &&f, const ProtoAllocator & /* a */) const {
894 std::forward<Func>(f)();
895 }
896 }
897 template <class Func, class ProtoAllocator>
898 void post(Func &&f, const ProtoAllocator &a) const;
899 template <class Func, class ProtoAllocator>
900 void defer(Func &&f, const ProtoAllocator &a) const;
901
902 private:
903 Executor inner_ex_;
904
905 bool running_{false};
906 std::queue<std::function<void()>> jobs_;
907};
908
909template <class Executor>
911
912template <class Executor>
914 return !(a == b);
915}
916
917// 13.26 [async.use.future] - not implemented
918
919// 13.27 [async.packaged.task.spec] - not implemented
920
921// 13.7.3 [async.exec.ctx.ops]
923 // prepare is in reverse
924 if (e == fork_event::prepare) {
925 std::for_each(services_.rbegin(), services_.rend(),
926 [e](auto &svc) { svc.ptr_->notify_fork(e); });
927 } else {
928 std::for_each(services_.begin(), services_.end(),
929 [e](auto &svc) { svc.ptr_->notify_fork(e); });
930 }
931}
932
933// 13.7.4 [async.exec.ctx.protected]
934inline void execution_context::shutdown() noexcept {
935 // shutdown in reverse insert-order
936 std::for_each(services_.rbegin(), services_.rend(), [](auto &svc) {
937 if (svc.active_) {
938 svc.ptr_->shutdown();
939 svc.active_ = false;
940 }
941 });
942}
943
944} // namespace net
945
946#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:4572
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:291
virtual void shutdown() noexcept=0
service(const service &)=delete
service & operator=(const service &)=delete
service(execution_context &owner)
Definition: executor.h:293
execution_context & context_
Definition: executor.h:304
virtual void notify_fork(fork_event) noexcept
Definition: executor.h:301
execution_context & context() noexcept
Definition: executor.h:297
Definition: executor.h:154
friend bool has_service(const execution_context &ctx) noexcept
Definition: executor.h:283
std::list< ServicePtr > services_
Definition: executor.h:214
execution_context(const execution_context &)=delete
void shutdown() noexcept
Definition: executor.h:934
void destroy() noexcept
Definition: executor.h:176
static void service_deleter(service *svc)
Definition: executor.h:186
friend Service & make_service(execution_context &ctx, Args &&... args)
Definition: executor.h:259
void notify_fork(fork_event e)
Definition: executor.h:922
service * add_service(Args &&... args)
Definition: executor.h:218
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:206
std::mutex services_mtx_
Definition: executor.h:211
friend Service::key_type & use_service(execution_context &ctx)
Definition: executor.h:237
std::type_index service_key_type
Definition: executor.h:200
std::unordered_map< service_key_type, service * > keys_
Definition: executor.h:215
Definition: executor.h:452
Executor executor_type
Definition: executor.h:454
executor_work_guard(const executor_work_guard &other) noexcept
Definition: executor.h:460
bool owns_
Definition: executor.h:490
executor_type get_executor() const noexcept
Definition: executor.h:477
executor_work_guard(executor_work_guard &&other) noexcept
Definition: executor.h:466
void reset() noexcept
Definition: executor.h:481
Executor ex_
Definition: executor.h:489
executor_work_guard(const executor_type &ex) noexcept
Definition: executor.h:456
executor_work_guard & operator=(const executor_work_guard &other)=delete
~executor_work_guard()
Definition: executor.h:471
bool owns_work() const noexcept
Definition: executor.h:479
static constexpr Value * contains(const Key *k)
check if a callstack contains a pointer already.
Definition: callstack.h:151
function object for net::dispatch(), net::post(), net::defer().
Definition: executor.h:673
Dispatcher(CompletionHandler &handler)
Definition: executor.h:675
decltype(net::make_work_guard(handler_)) work_guard_
Definition: executor.h:689
CompletionHandler handler_
Definition: executor.h:688
void operator()()
Definition: executor.h:679
Definition: executor.h:149
Definition: executor.h:828
void post(Func &&f, const ProtoAllocator &a) const
strand(Executor ex)
Definition: executor.h:834
strand()=default
strand operator=(const strand< OtherExecutor > &other) noexcept
Definition: executor.h:863
strand(strand< OtherExecutor > &&other) noexcept
Definition: executor.h:847
strand(const strand< OtherExecutor > &other) noexcept
Definition: executor.h:844
Executor inner_ex_
Definition: executor.h:903
bool running_in_this_thread() const noexcept
Definition: executor.h:882
void defer(Func &&f, const ProtoAllocator &a) const
strand operator=(strand< OtherExecutor > &&other) noexcept
Definition: executor.h:870
strand operator=(strand &&other) noexcept
Definition: executor.h:856
void on_work_started() const noexcept
Definition: executor.h:888
void on_work_finished() const noexcept
Definition: executor.h:889
void dispatch(Func &&f, const ProtoAllocator &) const
Definition: executor.h:892
execution_context & context() const noexcept
Definition: executor.h:886
Executor inner_executor_type
Definition: executor.h:830
strand(strand &&other) noexcept
Definition: executor.h:841
strand operator=(const strand &other) noexcept
Definition: executor.h:850
std::queue< std::function< void()> > jobs_
Definition: executor.h:906
strand(std::allocator_arg_t, const ProtoAllocator &, Executor ex)
Definition: executor.h:837
strand(const strand &other) noexcept
Definition: executor.h:840
inner_executor_type get_inner_executor() const noexcept
Definition: executor.h:880
bool running_
Definition: executor.h:905
Definition: executor.h:567
static system_context & get_() noexcept
Definition: executor.h:631
bool stopped_
Definition: executor.h:640
void join()
Definition: executor.h:591
std::condition_variable cv_
Definition: executor.h:638
std::queue< std::function< void()> > tasks_
Definition: executor.h:639
void run_()
Definition: executor.h:601
std::thread thread_
Definition: executor.h:636
system_context(const system_context &)=delete
bool stopped() const noexcept
Definition: executor.h:587
~system_context() override
Definition: executor.h:574
void post_(std::function< void()> f)
Definition: executor.h:618
std::mutex mtx_
Definition: executor.h:637
friend class system_executor
Definition: executor.h:599
executor_type get_executor() noexcept
Definition: executor.h:579
system_context & operator=(const system_context &)=delete
void stop()
Definition: executor.h:581
system_context(__tag)
Definition: executor.h:597
Definition: executor.h:537
system_executor()=default
void dispatch(Func &&f, const ProtoAllocator &a) const
Definition: executor.h:655
void defer(Func &&f, const ProtoAllocator &a) const
Definition: executor.h:659
void on_work_finished() const noexcept
Definition: executor.h:544
system_context & context() const noexcept
Definition: executor.h:645
void on_work_started() const noexcept
Definition: executor.h:543
void post(Func &&f, const ProtoAllocator &a) const
Definition: executor.h:650
Header for compiler-dependent features.
#define MY_COMPILER_DIAGNOSTIC_PUSH()
save the compiler's diagnostic (enabled warnings, errors, ...) state
Definition: my_compiler.h:285
#define MY_COMPILER_DIAGNOSTIC_POP()
restore the compiler's diagnostic (enabled warnings, errors, ...) state
Definition: my_compiler.h:286
static QUEUE queue
Definition: myisampack.cc:210
void for_each(const Shards< COUNT > &shards, Function &&f) noexcept
Iterate over the shards.
Definition: ut0counter.h:323
std::string_view Key
The key type for the hash structure in HashJoinRowBuffer.
Definition: hash_join_buffer.h:102
int key_type
Definition: method.h:38
Definition: http_server_component.cc:34
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:693
Definition: buffer.h:45
constexpr bool uses_executor_v
Definition: executor.h:380
bool operator!=(const system_executor &, const system_executor &)
Definition: executor.h:559
bool has_service(const execution_context &ctx) noexcept
Definition: executor.h:283
Service & make_service(execution_context &ctx, Args &&... args)
Definition: executor.h:259
auto defer(CompletionToken &&token)
Definition: executor.h:787
std::enable_if_t< is_executor< Executor >::value, executor_work_guard< Executor > > make_work_guard(const Executor &ex)
Definition: executor.h:507
typename associated_executor< T, Executor >::type associated_executor_t
Definition: executor.h:406
associated_allocator_t< T > get_associated_allocator(const T &t) noexcept
Definition: executor.h:138
auto dispatch(CompletionToken &&token)
Definition: executor.h:701
auto post(CompletionToken &&token)
queue a function call for later execution.
Definition: executor.h:746
constexpr executor_arg_t executor_arg
Definition: executor.h:361
Service::key_type & use_service(execution_context &ctx)
Definition: executor.h:237
typename associated_allocator< T, ProtoAllocator >::type associated_allocator_t
Definition: executor.h:104
constexpr bool is_executor_v
Definition: executor.h:356
associated_executor_t< T > get_associated_executor(const T &t) noexcept
Definition: executor.h:429
bool operator==(const system_executor &, const system_executor &)
Definition: executor.h:555
fork_event
Definition: executor.h:48
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:397
Definition: executor.h:384
static type __get(const T &, const Executor &ex) noexcept
Definition: executor.h:387
Executor type
Definition: executor.h:385
Definition: executor.h:409
static auto get(const T &t, const Executor &ex=Executor()) noexcept
Definition: executor.h:410
Definition: executor.h:190
ServicePtr(Service *svc)
Definition: executor.h:192
std::unique_ptr< service, void(*)(service *)> ptr_
Definition: executor.h:197
bool active_
Definition: executor.h:195
Definition: executor.h:359
Definition: executor.h:312
Definition: executor.h:368
Definition: executor.h:353
Definition: executor.h:596
Definition: executor.h:377
Definition: result.h:30
Definition: dtoa.cc:589