aboutsummaryrefslogtreecommitdiffstats
path: root/src/socketengine_poll.cpp
diff options
context:
space:
mode:
authorGravatar peavey2009-01-27 22:25:11 +0000
committerGravatar peavey2009-01-27 22:25:11 +0000
commite6e3de237726bee15062ef1d84a56e6f108a14e4 (patch)
tree15cc91f1c14a25c2b0fc557c98fe9988066d3087 /src/socketengine_poll.cpp
parentBackport r11000, properly check for handshake completion in m_ssl_gnutls. Apo... (diff)
Manually backport r11008 to stable:
=================================== Fix the poll socketengine to actually work. The old implementation tried to use holes for unused entries in the array for poll() and the OS replied with POLLNVAL to which we replied with 100% CPU. Improvements: - It does compile! - It works git-svn-id: http://svn.inspircd.org/repository/branches/1_1_stable@11010 e03df62e-2008-0410-955e-edbf42e46eb7
Diffstat (limited to 'src/socketengine_poll.cpp')
-rw-r--r--src/socketengine_poll.cpp107
1 files changed, 77 insertions, 30 deletions
diff --git a/src/socketengine_poll.cpp b/src/socketengine_poll.cpp
index 67a68d456..03a6cdaaa 100644
--- a/src/socketengine_poll.cpp
+++ b/src/socketengine_poll.cpp
@@ -36,28 +36,46 @@ bool PollEngine::AddFd(EventHandler* eh)
if (GetRemainingFds() <= 1)
return false;
- if (ref[fd])
+ if (fd_mappings.find(fd) != fd_mappings.end())
return false;
- ref[fd] = eh;
- events[fd].fd = fd;
+ unsigned int index = CurrentSetSize;
+
+ fd_mappings[fd] = index;
+ ref[index] = eh;
+ events[index].fd = fd;
if (eh->Readable())
{
- events[fd].events = POLLIN;
+ events[index].events = POLLIN;
}
else
{
- events[fd].events = POLLOUT;
+ events[index].events = POLLOUT;
}
- ServerInstance->Log(DEBUG,"New file descriptor: %d (%d)", fd, events[fd].events);
+ ServerInstance->Log(DEBUG,"New file descriptor: %d (%d; index %d)", fd, events[fd].events, index);
CurrentSetSize++;
return true;
}
+EventHandler* PollEngine::GetRef(int fd)
+{
+ std::map<int, unsigned int>::iterator it = fd_mappings.find(fd);
+ if (it == fd_mappings.end())
+ return NULL;
+ return ref[it->second];
+}
+
void PollEngine::WantWrite(EventHandler* eh)
{
- events[eh->GetFd()].events = POLLIN | POLLOUT;
+ std::map<int, unsigned int>::iterator it = fd_mappings.find(eh->GetFd());
+ if (it == fd_mappings.end())
+ {
+ ServerInstance->Log(DEBUG,"WantWrite() on unknown fd: %d", eh->GetFd());
+ return;
+ }
+
+ events[it->second].events = POLLIN | POLLOUT;
}
bool PollEngine::DelFd(EventHandler* eh, bool force)
@@ -66,13 +84,40 @@ bool PollEngine::DelFd(EventHandler* eh, bool force)
if ((fd < 0) || (fd > MAX_DESCRIPTORS))
return false;
- events[fd].fd = -1;
- events[fd].events = 0;
+ std::map<int, unsigned int>::iterator it = fd_mappings.find(fd);
+ if (it == fd_mappings.end())
+ {
+ ServerInstance->Log(DEBUG,"DelFd() on unknown fd: %d", fd);
+ return false;
+ }
- CurrentSetSize--;
- ref[fd] = NULL;
+ unsigned int index = it->second;
+ unsigned int last_index = CurrentSetSize - 1;
+ int last_fd = events[last_index].fd;
- ServerInstance->Log(DEBUG,"Remove file descriptor: %d", fd);
+ if (index != last_index)
+ {
+ // We need to move the last fd we got into this gap (gaps are evil!)
+
+ // So update the mapping for the last fd to its new position
+ fd_mappings[last_fd] = index;
+
+ // move last_fd from last_index into index
+ events[index].fd = last_fd;
+ events[index].events = events[last_index].events;
+
+ ref[index] = ref[last_index];
+ }
+
+ // Now remove all data for the last fd we got into out list.
+ // Above code made sure this always is right
+ fd_mappings.erase(it);
+ events[last_index].fd = 0;
+ events[last_index].events = 0;
+ ref[last_index] = NULL;
+
+ CurrentSetSize--;
+ ServerInstance->Log(DEBUG, "Remove file descriptor: %d (index: %d) (Filled gap with: %d (index: %d))", fd, index, last_fd, last_index);
return true;
}
@@ -88,51 +133,53 @@ int PollEngine::GetRemainingFds()
int PollEngine::DispatchEvents()
{
- int i = poll(events, MAX_DESCRIPTORS, 1000);
- int fd = 0;
+ int i = poll(events, CurrentSetSize, 1000);
+ int index;
socklen_t codesize = sizeof(int);
int errcode;
int processed = 0;
if (i > 0)
{
- for (fd = 0; fd < MAX_DESCRIPTORS && processed != i; fd++)
+ for (index = 0; index < CurrentSetSize && processed != i; index++)
{
- if (events[fd].revents)
+ if (events[index].revents)
processed++;
- if (events[fd].revents & POLLHUP)
+ if (events[index].revents & POLLHUP)
{
- if (ref[fd])
- ref[fd]->HandleEvent(EVENT_ERROR, 0);
+ if (ref[index])
+ ref[index]->HandleEvent(EVENT_ERROR, 0);
continue;
}
- if (events[fd].revents & POLLERR)
+ if (events[index].revents & POLLERR)
{
+ // Get fd
+ int fd = events[index].fd;
+
// Get error number
if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &errcode, &codesize) < 0)
errcode = errno;
- if (ref[fd])
- ref[fd]->HandleEvent(EVENT_ERROR, errcode);
+ if (ref[index])
+ ref[index]->HandleEvent(EVENT_ERROR, errcode);
continue;
}
- if (events[fd].revents & POLLOUT)
+ if (events[index].revents & POLLOUT)
{
// Switch to wanting read again
// event handlers have to request to write again if they need it
- events[fd].events = POLLIN;
-
+ events[index].events = POLLIN;
- if (ref[fd])
- ref[fd]->HandleEvent(EVENT_WRITE);
+ if (ref[index])
+ ref[index]->HandleEvent(EVENT_WRITE);
}
- if (events[fd].revents & POLLIN)
+ if (events[index].revents & POLLIN)
{
- if (ref[fd])
- ref[fd]->HandleEvent(EVENT_READ);
+ if (ref[index])
+ ref[index]->HandleEvent(EVENT_READ);
}
}
}