]> git.netwichtig.de Git - user/henk/code/inspircd.git/commitdiff
Add FD_WANT_SINGLE_WRITE to efficiently replace FD_WANT_POLL_WRITE
authordanieldg <danieldg@e03df62e-2008-0410-955e-edbf42e46eb7>
Sat, 26 Sep 2009 14:12:45 +0000 (14:12 +0000)
committerdanieldg <danieldg@e03df62e-2008-0410-955e-edbf42e46eb7>
Sat, 26 Sep 2009 14:12:45 +0000 (14:12 +0000)
git-svn-id: http://svn.inspircd.org/repository/trunk/inspircd@11762 e03df62e-2008-0410-955e-edbf42e46eb7

include/socketengine.h
src/inspsocket.cpp
src/modules/extra/m_ssl_gnutls.cpp
src/modules/extra/m_ssl_openssl.cpp
src/socketengines/socketengine_epoll.cpp
src/socketengines/socketengine_iocp.cpp
src/socketengines/socketengine_kqueue.cpp
src/socketengines/socketengine_poll.cpp
src/socketengines/socketengine_ports.cpp
src/socketengines/socketengine_select.cpp

index 9c45bcf21fd42a48321a0032ae712a28bf48ab24..1a0a61670f7e8439a03393c919d9bee3e1074735 100644 (file)
@@ -71,8 +71,10 @@ enum EventMask
        FD_WANT_NO_WRITE = 0x10,
        /** Give a write event at all times when writes will not block.
         *
-        * You probably don't need to use this state; try your write first, and
-        * then use FD_WANT_FAST_WRITE.
+        * You probably shouldn't use this state; if it's likely that the write
+        * will not block, try it first, then use FD_WANT_FAST_WRITE if it
+        * fails. If it's likely to block (or you are using polling-style reads)
+        * then use FD_WANT_SINGLE_WRITE.
         */
        FD_WANT_POLL_WRITE = 0x20,
        /** Give a write event when writes don't block any more
@@ -95,19 +97,23 @@ enum EventMask
         * FD_WANT_FAST_WRITE when writing data to a mostly-unblocked socket.
         */
        FD_WANT_EDGE_WRITE = 0x80,
+       /** Request a one-shot poll-style write notification. The socket will
+        * return to the FD_WANT_NO_WRITE state before HandleEvent is called.
+        */
+       FD_WANT_SINGLE_WRITE = 0x100,
 
        /** Mask for all write events */
-       FD_WANT_WRITE_MASK = 0xF0,
+       FD_WANT_WRITE_MASK = 0x1F0,
 
        /** Add a trial read. During the next DispatchEvents invocation, this
         * will call HandleEvent with EVENT_READ unless reads are known to be
-        * blocking. Useful for edge-triggered reads; does nothing if
-        * FD_READ_WILL_BLOCK has been set on this EventHandler.
+        * blocking.
         */
-       FD_ADD_TRIAL_READ  = 0x100,
+       FD_ADD_TRIAL_READ  = 0x1000,
        /** Assert that reads are known to block. This cancels FD_ADD_TRIAL_READ.
+        * Reset by SE before running EVENT_READ
         */
-       FD_READ_WILL_BLOCK = 0x200,
+       FD_READ_WILL_BLOCK = 0x2000,
 
        /** Add a trial write. During the next DispatchEvents invocation, this
         * will call HandleEvent with EVENT_WRITE unless writes are known to be
@@ -117,15 +123,14 @@ enum EventMask
         * send() syscall, or to ensure that writes are blocking when attempting
         * to use FD_WANT_FAST_WRITE.
         */
-       FD_ADD_TRIAL_WRITE = 0x1000,
+       FD_ADD_TRIAL_WRITE = 0x4000,
        /** Assert that writes are known to block. This cancels FD_ADD_TRIAL_WRITE.
+        * Reset by SE before running EVENT_WRITE
         */
-       FD_WRITE_WILL_BLOCK = 0x2000, 
+       FD_WRITE_WILL_BLOCK = 0x8000, 
 
-       /** Mask for trial read/write items */
-       FD_TRIAL_NOTE_MASK = 0x1100,
-       /** Mask for read/write blocking notifications */
-       FD_BLOCK_NOTE_MASK = 0x2200
+       /** Mask for trial read/trial write */
+       FD_TRIAL_NOTE_MASK = 0x5000
 };
 
 class InspIRCd;
index 6348d7982cabf6ad1deb20143b846cd4bbe965be..004d679ed37aaeb3279bbf91d405103193a0e054 100644 (file)
@@ -97,7 +97,7 @@ BufferedSocketError BufferedSocket::BeginConnect(const irc::sockets::sockaddrs&
 
        this->state = I_CONNECTING;
 
-       if (!ServerInstance->SE->AddFd(this, FD_WANT_NO_READ | FD_WANT_POLL_WRITE))
+       if (!ServerInstance->SE->AddFd(this, FD_WANT_NO_READ | FD_WANT_SINGLE_WRITE))
                return I_ERR_NOMOREFDS;
 
        this->Timeout = new SocketTimeout(this->GetFd(), this, timeout, ServerInstance->Time());
@@ -414,6 +414,8 @@ void BufferedSocket::DoWrite()
                this->OnConnected();
                if (GetIOHook())
                        GetIOHook()->OnStreamSocketConnect(this);
+               else
+                       ServerInstance->SE->ChangeEventMask(this, FD_WANT_FAST_READ | FD_WANT_EDGE_WRITE);
        }
        this->StreamSocket::DoWrite();
 }
index c65b8528a0c2b9755b086bfdfb0c06306be5eea8..3362e9378cd9c259c59807ae067fe12184f8df2f 100644 (file)
@@ -540,12 +540,12 @@ class ModuleSSLGnuTLS : public Module
                        else if (ret > 0)
                        {
                                sendq = sendq.substr(ret);
-                               ServerInstance->SE->ChangeEventMask(user, FD_WANT_POLL_WRITE);
+                               ServerInstance->SE->ChangeEventMask(user, FD_WANT_SINGLE_WRITE);
                                return 0;
                        }
                        else if (ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_INTERRUPTED)
                        {
-                               ServerInstance->SE->ChangeEventMask(user, FD_WANT_POLL_WRITE);
+                               ServerInstance->SE->ChangeEventMask(user, FD_WANT_SINGLE_WRITE);
                                return 0;
                        }
                        else if (ret == 0)
@@ -585,7 +585,7 @@ class ModuleSSLGnuTLS : public Module
                                {
                                        // gnutls_handshake() wants to write() again.
                                        session->status = ISSL_HANDSHAKING_WRITE;
-                                       ServerInstance->SE->ChangeEventMask(user, FD_WANT_NO_READ | FD_WANT_POLL_WRITE);
+                                       ServerInstance->SE->ChangeEventMask(user, FD_WANT_NO_READ | FD_WANT_SINGLE_WRITE);
                                }
                        }
                        else
index e72bdc816642bac631ce08d444f27339590ea1fd..645add4c28a4be963a59d49811f5276caf5846bb 100644 (file)
@@ -450,7 +450,7 @@ class ModuleSSLOpenSSL : public Module
                                }
                                else if (err == SSL_ERROR_WANT_WRITE)
                                {
-                                       ServerInstance->SE->ChangeEventMask(user, FD_WANT_NO_READ | FD_WANT_POLL_WRITE);
+                                       ServerInstance->SE->ChangeEventMask(user, FD_WANT_NO_READ | FD_WANT_SINGLE_WRITE);
                                        return 0;
                                }
                                else
@@ -501,7 +501,7 @@ class ModuleSSLOpenSSL : public Module
                        else if (ret > 0)
                        {
                                buffer = buffer.substr(ret);
-                               ServerInstance->SE->ChangeEventMask(user, FD_WANT_POLL_WRITE);
+                               ServerInstance->SE->ChangeEventMask(user, FD_WANT_SINGLE_WRITE);
                                return 0;
                        }
                        else if (ret == 0)
@@ -515,7 +515,7 @@ class ModuleSSLOpenSSL : public Module
 
                                if (err == SSL_ERROR_WANT_WRITE)
                                {
-                                       ServerInstance->SE->ChangeEventMask(user, FD_WANT_POLL_WRITE);
+                                       ServerInstance->SE->ChangeEventMask(user, FD_WANT_SINGLE_WRITE);
                                        return 0;
                                }
                                else if (err == SSL_ERROR_WANT_READ)
@@ -554,7 +554,7 @@ class ModuleSSLOpenSSL : public Module
                        }
                        else if (err == SSL_ERROR_WANT_WRITE)
                        {
-                               ServerInstance->SE->ChangeEventMask(user, FD_WANT_NO_READ | FD_WANT_POLL_WRITE);
+                               ServerInstance->SE->ChangeEventMask(user, FD_WANT_NO_READ | FD_WANT_SINGLE_WRITE);
                                session->status = ISSL_HANDSHAKING;
                                return true;
                        }
index 672ff4a7b9d3bb292e85cbbad652b5df5a8d1a23..059798d25ef77ae7743025097a9645c57ae68763 100644 (file)
@@ -58,12 +58,12 @@ EPollEngine::~EPollEngine()
 static int mask_to_epoll(int event_mask)
 {
        int rv = 0;
-       if (event_mask & (FD_WANT_POLL_READ | FD_WANT_POLL_WRITE))
+       if (event_mask & (FD_WANT_POLL_READ | FD_WANT_POLL_WRITE | FD_WANT_SINGLE_WRITE))
        {
                // we need to use standard polling on this FD
                if (event_mask & (FD_WANT_POLL_READ | FD_WANT_FAST_READ))
                        rv |= EPOLLIN;
-               if (event_mask & (FD_WANT_POLL_WRITE | FD_WANT_FAST_WRITE))
+               if (event_mask & (FD_WANT_POLL_WRITE | FD_WANT_FAST_WRITE | FD_WANT_SINGLE_WRITE))
                        rv |= EPOLLOUT;
        }
        else
@@ -182,16 +182,28 @@ int EPollEngine::DispatchEvents()
                        eh->HandleEvent(EVENT_ERROR, errcode);
                        continue;
                }
+               int mask = eh->GetEventMask();
+               if (events[j].events & EPOLLIN)
+                       mask &= ~FD_READ_WILL_BLOCK;
+               if (events[j].events & EPOLLOUT)
+               {
+                       mask &= ~FD_WRITE_WILL_BLOCK;
+                       if (mask & FD_WANT_SINGLE_WRITE)
+                       {
+                               int nm = mask & ~FD_WANT_SINGLE_WRITE;
+                               OnSetEvent(eh, mask, nm);
+                               mask = nm;
+                       }
+               }
+               SetEventMask(eh, mask);
                if (events[j].events & EPOLLIN)
                {
                        ReadEvents++;
-                       SetEventMask(eh, eh->GetEventMask() & ~FD_READ_WILL_BLOCK);
                        eh->HandleEvent(EVENT_READ);
                }
                if (events[j].events & EPOLLOUT)
                {
                        WriteEvents++;
-                       SetEventMask(eh, eh->GetEventMask() & ~FD_WRITE_WILL_BLOCK);
                        eh->HandleEvent(EVENT_WRITE);
                }
        }
index e09fb4d0a9345bacc84f7719ac8d83fd0332f0c2..c253bf0a629b6f4b6a4f6380a255498e8bafe80b 100644 (file)
@@ -91,7 +91,7 @@ bool IOCPEngine::AddFd(EventHandler* eh, int event_mask)
        ServerInstance->Logs->Log("SOCKET",DEBUG, "New fake fd: %u, real fd: %u, address 0x%p", *fake_fd, eh->GetFd(), eh);
 
        /* post a write event if there is data to be written */
-       if (event_mask & (FD_WANT_POLL_WRITE | FD_WANT_FAST_WRITE))
+       if (event_mask & (FD_WANT_POLL_WRITE | FD_WANT_FAST_WRITE | FD_WANT_SINGLE_WRITE))
                WantWrite(eh);
 
        /* we're all good =) */
@@ -183,7 +183,7 @@ void IOCPEngine::OnSetEvent(EventHandler* eh, int old_mask, int new_mask)
                return;
 
        /* Post event - write begin */
-       if((new_mask & (FD_WANT_POLL_WRITE | FD_WANT_FAST_WRITE)) && !eh->GetExt("windows_writeevent", m_writeEvent))
+       if((new_mask & (FD_WANT_POLL_WRITE | FD_WANT_FAST_WRITE | FD_WANT_SINGLE_WRITE)) && !eh->GetExt("windows_writeevent", m_writeEvent))
        {
                ULONG_PTR completion_key = (ULONG_PTR)*fake_fd;
                Overlapped * ov = new Overlapped(SOCKET_IO_EVENT_WRITE_READY, 0);
index c9734e85d192d6cb072ccab996cedb20c804258c..1a783153eae944ad333f0a9cdd4b656b92c22d11 100644 (file)
@@ -76,7 +76,7 @@ bool KQueueEngine::AddFd(EventHandler* eh, int event_mask)
                return false;
        }
 
-       if (event_mask & (FD_WANT_POLL_WRITE | FD_WANT_FAST_WRITE)) {
+       if (event_mask & (FD_WANT_POLL_WRITE | FD_WANT_FAST_WRITE | FD_WANT_SINGLE_WRITE)) {
                // ...and sometimes want to write
                WantWrite(eh);
        }
@@ -148,7 +148,7 @@ void KQueueEngine::OnSetEvent(EventHandler* eh, int old_mask, int new_mask)
                                                  eh->GetFd(), strerror(errno));
                }
        }
-       if ((new_mask & FD_WANT_EDGE_WRITE) && !(old_mask & FD_WANT_EDGE_WRITE))
+       if ((new_mask & (FD_WANT_FAST_WRITE | FD_WANT_SINGLE_WRITE)) && !(old_mask & (FD_WANT_FAST_WRITE | FD_WANT_SINGLE_WRITE)))
        {
                // new one-shot write
                struct kevent ke;
@@ -184,11 +184,11 @@ int KQueueEngine::DispatchEvents()
                if (ke_list[j].filter == EVFILT_WRITE)
                {
                        WriteEvents++;
-                       /* When mask is FD_WANT_FAST_WRITE, we set a one-shot
-                        * write, so we need to clear that bit to detect when it
-                        * set again.
+                       /* When mask is FD_WANT_FAST_WRITE or FD_WANT_SINGLE_WRITE,
+                        * we set a one-shot write, so we need to clear that bit
+                        * to detect when it set again.
                         */
-                       const int bits_to_clr = FD_WANT_FAST_WRITE | FD_WRITE_WILL_BLOCK;
+                       const int bits_to_clr = FD_WANT_SINGLE_WRITE | FD_WANT_FAST_WRITE | FD_WRITE_WILL_BLOCK;
                        SetEventMask(eh, eh->GetEventMask() & ~bits_to_clr);
                        eh->HandleEvent(EVENT_WRITE);
                }
index 6f50e27988cceab73496d87326631dcf5b9d311d..a72d21d1ff9a15a26d00a1cb142f19d16bafe87d 100644 (file)
@@ -63,7 +63,7 @@ static int mask_to_poll(int event_mask)
        int rv = 0;
        if (event_mask & (FD_WANT_POLL_READ | FD_WANT_FAST_READ))
                rv |= POLLIN;
-       if (event_mask & (FD_WANT_POLL_WRITE | FD_WANT_FAST_WRITE))
+       if (event_mask & (FD_WANT_POLL_WRITE | FD_WANT_FAST_WRITE | FD_WANT_SINGLE_WRITE))
                rv |= POLLOUT;
        return rv;
 }
@@ -208,7 +208,10 @@ int PollEngine::DispatchEvents()
                        
                        if (events[index].revents & POLLOUT)
                        {
-                               SetEventMask(eh, eh->GetEventMask() & ~FD_WRITE_WILL_BLOCK);
+                               int mask = eh->GetEventMask();
+                               mask &= ~(FD_WRITE_WILL_BLOCK | FD_WANT_SINGLE_WRITE);
+                               SetEventMask(eh, mask);
+                               events[index].events = mask_to_poll(mask);
                                eh->HandleEvent(EVENT_WRITE);
                        }
                }
index a99806fc49568a034214659480f803d36fdc5388..d23857f506d500293e7311dd61d17bfc3ee000da 100644 (file)
@@ -60,7 +60,7 @@ static int mask_to_events(int event_mask)
        int rv = 0;
        if (event_mask & (FD_WANT_POLL_READ | FD_WANT_FAST_READ))
                rv |= POLLRDNORM;
-       if (event_mask & (FD_WANT_POLL_WRITE | FD_WANT_FAST_WRITE))
+       if (event_mask & (FD_WANT_POLL_WRITE | FD_WANT_FAST_WRITE | FD_WANT_SINGLE_WRITE))
                rv |= POLLWRNORM;
        return rv;
 }
@@ -132,7 +132,7 @@ int PortsEngine::DispatchEvents()
                                {
                                        int mask = eh->GetEventMask();
                                        if (events[i].portev_events & POLLWRNORM)
-                                               mask &= ~(FD_WRITE_WILL_BLOCK | FD_WANT_FAST_WRITE);
+                                               mask &= ~(FD_WRITE_WILL_BLOCK | FD_WANT_FAST_WRITE | FD_WANT_SINGLE_WRITE);
                                        if (events[i].portev_events & POLLRDNORM)
                                                mask &= ~FD_READ_WILL_BLOCK;
                                        // reinsert port for next time around, pretending to be one-shot for writes
index f089fd698c9a5a228eaf4e47f9a04347d67b137e..eacfc0fbf1be46e0e871a66c020a98cca7e5d52a 100644 (file)
@@ -89,7 +89,7 @@ int SelectEngine::DispatchEvents()
                int state = eh->GetEventMask();
                if (state & (FD_WANT_POLL_READ | FD_WANT_FAST_READ))
                        FD_SET (i, &rfdset);
-               if (state & (FD_WANT_POLL_WRITE | FD_WANT_FAST_WRITE))
+               if (state & (FD_WANT_POLL_WRITE | FD_WANT_FAST_WRITE | FD_WANT_SINGLE_WRITE))
                        FD_SET (i, &wfdset);
                FD_SET (i, &errfdset);
        }
@@ -134,7 +134,7 @@ int SelectEngine::DispatchEvents()
                                if (FD_ISSET (i, &wfdset))
                                {
                                        WriteEvents++;
-                                       SetEventMask(eh, eh->GetEventMask() & ~FD_WRITE_WILL_BLOCK);
+                                       SetEventMask(eh, eh->GetEventMask() & ~(FD_WRITE_WILL_BLOCK | FD_WANT_SINGLE_WRITE));
                                        ev->HandleEvent(EVENT_WRITE);
                                }
                        }