diff options
-rw-r--r-- | include/socketengine.h | 31 | ||||
-rw-r--r-- | src/inspsocket.cpp | 4 | ||||
-rw-r--r-- | src/modules/extra/m_ssl_gnutls.cpp | 6 | ||||
-rw-r--r-- | src/modules/extra/m_ssl_openssl.cpp | 8 | ||||
-rw-r--r-- | src/socketengines/socketengine_epoll.cpp | 20 | ||||
-rw-r--r-- | src/socketengines/socketengine_iocp.cpp | 4 | ||||
-rw-r--r-- | src/socketengines/socketengine_kqueue.cpp | 12 | ||||
-rw-r--r-- | src/socketengines/socketengine_poll.cpp | 7 | ||||
-rw-r--r-- | src/socketengines/socketengine_ports.cpp | 4 | ||||
-rw-r--r-- | src/socketengines/socketengine_select.cpp | 4 |
10 files changed, 61 insertions, 39 deletions
diff --git a/include/socketengine.h b/include/socketengine.h index 9c45bcf21..1a0a61670 100644 --- a/include/socketengine.h +++ b/include/socketengine.h @@ -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; diff --git a/src/inspsocket.cpp b/src/inspsocket.cpp index 6348d7982..004d679ed 100644 --- a/src/inspsocket.cpp +++ b/src/inspsocket.cpp @@ -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(); } diff --git a/src/modules/extra/m_ssl_gnutls.cpp b/src/modules/extra/m_ssl_gnutls.cpp index c65b8528a..3362e9378 100644 --- a/src/modules/extra/m_ssl_gnutls.cpp +++ b/src/modules/extra/m_ssl_gnutls.cpp @@ -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 diff --git a/src/modules/extra/m_ssl_openssl.cpp b/src/modules/extra/m_ssl_openssl.cpp index e72bdc816..645add4c2 100644 --- a/src/modules/extra/m_ssl_openssl.cpp +++ b/src/modules/extra/m_ssl_openssl.cpp @@ -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; } diff --git a/src/socketengines/socketengine_epoll.cpp b/src/socketengines/socketengine_epoll.cpp index 672ff4a7b..059798d25 100644 --- a/src/socketengines/socketengine_epoll.cpp +++ b/src/socketengines/socketengine_epoll.cpp @@ -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); } } diff --git a/src/socketengines/socketengine_iocp.cpp b/src/socketengines/socketengine_iocp.cpp index e09fb4d0a..c253bf0a6 100644 --- a/src/socketengines/socketengine_iocp.cpp +++ b/src/socketengines/socketengine_iocp.cpp @@ -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); diff --git a/src/socketengines/socketengine_kqueue.cpp b/src/socketengines/socketengine_kqueue.cpp index c9734e85d..1a783153e 100644 --- a/src/socketengines/socketengine_kqueue.cpp +++ b/src/socketengines/socketengine_kqueue.cpp @@ -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); } diff --git a/src/socketengines/socketengine_poll.cpp b/src/socketengines/socketengine_poll.cpp index 6f50e2798..a72d21d1f 100644 --- a/src/socketengines/socketengine_poll.cpp +++ b/src/socketengines/socketengine_poll.cpp @@ -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); } } diff --git a/src/socketengines/socketengine_ports.cpp b/src/socketengines/socketengine_ports.cpp index a99806fc4..d23857f50 100644 --- a/src/socketengines/socketengine_ports.cpp +++ b/src/socketengines/socketengine_ports.cpp @@ -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 diff --git a/src/socketengines/socketengine_select.cpp b/src/socketengines/socketengine_select.cpp index f089fd698..eacfc0fbf 100644 --- a/src/socketengines/socketengine_select.cpp +++ b/src/socketengines/socketengine_select.cpp @@ -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); } } |