changeset 278:d10274d8393c

Irccd: use a Pollable concept instead of inheritance, closes #566
author David Demelier <markand@malikania.fr>
date Tue, 04 Oct 2016 20:43:04 +0200
parents 685a492c39ba
children af932dbab952
files lib/irccd/client.hpp lib/irccd/irccd.cpp lib/irccd/irccd.hpp lib/irccd/irccdctl.cpp lib/irccd/pollable.hpp lib/irccd/service-interrupt.hpp lib/irccd/service-server.hpp lib/irccd/service-transport.hpp lib/irccd/util.hpp
diffstat 9 files changed, 113 insertions(+), 160 deletions(-) [+]
line wrap: on
line diff
--- a/lib/irccd/client.hpp	Thu Sep 29 20:33:11 2016 +0200
+++ b/lib/irccd/client.hpp	Tue Oct 04 20:43:04 2016 +0200
@@ -28,9 +28,10 @@
 #include <memory>
 #include <string>
 
+#include <json.hpp>
+
 #include "net.hpp"
 #include "signals.hpp"
-#include "pollable.hpp"
 
 namespace irccd {
 
@@ -65,7 +66,7 @@
  *     |                                   |
  *     ------------------------------------+
  */
-class Client : public Pollable {
+class Client {
 public:
     /**
      * \brief The current connection state.
@@ -258,7 +259,7 @@
      * \param out the output set
      * \param max the maximum file descriptor
      */
-    void prepare(fd_set &in, fd_set &out, net::Handle &max) override;
+    virtual void prepare(fd_set &in, fd_set &out, net::Handle &max);
 
     /**
      * Do some I/O using the protected recv and send functions.
@@ -266,7 +267,7 @@
      * \param in the input set
      * \param out the output set
      */
-    void sync(fd_set &in, fd_set &out) override;
+    virtual void sync(fd_set &in, fd_set &out);
 };
 
 /**
--- a/lib/irccd/irccd.cpp	Thu Sep 29 20:33:11 2016 +0200
+++ b/lib/irccd/irccd.cpp	Tue Oct 04 20:43:04 2016 +0200
@@ -26,6 +26,7 @@
 #include "service-rule.hpp"
 #include "service-server.hpp"
 #include "service-transport.hpp"
+#include "util.hpp"
 
 using namespace std;
 using namespace std::placeholders;
@@ -42,9 +43,6 @@
     , m_moduleService(std::make_shared<ModuleService>())
     , m_plugins(std::make_shared<PluginService>(*this))
 {
-    m_services.push_back(m_interruptService);
-    m_services.push_back(m_servers);
-    m_services.push_back(m_transports);
 }
 
 void Irccd::post(std::function<void (Irccd &)> ev) noexcept
@@ -58,21 +56,19 @@
 void Irccd::run()
 {
     while (m_running) {
-        poll(250);
+        util::poller::poll(250, *m_interruptService, *m_servers, *m_transports);
         dispatch();
     }
 }
 
 void Irccd::prepare(fd_set &in, fd_set &out, net::Handle &max)
 {
-    for (const auto &service : m_services)
-        service->prepare(in, out, max);
+    util::poller::prepare(in, out, max, *m_interruptService, *m_servers, *m_transports);
 }
 
 void Irccd::sync(fd_set &in, fd_set &out)
 {
-    for (const auto &service : m_services)
-        service->sync(in, out);
+    util::poller::sync(in, out, *m_interruptService, *m_servers, *m_transports);
 }
 
 void Irccd::dispatch()
--- a/lib/irccd/irccd.hpp	Thu Sep 29 20:33:11 2016 +0200
+++ b/lib/irccd/irccd.hpp	Tue Oct 04 20:43:04 2016 +0200
@@ -30,7 +30,7 @@
 #include <mutex>
 #include <vector>
 
-#include "pollable.hpp"
+#include "net.hpp"
 #include "sysconfig.hpp"
 
 /**
@@ -42,7 +42,6 @@
 class InterruptService;
 class ModuleService;
 class PluginService;
-class Pollable;
 class RuleService;
 class ServerService;
 class TransportService;
@@ -51,7 +50,7 @@
  * \class Irccd
  * \brief Irccd main instance.
  */
-class Irccd : public Pollable {
+class Irccd {
 private:
     // Main loop stuff.
     std::atomic<bool> m_running{true};
@@ -66,7 +65,6 @@
     std::shared_ptr<RuleService> m_ruleService;
     std::shared_ptr<ModuleService> m_moduleService;
     std::shared_ptr<PluginService> m_plugins;
-    std::vector<std::shared_ptr<Pollable>> m_services;
 
     // Not copyable and not movable because services has references to irccd.
     Irccd(const Irccd &) = delete;
@@ -82,16 +80,6 @@
     IRCCD_EXPORT Irccd();
 
     /**
-     * Add a generic service.
-     *
-     * \param service the service
-     */
-    inline void addService(std::shared_ptr<Pollable> service)
-    {
-        m_services.push_back(std::move(service));
-    }
-
-    /**
      * Access the command service.
      *
      * \return the service
@@ -158,7 +146,7 @@
      * \param out the output set
      * \param max the maximum handle
      */
-    IRCCD_EXPORT void prepare(fd_set &in, fd_set &out, net::Handle &max) override;
+    IRCCD_EXPORT void prepare(fd_set &in, fd_set &out, net::Handle &max);
 
     /**
      * Synchronize the services.
@@ -166,7 +154,7 @@
      * \param in the input set
      * \param out the output set
      */
-    IRCCD_EXPORT void sync(fd_set &in, fd_set &out) override;
+    IRCCD_EXPORT void sync(fd_set &in, fd_set &out);
 
     /**
      * Add an event to the queue. This will immediately signals the event loop
--- a/lib/irccd/irccdctl.cpp	Thu Sep 29 20:33:11 2016 +0200
+++ b/lib/irccd/irccdctl.cpp	Tue Oct 04 20:43:04 2016 +0200
@@ -385,7 +385,7 @@
     ElapsedTimer timer;
 
     while (m_messages.empty() && m_connection->isConnected() && timer.elapsed() < m_timeout)
-        m_connection->poll();
+        util::poller::poll(250, *m_connection);
 
     if (m_messages.empty())
         return nlohmann::json();
@@ -425,7 +425,7 @@
     ElapsedTimer timer;
 
     while (m_events.empty() && m_connection->isConnected() && timer.elapsed() < m_timeout)
-        m_connection->poll();
+        util::poller::poll(250, *m_connection);
 
     if (m_events.empty())
         return nullptr;
--- a/lib/irccd/pollable.hpp	Thu Sep 29 20:33:11 2016 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,117 +0,0 @@
-/*
- * pollable.hpp -- pollable object
- *
- * Copyright (c) 2013-2016 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef IRCCD_POLLABLE_HPP
-#define IRCCD_POLLABLE_HPP
-
-/**
- * \file service.hpp
- * \brief Pollable object.
- */
-
-#include "net.hpp"
-#include "util.hpp"
-
-namespace irccd {
-
-/**
- * \brief Pollable object.
- *
- * This class can be used to prepare an object into a select(2) system call.
- *
- * The primary use case of these objects is to be polled in the main loop while
- * being generic.
- *
- * To use the pollable objects:
- *
- * 1. Create two fd_set, one for input and one for output. Don't forget to
- *    initialize them using FD_ZERO.
- *
- * 2. For all of your pollable objects, call the prepare function and pass the
- *    input and output sets. The max handle is usually the pollable socket.
- *
- * 3. Do your select(2) call using the input, output and socket handle and your
- *    desired timeout.
- *
- * 4. For all of your pollable objects, call the sync function and pass the
- *    input and output sets.
- *
- * Pollable objects are usually implemented using asynchronous signals defined
- * in signals.hpp file.
- */
-class Pollable {
-public:
-    /**
-     * Default constructor.
-     */
-    Pollable() noexcept = default;
-
-    /**
-     * Virtual destructor defaulted.
-     */
-    virtual ~Pollable() noexcept = default;
-
-    /**
-     * Prepare the input and output set.
-     *
-     * \param in the input set
-     * \param out the output set
-     * \param max the handle to update
-     */
-    virtual void prepare(fd_set &in, fd_set &out, net::Handle &max)
-    {
-        util::unused(in, out, max);
-    }
-
-    /**
-     * Synchronize with result sets.
-     *
-     * \param in the input set
-     * \param out the output set
-     */
-    virtual void sync(fd_set &in, fd_set &out)
-    {
-        util::unused(in, out);
-    }
-
-    /**
-     * Convenient function for polling events with a timeout.
-     *
-     * \param timeout the timeout in milliseconds
-     */
-    virtual void poll(int timeout = -1)
-    {
-        fd_set in, out;
-        timeval tv = {0, timeout * 1000};
-
-        FD_ZERO(&in);
-        FD_ZERO(&out);
-
-        net::Handle max = 0;
-
-        prepare(in, out, max);
-
-        // Timeout or error are discarded.
-        if (::select(max + 1, &in, &out, nullptr, timeout < 0 ? nullptr : &tv) > 0)
-            sync(in, out);
-    }
-};
-
-} // !irccd
-
-#endif // !IRCCD_POLLABLE_HPP
--- a/lib/irccd/service-interrupt.hpp	Thu Sep 29 20:33:11 2016 +0200
+++ b/lib/irccd/service-interrupt.hpp	Tue Oct 04 20:43:04 2016 +0200
@@ -24,7 +24,7 @@
  * \brief Interrupt irccd event loop.
  */
 
-#include "pollable.hpp"
+#include "net.hpp"
 
 namespace irccd {
 
@@ -32,7 +32,7 @@
  * \brief Interrupt irccd event loop.
  * \ingroup services
  */
-class InterruptService : public Pollable {
+class InterruptService {
 private:
     net::TcpSocket m_in;
     net::TcpSocket m_out;
@@ -48,12 +48,12 @@
     /**
      * \copydoc Service::prepare
      */
-    IRCCD_EXPORT void prepare(fd_set &in, fd_set &out, net::Handle &max) override;
+    IRCCD_EXPORT void prepare(fd_set &in, fd_set &out, net::Handle &max);
 
     /**
      * \copydoc Service::sync
      */
-    IRCCD_EXPORT void sync(fd_set &in, fd_set &out) override;
+    IRCCD_EXPORT void sync(fd_set &in, fd_set &out);
 
     /**
      * Request interruption.
--- a/lib/irccd/service-server.hpp	Thu Sep 29 20:33:11 2016 +0200
+++ b/lib/irccd/service-server.hpp	Tue Oct 04 20:43:04 2016 +0200
@@ -29,7 +29,6 @@
 #include <string>
 
 #include "server.hpp"
-#include "pollable.hpp"
 
 namespace irccd {
 
@@ -39,7 +38,7 @@
  * \brief Manage IRC servers.
  * \ingroup services
  */
-class ServerService : public Pollable {
+class ServerService {
 private:
     Irccd &m_irccd;
     std::vector<std::shared_ptr<Server>> m_servers;
@@ -70,12 +69,12 @@
     /**
      * \copydoc Service::prepare
      */
-    IRCCD_EXPORT void prepare(fd_set &in, fd_set &out, net::Handle &max) override;
+    IRCCD_EXPORT void prepare(fd_set &in, fd_set &out, net::Handle &max);
 
     /**
      * \copydoc Service::sync
      */
-    IRCCD_EXPORT void sync(fd_set &in, fd_set &out) override;
+    IRCCD_EXPORT void sync(fd_set &in, fd_set &out);
 
     /**
      * Get the list of servers
--- a/lib/irccd/service-transport.hpp	Thu Sep 29 20:33:11 2016 +0200
+++ b/lib/irccd/service-transport.hpp	Tue Oct 04 20:43:04 2016 +0200
@@ -26,8 +26,6 @@
 
 #include <json.hpp>
 
-#include "pollable.hpp"
-
 namespace irccd {
 
 class TransportServer;
@@ -37,7 +35,7 @@
  * \brief manage transport servers and clients.
  * \ingroup services
  */
-class TransportService : public Pollable {
+class TransportService {
 private:
     Irccd &m_irccd;
 
@@ -58,12 +56,12 @@
     /**
      * \copydoc Service::prepare
      */
-    IRCCD_EXPORT void prepare(fd_set &in, fd_set &out, net::Handle &max) override;
+    IRCCD_EXPORT void prepare(fd_set &in, fd_set &out, net::Handle &max);
 
     /**
      * \copydoc Service::sync
      */
-    IRCCD_EXPORT void sync(fd_set &in, fd_set &out) override;
+    IRCCD_EXPORT void sync(fd_set &in, fd_set &out);
 
     /**
      * Add a transport server.
--- a/lib/irccd/util.hpp	Thu Sep 29 20:33:11 2016 +0200
+++ b/lib/irccd/util.hpp	Tue Oct 04 20:43:04 2016 +0200
@@ -38,6 +38,7 @@
 #include <format.h>
 #include <json.hpp>
 
+#include "net.hpp"
 #include "sysconfig.hpp"
 
 namespace irccd {
@@ -599,6 +600,93 @@
 
 } // !json
 
+/**
+ * \brief Miscellaneous utilities for Pollable objects
+ */
+namespace poller {
+
+/**
+ * \cond HIDDEN_SYMBOLS
+ */
+
+inline void prepare(fd_set &, fd_set &, net::Handle &) noexcept
+{
+}
+
+/**
+ * \endcond
+ */
+
+/**
+ * Call prepare function for every Pollable objects.
+ *
+ * \param in the input set
+ * \param out the output set
+ * \param max the maximum handle
+ * \param first the first Pollable object
+ * \param rest the additional Pollable objects
+ */
+template <typename Pollable, typename... Rest>
+inline void prepare(fd_set &in, fd_set &out, net::Handle &max, Pollable &first, Rest&... rest)
+{
+    first.prepare(in, out, max);
+    prepare(in, out, max, rest...);
+}
+
+/**
+ * \cond HIDDEN_SYMBOLS
+ */
+
+inline void sync(fd_set &, fd_set &) noexcept
+{
+}
+
+/**
+ * \endcond
+ */
+
+/**
+ * Call sync function for every Pollable objects.
+ *
+ * \param in the input set
+ * \param out the output set
+ * \param first the first Pollable object
+ * \param rest the additional Pollable objects
+ */
+template <typename Pollable, typename... Rest>
+inline void sync(fd_set &in, fd_set &out, Pollable &first, Rest&... rest)
+{
+    first.sync(in, out);
+    sync(in, out, rest...);
+}
+
+/**
+ * Prepare and sync Pollable objects.
+ *
+ * \param timeout the timeout in milliseconds (< 0 means forever)
+ * \param first the the first Pollable object
+ * \param rest the additional Pollable objects
+ */
+template <typename Pollable, typename... Rest>
+void poll(int timeout, Pollable &first, Rest&... rest)
+{
+    fd_set in, out;
+    timeval tv = {0, timeout * 1000};
+
+    FD_ZERO(&in);
+    FD_ZERO(&out);
+
+    net::Handle max = 0;
+
+    prepare(in, out, max, first, rest...);
+
+    // Timeout or error are discarded.
+    if (::select(max + 1, &in, &out, nullptr, timeout < 0 ? nullptr : &tv) > 0)
+        sync(in, out, first, rest...);
+}
+
+} // !poller
+
 } // !util
 
 } // !irccd