2018-12-31 20:04:05 +01:00
|
|
|
//
|
2022-01-01 01:35:39 +01:00
|
|
|
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2022
|
2018-12-31 20:04:05 +01:00
|
|
|
//
|
|
|
|
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
|
|
|
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
|
|
|
//
|
|
|
|
#pragma once
|
|
|
|
|
2020-11-23 01:24:36 +01:00
|
|
|
#include "td/actor/actor.h"
|
2018-12-31 20:04:05 +01:00
|
|
|
|
|
|
|
#include "td/utils/common.h"
|
|
|
|
#include "td/utils/port/thread.h"
|
|
|
|
#include "td/utils/Slice.h"
|
2018-09-27 15:37:15 +02:00
|
|
|
#include "td/utils/Time.h"
|
2018-12-31 20:04:05 +01:00
|
|
|
|
2018-09-11 16:43:43 +02:00
|
|
|
#if TD_PORT_WINDOWS
|
|
|
|
#include "td/utils/port/detail/Iocp.h"
|
|
|
|
#endif
|
|
|
|
|
2018-12-31 20:04:05 +01:00
|
|
|
#include <atomic>
|
|
|
|
#include <functional>
|
|
|
|
#include <mutex>
|
|
|
|
#include <utility>
|
|
|
|
|
|
|
|
namespace td {
|
|
|
|
|
2021-07-04 04:58:54 +02:00
|
|
|
class ConcurrentScheduler final : private Scheduler::Callback {
|
2018-12-31 20:04:05 +01:00
|
|
|
public:
|
2022-09-14 14:06:52 +02:00
|
|
|
explicit ConcurrentScheduler(int32 additional_thread_count, uint64 thread_affinity_mask = 0);
|
2018-12-31 20:04:05 +01:00
|
|
|
|
|
|
|
void finish_async() {
|
|
|
|
schedulers_[0]->finish();
|
|
|
|
}
|
2022-10-04 22:12:50 +02:00
|
|
|
|
2018-12-31 20:04:05 +01:00
|
|
|
void wakeup() {
|
|
|
|
schedulers_[0]->wakeup();
|
|
|
|
}
|
2022-10-04 22:12:50 +02:00
|
|
|
|
2018-09-18 15:43:16 +02:00
|
|
|
SchedulerGuard get_main_guard() {
|
2018-12-31 20:04:05 +01:00
|
|
|
return schedulers_[0]->get_guard();
|
|
|
|
}
|
|
|
|
|
2018-08-16 15:56:16 +02:00
|
|
|
SchedulerGuard get_send_guard() {
|
2018-08-17 11:19:21 +02:00
|
|
|
return schedulers_.back()->get_const_guard();
|
2018-08-16 15:56:16 +02:00
|
|
|
}
|
|
|
|
|
2018-12-31 20:04:05 +01:00
|
|
|
void test_one_thread_run();
|
|
|
|
|
2020-11-22 18:40:47 +01:00
|
|
|
bool is_finished() const {
|
2018-12-31 20:04:05 +01:00
|
|
|
return is_finished_.load(std::memory_order_relaxed);
|
|
|
|
}
|
|
|
|
|
2022-10-04 22:12:50 +02:00
|
|
|
thread::id get_thread_id(int32 sched_id);
|
|
|
|
|
2018-12-31 20:04:05 +01:00
|
|
|
void start();
|
|
|
|
|
2018-09-18 15:43:16 +02:00
|
|
|
bool run_main(double timeout) {
|
|
|
|
return run_main(Timestamp::in(timeout));
|
|
|
|
}
|
|
|
|
bool run_main(Timestamp timeout);
|
|
|
|
|
|
|
|
Timestamp get_main_timeout();
|
|
|
|
static double emscripten_get_main_timeout();
|
|
|
|
static void emscripten_clear_main_timeout();
|
2018-12-31 20:04:05 +01:00
|
|
|
|
|
|
|
void finish();
|
|
|
|
|
|
|
|
template <class ActorT, class... Args>
|
2021-12-09 22:27:13 +01:00
|
|
|
ActorOwn<ActorT> create_actor_unsafe(int32 sched_id, Slice name, Args &&...args) {
|
2018-12-31 20:04:05 +01:00
|
|
|
#if TD_THREAD_UNSUPPORTED || TD_EVENTFD_UNSUPPORTED
|
|
|
|
sched_id = 0;
|
|
|
|
#endif
|
|
|
|
CHECK(0 <= sched_id && sched_id < static_cast<int32>(schedulers_.size()));
|
|
|
|
auto guard = schedulers_[sched_id]->get_guard();
|
|
|
|
return schedulers_[sched_id]->create_actor<ActorT>(name, std::forward<Args>(args)...);
|
|
|
|
}
|
|
|
|
|
|
|
|
template <class ActorT>
|
|
|
|
ActorOwn<ActorT> register_actor_unsafe(int32 sched_id, Slice name, ActorT *actor) {
|
|
|
|
#if TD_THREAD_UNSUPPORTED || TD_EVENTFD_UNSUPPORTED
|
|
|
|
sched_id = 0;
|
|
|
|
#endif
|
|
|
|
CHECK(0 <= sched_id && sched_id < static_cast<int32>(schedulers_.size()));
|
|
|
|
auto guard = schedulers_[sched_id]->get_guard();
|
|
|
|
return schedulers_[sched_id]->register_actor<ActorT>(name, actor);
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
enum class State { Start, Run };
|
2018-10-26 16:11:20 +02:00
|
|
|
State state_ = State::Start;
|
2020-11-22 18:40:47 +01:00
|
|
|
std::mutex at_finish_mutex_;
|
2020-11-23 01:24:36 +01:00
|
|
|
vector<std::function<void()>> at_finish_; // can be used during destruction by Scheduler destructors
|
|
|
|
vector<unique_ptr<Scheduler>> schedulers_;
|
2019-01-24 04:18:14 +01:00
|
|
|
std::atomic<bool> is_finished_{false};
|
2018-12-31 20:04:05 +01:00
|
|
|
#if !TD_THREAD_UNSUPPORTED && !TD_EVENTFD_UNSUPPORTED
|
2020-11-23 01:24:36 +01:00
|
|
|
vector<td::thread> threads_;
|
2022-09-14 13:49:48 +02:00
|
|
|
uint64 thread_affinity_mask_ = 0;
|
2018-12-31 20:04:05 +01:00
|
|
|
#endif
|
2018-08-16 16:29:13 +02:00
|
|
|
#if TD_PORT_WINDOWS
|
2018-09-27 03:19:03 +02:00
|
|
|
unique_ptr<detail::Iocp> iocp_;
|
2018-08-16 16:29:13 +02:00
|
|
|
td::thread iocp_thread_;
|
|
|
|
#endif
|
2021-11-11 15:39:09 +01:00
|
|
|
int32 extra_scheduler_ = 0;
|
2018-12-31 20:04:05 +01:00
|
|
|
|
2021-07-03 22:51:36 +02:00
|
|
|
void on_finish() final;
|
2018-12-31 20:04:05 +01:00
|
|
|
|
2021-07-03 22:51:36 +02:00
|
|
|
void register_at_finish(std::function<void()> f) final;
|
2018-12-31 20:04:05 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
} // namespace td
|