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