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

initial commit

This commit is contained in:
initial commit 2019-09-07 14:03:22 +04:00 committed by vvaltman
commit c2da007f40
1610 changed files with 398047 additions and 0 deletions

View file

@ -0,0 +1,136 @@
/*
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-2019 Telegram Systems LLP
*/
#include "td/utils/port/detail/Epoll.h"
char disable_linker_warning_about_empty_file_epoll_cpp TD_UNUSED;
#ifdef TD_POLL_EPOLL
#include "td/utils/format.h"
#include "td/utils/logging.h"
#include "td/utils/Status.h"
#include <unistd.h>
namespace td {
namespace detail {
void Epoll::init() {
CHECK(!epoll_fd_);
epoll_fd_ = NativeFd(epoll_create(1));
auto epoll_create_errno = errno;
LOG_IF(FATAL, !epoll_fd_) << Status::PosixError(epoll_create_errno, "epoll_create failed");
events_.resize(1000);
}
void Epoll::clear() {
if (!epoll_fd_) {
return;
}
events_.clear();
epoll_fd_.close();
for (auto *list_node = list_root_.next; list_node != &list_root_;) {
auto pollable_fd = PollableFd::from_list_node(list_node);
list_node = list_node->next;
}
}
void Epoll::subscribe(PollableFd fd, PollFlags flags) {
epoll_event event;
event.events = EPOLLHUP | EPOLLERR | EPOLLET;
#ifdef EPOLLRDHUP
event.events |= EPOLLRDHUP;
#endif
if (flags.can_read()) {
event.events |= EPOLLIN;
}
if (flags.can_write()) {
event.events |= EPOLLOUT;
}
auto native_fd = fd.native_fd().fd();
auto *list_node = fd.release_as_list_node();
list_root_.put(list_node);
event.data.ptr = list_node;
int err = epoll_ctl(epoll_fd_.fd(), EPOLL_CTL_ADD, native_fd, &event);
auto epoll_ctl_errno = errno;
LOG_IF(FATAL, err == -1) << Status::PosixError(epoll_ctl_errno, "epoll_ctl ADD failed")
<< ", epoll_fd = " << epoll_fd_.fd() << ", fd = " << native_fd;
}
void Epoll::unsubscribe(PollableFdRef fd_ref) {
auto fd = fd_ref.lock();
auto native_fd = fd.native_fd().fd();
int err = epoll_ctl(epoll_fd_.fd(), EPOLL_CTL_DEL, native_fd, nullptr);
auto epoll_ctl_errno = errno;
LOG_IF(FATAL, err == -1) << Status::PosixError(epoll_ctl_errno, "epoll_ctl DEL failed")
<< ", epoll_fd = " << epoll_fd_.fd() << ", fd = " << native_fd << fd.native_fd().validate();
}
void Epoll::unsubscribe_before_close(PollableFdRef fd) {
unsubscribe(fd);
}
void Epoll::run(int timeout_ms) {
int ready_n = epoll_wait(epoll_fd_.fd(), &events_[0], static_cast<int>(events_.size()), timeout_ms);
auto epoll_wait_errno = errno;
LOG_IF(FATAL, ready_n == -1 && epoll_wait_errno != EINTR)
<< Status::PosixError(epoll_wait_errno, "epoll_wait failed");
for (int i = 0; i < ready_n; i++) {
PollFlags flags;
epoll_event *event = &events_[i];
if (event->events & EPOLLIN) {
event->events &= ~EPOLLIN;
flags = flags | PollFlags::Read();
}
if (event->events & EPOLLOUT) {
event->events &= ~EPOLLOUT;
flags = flags | PollFlags::Write();
}
#ifdef EPOLLRDHUP
if (event->events & EPOLLRDHUP) {
event->events &= ~EPOLLRDHUP;
// flags |= Fd::Close;
// TODO
}
#endif
if (event->events & EPOLLHUP) {
event->events &= ~EPOLLHUP;
flags = flags | PollFlags::Close();
}
if (event->events & EPOLLERR) {
event->events &= ~EPOLLERR;
flags = flags | PollFlags::Error();
}
if (event->events) {
LOG(FATAL) << "Unsupported epoll events: " << event->events;
}
//LOG(DEBUG) << "Epoll event " << tag("fd", event->data.fd) << tag("flags", format::as_binary(flags));
auto pollable_fd = PollableFd::from_list_node(static_cast<ListNode *>(event->data.ptr));
pollable_fd.add_flags(flags);
pollable_fd.release_as_list_node();
}
}
} // namespace detail
} // namespace td
#endif

View file

@ -0,0 +1,71 @@
/*
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-2019 Telegram Systems LLP
*/
#pragma once
#include "td/utils/port/config.h"
#ifdef TD_POLL_EPOLL
#include "td/utils/common.h"
#include "td/utils/List.h"
#include "td/utils/port/detail/NativeFd.h"
#include "td/utils/port/detail/PollableFd.h"
#include "td/utils/port/PollBase.h"
#include "td/utils/port/PollFlags.h"
#include <sys/epoll.h>
namespace td {
namespace detail {
class Epoll final : public PollBase {
public:
Epoll() = default;
Epoll(const Epoll &) = delete;
Epoll &operator=(const Epoll &) = delete;
Epoll(Epoll &&) = delete;
Epoll &operator=(Epoll &&) = delete;
~Epoll() override = default;
void init() override;
void clear() override;
void subscribe(PollableFd fd, PollFlags flags) override;
void unsubscribe(PollableFdRef fd) override;
void unsubscribe_before_close(PollableFdRef fd) override;
void run(int timeout_ms) override;
static bool is_edge_triggered() {
return true;
}
private:
NativeFd epoll_fd_;
vector<struct epoll_event> events_;
ListNode list_root_;
};
} // namespace detail
} // namespace td
#endif

View file

@ -0,0 +1,114 @@
/*
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-2019 Telegram Systems LLP
*/
#include "td/utils/port/detail/EventFdBsd.h"
char disable_linker_warning_about_empty_file_event_fd_bsd_cpp TD_UNUSED;
#ifdef TD_EVENTFD_BSD
#include "td/utils/logging.h"
#include "td/utils/port/detail/NativeFd.h"
#include "td/utils/port/PollFlags.h"
#include "td/utils/port/SocketFd.h"
#include "td/utils/Slice.h"
#include <fcntl.h>
#include <poll.h>
#include <sys/socket.h>
#include <sys/types.h>
namespace td {
namespace detail {
// TODO: it is extremely non optimal on Darwin. kqueue events should be used instead
void EventFdBsd::init() {
int fds[2];
int err = socketpair(AF_UNIX, SOCK_STREAM, 0, fds);
auto socketpair_errno = errno;
#if TD_CYGWIN
// it looks like CYGWIN bug
int max_retries = 1000000;
while (err == -1 && socketpair_errno == EADDRINUSE && max_retries-- > 0) {
err = socketpair(AF_UNIX, SOCK_STREAM, 0, fds);
socketpair_errno = errno;
}
// LOG_IF(ERROR, max_retries < 1000000) << max_retries;
#endif
LOG_IF(FATAL, err == -1) << Status::PosixError(socketpair_errno, "socketpair failed");
auto fd_a = NativeFd(fds[0]);
auto fd_b = NativeFd(fds[1]);
fd_a.set_is_blocking_unsafe(false).ensure();
fd_b.set_is_blocking_unsafe(false).ensure();
in_ = SocketFd::from_native_fd(std::move(fd_a)).move_as_ok();
out_ = SocketFd::from_native_fd(std::move(fd_b)).move_as_ok();
}
bool EventFdBsd::empty() {
return in_.empty();
}
void EventFdBsd::close() {
in_.close();
out_.close();
}
Status EventFdBsd::get_pending_error() {
return Status::OK();
}
PollableFdInfo &EventFdBsd::get_poll_info() {
return out_.get_poll_info();
}
void EventFdBsd::release() {
int value = 1;
auto result = in_.write(Slice(reinterpret_cast<const char *>(&value), sizeof(value)));
if (result.is_error()) {
LOG(FATAL) << "EventFdBsd write failed: " << result.error();
}
size_t size = result.ok();
if (size != sizeof(value)) {
LOG(FATAL) << "EventFdBsd write returned " << value << " instead of " << sizeof(value);
}
}
void EventFdBsd::acquire() {
out_.get_poll_info().add_flags(PollFlags::Read());
while (can_read(out_)) {
uint8 value[1024];
auto result = out_.read(MutableSlice(value, sizeof(value)));
if (result.is_error()) {
LOG(FATAL) << "EventFdBsd read failed:" << result.error();
}
}
}
void EventFdBsd::wait(int timeout_ms) {
pollfd fd;
fd.fd = get_poll_info().native_fd().fd();
fd.events = POLLIN;
poll(&fd, 1, timeout_ms);
}
} // namespace detail
} // namespace td
#endif

View file

@ -0,0 +1,61 @@
/*
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-2019 Telegram Systems LLP
*/
#pragma once
#include "td/utils/port/config.h"
#ifdef TD_EVENTFD_BSD
#include "td/utils/common.h"
#include "td/utils/port/detail/PollableFd.h"
#include "td/utils/port/EventFdBase.h"
#include "td/utils/port/SocketFd.h"
#include "td/utils/Status.h"
namespace td {
namespace detail {
class EventFdBsd final : public EventFdBase {
SocketFd in_;
SocketFd out_;
public:
EventFdBsd() = default;
void init() override;
bool empty() override;
void close() override;
Status get_pending_error() override TD_WARN_UNUSED_RESULT;
PollableFdInfo &get_poll_info() override;
void release() override;
void acquire() override;
void wait(int timeout_ms) override;
};
} // namespace detail
} // namespace td
#endif

View file

@ -0,0 +1,138 @@
/*
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-2019 Telegram Systems LLP
*/
#include "td/utils/port/detail/EventFdLinux.h"
char disable_linker_warning_about_empty_file_event_fd_linux_cpp TD_UNUSED;
#ifdef TD_EVENTFD_LINUX
#include "td/utils/logging.h"
#include "td/utils/misc.h"
#include "td/utils/port/detail/NativeFd.h"
#include "td/utils/port/PollFlags.h"
#include "td/utils/ScopeGuard.h"
#include "td/utils/Slice.h"
#include <poll.h>
#include <sys/eventfd.h>
#include <unistd.h>
namespace td {
namespace detail {
class EventFdLinuxImpl {
public:
PollableFdInfo info;
};
EventFdLinux::EventFdLinux() = default;
EventFdLinux::EventFdLinux(EventFdLinux &&) = default;
EventFdLinux &EventFdLinux::operator=(EventFdLinux &&) = default;
EventFdLinux::~EventFdLinux() = default;
void EventFdLinux::init() {
auto fd = NativeFd(eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC));
auto eventfd_errno = errno;
LOG_IF(FATAL, !fd) << Status::PosixError(eventfd_errno, "eventfd call failed");
impl_ = make_unique<EventFdLinuxImpl>();
impl_->info.set_native_fd(std::move(fd));
}
bool EventFdLinux::empty() {
return !impl_;
}
void EventFdLinux::close() {
impl_.reset();
}
Status EventFdLinux::get_pending_error() {
return Status::OK();
}
PollableFdInfo &EventFdLinux::get_poll_info() {
return impl_->info;
}
// NB: will be called from multiple threads
void EventFdLinux::release() {
const uint64 value = 1;
auto slice = Slice(reinterpret_cast<const char *>(&value), sizeof(value));
auto native_fd = impl_->info.native_fd().fd();
auto result = [&]() -> Result<size_t> {
auto write_res = detail::skip_eintr([&] { return ::write(native_fd, slice.begin(), slice.size()); });
auto write_errno = errno;
if (write_res >= 0) {
return narrow_cast<size_t>(write_res);
}
return Status::PosixError(write_errno, PSLICE() << "Write to fd " << native_fd << " has failed");
}();
if (result.is_error()) {
LOG(FATAL) << "EventFdLinux write failed: " << result.error();
}
size_t size = result.ok();
if (size != sizeof(value)) {
LOG(FATAL) << "EventFdLinux write returned " << value << " instead of " << sizeof(value);
}
}
void EventFdLinux::acquire() {
impl_->info.get_flags();
SCOPE_EXIT {
// Clear flags without EAGAIN and EWOULDBLOCK
// Looks like it is safe thing to do with eventfd
get_poll_info().clear_flags(PollFlags::Read());
};
uint64 res;
auto slice = MutableSlice(reinterpret_cast<char *>(&res), sizeof(res));
auto native_fd = impl_->info.native_fd().fd();
auto result = [&]() -> Result<size_t> {
CHECK(slice.size() > 0);
auto read_res = detail::skip_eintr([&] { return ::read(native_fd, slice.begin(), slice.size()); });
auto read_errno = errno;
if (read_res >= 0) {
CHECK(read_res != 0);
return narrow_cast<size_t>(read_res);
}
if (read_errno == EAGAIN
#if EAGAIN != EWOULDBLOCK
|| read_errno == EWOULDBLOCK
#endif
) {
return 0;
}
return Status::PosixError(read_errno, PSLICE() << "Read from fd " << native_fd << " has failed");
}();
if (result.is_error()) {
LOG(FATAL) << "EventFdLinux read failed: " << result.error();
}
}
void EventFdLinux::wait(int timeout_ms) {
pollfd fd;
fd.fd = get_poll_info().native_fd().fd();
fd.events = POLLIN;
poll(&fd, 1, timeout_ms);
}
} // namespace detail
} // namespace td
#endif

View file

@ -0,0 +1,63 @@
/*
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-2019 Telegram Systems LLP
*/
#pragma once
#include "td/utils/port/config.h"
#ifdef TD_EVENTFD_LINUX
#include "td/utils/common.h"
#include "td/utils/port/detail/PollableFd.h"
#include "td/utils/port/EventFdBase.h"
#include "td/utils/Status.h"
namespace td {
namespace detail {
class EventFdLinuxImpl;
class EventFdLinux final : public EventFdBase {
unique_ptr<EventFdLinuxImpl> impl_;
public:
EventFdLinux();
EventFdLinux(EventFdLinux &&);
EventFdLinux &operator=(EventFdLinux &&);
~EventFdLinux();
void init() override;
bool empty() override;
void close() override;
Status get_pending_error() override TD_WARN_UNUSED_RESULT;
PollableFdInfo &get_poll_info() override;
void release() override;
void acquire() override;
void wait(int timeout_ms) override;
};
} // namespace detail
} // namespace td
#endif

View file

@ -0,0 +1,80 @@
/*
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-2019 Telegram Systems LLP
*/
#include "td/utils/port/detail/EventFdWindows.h"
char disable_linker_warning_about_empty_file_event_fd_windows_cpp TD_UNUSED;
#ifdef TD_EVENTFD_WINDOWS
#include "td/utils/logging.h"
namespace td {
namespace detail {
void EventFdWindows::init() {
auto handle = CreateEventW(nullptr, true, false, nullptr);
if (handle == nullptr) {
auto error = OS_ERROR("CreateEventW failed");
LOG(FATAL) << error;
}
event_ = NativeFd(handle);
}
bool EventFdWindows::empty() {
return !event_;
}
void EventFdWindows::close() {
event_.close();
}
Status EventFdWindows::get_pending_error() {
return Status::OK();
}
PollableFdInfo &EventFdWindows::get_poll_info() {
UNREACHABLE();
}
void EventFdWindows::release() {
if (SetEvent(event_.fd()) == 0) {
auto error = OS_ERROR("SetEvent failed");
LOG(FATAL) << error;
}
}
void EventFdWindows::acquire() {
if (ResetEvent(event_.fd()) == 0) {
auto error = OS_ERROR("ResetEvent failed");
LOG(FATAL) << error;
}
}
void EventFdWindows::wait(int timeout_ms) {
WaitForSingleObject(event_.fd(), timeout_ms);
if (ResetEvent(event_.fd()) == 0) {
auto error = OS_ERROR("ResetEvent failed");
LOG(FATAL) << error;
}
}
} // namespace detail
} // namespace td
#endif

View file

@ -0,0 +1,60 @@
/*
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-2019 Telegram Systems LLP
*/
#pragma once
#include "td/utils/port/config.h"
#ifdef TD_EVENTFD_WINDOWS
#include "td/utils/common.h"
#include "td/utils/port/detail/NativeFd.h"
#include "td/utils/port/detail/PollableFd.h"
#include "td/utils/port/EventFdBase.h"
#include "td/utils/Status.h"
namespace td {
namespace detail {
class EventFdWindows final : public EventFdBase {
NativeFd event_;
public:
EventFdWindows() = default;
void init() override;
bool empty() override;
void close() override;
Status get_pending_error() override TD_WARN_UNUSED_RESULT;
PollableFdInfo &get_poll_info() override;
void release() override;
void acquire() override;
void wait(int timeout_ms) override;
};
} // namespace detail
} // namespace td
#endif

View file

@ -0,0 +1,122 @@
/*
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-2019 Telegram Systems LLP
*/
#include "td/utils/port/detail/Iocp.h"
char disable_linker_warning_about_empty_file_iocp_cpp TD_UNUSED;
#ifdef TD_PORT_WINDOWS
#include "td/utils/logging.h"
namespace td {
namespace detail {
Iocp::~Iocp() {
clear();
}
void Iocp::loop() {
Iocp::Guard guard(this);
while (true) {
DWORD bytes = 0;
ULONG_PTR key = 0;
WSAOVERLAPPED *overlapped = nullptr;
BOOL ok =
GetQueuedCompletionStatus(iocp_handle_->fd(), &bytes, &key, reinterpret_cast<OVERLAPPED **>(&overlapped), 1000);
if (bytes || key || overlapped) {
// LOG(ERROR) << "Got IOCP " << bytes << " " << key << " " << overlapped;
}
if (ok) {
auto callback = reinterpret_cast<Iocp::Callback *>(key);
if (callback == nullptr) {
// LOG(ERROR) << "Interrupt IOCP loop";
return;
}
callback->on_iocp(bytes, overlapped);
} else {
if (overlapped != nullptr) {
auto error = OS_ERROR("Received from IOCP");
auto callback = reinterpret_cast<Iocp::Callback *>(key);
CHECK(callback != nullptr);
callback->on_iocp(std::move(error), overlapped);
}
}
}
}
void Iocp::interrupt_loop() {
post(0, nullptr, nullptr);
}
void Iocp::init() {
CHECK(!iocp_handle_);
auto res = CreateIoCompletionPort(INVALID_HANDLE_VALUE, nullptr, 0, 0);
if (res == nullptr) {
auto error = OS_ERROR("IOCP creation failed");
LOG(FATAL) << error;
}
iocp_handle_ = std::make_shared<NativeFd>(res);
}
void Iocp::clear() {
iocp_handle_.reset();
}
void Iocp::subscribe(const NativeFd &native_fd, Callback *callback) {
CHECK(iocp_handle_);
auto iocp_handle =
CreateIoCompletionPort(native_fd.fd(), iocp_handle_->fd(), reinterpret_cast<ULONG_PTR>(callback), 0);
if (iocp_handle == nullptr) {
auto error = OS_ERROR("CreateIoCompletionPort");
LOG(FATAL) << error;
}
LOG_CHECK(iocp_handle == iocp_handle_->fd()) << iocp_handle << " " << iocp_handle_->fd();
}
IocpRef Iocp::get_ref() const {
return IocpRef(iocp_handle_);
}
static void iocp_post(NativeFd &iocp_handle, size_t size, Iocp::Callback *callback, WSAOVERLAPPED *overlapped) {
if (PostQueuedCompletionStatus(iocp_handle.fd(), DWORD(size), reinterpret_cast<ULONG_PTR>(callback),
reinterpret_cast<OVERLAPPED *>(overlapped)) == 0) {
auto error = OS_ERROR("IOCP post failed");
LOG(FATAL) << error;
}
}
void Iocp::post(size_t size, Callback *callback, WSAOVERLAPPED *overlapped) {
iocp_post(*iocp_handle_, size, callback, overlapped);
}
IocpRef::IocpRef(std::weak_ptr<NativeFd> iocp_handle) : iocp_handle_(std::move(iocp_handle)) {
}
bool IocpRef::post(size_t size, Iocp::Callback *callback, WSAOVERLAPPED *overlapped) {
auto iocp_handle = iocp_handle_.lock();
if (!iocp_handle) {
return false;
}
iocp_post(*iocp_handle, size, callback, overlapped);
return true;
}
} // namespace detail
} // namespace td
#endif

View file

@ -0,0 +1,83 @@
/*
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-2019 Telegram Systems LLP
*/
#pragma once
#include "td/utils/port/config.h"
#ifdef TD_PORT_WINDOWS
#include "td/utils/common.h"
#include "td/utils/Context.h"
#include "td/utils/port/detail/NativeFd.h"
#include "td/utils/Status.h"
#include <memory>
namespace td {
namespace detail {
class IocpRef;
class Iocp final : public Context<Iocp> {
public:
Iocp() = default;
Iocp(const Iocp &) = delete;
Iocp &operator=(const Iocp &) = delete;
Iocp(Iocp &&) = delete;
Iocp &operator=(Iocp &&) = delete;
~Iocp();
class Callback {
public:
virtual ~Callback() = default;
virtual void on_iocp(Result<size_t> r_size, WSAOVERLAPPED *overlapped) = 0;
};
void init();
void subscribe(const NativeFd &fd, Callback *callback);
void post(size_t size, Callback *callback, WSAOVERLAPPED *overlapped);
void loop();
void interrupt_loop();
void clear();
IocpRef get_ref() const;
private:
std::shared_ptr<NativeFd> iocp_handle_;
};
class IocpRef {
public:
IocpRef() = default;
IocpRef(const Iocp &) = delete;
IocpRef &operator=(const Iocp &) = delete;
IocpRef(IocpRef &&) = default;
IocpRef &operator=(IocpRef &&) = default;
explicit IocpRef(std::weak_ptr<NativeFd> iocp_handle);
bool post(size_t size, Iocp::Callback *callback, WSAOVERLAPPED *overlapped);
private:
std::weak_ptr<NativeFd> iocp_handle_;
};
} // namespace detail
} // namespace td
#endif

View file

@ -0,0 +1,192 @@
/*
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-2019 Telegram Systems LLP
*/
#include "td/utils/port/detail/KQueue.h"
char disable_linker_warning_about_empty_file_kqueue_cpp TD_UNUSED;
#ifdef TD_POLL_KQUEUE
#include "td/utils/logging.h"
#include "td/utils/Status.h"
#include <utility>
#include <sys/time.h>
#include <unistd.h>
namespace td {
namespace detail {
KQueue::~KQueue() {
clear();
}
void KQueue::init() {
kq_ = NativeFd(kqueue());
auto kqueue_errno = errno;
LOG_IF(FATAL, !kq_) << Status::PosixError(kqueue_errno, "kqueue creation failed");
// TODO: const
events_.resize(1000);
changes_n_ = 0;
}
void KQueue::clear() {
if (!kq_) {
return;
}
events_.clear();
kq_.close();
for (auto *list_node = list_root_.next; list_node != &list_root_;) {
auto pollable_fd = PollableFd::from_list_node(list_node);
list_node = list_node->next;
}
}
int KQueue::update(int nevents, const timespec *timeout, bool may_fail) {
int err = kevent(kq_.fd(), &events_[0], changes_n_, &events_[0], nevents, timeout);
auto kevent_errno = errno;
bool is_fatal_error = [&] {
if (err != -1) {
return false;
}
if (may_fail) {
return kevent_errno != ENOENT;
}
return kevent_errno != EINTR;
}();
LOG_IF(FATAL, is_fatal_error) << Status::PosixError(kevent_errno, "kevent failed");
changes_n_ = 0;
if (err < 0) {
return 0;
}
return err;
}
void KQueue::flush_changes(bool may_fail) {
if (!changes_n_) {
return;
}
int n = update(0, nullptr, may_fail);
CHECK(n == 0);
}
void KQueue::add_change(std::uintptr_t ident, int16 filter, uint16 flags, uint32 fflags, std::intptr_t data,
void *udata) {
if (changes_n_ == static_cast<int>(events_.size())) {
flush_changes();
}
#if TD_NETBSD
auto set_udata = reinterpret_cast<std::intptr_t>(udata);
#else
auto set_udata = udata;
#endif
EV_SET(&events_[changes_n_], ident, filter, flags, fflags, data, set_udata);
VLOG(fd) << "Subscribe [fd:" << ident << "] [filter:" << filter << "] [udata: " << udata << "]";
changes_n_++;
}
void KQueue::subscribe(PollableFd fd, PollFlags flags) {
auto native_fd = fd.native_fd().fd();
auto list_node = fd.release_as_list_node();
list_root_.put(list_node);
if (flags.can_read()) {
add_change(native_fd, EVFILT_READ, EV_ADD | EV_CLEAR, 0, 0, list_node);
}
if (flags.can_write()) {
add_change(native_fd, EVFILT_WRITE, EV_ADD | EV_CLEAR, 0, 0, list_node);
}
}
void KQueue::invalidate(int native_fd) {
for (int i = 0; i < changes_n_; i++) {
if (events_[i].ident == static_cast<std::uintptr_t>(native_fd)) {
changes_n_--;
std::swap(events_[i], events_[changes_n_]);
i--;
}
}
}
void KQueue::unsubscribe(PollableFdRef fd_ref) {
auto pollable_fd = fd_ref.lock();
auto native_fd = pollable_fd.native_fd().fd();
// invalidate(fd);
flush_changes();
add_change(native_fd, EVFILT_READ, EV_DELETE, 0, 0, nullptr);
flush_changes(true);
add_change(native_fd, EVFILT_WRITE, EV_DELETE, 0, 0, nullptr);
flush_changes(true);
}
void KQueue::unsubscribe_before_close(PollableFdRef fd_ref) {
auto pollable_fd = fd_ref.lock();
invalidate(pollable_fd.native_fd().fd());
// just to avoid O(changes_n ^ 2)
if (changes_n_ != 0) {
flush_changes();
}
}
void KQueue::run(int timeout_ms) {
timespec timeout_data;
timespec *timeout_ptr;
if (timeout_ms == -1) {
timeout_ptr = nullptr;
} else {
timeout_data.tv_sec = timeout_ms / 1000;
timeout_data.tv_nsec = timeout_ms % 1000 * 1000000;
timeout_ptr = &timeout_data;
}
int n = update(static_cast<int>(events_.size()), timeout_ptr);
for (int i = 0; i < n; i++) {
struct kevent *event = &events_[i];
PollFlags flags;
if (event->filter == EVFILT_WRITE) {
flags.add_flags(PollFlags::Write());
}
if (event->filter == EVFILT_READ) {
flags.add_flags(PollFlags::Read());
}
if (event->flags & EV_EOF) {
flags.add_flags(PollFlags::Close());
}
if (event->fflags & EV_ERROR) {
LOG(FATAL) << "EV_ERROR in kqueue is not supported";
}
#if TD_NETBSD
auto udata = reinterpret_cast<void *>(event->udata);
#else
auto udata = event->udata;
#endif
VLOG(fd) << "Event [fd:" << event->ident << "] [filter:" << event->filter << "] [udata: " << udata << "]";
// LOG(WARNING) << "Have event->ident = " << event->ident << "event->filter = " << event->filter;
auto pollable_fd = PollableFd::from_list_node(static_cast<ListNode *>(udata));
pollable_fd.add_flags(flags);
pollable_fd.release_as_list_node();
}
}
} // namespace detail
} // namespace td
#endif

View file

@ -0,0 +1,84 @@
/*
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-2019 Telegram Systems LLP
*/
#pragma once
#include "td/utils/port/config.h"
#ifdef TD_POLL_KQUEUE
#include "td/utils/common.h"
#include "td/utils/List.h"
#include "td/utils/port/detail/NativeFd.h"
#include "td/utils/port/detail/PollableFd.h"
#include "td/utils/port/PollBase.h"
#include "td/utils/port/PollFlags.h"
#include <cstdint>
#include <sys/types.h> // must be included before sys/event.h, which depends on sys/types.h on FreeBSD
#include <sys/event.h>
namespace td {
namespace detail {
class KQueue final : public PollBase {
public:
KQueue() = default;
KQueue(const KQueue &) = delete;
KQueue &operator=(const KQueue &) = delete;
KQueue(KQueue &&) = delete;
KQueue &operator=(KQueue &&) = delete;
~KQueue() override;
void init() override;
void clear() override;
void subscribe(PollableFd fd, PollFlags flags) override;
void unsubscribe(PollableFdRef fd) override;
void unsubscribe_before_close(PollableFdRef fd) override;
void run(int timeout_ms) override;
static bool is_edge_triggered() {
return true;
}
private:
vector<struct kevent> events_;
int changes_n_;
NativeFd kq_;
ListNode list_root_;
int update(int nevents, const timespec *timeout, bool may_fail = false);
void invalidate(int native_fd);
void flush_changes(bool may_fail = false);
void add_change(std::uintptr_t ident, int16 filter, uint16 flags, uint32 fflags, std::intptr_t data, void *udata);
};
} // namespace detail
} // namespace td
#endif

View file

@ -0,0 +1,259 @@
/*
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-2019 Telegram Systems LLP
*/
#include "td/utils/port/detail/NativeFd.h"
#include "td/utils/format.h"
#include "td/utils/logging.h"
#include "td/utils/Status.h"
#if TD_PORT_POSIX
#include <fcntl.h>
#include <unistd.h>
#endif
#if TD_FD_DEBUG
#include <mutex>
#include <set>
#endif
namespace td {
#if TD_FD_DEBUG
class FdSet {
public:
void on_create_fd(NativeFd::Fd fd) {
CHECK(is_valid(fd));
if (is_stdio(fd)) {
return;
}
std::unique_lock<std::mutex> guard(mutex_);
if (fds_.count(fd) >= 1) {
LOG(FATAL) << "Create duplicated fd: " << fd;
}
fds_.insert(fd);
}
Status validate(NativeFd::Fd fd) {
if (!is_valid(fd)) {
return Status::Error(PSLICE() << "Invalid fd: " << fd);
}
if (is_stdio(fd)) {
return Status::OK();
}
std::unique_lock<std::mutex> guard(mutex_);
if (fds_.count(fd) != 1) {
return Status::Error(PSLICE() << "Unknown fd: " << fd);
}
return Status::OK();
}
void on_close_fd(NativeFd::Fd fd) {
CHECK(is_valid(fd));
if (is_stdio(fd)) {
return;
}
std::unique_lock<std::mutex> guard(mutex_);
if (fds_.count(fd) != 1) {
LOG(FATAL) << "Close unknown fd: " << fd;
}
fds_.erase(fd);
}
private:
std::mutex mutex_;
std::set<NativeFd::Fd> fds_;
bool is_stdio(NativeFd::Fd fd) const {
#if TD_PORT_WINDOWS
#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM)
return fd == GetStdHandle(STD_INPUT_HANDLE) || fd == GetStdHandle(STD_OUTPUT_HANDLE) ||
fd == GetStdHandle(STD_ERROR_HANDLE);
#else
return false;
#endif
#else
return fd >= 0 && fd <= 2;
#endif
}
bool is_valid(NativeFd::Fd fd) const {
#if TD_PORT_WINDOWS
return fd != INVALID_HANDLE_VALUE;
#else
return fd >= 0;
#endif
}
};
namespace {
FdSet &get_fd_set() {
static FdSet res;
return res;
}
} // namespace
#endif
Status NativeFd::validate() const {
#if TD_FD_DEBUG
return get_fd_set().validate(fd_.get());
#else
return Status::OK();
#endif
}
NativeFd::NativeFd(Fd fd) : fd_(fd) {
VLOG(fd) << *this << " create";
#if TD_FD_DEBUG
get_fd_set().on_create_fd(fd_.get());
#endif
}
NativeFd::NativeFd(Fd fd, bool nolog) : fd_(fd) {
#if TD_FD_DEBUG
get_fd_set().on_create_fd(fd_.get());
#endif
}
#if TD_PORT_WINDOWS
NativeFd::NativeFd(Socket socket) : fd_(reinterpret_cast<Fd>(socket)), is_socket_(true) {
VLOG(fd) << *this << " create";
#if TD_FD_DEBUG
get_fd_set().on_create_fd(fd_.get());
#endif
}
#endif
NativeFd &NativeFd::operator=(NativeFd &&from) {
CHECK(this != &from);
close();
fd_ = std::move(from.fd_);
#if TD_PORT_WINDOWS
is_socket_ = from.is_socket_;
#endif
return *this;
}
NativeFd::~NativeFd() {
close();
}
NativeFd::operator bool() const {
return fd_.get() != empty_fd();
}
NativeFd::Fd NativeFd::empty_fd() {
#if TD_PORT_POSIX
return -1;
#elif TD_PORT_WINDOWS
return INVALID_HANDLE_VALUE;
#endif
}
NativeFd::Fd NativeFd::fd() const {
return fd_.get();
}
NativeFd::Socket NativeFd::socket() const {
#if TD_PORT_POSIX
return fd();
#elif TD_PORT_WINDOWS
CHECK(is_socket_);
return reinterpret_cast<Socket>(fd_.get());
#endif
}
Status NativeFd::set_is_blocking(bool is_blocking) const {
#if TD_PORT_POSIX
auto old_flags = fcntl(fd(), F_GETFL);
if (old_flags == -1) {
return OS_SOCKET_ERROR("Failed to get socket flags");
}
auto new_flags = is_blocking ? old_flags & ~O_NONBLOCK : old_flags | O_NONBLOCK;
if (new_flags != old_flags && fcntl(fd(), F_SETFL, new_flags) == -1) {
return OS_SOCKET_ERROR("Failed to set socket flags");
}
return Status::OK();
#elif TD_PORT_WINDOWS
return set_is_blocking_unsafe(is_blocking);
#endif
}
Status NativeFd::set_is_blocking_unsafe(bool is_blocking) const {
#if TD_PORT_POSIX
if (fcntl(fd(), F_SETFL, is_blocking ? 0 : O_NONBLOCK) == -1) {
#elif TD_PORT_WINDOWS
u_long mode = is_blocking;
if (ioctlsocket(socket(), FIONBIO, &mode) != 0) {
#endif
return OS_SOCKET_ERROR("Failed to change socket flags");
}
return Status::OK();
}
Status NativeFd::duplicate(const NativeFd &to) const {
#if TD_PORT_POSIX
CHECK(*this);
CHECK(to);
if (dup2(fd(), to.fd()) == -1) {
return OS_ERROR("Failed to duplicate file descriptor");
}
return Status::OK();
#elif TD_PORT_WINDOWS
return Status::Error("Not supported");
#endif
}
void NativeFd::close() {
if (!*this) {
return;
}
#if TD_FD_DEBUG
get_fd_set().on_close_fd(fd());
#endif
VLOG(fd) << *this << " close";
#if TD_PORT_WINDOWS
if (is_socket_ ? closesocket(socket()) : !CloseHandle(fd())) {
#elif TD_PORT_POSIX
if (::close(fd()) < 0) {
#endif
auto error = OS_ERROR("Close fd");
LOG(ERROR) << error;
}
fd_ = {};
}
NativeFd::Fd NativeFd::release() {
VLOG(fd) << *this << " release";
auto res = fd_.get();
fd_ = {};
#if TD_FD_DEBUG
get_fd_set().on_close_fd(res);
#endif
return res;
}
StringBuilder &operator<<(StringBuilder &sb, const NativeFd &fd) {
return sb << tag("fd", fd.fd());
}
} // namespace td

View file

@ -0,0 +1,80 @@
/*
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-2019 Telegram Systems LLP
*/
#pragma once
#include "td/utils/port/config.h"
#include "td/utils/common.h"
#include "td/utils/MovableValue.h"
#include "td/utils/Status.h"
#include "td/utils/StringBuilder.h"
namespace td {
class NativeFd {
public:
#if TD_PORT_POSIX
using Fd = int;
using Socket = int;
#elif TD_PORT_WINDOWS
using Fd = HANDLE;
using Socket = SOCKET;
#endif
NativeFd() = default;
NativeFd(NativeFd &&) = default;
NativeFd &operator=(NativeFd &&);
explicit NativeFd(Fd fd);
NativeFd(Fd fd, bool nolog);
#if TD_PORT_WINDOWS
explicit NativeFd(Socket socket);
#endif
NativeFd(const NativeFd &) = delete;
NativeFd &operator=(const NativeFd &) = delete;
~NativeFd();
explicit operator bool() const;
static Fd empty_fd();
Fd fd() const;
Socket socket() const;
Status set_is_blocking(bool is_blocking) const;
Status set_is_blocking_unsafe(bool is_blocking) const; // may drop other Fd flags on non-Windows
Status duplicate(const NativeFd &to) const;
void close();
Fd release();
Status validate() const;
private:
#if TD_PORT_POSIX
MovableValue<Fd, -1> fd_;
#elif TD_PORT_WINDOWS
MovableValue<Fd, INVALID_HANDLE_VALUE> fd_;
bool is_socket_{false};
#endif
};
StringBuilder &operator<<(StringBuilder &sb, const NativeFd &fd);
} // namespace td

View file

@ -0,0 +1,114 @@
/*
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-2019 Telegram Systems LLP
*/
#include "td/utils/port/detail/Poll.h"
char disable_linker_warning_about_empty_file_poll_cpp TD_UNUSED;
#ifdef TD_POLL_POLL
#include "td/utils/format.h"
#include "td/utils/logging.h"
#include "td/utils/misc.h"
#include "td/utils/ScopeGuard.h"
#include "td/utils/Status.h"
namespace td {
namespace detail {
void Poll::init() {
}
void Poll::clear() {
pollfds_.clear();
}
void Poll::subscribe(PollableFd fd, PollFlags flags) {
unsubscribe(fd.ref());
struct pollfd pollfd;
pollfd.fd = fd.native_fd().fd();
pollfd.events = 0;
if (flags.can_read()) {
pollfd.events |= POLLIN;
}
if (flags.can_write()) {
pollfd.events |= POLLOUT;
}
pollfd.revents = 0;
pollfds_.push_back(pollfd);
fds_.push_back(std::move(fd));
}
void Poll::unsubscribe(PollableFdRef fd_ref) {
auto fd = fd_ref.lock();
SCOPE_EXIT {
fd.release_as_list_node();
};
for (auto it = pollfds_.begin(); it != pollfds_.end(); ++it) {
if (it->fd == fd.native_fd().fd()) {
pollfds_.erase(it);
fds_.erase(fds_.begin() + (it - pollfds_.begin()));
return;
}
}
}
void Poll::unsubscribe_before_close(PollableFdRef fd) {
unsubscribe(fd);
}
void Poll::run(int timeout_ms) {
int err = poll(pollfds_.data(), narrow_cast<int>(pollfds_.size()), timeout_ms);
auto poll_errno = errno;
LOG_IF(FATAL, err == -1 && poll_errno != EINTR) << Status::PosixError(poll_errno, "poll failed");
for (size_t i = 0; i < pollfds_.size(); i++) {
auto &pollfd = pollfds_[i];
auto &fd = fds_[i];
PollFlags flags;
if (pollfd.revents & POLLIN) {
pollfd.revents &= ~POLLIN;
flags = flags | PollFlags::Read();
}
if (pollfd.revents & POLLOUT) {
pollfd.revents &= ~POLLOUT;
flags = flags | PollFlags::Write();
}
if (pollfd.revents & POLLHUP) {
pollfd.revents &= ~POLLHUP;
flags = flags | PollFlags::Close();
}
if (pollfd.revents & POLLERR) {
pollfd.revents &= ~POLLERR;
flags = flags | PollFlags::Error();
}
if (pollfd.revents & POLLNVAL) {
LOG(FATAL) << "Unexpected POLLNVAL " << tag("fd", pollfd.fd);
}
if (pollfd.revents) {
LOG(FATAL) << "Unsupported poll events: " << pollfd.revents;
}
fd.add_flags(flags);
}
}
} // namespace detail
} // namespace td
#endif

View file

@ -0,0 +1,68 @@
/*
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-2019 Telegram Systems LLP
*/
#pragma once
#include "td/utils/port/config.h"
#ifdef TD_POLL_POLL
#include "td/utils/common.h"
#include "td/utils/port/detail/PollableFd.h"
#include "td/utils/port/PollBase.h"
#include "td/utils/port/PollFlags.h"
#include <poll.h>
namespace td {
namespace detail {
class Poll final : public PollBase {
public:
Poll() = default;
Poll(const Poll &) = delete;
Poll &operator=(const Poll &) = delete;
Poll(Poll &&) = delete;
Poll &operator=(Poll &&) = delete;
~Poll() override = default;
void init() override;
void clear() override;
void subscribe(PollableFd fd, PollFlags flags) override;
void unsubscribe(PollableFdRef fd) override;
void unsubscribe_before_close(PollableFdRef fd) override;
void run(int timeout_ms) override;
static bool is_edge_triggered() {
return false;
}
private:
vector<pollfd> pollfds_;
vector<PollableFd> fds_;
};
} // namespace detail
} // namespace td
#endif

View file

@ -0,0 +1,262 @@
/*
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-2019 Telegram Systems LLP
*/
#pragma once
#include "td/utils/common.h"
#include "td/utils/format.h"
#include "td/utils/List.h"
#include "td/utils/logging.h"
#include "td/utils/Observer.h"
#include "td/utils/port/detail/NativeFd.h"
#include "td/utils/port/PollFlags.h"
#include "td/utils/SpinLock.h"
#include <atomic>
#include <memory>
#include <type_traits>
namespace td {
class PollableFdInfo;
class PollableFdInfoUnlock {
public:
void operator()(PollableFdInfo *ptr);
};
class PollableFd;
class PollableFdRef {
public:
explicit PollableFdRef(ListNode *list_node) : list_node_(list_node) {
}
PollableFd lock();
private:
ListNode *list_node_;
};
class PollableFd {
public:
// Interface for kqueue, epoll and e.t.c.
const NativeFd &native_fd() const;
ListNode *release_as_list_node();
PollableFdRef ref();
static PollableFd from_list_node(ListNode *node);
void add_flags(PollFlags flags);
PollFlags get_flags_unsafe() const;
private:
std::unique_ptr<PollableFdInfo, PollableFdInfoUnlock> fd_info_;
friend class PollableFdInfo;
explicit PollableFd(std::unique_ptr<PollableFdInfo, PollableFdInfoUnlock> fd_info) : fd_info_(std::move(fd_info)) {
}
};
inline PollableFd PollableFdRef::lock() {
return PollableFd::from_list_node(list_node_);
}
class PollableFdInfo : private ListNode {
public:
PollableFdInfo() = default;
PollableFdInfo(const PollableFdInfo &) = delete;
PollableFdInfo &operator=(const PollableFdInfo &) = delete;
PollableFdInfo(PollableFdInfo &&) = delete;
PollableFdInfo &operator=(PollableFdInfo &&) = delete;
PollableFd extract_pollable_fd(ObserverBase *observer) {
VLOG(fd) << native_fd() << " extract pollable fd " << tag("observer", observer);
CHECK(!empty());
bool was_locked = lock_.test_and_set(std::memory_order_acquire);
CHECK(!was_locked);
set_observer(observer);
return PollableFd{std::unique_ptr<PollableFdInfo, PollableFdInfoUnlock>{this}};
}
PollableFdRef get_pollable_fd_ref() {
CHECK(!empty());
bool was_locked = lock_.test_and_set(std::memory_order_acquire);
CHECK(was_locked);
return PollableFdRef{as_list_node()};
}
void add_flags(PollFlags flags) {
flags_.write_flags_local(flags);
}
void clear_flags(PollFlags flags) {
flags_.clear_flags(flags);
}
PollFlags get_flags() const {
return flags_.read_flags();
}
PollFlags get_flags_local() const {
return flags_.read_flags_local();
}
bool empty() const {
return !fd_;
}
void set_native_fd(NativeFd new_native_fd) {
if (fd_) {
CHECK(!new_native_fd);
bool was_locked = lock_.test_and_set(std::memory_order_acquire);
CHECK(!was_locked);
lock_.clear(std::memory_order_release);
}
fd_ = std::move(new_native_fd);
}
explicit PollableFdInfo(NativeFd native_fd) {
set_native_fd(std::move(native_fd));
}
const NativeFd &native_fd() const {
//CHECK(!empty());
return fd_;
}
NativeFd move_as_native_fd() {
return std::move(fd_);
}
~PollableFdInfo() {
VLOG(fd) << native_fd() << " destroy PollableFdInfo";
bool was_locked = lock_.test_and_set(std::memory_order_acquire);
CHECK(!was_locked);
}
void add_flags_from_poll(PollFlags flags) {
VLOG(fd) << native_fd() << " add flags from poll " << flags;
if (flags_.write_flags(flags)) {
notify_observer();
}
}
private:
NativeFd fd_{};
std::atomic_flag lock_ = ATOMIC_FLAG_INIT;
PollFlagsSet flags_;
#if TD_PORT_WINDOWS
SpinLock observer_lock_;
#endif
ObserverBase *observer_{nullptr};
friend class PollableFd;
friend class PollableFdInfoUnlock;
void set_observer(ObserverBase *observer) {
#if TD_PORT_WINDOWS
auto lock = observer_lock_.lock();
#endif
CHECK(!observer_);
observer_ = observer;
}
void clear_observer() {
#if TD_PORT_WINDOWS
auto lock = observer_lock_.lock();
#endif
observer_ = nullptr;
}
void notify_observer() {
#if TD_PORT_WINDOWS
auto lock = observer_lock_.lock();
#endif
VLOG(fd) << native_fd() << " notify " << tag("observer", observer_);
if (observer_) {
observer_->notify();
}
}
void unlock() {
clear_observer();
lock_.clear(std::memory_order_release);
as_list_node()->remove();
}
ListNode *as_list_node() {
return static_cast<ListNode *>(this);
}
static PollableFdInfo *from_list_node(ListNode *list_node) {
return static_cast<PollableFdInfo *>(list_node);
}
};
inline void PollableFdInfoUnlock::operator()(PollableFdInfo *ptr) {
ptr->unlock();
}
inline ListNode *PollableFd::release_as_list_node() {
return fd_info_.release()->as_list_node();
}
inline PollableFdRef PollableFd::ref() {
return PollableFdRef{fd_info_->as_list_node()};
}
inline PollableFd PollableFd::from_list_node(ListNode *node) {
return PollableFd(std::unique_ptr<PollableFdInfo, PollableFdInfoUnlock>(PollableFdInfo::from_list_node(node)));
}
inline void PollableFd::add_flags(PollFlags flags) {
fd_info_->add_flags_from_poll(flags);
}
inline PollFlags PollableFd::get_flags_unsafe() const {
return fd_info_->get_flags_local();
}
inline const NativeFd &PollableFd::native_fd() const {
return fd_info_->native_fd();
}
#if TD_PORT_POSIX
namespace detail {
template <class F>
auto skip_eintr(F &&f) {
decltype(f()) res;
static_assert(std::is_integral<decltype(res)>::value, "integral type expected");
do {
errno = 0; // just in case
res = f();
} while (res < 0 && errno == EINTR);
return res;
}
template <class F>
auto skip_eintr_cstr(F &&f) {
char *res;
do {
errno = 0; // just in case
res = f();
} while (res == nullptr && errno == EINTR);
return res;
}
} // namespace detail
#endif
template <class FdT>
bool can_read(const FdT &fd) {
return fd.get_poll_info().get_flags().can_read() || fd.get_poll_info().get_flags().has_pending_error();
}
template <class FdT>
bool can_write(const FdT &fd) {
return fd.get_poll_info().get_flags().can_write();
}
template <class FdT>
bool can_close(const FdT &fd) {
return fd.get_poll_info().get_flags().can_close();
}
} // namespace td

View file

@ -0,0 +1,132 @@
/*
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-2019 Telegram Systems LLP
*/
#include "td/utils/port/detail/Select.h"
char disable_linker_warning_about_empty_file_select_cpp TD_UNUSED;
#ifdef TD_POLL_SELECT
#include "td/utils/logging.h"
#include <utility>
namespace td {
namespace detail {
void Select::init() {
FD_ZERO(&all_fd_);
FD_ZERO(&read_fd_);
FD_ZERO(&write_fd_);
FD_ZERO(&except_fd_);
max_fd_ = -1;
}
void Select::clear() {
fds_.clear();
}
void Select::subscribe(PollableFd fd, PollFlags flags) {
int native_fd = fd.native_fd().fd();
for (auto &it : fds_) {
CHECK(it.fd.native_fd().fd() != native_fd);
}
fds_.push_back(FdInfo{std::move(fd), flags});
LOG_CHECK(0 <= native_fd && native_fd < FD_SETSIZE) << native_fd << " " << FD_SETSIZE;
FD_SET(native_fd, &all_fd_);
if (native_fd > max_fd_) {
max_fd_ = native_fd;
}
}
void Select::unsubscribe(PollableFdRef fd) {
auto fd_locked = fd.lock();
int native_fd = fd_locked.native_fd().fd();
fd_locked.release_as_list_node();
LOG_CHECK(0 <= native_fd && native_fd < FD_SETSIZE) << native_fd << " " << FD_SETSIZE;
FD_CLR(native_fd, &all_fd_);
FD_CLR(native_fd, &read_fd_);
FD_CLR(native_fd, &write_fd_);
FD_CLR(native_fd, &except_fd_);
while (max_fd_ >= 0 && !FD_ISSET(max_fd_, &all_fd_)) {
max_fd_--;
}
for (auto it = fds_.begin(); it != fds_.end();) {
if (it->fd.native_fd().fd() == native_fd) {
std::swap(*it, fds_.back());
fds_.pop_back();
break;
} else {
++it;
}
}
}
void Select::unsubscribe_before_close(PollableFdRef fd) {
unsubscribe(fd);
}
void Select::run(int timeout_ms) {
timeval timeout_data;
timeval *timeout_ptr;
if (timeout_ms == -1) {
timeout_ptr = nullptr;
} else {
timeout_data.tv_sec = timeout_ms / 1000;
timeout_data.tv_usec = timeout_ms % 1000 * 1000;
timeout_ptr = &timeout_data;
}
for (auto &it : fds_) {
int native_fd = it.fd.native_fd().fd();
PollFlags fd_flags = it.fd.get_flags_unsafe(); // concurrent calls are UB
if (it.flags.can_write() && !fd_flags.can_write()) {
FD_SET(native_fd, &write_fd_);
} else {
FD_CLR(native_fd, &write_fd_);
}
if (it.flags.can_read() && !fd_flags.can_read()) {
FD_SET(native_fd, &read_fd_);
} else {
FD_CLR(native_fd, &read_fd_);
}
FD_SET(native_fd, &except_fd_);
}
select(max_fd_ + 1, &read_fd_, &write_fd_, &except_fd_, timeout_ptr);
for (auto &it : fds_) {
int native_fd = it.fd.native_fd().fd();
PollFlags flags;
if (FD_ISSET(native_fd, &read_fd_)) {
flags = flags | PollFlags::Read();
}
if (FD_ISSET(native_fd, &write_fd_)) {
flags = flags | PollFlags::Write();
}
if (FD_ISSET(native_fd, &except_fd_)) {
flags = flags | PollFlags::Error();
}
it.fd.add_flags(flags);
}
}
} // namespace detail
} // namespace td
#endif

View file

@ -0,0 +1,76 @@
/*
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-2019 Telegram Systems LLP
*/
#pragma once
#include "td/utils/port/config.h"
#ifdef TD_POLL_SELECT
#include "td/utils/common.h"
#include "td/utils/port/detail/PollableFd.h"
#include "td/utils/port/PollBase.h"
#include "td/utils/port/PollFlags.h"
#include <sys/select.h>
namespace td {
namespace detail {
class Select final : public PollBase {
public:
Select() = default;
Select(const Select &) = delete;
Select &operator=(const Select &) = delete;
Select(Select &&) = delete;
Select &operator=(Select &&) = delete;
~Select() override = default;
void init() override;
void clear() override;
void subscribe(PollableFd fd, PollFlags flags) override;
void unsubscribe(PollableFdRef fd) override;
void unsubscribe_before_close(PollableFdRef fd) override;
void run(int timeout_ms) override;
static bool is_edge_triggered() {
return false;
}
private:
struct FdInfo {
PollableFd fd;
PollFlags flags;
};
vector<FdInfo> fds_;
fd_set all_fd_;
fd_set read_fd_;
fd_set write_fd_;
fd_set except_fd_;
int max_fd_;
};
} // namespace detail
} // namespace td
#endif

View file

@ -0,0 +1,64 @@
/*
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-2019 Telegram Systems LLP
*/
#include "td/utils/port/detail/ThreadIdGuard.h"
#include "td/utils/common.h"
#include "td/utils/port/thread_local.h"
#include <mutex>
#include <set>
namespace td {
namespace detail {
class ThreadIdManager {
public:
int32 register_thread() {
std::lock_guard<std::mutex> guard(mutex_);
if (unused_thread_ids_.empty()) {
return ++max_thread_id_;
}
auto it = unused_thread_ids_.begin();
auto result = *it;
unused_thread_ids_.erase(it);
return result;
}
void unregister_thread(int32 thread_id) {
std::lock_guard<std::mutex> guard(mutex_);
CHECK(0 < thread_id && thread_id <= max_thread_id_);
bool is_inserted = unused_thread_ids_.insert(thread_id).second;
CHECK(is_inserted);
}
private:
std::mutex mutex_;
std::set<int32> unused_thread_ids_;
int32 max_thread_id_ = 0;
};
static ThreadIdManager thread_id_manager;
ThreadIdGuard::ThreadIdGuard() {
thread_id_ = thread_id_manager.register_thread();
set_thread_id(thread_id_);
}
ThreadIdGuard::~ThreadIdGuard() {
thread_id_manager.unregister_thread(thread_id_);
set_thread_id(0);
}
} // namespace detail
} // namespace td

View file

@ -0,0 +1,38 @@
/*
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-2019 Telegram Systems LLP
*/
#pragma once
#include "td/utils/common.h"
namespace td {
namespace detail {
class ThreadIdGuard {
public:
ThreadIdGuard();
~ThreadIdGuard();
ThreadIdGuard(const ThreadIdGuard &) = delete;
ThreadIdGuard &operator=(const ThreadIdGuard &) = delete;
ThreadIdGuard(ThreadIdGuard &&) = delete;
ThreadIdGuard &operator=(ThreadIdGuard &&) = delete;
private:
int32 thread_id_;
};
} // namespace detail
} // namespace td

View file

@ -0,0 +1,121 @@
/*
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-2019 Telegram Systems LLP
*/
#pragma once
#include "td/utils/port/config.h"
#ifdef TD_THREAD_PTHREAD
#include "td/utils/common.h"
#include "td/utils/Destructor.h"
#include "td/utils/invoke.h"
#include "td/utils/MovableValue.h"
#include "td/utils/port/detail/ThreadIdGuard.h"
#include "td/utils/port/thread_local.h"
#include "td/utils/Slice.h"
#include <tuple>
#include <type_traits>
#include <utility>
#include <pthread.h>
#include <sched.h>
namespace td {
namespace detail {
class ThreadPthread {
public:
ThreadPthread() = default;
ThreadPthread(const ThreadPthread &other) = delete;
ThreadPthread &operator=(const ThreadPthread &other) = delete;
ThreadPthread(ThreadPthread &&) = default;
ThreadPthread &operator=(ThreadPthread &&other) {
join();
is_inited_ = std::move(other.is_inited_);
thread_ = other.thread_;
return *this;
}
template <class Function, class... Args>
explicit ThreadPthread(Function &&f, Args &&... args) {
auto func = create_destructor([args = std::make_tuple(decay_copy(std::forward<Function>(f)),
decay_copy(std::forward<Args>(args))...)]() mutable {
invoke_tuple(std::move(args));
clear_thread_locals();
});
pthread_create(&thread_, nullptr, run_thread, func.release());
is_inited_ = true;
}
void set_name(CSlice name) {
#if defined(_GNU_SOURCE) && defined(__GLIBC_PREREQ)
#if __GLIBC_PREREQ(2, 12)
pthread_setname_np(thread_, name.c_str());
#endif
#endif
}
void join() {
if (is_inited_.get()) {
is_inited_ = false;
pthread_join(thread_, nullptr);
}
}
void detach() {
if (is_inited_.get()) {
is_inited_ = false;
pthread_detach(thread_);
}
}
~ThreadPthread() {
join();
}
static unsigned hardware_concurrency() {
return 8;
}
using id = pthread_t;
private:
MovableValue<bool> is_inited_;
pthread_t thread_;
template <class T>
std::decay_t<T> decay_copy(T &&v) {
return std::forward<T>(v);
}
static void *run_thread(void *ptr) {
ThreadIdGuard thread_id_guard;
auto func = unique_ptr<Destructor>(static_cast<Destructor *>(ptr));
return nullptr;
}
};
namespace this_thread_pthread {
inline void yield() {
sched_yield();
}
inline ThreadPthread::id get_id() {
return pthread_self();
}
} // namespace this_thread_pthread
} // namespace detail
} // namespace td
#endif

View file

@ -0,0 +1,89 @@
/*
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-2019 Telegram Systems LLP
*/
#pragma once
#include "td/utils/port/config.h"
#ifdef TD_THREAD_STL
#include "td/utils/common.h"
#include "td/utils/invoke.h"
#include "td/utils/port/detail/ThreadIdGuard.h"
#include "td/utils/port/thread_local.h"
#include "td/utils/Slice.h"
#include <thread>
#include <tuple>
#include <type_traits>
#include <utility>
namespace td {
namespace detail {
class ThreadStl {
public:
ThreadStl() = default;
ThreadStl(const ThreadStl &other) = delete;
ThreadStl &operator=(const ThreadStl &other) = delete;
ThreadStl(ThreadStl &&) = default;
ThreadStl &operator=(ThreadStl &&) = default;
~ThreadStl() {
join();
}
template <class Function, class... Args>
explicit ThreadStl(Function &&f, Args &&... args) {
thread_ = std::thread([args = std::make_tuple(decay_copy(std::forward<Function>(f)),
decay_copy(std::forward<Args>(args))...)]() mutable {
ThreadIdGuard thread_id_guard;
invoke_tuple(std::move(args));
clear_thread_locals();
});
}
void join() {
if (thread_.joinable()) {
thread_.join();
}
}
void detach() {
if (thread_.joinable()) {
thread_.detach();
}
}
void set_name(CSlice name) {
}
static unsigned hardware_concurrency() {
return std::thread::hardware_concurrency();
}
using id = std::thread::id;
private:
std::thread thread_;
template <class T>
std::decay_t<T> decay_copy(T &&v) {
return std::forward<T>(v);
}
};
namespace this_thread_stl = std::this_thread;
} // namespace detail
} // namespace td
#endif

View file

@ -0,0 +1,55 @@
/*
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-2019 Telegram Systems LLP
*/
#include "td/utils/port/detail/WineventPoll.h"
char disable_linker_warning_about_empty_file_wineventpoll_cpp TD_UNUSED;
#ifdef TD_POLL_WINEVENT
#include "td/utils/common.h"
namespace td {
namespace detail {
void WineventPoll::init() {
}
void WineventPoll::clear() {
}
void WineventPoll::subscribe(PollableFd fd, PollFlags flags) {
fd.release_as_list_node();
}
void WineventPoll::unsubscribe(PollableFdRef fd) {
auto pollable_fd = fd.lock(); // unlocked in destructor
}
void WineventPoll::unsubscribe_before_close(PollableFdRef fd) {
unsubscribe(std::move(fd));
}
void WineventPoll::run(int timeout_ms) {
UNREACHABLE();
}
} // namespace detail
} // namespace td
#endif

View file

@ -0,0 +1,62 @@
/*
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-2019 Telegram Systems LLP
*/
#pragma once
#include "td/utils/port/config.h"
#ifdef TD_POLL_WINEVENT
#include "td/utils/common.h"
#include "td/utils/port/detail/PollableFd.h"
#include "td/utils/port/PollBase.h"
#include "td/utils/port/PollFlags.h"
namespace td {
namespace detail {
class WineventPoll final : public PollBase {
public:
WineventPoll() = default;
WineventPoll(const WineventPoll &) = delete;
WineventPoll &operator=(const WineventPoll &) = delete;
WineventPoll(WineventPoll &&) = delete;
WineventPoll &operator=(WineventPoll &&) = delete;
~WineventPoll() override = default;
void init() override;
void clear() override;
void subscribe(PollableFd fd, PollFlags flags) override;
void unsubscribe(PollableFdRef fd) override;
void unsubscribe_before_close(PollableFdRef fd) override;
void run(int timeout_ms) override;
static bool is_edge_triggered() {
return true;
}
};
} // namespace detail
} // namespace td
#endif