Merge tag 'v0.21.18'

release v0.21.18
This commit is contained in:
Max Kellermann
2019-12-24 16:17:10 +01:00
20 changed files with 375 additions and 77 deletions
+2 -2
View File
@@ -137,7 +137,8 @@ static constexpr int
ExportTimeoutMS(std::chrono::steady_clock::duration timeout)
{
return timeout >= timeout.zero()
? int(std::chrono::duration_cast<std::chrono::milliseconds>(timeout).count())
/* round up (+1) to avoid unnecessary wakeups */
? int(std::chrono::duration_cast<std::chrono::milliseconds>(timeout).count()) + 1
: -1;
}
@@ -220,7 +221,6 @@ EventLoop::Run() noexcept
} while (!quit);
#ifndef NDEBUG
assert(busy);
assert(thread.IsInside());
#endif
}
+48 -4
View File
@@ -22,6 +22,10 @@
#include <algorithm>
#ifdef USE_EPOLL
#include <errno.h>
#endif
#ifndef _WIN32
#include <poll.h>
#endif
@@ -37,17 +41,42 @@ MultiSocketMonitor::Reset() noexcept
assert(GetEventLoop().IsInside());
fds.clear();
#ifdef USE_EPOLL
always_ready_fds.clear();
#endif
IdleMonitor::Cancel();
timeout_event.Cancel();
ready = refresh = false;
}
bool
MultiSocketMonitor::AddSocket(SocketDescriptor fd, unsigned events) noexcept
{
fds.emplace_front(*this, fd);
bool success = fds.front().Schedule(events);
if (!success) {
fds.pop_front();
#ifdef USE_EPOLL
if (errno == EPERM)
/* not supported by epoll (e.g. "/dev/null"):
add it to the "always ready" list */
always_ready_fds.push_front({fd, events});
#endif
}
return success;
}
void
MultiSocketMonitor::ClearSocketList() noexcept
{
assert(GetEventLoop().IsInside());
fds.clear();
#ifdef USE_EPOLL
always_ready_fds.clear();
#endif
}
#ifndef _WIN32
@@ -55,6 +84,10 @@ MultiSocketMonitor::ClearSocketList() noexcept
void
MultiSocketMonitor::ReplaceSocketList(pollfd *pfds, unsigned n) noexcept
{
#ifdef USE_EPOLL
always_ready_fds.clear();
#endif
pollfd *const end = pfds + n;
UpdateSocketList([pfds, end](SocketDescriptor fd) -> unsigned {
@@ -64,9 +97,7 @@ MultiSocketMonitor::ReplaceSocketList(pollfd *pfds, unsigned n) noexcept
if (i == end)
return 0;
auto events = i->events;
i->events = 0;
return events;
return std::exchange(i->events, 0);
});
for (auto i = pfds; i != end; ++i)
@@ -79,7 +110,20 @@ MultiSocketMonitor::ReplaceSocketList(pollfd *pfds, unsigned n) noexcept
void
MultiSocketMonitor::Prepare() noexcept
{
const auto timeout = PrepareSockets();
auto timeout = PrepareSockets();
#ifdef USE_EPOLL
if (!always_ready_fds.empty()) {
/* if there was at least one file descriptor not
supported by epoll, install a very short timeout
because we assume it's always ready */
constexpr std::chrono::steady_clock::duration ready_timeout =
std::chrono::milliseconds(1);
if (timeout < timeout.zero() || timeout > ready_timeout)
timeout = ready_timeout;
}
#endif
if (timeout >= timeout.zero())
timeout_event.Schedule(timeout);
else
+24 -11
View File
@@ -49,12 +49,10 @@ class MultiSocketMonitor : IdleMonitor
unsigned revents;
public:
SingleFD(MultiSocketMonitor &_multi, SocketDescriptor _fd,
unsigned events) noexcept
SingleFD(MultiSocketMonitor &_multi,
SocketDescriptor _fd) noexcept
:SocketMonitor(_fd, _multi.GetEventLoop()),
multi(_multi), revents(0) {
Schedule(events);
}
multi(_multi), revents(0) {}
SocketDescriptor GetSocket() const noexcept {
return SocketMonitor::GetSocket();
@@ -85,8 +83,6 @@ class MultiSocketMonitor : IdleMonitor
}
};
friend class SingleFD;
TimerEvent timeout_event;
/**
@@ -105,6 +101,21 @@ class MultiSocketMonitor : IdleMonitor
std::forward_list<SingleFD> fds;
#ifdef USE_EPOLL
struct AlwaysReady {
const SocketDescriptor fd;
const unsigned revents;
};
/**
* A list of file descriptors which are always ready. This is
* a kludge needed because the ALSA output plugin gives us a
* file descriptor to /dev/null, which is incompatible with
* epoll (epoll_ctl() returns -EPERM).
*/
std::forward_list<AlwaysReady> always_ready_fds;
#endif
public:
static constexpr unsigned READ = SocketMonitor::READ;
static constexpr unsigned WRITE = SocketMonitor::WRITE;
@@ -146,9 +157,7 @@ public:
*
* May only be called from PrepareSockets().
*/
void AddSocket(SocketDescriptor fd, unsigned events) noexcept {
fds.emplace_front(*this, fd, events);
}
bool AddSocket(SocketDescriptor fd, unsigned events) noexcept;
/**
* Remove all sockets.
@@ -203,6 +212,11 @@ public:
i.ClearReturnedEvents();
}
}
#ifdef USE_EPOLL
for (const auto &i : always_ready_fds)
f(i.fd, i.revents);
#endif
}
protected:
@@ -231,7 +245,6 @@ private:
void OnTimeout() noexcept {
SetReady();
IdleMonitor::Schedule();
}
virtual void OnIdle() noexcept final;
+10 -6
View File
@@ -64,20 +64,24 @@ SocketMonitor::Close() noexcept
Steal().Close();
}
void
bool
SocketMonitor::Schedule(unsigned flags) noexcept
{
assert(IsDefined());
if (flags == GetScheduledFlags())
return;
return true;
bool success;
if (scheduled_flags == 0)
loop.AddFD(fd.Get(), flags, *this);
success = loop.AddFD(fd.Get(), flags, *this);
else if (flags == 0)
loop.RemoveFD(fd.Get(), *this);
success = loop.RemoveFD(fd.Get(), *this);
else
loop.ModifyFD(fd.Get(), flags, *this);
success = loop.ModifyFD(fd.Get(), flags, *this);
scheduled_flags = flags;
if (success)
scheduled_flags = flags;
return success;
}
+9 -5
View File
@@ -98,18 +98,22 @@ public:
return scheduled_flags;
}
void Schedule(unsigned flags) noexcept;
/**
* @return true on success, false on error (with errno set if
* USE_EPOLL is defined)
*/
bool Schedule(unsigned flags) noexcept;
void Cancel() noexcept {
Schedule(0);
}
void ScheduleRead() noexcept {
Schedule(GetScheduledFlags() | READ | HANGUP | ERROR);
bool ScheduleRead() noexcept {
return Schedule(GetScheduledFlags() | READ | HANGUP | ERROR);
}
void ScheduleWrite() noexcept {
Schedule(GetScheduledFlags() | WRITE);
bool ScheduleWrite() noexcept {
return Schedule(GetScheduledFlags() | WRITE);
}
void CancelRead() noexcept {