mirror of
https://github.com/ton-blockchain/ton
synced 2025-03-09 15:40:10 +00:00
initial commit
This commit is contained in:
commit
c2da007f40
1610 changed files with 398047 additions and 0 deletions
136
tdutils/td/utils/port/detail/Epoll.cpp
Normal file
136
tdutils/td/utils/port/detail/Epoll.cpp
Normal 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
|
71
tdutils/td/utils/port/detail/Epoll.h
Normal file
71
tdutils/td/utils/port/detail/Epoll.h
Normal 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
|
114
tdutils/td/utils/port/detail/EventFdBsd.cpp
Normal file
114
tdutils/td/utils/port/detail/EventFdBsd.cpp
Normal 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
|
61
tdutils/td/utils/port/detail/EventFdBsd.h
Normal file
61
tdutils/td/utils/port/detail/EventFdBsd.h
Normal 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
|
138
tdutils/td/utils/port/detail/EventFdLinux.cpp
Normal file
138
tdutils/td/utils/port/detail/EventFdLinux.cpp
Normal 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
|
63
tdutils/td/utils/port/detail/EventFdLinux.h
Normal file
63
tdutils/td/utils/port/detail/EventFdLinux.h
Normal 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
|
80
tdutils/td/utils/port/detail/EventFdWindows.cpp
Normal file
80
tdutils/td/utils/port/detail/EventFdWindows.cpp
Normal 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
|
60
tdutils/td/utils/port/detail/EventFdWindows.h
Normal file
60
tdutils/td/utils/port/detail/EventFdWindows.h
Normal 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
|
122
tdutils/td/utils/port/detail/Iocp.cpp
Normal file
122
tdutils/td/utils/port/detail/Iocp.cpp
Normal 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
|
83
tdutils/td/utils/port/detail/Iocp.h
Normal file
83
tdutils/td/utils/port/detail/Iocp.h
Normal 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
|
192
tdutils/td/utils/port/detail/KQueue.cpp
Normal file
192
tdutils/td/utils/port/detail/KQueue.cpp
Normal 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
|
84
tdutils/td/utils/port/detail/KQueue.h
Normal file
84
tdutils/td/utils/port/detail/KQueue.h
Normal 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
|
259
tdutils/td/utils/port/detail/NativeFd.cpp
Normal file
259
tdutils/td/utils/port/detail/NativeFd.cpp
Normal 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
|
80
tdutils/td/utils/port/detail/NativeFd.h
Normal file
80
tdutils/td/utils/port/detail/NativeFd.h
Normal 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
|
114
tdutils/td/utils/port/detail/Poll.cpp
Normal file
114
tdutils/td/utils/port/detail/Poll.cpp
Normal 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
|
68
tdutils/td/utils/port/detail/Poll.h
Normal file
68
tdutils/td/utils/port/detail/Poll.h
Normal 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
|
262
tdutils/td/utils/port/detail/PollableFd.h
Normal file
262
tdutils/td/utils/port/detail/PollableFd.h
Normal 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
|
132
tdutils/td/utils/port/detail/Select.cpp
Normal file
132
tdutils/td/utils/port/detail/Select.cpp
Normal 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
|
76
tdutils/td/utils/port/detail/Select.h
Normal file
76
tdutils/td/utils/port/detail/Select.h
Normal 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
|
64
tdutils/td/utils/port/detail/ThreadIdGuard.cpp
Normal file
64
tdutils/td/utils/port/detail/ThreadIdGuard.cpp
Normal 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
|
38
tdutils/td/utils/port/detail/ThreadIdGuard.h
Normal file
38
tdutils/td/utils/port/detail/ThreadIdGuard.h
Normal 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
|
121
tdutils/td/utils/port/detail/ThreadPthread.h
Normal file
121
tdutils/td/utils/port/detail/ThreadPthread.h
Normal 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
|
89
tdutils/td/utils/port/detail/ThreadStl.h
Normal file
89
tdutils/td/utils/port/detail/ThreadStl.h
Normal 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
|
55
tdutils/td/utils/port/detail/WineventPoll.cpp
Normal file
55
tdutils/td/utils/port/detail/WineventPoll.cpp
Normal 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
|
62
tdutils/td/utils/port/detail/WineventPoll.h
Normal file
62
tdutils/td/utils/port/detail/WineventPoll.h
Normal 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
|
Loading…
Add table
Add a link
Reference in a new issue