1
0
Fork 0
mirror of https://github.com/ton-blockchain/ton synced 2025-03-09 15:40:10 +00:00

updated vm (breaking compatibility)

- updated vm
- new actor scheduler
- updated tonlib
- updated DNS smartcontract
This commit is contained in:
ton 2020-02-28 14:28:47 +04:00
parent 9e4816e7f6
commit e27fb1e09c
100 changed files with 3692 additions and 1299 deletions

View file

@ -14,7 +14,7 @@
You should have received a copy of the GNU Lesser General Public License
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
Copyright 2017-2019 Telegram Systems LLP
Copyright 2017-2020 Telegram Systems LLP
*/
#pragma once
@ -117,24 +117,28 @@ template <class T>
class OneValue<T *> {
public:
bool set_value(T *value) {
T *was = nullptr;
T *was = Empty();
return state_.compare_exchange_strong(was, value, std::memory_order_acq_rel);
}
bool get_value(T *&value) {
value = state_.exchange(Taken(), std::memory_order_acq_rel);
return value != nullptr;
return value != Empty();
}
void reset() {
state_ = nullptr;
state_ = Empty();
}
OneValue() {
}
private:
std::atomic<T *> state_{nullptr};
T *Taken() {
static T xxx;
return &xxx;
std::atomic<T *> state_{Empty()};
static T *Empty() {
static int64 xxx;
return reinterpret_cast<T *>(&xxx);
}
static T *Taken() {
static int64 xxx;
return reinterpret_cast<T *>(&xxx);
}
};

View file

@ -14,63 +14,86 @@
You should have received a copy of the GNU Lesser General Public License
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
Copyright 2017-2019 Telegram Systems LLP
Copyright 2017-2020 Telegram Systems LLP
*/
#pragma once
#include "td/utils/common.h"
#include "td/utils/logging.h"
#include "td/utils/port/thread.h"
#include <atomic>
#include <algorithm>
#include <condition_variable>
#include <mutex>
namespace td {
class MpmcWaiter {
class MpmcEagerWaiter {
public:
int wait(int yields, uint32 worker_id) {
if (yields < RoundsTillSleepy) {
struct Slot {
private:
friend class MpmcEagerWaiter;
int yields;
uint32 worker_id;
};
void init_slot(Slot &slot, uint32 worker_id) {
slot.yields = 0;
slot.worker_id = worker_id;
}
void wait(Slot &slot) {
if (slot.yields < RoundsTillSleepy) {
td::this_thread::yield();
return yields + 1;
} else if (yields == RoundsTillSleepy) {
slot.yields++;
return;
} else if (slot.yields == RoundsTillSleepy) {
auto state = state_.load(std::memory_order_relaxed);
if (!State::has_worker(state)) {
auto new_state = State::with_worker(state, worker_id);
auto new_state = State::with_worker(state, slot.worker_id);
if (state_.compare_exchange_strong(state, new_state, std::memory_order_acq_rel)) {
td::this_thread::yield();
return yields + 1;
slot.yields++;
return;
}
if (state == State::awake()) {
return 0;
slot.yields = 0;
return;
}
}
td::this_thread::yield();
return 0;
} else if (yields < RoundsTillAsleep) {
slot.yields = 0;
return;
} else if (slot.yields < RoundsTillAsleep) {
auto state = state_.load(std::memory_order_acquire);
if (State::still_sleepy(state, worker_id)) {
if (State::still_sleepy(state, slot.worker_id)) {
td::this_thread::yield();
return yields + 1;
slot.yields++;
return;
}
return 0;
slot.yields = 0;
return;
} else {
auto state = state_.load(std::memory_order_acquire);
if (State::still_sleepy(state, worker_id)) {
if (State::still_sleepy(state, slot.worker_id)) {
std::unique_lock<std::mutex> lock(mutex_);
if (state_.compare_exchange_strong(state, State::asleep(), std::memory_order_acq_rel)) {
condition_variable_.wait(lock);
}
}
return 0;
slot.yields = 0;
return;
}
}
int stop_wait(int yields, uint32 worker_id) {
if (yields > RoundsTillSleepy) {
void stop_wait(Slot &slot) {
if (slot.yields > RoundsTillSleepy) {
notify_cold();
}
return 0;
slot.yields = 0;
return;
}
void close() {
}
void notify() {
@ -102,8 +125,8 @@ class MpmcWaiter {
return (state >> 1) == (worker + 1);
}
};
//enum { RoundsTillSleepy = 32, RoundsTillAsleep = 64 };
enum { RoundsTillSleepy = 1, RoundsTillAsleep = 2 };
enum { RoundsTillSleepy = 32, RoundsTillAsleep = 64 };
// enum { RoundsTillSleepy = 1, RoundsTillAsleep = 2 };
std::atomic<uint32> state_{State::awake()};
std::mutex mutex_;
std::condition_variable condition_variable_;
@ -117,4 +140,208 @@ class MpmcWaiter {
}
};
class MpmcSleepyWaiter {
public:
struct Slot {
private:
friend class MpmcSleepyWaiter;
enum State { Search, Work, Sleep } state_{Work};
void park() {
std::unique_lock<std::mutex> guard(mutex_);
condition_variable_.wait(guard, [&] { return unpark_flag_; });
unpark_flag_ = false;
}
bool cancel_park() {
auto res = unpark_flag_;
unpark_flag_ = false;
return res;
}
void unpark() {
//TODO: try unlock guard before notify_all
std::unique_lock<std::mutex> guard(mutex_);
unpark_flag_ = true;
condition_variable_.notify_all();
}
std::mutex mutex_;
std::condition_variable condition_variable_;
bool unpark_flag_{false}; // TODO: move out of lock
int yield_cnt{0};
int32 worker_id{0};
char padding[128];
};
// There are a lot of workers
// Each has a slot
//
// States of a worker:
// - searching for work | Search
// - processing work | Work
// - sleeping | Sleep
//
// When somebody adds a work it calls notify
//
// notify
// if there are workers in search phase do nothing.
// if all workers are awake do nothing
// otherwise wake some random worker
//
// Initially all workers are in Search mode.
//
// When worker found nothing it may try to call wait.
// This may put it in a Sleep for some time.
// After wait return worker will be in Search state again.
//
// Suppose worker found a work and ready to process it.
// Than it may call stop_wait. This will cause transition from
// Search to Work state.
//
// Main invariant:
// After notify is called there should be at least on worker in Search or Work state.
// If possible - in Search state
//
void init_slot(Slot &slot, int32 worker_id) {
slot.state_ = Slot::State::Work;
slot.unpark_flag_ = false;
slot.worker_id = worker_id;
VLOG(waiter) << "Init slot " << worker_id;
}
int VERBOSITY_NAME(waiter) = VERBOSITY_NAME(DEBUG) + 10;
void wait(Slot &slot) {
if (slot.state_ == Slot::State::Work) {
VLOG(waiter) << "Work -> Search";
state_++;
slot.state_ = Slot::State::Search;
slot.yield_cnt = 0;
return;
}
if (slot.state_ == Slot::Search) {
if (slot.yield_cnt++ < 10 && false) {
td::this_thread::yield();
return;
}
slot.state_ = Slot::State::Sleep;
std::unique_lock<std::mutex> guard(sleepers_mutex_);
auto state_view = StateView(state_.fetch_add((1 << PARKING_SHIFT) - 1));
CHECK(state_view.searching_count != 0);
bool should_search = state_view.searching_count == 1;
if (closed_) {
return;
}
sleepers_.push_back(&slot);
LOG_CHECK(slot.unpark_flag_ == false) << slot.worker_id;
VLOG(waiter) << "add to sleepers " << slot.worker_id;
//guard.unlock();
if (should_search) {
VLOG(waiter) << "Search -> Search once then Sleep ";
return;
}
VLOG(waiter) << "Search -> Sleep " << state_view.searching_count << " " << state_view.parked_count;
}
CHECK(slot.state_ == Slot::State::Sleep);
VLOG(waiter) << "Park " << slot.worker_id;
slot.park();
VLOG(waiter) << "Resume " << slot.worker_id;
slot.state_ = Slot::State::Search;
slot.yield_cnt = 0;
}
void stop_wait(Slot &slot) {
if (slot.state_ == Slot::State::Work) {
return;
}
if (slot.state_ == Slot::State::Sleep) {
VLOG(waiter) << "Search once then Sleep -> Work/Search " << slot.worker_id;
slot.state_ = Slot::State::Work;
std::unique_lock<std::mutex> guard(sleepers_mutex_);
auto it = std::find(sleepers_.begin(), sleepers_.end(), &slot);
if (it != sleepers_.end()) {
sleepers_.erase(it);
VLOG(waiter) << "remove from sleepers " << slot.worker_id;
state_.fetch_sub((1 << PARKING_SHIFT) - 1);
guard.unlock();
} else {
guard.unlock();
VLOG(waiter) << "not in sleepers" << slot.worker_id;
CHECK(slot.cancel_park());
}
}
VLOG(waiter) << "Search once then Sleep -> Work " << slot.worker_id;
slot.state_ = Slot::State::Search;
auto state_view = StateView(state_.fetch_sub(1));
CHECK(state_view.searching_count != 0);
CHECK(state_view.searching_count < 1000);
bool should_notify = state_view.searching_count == 1;
if (should_notify) {
VLOG(waiter) << "Notify others";
notify();
}
VLOG(waiter) << "Search -> Work ";
slot.state_ = Slot::State::Work;
}
void notify() {
auto view = StateView(state_.load());
//LOG(ERROR) << view.parked_count;
if (view.searching_count > 0 || view.parked_count == 0) {
VLOG(waiter) << "Ingore notify: " << view.searching_count << " " << view.parked_count;
return;
}
VLOG(waiter) << "Notify: " << view.searching_count << " " << view.parked_count;
std::unique_lock<std::mutex> guard(sleepers_mutex_);
view = StateView(state_.load());
if (view.searching_count > 0) {
VLOG(waiter) << "Skip notify: got searching";
return;
}
CHECK(view.parked_count == static_cast<int>(sleepers_.size()));
if (sleepers_.empty()) {
VLOG(waiter) << "Skip notify: no sleepers";
return;
}
auto sleeper = sleepers_.back();
sleepers_.pop_back();
state_.fetch_sub((1 << PARKING_SHIFT) - 1);
VLOG(waiter) << "Unpark " << sleeper->worker_id;
sleeper->unpark();
}
void close() {
StateView state(state_.load());
LOG_CHECK(state.parked_count == 0) << state.parked_count;
LOG_CHECK(state.searching_count == 0) << state.searching_count;
}
private:
static constexpr td::int32 PARKING_SHIFT = 16;
struct StateView {
td::int32 parked_count;
td::int32 searching_count;
explicit StateView(int32 x) {
parked_count = x >> PARKING_SHIFT;
searching_count = x & ((1 << PARKING_SHIFT) - 1);
}
};
std::atomic<td::int32> state_{0};
std::mutex sleepers_mutex_;
std::vector<Slot *> sleepers_;
bool closed_ = false;
};
using MpmcWaiter = MpmcSleepyWaiter;
} // namespace td

View file

@ -14,7 +14,7 @@
You should have received a copy of the GNU Lesser General Public License
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
Copyright 2017-2019 Telegram Systems LLP
Copyright 2017-2020 Telegram Systems LLP
*/
#pragma once
@ -49,9 +49,7 @@ class AtomicRefCnt {
};
template <class DataT, class DeleterT>
class SharedPtrRaw
: public DeleterT
, private MpscLinkQueueImpl::Node {
class SharedPtrRaw : public DeleterT, private MpscLinkQueueImpl::Node {
public:
explicit SharedPtrRaw(DeleterT deleter) : DeleterT(std::move(deleter)), ref_cnt_{0}, option_magic_(Magic) {
}
@ -100,6 +98,7 @@ template <class T, class DeleterT = std::default_delete<T>>
class SharedPtr {
public:
using Raw = detail::SharedPtrRaw<T, DeleterT>;
struct acquire_t {};
SharedPtr() = default;
~SharedPtr() {
if (!raw_) {
@ -112,6 +111,8 @@ class SharedPtr {
raw_->inc();
}
}
SharedPtr(acquire_t, Raw *raw) : raw_(raw) {
}
SharedPtr(const SharedPtr &other) : SharedPtr(other.raw_) {
}
SharedPtr &operator=(const SharedPtr &other) {

View file

@ -0,0 +1,124 @@
/*
This file is part of TON Blockchain Library.
TON Blockchain Library is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.
TON Blockchain Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
Copyright 2019-2020 Telegram Systems LLP
*/
#pragma once
#include "td/utils/Status.h"
#include "td/utils/Span.h"
namespace td {
template <class T, size_t N = 256 /*must be a power of two*/>
class StealingQueue {
public:
// tries to put a value
// returns if succeeded
// only owner is alowed to to do this
template <class F>
void local_push(T value, F&& overflow_f) {
while (true) {
auto tail = tail_.load(std::memory_order_relaxed);
auto head = head_.load(); //TODO: memory order
if (static_cast<size_t>(tail - head) < N) {
buf_[tail & MASK].store(value, std::memory_order_relaxed);
tail_.store(tail + 1, std::memory_order_release);
return;
}
// queue is full
// TODO: batch insert into global queue?
auto n = N / 2 + 1;
auto new_head = head + n;
if (!head_.compare_exchange_strong(head, new_head)) {
continue;
}
for (size_t i = 0; i < n; i++) {
overflow_f(buf_[(i + head) & MASK].load(std::memory_order_relaxed));
}
overflow_f(value);
return;
}
}
// tries to pop a value
// returns if succeeded
// only owner is alowed to to do this
bool local_pop(T& value) {
auto tail = tail_.load(std::memory_order_relaxed);
auto head = head_.load();
if (head == tail) {
return false;
}
value = buf_[head & MASK].load(std::memory_order_relaxed);
return head_.compare_exchange_strong(head, head + 1);
}
bool steal(T& value, StealingQueue<T, N>& other) {
while (true) {
auto tail = tail_.load(std::memory_order_relaxed);
auto head = head_.load(); //TODO: memory order
auto other_head = other.head_.load();
auto other_tail = other.tail_.load(std::memory_order_acquire);
if (other_tail < other_head) {
continue;
}
size_t n = other_tail - other_head;
if (n > N) {
continue;
}
n -= n / 2;
n = td::min(n, static_cast<size_t>(head + N - tail));
if (n == 0) {
return false;
}
for (size_t i = 0; i < n; i++) {
buf_[(i + tail) & MASK].store(other.buf_[(i + other_head) & MASK].load(std::memory_order_relaxed),
std::memory_order_relaxed);
}
if (!other.head_.compare_exchange_strong(other_head, other_head + n)) {
continue;
}
n--;
value = buf_[(tail + n) & MASK].load(std::memory_order_relaxed);
tail_.store(tail + n, std::memory_order_release);
return true;
}
}
StealingQueue() {
for (auto& x : buf_) {
x.store(T{}, std::memory_order_relaxed);
}
std::atomic_thread_fence(std::memory_order_seq_cst);
}
private:
std::atomic<td::int64> head_{0};
std::atomic<td::int64> tail_{0};
static constexpr size_t MASK{N - 1};
std::array<std::atomic<T>, N> buf_;
};
}; // namespace td

View file

@ -14,7 +14,7 @@
You should have received a copy of the GNU Lesser General Public License
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
Copyright 2017-2019 Telegram Systems LLP
Copyright 2017-2020 Telegram Systems LLP
*/
#pragma once

View file

@ -14,7 +14,7 @@
You should have received a copy of the GNU Lesser General Public License
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
Copyright 2017-2019 Telegram Systems LLP
Copyright 2017-2020 Telegram Systems LLP
*/
#include "TsFileLog.h"
@ -24,8 +24,10 @@ namespace td {
namespace detail {
class TsFileLog : public LogInterface {
public:
Status init(string path) {
Status init(string path, td::int64 rotate_threshold, bool redirect_stderr) {
path_ = std::move(path);
rotate_threshold_ = rotate_threshold;
redirect_stderr_ = redirect_stderr;
for (int i = 0; i < (int)logs_.size(); i++) {
logs_[i].id = i;
}
@ -54,6 +56,8 @@ class TsFileLog : public LogInterface {
int id;
};
static constexpr int MAX_THREAD_ID = 128;
td::int64 rotate_threshold_;
bool redirect_stderr_;
std::string path_;
std::array<Info, MAX_THREAD_ID> logs_;
@ -70,7 +74,7 @@ class TsFileLog : public LogInterface {
}
Status init_info(Info *info) {
TRY_STATUS(info->log.init(get_path(info), std::numeric_limits<int64>::max(), info->id == 0));
TRY_STATUS(info->log.init(get_path(info), std::numeric_limits<int64>::max(), info->id == 0 && redirect_stderr_));
info->is_inited = true;
return Status::OK();
}
@ -92,9 +96,9 @@ class TsFileLog : public LogInterface {
};
} // namespace detail
Result<td::unique_ptr<LogInterface>> TsFileLog::create(string path) {
Result<td::unique_ptr<LogInterface>> TsFileLog::create(string path, td::int64 rotate_threshold, bool redirect_stderr) {
auto res = td::make_unique<detail::TsFileLog>();
TRY_STATUS(res->init(path));
TRY_STATUS(res->init(path, rotate_threshold, redirect_stderr));
return std::move(res);
}
} // namespace td

View file

@ -14,7 +14,7 @@
You should have received a copy of the GNU Lesser General Public License
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
Copyright 2017-2019 Telegram Systems LLP
Copyright 2017-2020 Telegram Systems LLP
*/
#pragma once
@ -22,7 +22,10 @@
namespace td {
class TsFileLog {
static constexpr int64 DEFAULT_ROTATE_THRESHOLD = 10 * (1 << 20);
public:
static Result<td::unique_ptr<LogInterface>> create(string path);
static Result<td::unique_ptr<LogInterface>> create(string path, int64 rotate_threshold = DEFAULT_ROTATE_THRESHOLD,
bool redirect_stderr = true);
};
} // namespace td

View file

@ -1,3 +1,21 @@
/*
This file is part of TON Blockchain Library.
TON Blockchain Library is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.
TON Blockchain Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
Copyright 2019-2020 Telegram Systems LLP
*/
#include "rlimit.h"
#if TD_LINUX || TD_ANDROID
#include <unistd.h>

View file

@ -1,3 +1,21 @@
/*
This file is part of TON Blockchain Library.
TON Blockchain Library is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.
TON Blockchain Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
Copyright 2017-2020 Telegram Systems LLP
*/
#pragma once
#include "td/utils/port/config.h"

View file

@ -1,3 +1,21 @@
/*
This file is part of TON Blockchain Library.
TON Blockchain Library is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.
TON Blockchain Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
Copyright 2017-2020 Telegram Systems LLP
*/
#include "user.h"
#if TD_LINUX
#include <unistd.h>

View file

@ -1,3 +1,21 @@
/*
This file is part of TON Blockchain Library.
TON Blockchain Library is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.
TON Blockchain Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
Copyright 2017-2020 Telegram Systems LLP
*/
#pragma once
#include "td/utils/port/config.h"