event/SocketMonitor: refactor to SocketEvent
Similar to commits1686f4e857
and30a5dd267b
This commit is contained in:
@@ -31,7 +31,7 @@
|
||||
#include "Request.hxx"
|
||||
#include "Log.hxx"
|
||||
#include "event/Loop.hxx"
|
||||
#include "event/SocketMonitor.hxx"
|
||||
#include "event/SocketEvent.hxx"
|
||||
#include "util/RuntimeError.hxx"
|
||||
#include "util/Domain.hxx"
|
||||
|
||||
@@ -42,12 +42,15 @@ static constexpr Domain curlm_domain("curlm");
|
||||
/**
|
||||
* Monitor for one socket created by CURL.
|
||||
*/
|
||||
class CurlSocket final : SocketMonitor {
|
||||
class CurlSocket final {
|
||||
CurlGlobal &global;
|
||||
|
||||
SocketEvent socket_event;
|
||||
|
||||
public:
|
||||
CurlSocket(CurlGlobal &_global, EventLoop &_loop, SocketDescriptor _fd)
|
||||
:SocketMonitor(_fd, _loop), global(_global) {}
|
||||
:global(_global),
|
||||
socket_event(_loop, BIND_THIS_METHOD(OnSocketReady), _fd) {}
|
||||
|
||||
~CurlSocket() noexcept {
|
||||
/* TODO: sometimes, CURL uses CURL_POLL_REMOVE after
|
||||
@@ -59,6 +62,10 @@ public:
|
||||
better solution? */
|
||||
}
|
||||
|
||||
auto &GetEventLoop() const noexcept {
|
||||
return socket_event.GetEventLoop();
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback function for CURLMOPT_SOCKETFUNCTION.
|
||||
*/
|
||||
@@ -66,13 +73,17 @@ public:
|
||||
curl_socket_t s, int action,
|
||||
void *userp, void *socketp) noexcept;
|
||||
|
||||
bool OnSocketReady(unsigned flags) noexcept override;
|
||||
|
||||
private:
|
||||
SocketDescriptor GetSocket() const noexcept {
|
||||
return socket_event.GetSocket();
|
||||
}
|
||||
|
||||
void OnSocketReady(unsigned flags) noexcept;
|
||||
|
||||
static constexpr int FlagsToCurlCSelect(unsigned flags) noexcept {
|
||||
return (flags & (READ | HANGUP) ? CURL_CSELECT_IN : 0) |
|
||||
(flags & WRITE ? CURL_CSELECT_OUT : 0) |
|
||||
(flags & ERROR ? CURL_CSELECT_ERR : 0);
|
||||
return (flags & (SocketEvent::READ | SocketEvent::HANGUP) ? CURL_CSELECT_IN : 0) |
|
||||
(flags & SocketEvent::WRITE ? CURL_CSELECT_OUT : 0) |
|
||||
(flags & SocketEvent::ERROR ? CURL_CSELECT_ERR : 0);
|
||||
}
|
||||
|
||||
gcc_const
|
||||
@@ -82,13 +93,13 @@ private:
|
||||
return 0;
|
||||
|
||||
case CURL_POLL_IN:
|
||||
return READ;
|
||||
return SocketEvent::READ;
|
||||
|
||||
case CURL_POLL_OUT:
|
||||
return WRITE;
|
||||
return SocketEvent::WRITE;
|
||||
|
||||
case CURL_POLL_INOUT:
|
||||
return READ|WRITE;
|
||||
return SocketEvent::READ|SocketEvent::WRITE;
|
||||
}
|
||||
|
||||
assert(false);
|
||||
@@ -130,17 +141,16 @@ CurlSocket::SocketFunction([[maybe_unused]] CURL *easy,
|
||||
|
||||
unsigned flags = CurlPollToFlags(action);
|
||||
if (flags != 0)
|
||||
cs->Schedule(flags);
|
||||
cs->socket_event.Schedule(flags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool
|
||||
void
|
||||
CurlSocket::OnSocketReady(unsigned flags) noexcept
|
||||
{
|
||||
assert(GetEventLoop().IsInside());
|
||||
|
||||
global.SocketAction(GetSocket().Get(), FlagsToCurlCSelect(flags));
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2007-2018 Content Management AG
|
||||
* Copyright 2007-2020 CM4all GmbH
|
||||
* All rights reserved.
|
||||
*
|
||||
* author: Max Kellermann <mk@cm4all.com>
|
||||
@@ -36,8 +36,8 @@ namespace ODBus {
|
||||
|
||||
WatchManager::Watch::Watch(EventLoop &event_loop,
|
||||
WatchManager &_parent, DBusWatch &_watch) noexcept
|
||||
:SocketMonitor(event_loop),
|
||||
parent(_parent), watch(_watch)
|
||||
:parent(_parent), watch(_watch),
|
||||
event(event_loop, BIND_THIS_METHOD(OnSocketReady))
|
||||
{
|
||||
Toggled();
|
||||
}
|
||||
@@ -45,30 +45,30 @@ WatchManager::Watch::Watch(EventLoop &event_loop,
|
||||
static constexpr unsigned
|
||||
DbusToLibevent(unsigned flags) noexcept
|
||||
{
|
||||
return ((flags & DBUS_WATCH_READABLE) != 0) * SocketMonitor::READ |
|
||||
((flags & DBUS_WATCH_WRITABLE) != 0) * SocketMonitor::WRITE;
|
||||
return ((flags & DBUS_WATCH_READABLE) != 0) * SocketEvent::READ |
|
||||
((flags & DBUS_WATCH_WRITABLE) != 0) * SocketEvent::WRITE;
|
||||
}
|
||||
|
||||
void
|
||||
WatchManager::Watch::Toggled() noexcept
|
||||
{
|
||||
if (SocketMonitor::IsDefined())
|
||||
SocketMonitor::Cancel();
|
||||
if (event.IsDefined())
|
||||
event.Cancel();
|
||||
|
||||
if (dbus_watch_get_enabled(&watch)) {
|
||||
SocketMonitor::Open(SocketDescriptor(dbus_watch_get_unix_fd(&watch)));
|
||||
SocketMonitor::Schedule(DbusToLibevent(dbus_watch_get_flags(&watch)));
|
||||
event.Open(SocketDescriptor(dbus_watch_get_unix_fd(&watch)));
|
||||
event.Schedule(DbusToLibevent(dbus_watch_get_flags(&watch)));
|
||||
}
|
||||
}
|
||||
|
||||
static constexpr unsigned
|
||||
LibeventToDbus(unsigned flags) noexcept
|
||||
{
|
||||
return ((flags & SocketMonitor::READ) != 0) * DBUS_WATCH_READABLE |
|
||||
((flags & SocketMonitor::WRITE) != 0) * DBUS_WATCH_WRITABLE;
|
||||
return ((flags & SocketEvent::READ) != 0) * DBUS_WATCH_READABLE |
|
||||
((flags & SocketEvent::WRITE) != 0) * DBUS_WATCH_WRITABLE;
|
||||
}
|
||||
|
||||
bool
|
||||
void
|
||||
WatchManager::Watch::OnSocketReady(unsigned events) noexcept
|
||||
{
|
||||
/* copy the "parent" reference to the stack, because the
|
||||
@@ -79,7 +79,6 @@ WatchManager::Watch::OnSocketReady(unsigned events) noexcept
|
||||
dbus_watch_handle(&watch, LibeventToDbus(events));
|
||||
|
||||
_parent.ScheduleDispatch();
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2007-2018 Content Management AG
|
||||
* Copyright 2007-2020 CM4all GmbH
|
||||
* All rights reserved.
|
||||
*
|
||||
* author: Max Kellermann <mk@cm4all.com>
|
||||
@@ -34,7 +34,7 @@
|
||||
#define ODBUS_WATCH_HXX
|
||||
|
||||
#include "Connection.hxx"
|
||||
#include "event/SocketMonitor.hxx"
|
||||
#include "event/SocketEvent.hxx"
|
||||
#include "event/DeferEvent.hxx"
|
||||
|
||||
#include <dbus/dbus.h>
|
||||
@@ -58,9 +58,10 @@ class WatchManager {
|
||||
|
||||
Connection connection;
|
||||
|
||||
class Watch final : SocketMonitor {
|
||||
class Watch {
|
||||
WatchManager &parent;
|
||||
DBusWatch &watch;
|
||||
SocketEvent event;
|
||||
|
||||
public:
|
||||
Watch(EventLoop &event_loop, WatchManager &_parent,
|
||||
@@ -69,7 +70,7 @@ class WatchManager {
|
||||
void Toggled() noexcept;
|
||||
|
||||
private:
|
||||
bool OnSocketReady(unsigned flags) noexcept override;
|
||||
void OnSocketReady(unsigned flags) noexcept;
|
||||
};
|
||||
|
||||
std::map<DBusWatch *, Watch> watches;
|
||||
|
@@ -183,17 +183,17 @@ NfsConnection::CancellableCallback::Callback(int err,
|
||||
static constexpr unsigned
|
||||
libnfs_to_events(int i) noexcept
|
||||
{
|
||||
return ((i & POLLIN) ? SocketMonitor::READ : 0) |
|
||||
((i & POLLOUT) ? SocketMonitor::WRITE : 0);
|
||||
return ((i & POLLIN) ? SocketEvent::READ : 0) |
|
||||
((i & POLLOUT) ? SocketEvent::WRITE : 0);
|
||||
}
|
||||
|
||||
static constexpr int
|
||||
events_to_libnfs(unsigned i) noexcept
|
||||
{
|
||||
return ((i & SocketMonitor::READ) ? POLLIN : 0) |
|
||||
((i & SocketMonitor::WRITE) ? POLLOUT : 0) |
|
||||
((i & SocketMonitor::HANGUP) ? POLLHUP : 0) |
|
||||
((i & SocketMonitor::ERROR) ? POLLERR : 0);
|
||||
return ((i & SocketEvent::READ) ? POLLIN : 0) |
|
||||
((i & SocketEvent::WRITE) ? POLLOUT : 0) |
|
||||
((i & SocketEvent::HANGUP) ? POLLHUP : 0) |
|
||||
((i & SocketEvent::ERROR) ? POLLERR : 0);
|
||||
}
|
||||
|
||||
NfsConnection::~NfsConnection() noexcept
|
||||
@@ -403,8 +403,8 @@ NfsConnection::DestroyContext() noexcept
|
||||
new leases */
|
||||
defer_new_lease.Cancel();
|
||||
|
||||
if (SocketMonitor::IsDefined())
|
||||
SocketMonitor::Steal();
|
||||
if (socket_event.IsDefined())
|
||||
socket_event.Steal();
|
||||
|
||||
callbacks.ForEach([](CancellableCallback &c){
|
||||
c.PrepareDestroyContext();
|
||||
@@ -434,25 +434,25 @@ NfsConnection::ScheduleSocket() noexcept
|
||||
|
||||
const int which_events = nfs_which_events(context);
|
||||
|
||||
if (which_events == POLLOUT && SocketMonitor::IsDefined())
|
||||
if (which_events == POLLOUT && socket_event.IsDefined())
|
||||
/* kludge: if libnfs asks only for POLLOUT, it means
|
||||
that it is currently waiting for the connect() to
|
||||
finish - rpc_reconnect_requeue() may have been
|
||||
called from inside nfs_service(); we must now
|
||||
unregister the old socket and register the new one
|
||||
instead */
|
||||
SocketMonitor::Steal();
|
||||
socket_event.Steal();
|
||||
|
||||
if (!SocketMonitor::IsDefined()) {
|
||||
if (!socket_event.IsDefined()) {
|
||||
SocketDescriptor _fd(nfs_get_fd(context));
|
||||
if (!_fd.IsDefined())
|
||||
return;
|
||||
|
||||
_fd.EnableCloseOnExec();
|
||||
SocketMonitor::Open(_fd);
|
||||
socket_event.Open(_fd);
|
||||
}
|
||||
|
||||
SocketMonitor::Schedule(libnfs_to_events(which_events));
|
||||
socket_event.Schedule(libnfs_to_events(which_events));
|
||||
}
|
||||
|
||||
inline int
|
||||
@@ -480,16 +480,14 @@ NfsConnection::Service(unsigned flags) noexcept
|
||||
return result;
|
||||
}
|
||||
|
||||
bool
|
||||
void
|
||||
NfsConnection::OnSocketReady(unsigned flags) noexcept
|
||||
{
|
||||
assert(GetEventLoop().IsInside());
|
||||
assert(deferred_close.empty());
|
||||
|
||||
bool closed = false;
|
||||
|
||||
const bool was_mounted = mount_finished;
|
||||
if (!mount_finished || (flags & SocketMonitor::HANGUP) != 0)
|
||||
if (!mount_finished || (flags & SocketEvent::HANGUP) != 0)
|
||||
/* until the mount is finished, the NFS client may use
|
||||
various sockets, therefore we unregister and
|
||||
re-register it each time */
|
||||
@@ -497,7 +495,7 @@ NfsConnection::OnSocketReady(unsigned flags) noexcept
|
||||
which is a sure sign that libnfs will close the
|
||||
socket, which can lead to a race condition if
|
||||
epoll_ctl() is called later */
|
||||
SocketMonitor::Steal();
|
||||
socket_event.Steal();
|
||||
|
||||
const int result = Service(flags);
|
||||
|
||||
@@ -509,7 +507,6 @@ NfsConnection::OnSocketReady(unsigned flags) noexcept
|
||||
if (!was_mounted && mount_finished) {
|
||||
if (postponed_mount_error) {
|
||||
DestroyContext();
|
||||
closed = true;
|
||||
BroadcastMountError(std::move(postponed_mount_error));
|
||||
} else if (result == 0)
|
||||
BroadcastMountSuccess();
|
||||
@@ -521,7 +518,6 @@ NfsConnection::OnSocketReady(unsigned flags) noexcept
|
||||
BroadcastError(std::make_exception_ptr(e));
|
||||
|
||||
DestroyContext();
|
||||
closed = true;
|
||||
} else if (nfs_get_fd(context) < 0) {
|
||||
/* this happens when rpc_reconnect_requeue() is called
|
||||
after the connection broke, but autoreconnect was
|
||||
@@ -535,7 +531,6 @@ NfsConnection::OnSocketReady(unsigned flags) noexcept
|
||||
BroadcastError(std::make_exception_ptr(e));
|
||||
|
||||
DestroyContext();
|
||||
closed = true;
|
||||
}
|
||||
|
||||
assert(context == nullptr || nfs_get_fd(context) >= 0);
|
||||
@@ -547,8 +542,6 @@ NfsConnection::OnSocketReady(unsigned flags) noexcept
|
||||
|
||||
if (context != nullptr)
|
||||
ScheduleSocket();
|
||||
|
||||
return !closed;
|
||||
}
|
||||
|
||||
inline void
|
||||
|
@@ -21,7 +21,7 @@
|
||||
#define MPD_NFS_CONNECTION_HXX
|
||||
|
||||
#include "Cancellable.hxx"
|
||||
#include "event/SocketMonitor.hxx"
|
||||
#include "event/SocketEvent.hxx"
|
||||
#include "event/TimerEvent.hxx"
|
||||
#include "event/DeferEvent.hxx"
|
||||
#include "util/Compiler.h"
|
||||
@@ -40,7 +40,7 @@ class NfsLease;
|
||||
/**
|
||||
* An asynchronous connection to a NFS server.
|
||||
*/
|
||||
class NfsConnection : SocketMonitor {
|
||||
class NfsConnection {
|
||||
class CancellableCallback : public CancellablePointer<NfsCallback> {
|
||||
NfsConnection &connection;
|
||||
|
||||
@@ -93,6 +93,7 @@ class NfsConnection : SocketMonitor {
|
||||
void Callback(int err, void *data) noexcept;
|
||||
};
|
||||
|
||||
SocketEvent socket_event;
|
||||
DeferEvent defer_new_lease;
|
||||
TimerEvent mount_timeout_event;
|
||||
|
||||
@@ -141,7 +142,7 @@ public:
|
||||
gcc_nonnull_all
|
||||
NfsConnection(EventLoop &_loop,
|
||||
const char *_server, const char *_export_name) noexcept
|
||||
:SocketMonitor(_loop),
|
||||
:socket_event(_loop, BIND_THIS_METHOD(OnSocketReady)),
|
||||
defer_new_lease(_loop, BIND_THIS_METHOD(RunDeferred)),
|
||||
mount_timeout_event(_loop, BIND_THIS_METHOD(OnMountTimeout)),
|
||||
server(_server), export_name(_export_name),
|
||||
@@ -152,6 +153,10 @@ public:
|
||||
*/
|
||||
~NfsConnection() noexcept;
|
||||
|
||||
auto &GetEventLoop() const noexcept {
|
||||
return socket_event.GetEventLoop();
|
||||
}
|
||||
|
||||
gcc_pure
|
||||
const char *GetServer() const noexcept {
|
||||
return server.c_str();
|
||||
@@ -162,8 +167,6 @@ public:
|
||||
return export_name.c_str();
|
||||
}
|
||||
|
||||
using SocketMonitor::GetEventLoop;
|
||||
|
||||
/**
|
||||
* Ensure that the connection is established. The connection
|
||||
* is kept up while at least one #NfsLease is registered.
|
||||
@@ -231,8 +234,7 @@ private:
|
||||
*/
|
||||
int Service(unsigned flags) noexcept;
|
||||
|
||||
/* virtual methods from SocketMonitor */
|
||||
bool OnSocketReady(unsigned flags) noexcept override;
|
||||
void OnSocketReady(unsigned flags) noexcept;
|
||||
|
||||
/* callback for #mount_timeout_event */
|
||||
void OnMountTimeout() noexcept;
|
||||
|
Reference in New Issue
Block a user