MySQL 9.1.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
495template <class Executor>
497 requires(is_executor_v<Executor>)
498{
500}
501
502template <class ExecutionContext>
504 ExecutionContext &ctx)
505 requires(std::is_convertible_v<ExecutionContext &, execution_context &>)
506{
507 return make_work_guard(ctx.get_executor());
508}
509
510template <class T>
512 requires(!is_executor_v<T> &&
513 !std::is_convertible_v<T &, execution_context &>)
514
515{
517}
518
519template <class T, class U>
520auto make_work_guard(const T &t, U &&u)
522 std::forward<U>(u)))) {
523 return make_work_guard(get_associated_executor(t, std::forward<U>(u)));
524}
525
526class system_context;
527
528// 13.18 [async.system.exec]
530 public:
531 system_executor() = default;
532
533 system_context &context() const noexcept;
534
535 void on_work_started() const noexcept {}
536 void on_work_finished() const noexcept {}
537
538 template <class Func, class ProtoAllocator>
539 void dispatch(Func &&f, const ProtoAllocator &a) const;
540 template <class Func, class ProtoAllocator>
541 void post(Func &&f, const ProtoAllocator &a) const;
542 template <class Func, class ProtoAllocator>
543 void defer(Func &&f, const ProtoAllocator &a) const;
544};
545
546// 13.18.2 [async.system.exec.comparisons]
547inline bool operator==(const system_executor &, const system_executor &) {
548 return true;
549}
550
551inline bool operator!=(const system_executor &, const system_executor &) {
552 return false;
553}
554
555// 13.19 [async.system.context]
556//
557// just barely enough of a system_context to run everything in the
558// main-thread
560 public:
562
563 system_context() = delete;
566 ~system_context() override {
567 stop();
568 join();
569 }
570
571 executor_type get_executor() noexcept { return {}; }
572
573 void stop() {
574 std::lock_guard<std::mutex> lk(mtx_);
575 stopped_ = true;
576
577 cv_.notify_all();
578 }
579 bool stopped() const noexcept {
580 std::lock_guard<std::mutex> lk(mtx_);
581 return stopped_;
582 }
583 void join() {
584 if (thread_.joinable()) thread_.join();
585 }
586
587 private:
588 struct __tag {};
590
591 friend class system_executor;
592
593 void run_() {
594 for (;;) {
595 std::function<void()> f;
596 {
597 std::unique_lock<std::mutex> lk(mtx_);
598
599 cv_.wait(lk, [this] { return stopped_ || !tasks_.empty(); });
600
601 if (stopped_) return;
602
603 f = std::move(tasks_.front());
604 tasks_.pop();
605 }
606 f();
607 }
608 }
609
610 void post_(std::function<void()> f) {
611 std::lock_guard<std::mutex> lk(mtx_);
612 if (stopped_) return;
613
614 if (!thread_.joinable()) {
615 thread_ = std::thread(&system_context::run_, this);
616 }
617
618 tasks_.push(std::move(f));
619
620 cv_.notify_one();
621 }
622
623 static system_context &get_() noexcept {
624 static system_context sc(__tag{});
625 return sc;
626 }
627
628 std::thread thread_;
629 mutable std::mutex mtx_;
630 std::condition_variable cv_;
631 std::queue<std::function<void()>> tasks_;
632 bool stopped_{false};
633};
634
635// 13.18.1 [async.system.exec.ops]
636
637inline system_context &system_executor::context() const noexcept {
638 return system_context::get_();
639}
640
641template <class Func, class ProtoAllocator>
642void system_executor::post(Func &&f, const ProtoAllocator &) const {
643 system_context::get_().post_(std::forward<Func>(f));
644}
645
646template <class Func, class ProtoAllocator>
647void system_executor::dispatch(Func &&f, const ProtoAllocator &) const {
648 std::decay_t<Func>{std::forward<Func>(f)}();
649}
650template <class Func, class ProtoAllocator>
651void system_executor::defer(Func &&f, const ProtoAllocator &a) const {
652 post(std::forward<Func>(f), a);
653}
654
655// 13.20 [async.bad.exec] - not implemented
656
657// 13.21 [async.executor] - not implemented
658//
659//
660namespace impl {
661/**
662 * function object for net::dispatch(), net::post(), net::defer().
663 */
664template <class CompletionHandler>
666 public:
667 explicit Dispatcher(CompletionHandler &handler)
668 : handler_{std::move(handler)},
670
671 void operator()() {
673
674 work_guard_.get_executor().dispatch(std::move(handler_), alloc);
675
676 work_guard_.reset();
677 }
678
679 private:
680 CompletionHandler handler_;
682};
683
684template <class CompletionHandler>
687}
688} // namespace impl
689
690// 13.22 [async.dispatch]
691
692template <class CompletionToken>
693auto dispatch(CompletionToken &&token) {
694 async_completion<CompletionToken, void()> completion(token);
695
696 auto ex = get_associated_executor(completion.completion_handler);
697 auto alloc = get_associated_allocator(completion.completion_handler);
698 ex.dispatch(std::move(completion.completion_handler), alloc);
699
700 return completion.result.get();
701}
702
703/**
704 * queue a function call for later execution.
705 */
706template <class Executor, class CompletionToken>
707typename async_result<std::decay_t<CompletionToken>, void()>::return_type
708dispatch(const Executor &ex, CompletionToken &&token)
709 requires(is_executor_v<Executor>)
710{
711 async_completion<CompletionToken, void()> completion(token);
712
713 auto alloc = get_associated_allocator(completion.completion_handler);
714
715 ex.dispatch(impl::make_dispatcher(completion.completion_handler), alloc);
716
717 return completion.result.get();
718}
719
720/**
721 * queue a function call for later execution.
722 */
723template <class ExecutionContext, class CompletionToken>
724typename async_result<std::decay_t<CompletionToken>, void()>::return_type
725dispatch(ExecutionContext &ctx, CompletionToken &&token)
726 requires(std::is_convertible_v<ExecutionContext &, execution_context &>)
727{
728 return net::dispatch(ctx.get_executor(),
729 std::forward<CompletionToken>(token));
730}
731
732// 13.23 [async.post]
733
734/**
735 * queue a function call for later execution.
736 */
737template <class CompletionToken>
738auto post(CompletionToken &&token) {
739 async_completion<CompletionToken, void()> completion(token);
740
741 auto ex = get_associated_executor(completion.completion_handler);
742 auto alloc = get_associated_allocator(completion.completion_handler);
743 ex.post(std::move(completion.completion_handler), alloc);
744
745 return completion.result.get();
746}
747
748/**
749 * queue a function call for later execution.
750 */
751template <class Executor, class CompletionToken>
752typename async_result<std::decay_t<CompletionToken>, void()>::return_type //
753post(const Executor &ex, CompletionToken &&token)
754 requires(is_executor_v<Executor>)
755{
756 async_completion<CompletionToken, void()> completion(token);
757
758 auto alloc = get_associated_allocator(completion.completion_handler);
759
760 ex.post(impl::make_dispatcher(completion.completion_handler), alloc);
761
762 return completion.result.get();
763}
764
765/**
766 * queue a function call for later execution.
767 */
768template <class ExecutionContext, class CompletionToken>
769typename async_result<std::decay_t<CompletionToken>, void()>::return_type //
770post(ExecutionContext &ctx, CompletionToken &&token)
771 requires(std::is_convertible_v<ExecutionContext &, execution_context &>)
772{
773 return net::post(ctx.get_executor(), std::forward<CompletionToken>(token));
774}
775
776// 13.24 [async.defer]
777
778template <class CompletionToken>
779auto defer(CompletionToken &&token) {
780 async_completion<CompletionToken, void()> completion(token);
781
782 auto ex = get_associated_executor(completion.completion_handler);
783 auto alloc = get_associated_allocator(completion.completion_handler);
784 ex.defer(std::move(completion.completion_handler), alloc);
785
786 return completion.result.get();
787}
788
789/**
790 * queue a function call for later execution.
791 */
792template <class Executor, class CompletionToken>
793typename async_result<std::decay_t<CompletionToken>, void()>::return_type //
794defer(const Executor &ex, CompletionToken &&token)
795 requires(is_executor_v<Executor>)
796{
797 async_completion<CompletionToken, void()> completion(token);
798
799 auto alloc = get_associated_allocator(completion.completion_handler);
800
801 ex.defer(impl::make_dispatcher(completion.completion_handler), alloc);
802
803 return completion.result.get();
804}
805
806/**
807 * queue a function call for later execution.
808 */
809template <class ExecutionContext, class CompletionToken>
810typename async_result<std::decay_t<CompletionToken>, void()>::return_type //
811defer(ExecutionContext &ctx, CompletionToken &&token)
812 requires(std::is_convertible_v<ExecutionContext &, execution_context &>)
813{
814 return net::defer(ctx.get_executor(), std::forward<CompletionToken>(token));
815}
816
817// 13.25 [async.strand] - partially implemented
818
819template <class Executor>
820class strand {
821 public:
822 using inner_executor_type = Executor;
823
824 strand() = default;
825
826 explicit strand(Executor ex) : inner_ex_{ex} {}
827
828 template <class ProtoAllocator>
829 strand(std::allocator_arg_t, const ProtoAllocator & /* alloc */, Executor ex)
830 : inner_ex_{ex} {}
831
832 strand(const strand &other) noexcept : inner_ex_{other.inner_ex_} {}
833 strand(strand &&other) noexcept : inner_ex_{std::move(other.inner_ex_)} {}
834
835 template <class OtherExecutor>
836 strand(const strand<OtherExecutor> &other) noexcept
837 : inner_ex_{other.inner_ex_} {}
838 template <class OtherExecutor>
840 : inner_ex_{std::move(other.inner_ex_)} {}
841
842 strand operator=(const strand &other) noexcept {
843 inner_ex_ = other.inner_ex_;
844
845 return *this;
846 }
847
848 strand operator=(strand &&other) noexcept {
849 inner_ex_ = std::move(other.inner_ex_);
850
851 return *this;
852 }
853
854 template <class OtherExecutor>
855 strand operator=(const strand<OtherExecutor> &other) noexcept {
856 inner_ex_ = other.inner_ex_;
857
858 return *this;
859 }
860
861 template <class OtherExecutor>
863 inner_ex_ = std::move(other.inner_ex_);
864
865 return *this;
866 }
867
869
870 // strand ops
871
873
874 bool running_in_this_thread() const noexcept {
875 return impl::Callstack<strand>::contains(this) != nullptr;
876 }
877
878 execution_context &context() const noexcept { return inner_ex_.context(); }
879
880 void on_work_started() const noexcept { inner_ex_.on_work_started(); }
881 void on_work_finished() const noexcept { inner_ex_.on_work_finished(); }
882
883 template <class Func, class ProtoAllocator>
884 void dispatch(Func &&f, const ProtoAllocator & /* a */) const {
886 std::forward<Func>(f)();
887 }
888 }
889 template <class Func, class ProtoAllocator>
890 void post(Func &&f, const ProtoAllocator &a) const;
891 template <class Func, class ProtoAllocator>
892 void defer(Func &&f, const ProtoAllocator &a) const;
893
894 private:
895 Executor inner_ex_;
896
897 bool running_{false};
898 std::queue<std::function<void()>> jobs_;
899};
900
901template <class Executor>
903
904template <class Executor>
906 return !(a == b);
907}
908
909// 13.26 [async.use.future] - not implemented
910
911// 13.27 [async.packaged.task.spec] - not implemented
912
913// 13.7.3 [async.exec.ctx.ops]
915 // prepare is in reverse
916 if (e == fork_event::prepare) {
917 std::for_each(services_.rbegin(), services_.rend(),
918 [e](auto &svc) { svc.ptr_->notify_fork(e); });
919 } else {
920 std::for_each(services_.begin(), services_.end(),
921 [e](auto &svc) { svc.ptr_->notify_fork(e); });
922 }
923}
924
925// 13.7.4 [async.exec.ctx.protected]
926inline void execution_context::shutdown() noexcept {
927 // shutdown in reverse insert-order
928 std::for_each(services_.rbegin(), services_.rend(), [](auto &svc) {
929 if (svc.active_) {
930 svc.ptr_->shutdown();
931 svc.active_ = false;
932 }
933 });
934}
935
936} // namespace net
937
938#endif
execution context for SQL.
Definition: sql_exec_context.h:39
The handler class is the interface for dynamically loadable storage engines.
Definition: handler.h:4583
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
service * add_service(Args &&...args)
Definition: executor.h:218
std::list< ServicePtr > services_
Definition: executor.h:214
execution_context(const execution_context &)=delete
void shutdown() noexcept
Definition: executor.h:926
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:914
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:665
Dispatcher(CompletionHandler &handler)
Definition: executor.h:667
decltype(net::make_work_guard(handler_)) work_guard_
Definition: executor.h:681
CompletionHandler handler_
Definition: executor.h:680
void operator()()
Definition: executor.h:671
Definition: executor.h:149
Definition: executor.h:820
void post(Func &&f, const ProtoAllocator &a) const
strand(Executor ex)
Definition: executor.h:826
strand()=default
strand operator=(const strand< OtherExecutor > &other) noexcept
Definition: executor.h:855
strand(strand< OtherExecutor > &&other) noexcept
Definition: executor.h:839
strand(const strand< OtherExecutor > &other) noexcept
Definition: executor.h:836
Executor inner_ex_
Definition: executor.h:895
bool running_in_this_thread() const noexcept
Definition: executor.h:874
void defer(Func &&f, const ProtoAllocator &a) const
strand operator=(strand< OtherExecutor > &&other) noexcept
Definition: executor.h:862
strand operator=(strand &&other) noexcept
Definition: executor.h:848
void on_work_started() const noexcept
Definition: executor.h:880
void on_work_finished() const noexcept
Definition: executor.h:881
void dispatch(Func &&f, const ProtoAllocator &) const
Definition: executor.h:884
execution_context & context() const noexcept
Definition: executor.h:878
Executor inner_executor_type
Definition: executor.h:822
strand(strand &&other) noexcept
Definition: executor.h:833
strand operator=(const strand &other) noexcept
Definition: executor.h:842
std::queue< std::function< void()> > jobs_
Definition: executor.h:898
strand(std::allocator_arg_t, const ProtoAllocator &, Executor ex)
Definition: executor.h:829
strand(const strand &other) noexcept
Definition: executor.h:832
inner_executor_type get_inner_executor() const noexcept
Definition: executor.h:872
bool running_
Definition: executor.h:897
Definition: executor.h:559
static system_context & get_() noexcept
Definition: executor.h:623
bool stopped_
Definition: executor.h:632
void join()
Definition: executor.h:583
std::condition_variable cv_
Definition: executor.h:630
std::queue< std::function< void()> > tasks_
Definition: executor.h:631
void run_()
Definition: executor.h:593
std::thread thread_
Definition: executor.h:628
system_context(const system_context &)=delete
bool stopped() const noexcept
Definition: executor.h:579
~system_context() override
Definition: executor.h:566
void post_(std::function< void()> f)
Definition: executor.h:610
std::mutex mtx_
Definition: executor.h:629
friend class system_executor
Definition: executor.h:591
executor_type get_executor() noexcept
Definition: executor.h:571
system_context & operator=(const system_context &)=delete
void stop()
Definition: executor.h:573
system_context(__tag)
Definition: executor.h:589
Definition: executor.h:529
system_executor()=default
void dispatch(Func &&f, const ProtoAllocator &a) const
Definition: executor.h:647
void defer(Func &&f, const ProtoAllocator &a) const
Definition: executor.h:651
void on_work_finished() const noexcept
Definition: executor.h:536
system_context & context() const noexcept
Definition: executor.h:637
void on_work_started() const noexcept
Definition: executor.h:535
void post(Func &&f, const ProtoAllocator &a) const
Definition: executor.h:642
Header for compiler-dependent features.
#define MY_COMPILER_DIAGNOSTIC_PUSH()
save the compiler's diagnostic (enabled warnings, errors, ...) state
Definition: my_compiler.h:277
#define MY_COMPILER_DIAGNOSTIC_POP()
restore the compiler's diagnostic (enabled warnings, errors, ...) state
Definition: my_compiler.h:278
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:108
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:685
Definition: buffer.h:45
constexpr bool uses_executor_v
Definition: executor.h:380
bool operator!=(const system_executor &, const system_executor &)
Definition: executor.h:551
bool has_service(const execution_context &ctx) noexcept
Definition: executor.h:283
auto defer(CompletionToken &&token)
Definition: executor.h:779
typename associated_executor< T, Executor >::type associated_executor_t
Definition: executor.h:406
executor_work_guard< Executor > make_work_guard(const Executor &ex)
Definition: executor.h:496
Service & make_service(execution_context &ctx, Args &&...args)
Definition: executor.h:259
associated_allocator_t< T > get_associated_allocator(const T &t) noexcept
Definition: executor.h:138
auto dispatch(CompletionToken &&token)
Definition: executor.h:693
auto post(CompletionToken &&token)
queue a function call for later execution.
Definition: executor.h:738
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:547
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:2440
MY_COMPILER_CLANG_DIAGNOSTIC_IGNORE("-Winconsistent-missing-destructor-override") static Scope_guard static_guard([]()
Definition: protobuf_plugin.cc:33
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:588
Definition: executor.h:377
Definition: result.h:30
Definition: dtoa.cc:595