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