Switch socket manager notification from pipe to eventfd 23/277723/2
authorKonrad Lipinski <k.lipinski2@samsung.com>
Tue, 12 Jul 2022 09:49:53 +0000 (11:49 +0200)
committerKonrad Lipinski <k.lipinski2@samsung.com>
Tue, 12 Jul 2022 11:28:55 +0000 (13:28 +0200)
* use eventfd for a more efficient wakeup mechanism
* handle it directly in the manager thread to reduce thrashing
* drop the now useless DummyService and SIGPIPE-related code
* check m_working in the main loop only if eventfd is ready for reading

Change-Id: I090d90a50f3c789445dd6d0daa637abf0d189348

src/server/main/include/socket-manager.h
src/server/main/socket-manager.cpp

index 69a33ec..e8113d0 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014-2020 Samsung Electronics Co., Ltd. All rights reserved.
+ * Copyright (c) 2014-2022 Samsung Electronics Co., Ltd. All rights reserved.
  *
  * This file is licensed under the terms of MIT License or the Apache License
  * Version 2.0 of your choice. See the LICENSE.MIT file for MIT license details.
@@ -72,6 +72,8 @@ protected:
     void NotifyMe(void);
     void CloseSocket(int sock);
 
+    void RegisterFdForReading(int fd);
+
     struct SocketDescription {
         bool isListen;
         bool isOpen;
@@ -113,13 +115,13 @@ protected:
     SocketDescriptionVector m_socketDescriptionVector;
     fd_set m_readSet;
     fd_set m_writeSet;
-    int m_maxDesc;
-    bool m_working;
+    int m_maxDesc = 0;
+    int m_notifyMe;
+    int m_counter = 0;
+    bool m_working = false;
     std::mutex m_eventQueueMutex;
     std::queue<WriteBuffer> m_writeBufferQueue;
     std::queue<ConnectionID> m_closeQueue;
-    int m_notifyMe[2];
-    int m_counter;
     std::priority_queue<Timeout> m_timeoutQueue;
 };
 
index 2bd4f3a..593f0e4 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013-2020 Samsung Electronics Co., Ltd. All rights reserved.
+ * Copyright (c) 2013-2022 Samsung Electronics Co., Ltd. All rights reserved.
  *
  * This file is licensed under the terms of MIT License or the Apache License
  * Version 2.0 of your choice. See the LICENSE.MIT file for MIT license details.
 
 #include <set>
 
+#include <errno.h>
+#include <fcntl.h>
+#include <linux/xattr.h>
 #include <signal.h>
+#include <sys/eventfd.h>
 #include <sys/select.h>
 #include <sys/signalfd.h>
-#include <sys/types.h>
-#include <sys/socket.h>
 #include <sys/smack.h>
-#include <sys/wait.h>
-#include <linux/xattr.h>
-#include <sys/un.h>
+#include <sys/socket.h>
 #include <sys/stat.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <signal.h>
-#include <errno.h>
+#include <sys/types.h>
+#include <sys/un.h>
+#include <sys/wait.h>
 #include <time.h>
+#include <unistd.h>
 
 #include <systemd/sd-daemon.h>
 
@@ -63,16 +63,6 @@ const time_t SOCKET_TIMEOUT = 300;
 
 namespace SecurityManager {
 
-struct DummyService : public GenericSocketService {
-    ServiceDescriptionVector GetServiceDescription() {
-        return ServiceDescriptionVector();
-    }
-    void Event(AcceptEvent &&) { }
-    void Event(WriteEvent &&) { }
-    void Event(ReadEvent &&) { }
-    void Event(CloseEvent &&) { }
-};
-
 struct SignalService : public GenericSocketService {
     int GetDescriptor() {
         LogInfo("set up");
@@ -120,6 +110,11 @@ struct SignalService : public GenericSocketService {
     }
 };
 
+void SocketManager::RegisterFdForReading(int fd) {
+    FD_SET(fd, &m_readSet);
+    m_maxDesc = std::max(m_maxDesc, fd);
+}
+
 SocketManager::SocketDescription&
 SocketManager::CreateDefaultReadSocketDescription(int sock, bool timeout)
 {
@@ -145,32 +140,20 @@ SocketManager::CreateDefaultReadSocketDescription(int sock, bool timeout)
 
     desc.isTimeout = timeout;
 
-    FD_SET(sock, &m_readSet);
-    m_maxDesc = sock > m_maxDesc ? sock : m_maxDesc;
+    RegisterFdForReading(sock);
     return desc;
 }
 
 SocketManager::SocketManager()
-  : m_maxDesc(0)
-  , m_working(false)
-  , m_counter(0)
 {
     FD_ZERO(&m_readSet);
     FD_ZERO(&m_writeSet);
-    if (-1 == pipe(m_notifyMe)) {
+    if ((m_notifyMe = eventfd(0, 0)) < 0) {
         int err = errno;
-        ThrowMsg(Exception::InitFailed, "Error in pipe: " << GetErrnoString(err));
+        ThrowMsg(Exception::InitFailed, "Error in eventfd: " << GetErrnoString(err));
     }
-    LogInfo("Pipe: Read desc: " << m_notifyMe[0] << " Write desc: " << m_notifyMe[1]);
-
-    auto &desc = CreateDefaultReadSocketDescription(m_notifyMe[0], false);
-    desc.service = new DummyService;
-
-    // std::thread bases on pthread so this should work fine
-    sigset_t set;
-    sigemptyset(&set);
-    sigaddset(&set, SIGPIPE);
-    pthread_sigmask(SIG_BLOCK, &set, NULL);
+    LogInfo("Eventfd desc: " << m_notifyMe);
+    RegisterFdForReading(m_notifyMe);
 
     // add support for TERM signal (passed from systemd)
     auto *signalService = new SignalService;
@@ -206,8 +189,8 @@ SocketManager::~SocketManager() {
         if (m_socketDescriptionVector[i].isOpen)
             close(i);
 
-    // All socket except one were closed. Now pipe input must be closed.
-    close(m_notifyMe[1]);
+    // All service sockets have been closed. Close internal descriptors.
+    close(m_notifyMe);
 }
 
 void SocketManager::ReadyForAccept(int sock) {
@@ -278,7 +261,6 @@ void SocketManager::ReadyForWrite(int sock) {
         case EINTR:
             // select will trigger write once again, nothing to do
             break;
-        case EPIPE:
         default:
             LogError("Error during write: " << GetErrnoString(err));
             CloseSocket(sock);
@@ -311,7 +293,7 @@ void SocketManager::MainLoop() {
     sd_notify(0, "READY=1");
 
     m_working = true;
-    while (m_working) {
+    for (;;) {
         fd_set readSet = m_readSet;
         fd_set writeSet = m_writeSet;
 
@@ -400,6 +382,15 @@ void SocketManager::MainLoop() {
             }
             continue;
         }
+
+        if (FD_ISSET(m_notifyMe, &readSet)) {
+            if (!m_working)
+                return;
+            eventfd_t dummyValue;
+            TEMP_FAILURE_RETRY(eventfd_read(m_notifyMe, &dummyValue));
+            FD_CLR(m_notifyMe, &readSet);
+        }
+
         for (int i = 0; i < m_maxDesc+1 && ret; ++i) {
             if (FD_ISSET(i, &readSet)) {
                 ReadyForRead(i);
@@ -580,7 +571,7 @@ void SocketManager::Write(ConnectionID connectionID, const RawBuffer &rawBuffer)
 }
 
 void SocketManager::NotifyMe() {
-    TEMP_FAILURE_RETRY(write(m_notifyMe[1], "You have message ;-)", 1));
+    TEMP_FAILURE_RETRY(eventfd_write(m_notifyMe, 1));
 }
 
 void SocketManager::ProcessQueue() {