From 8d29aae7013a20b83a5d1b9169d55b1dc1c675c4 Mon Sep 17 00:00:00 2001 From: w00t Date: Mon, 9 Feb 2009 18:47:46 +0000 Subject: BNow with less fucked up goodness(tm). Backport multiplexing fixed kqueue from 1.2, thanks to psychon! git-svn-id: http://svn.inspircd.org/repository/branches/1_1_stable@11074 e03df62e-2008-0410-955e-edbf42e46eb7 --- src/socketengine_kqueue.cpp | 74 ++++++++++++++++++++++++++++++--------------- 1 file changed, 49 insertions(+), 25 deletions(-) (limited to 'src/socketengine_kqueue.cpp') diff --git a/src/socketengine_kqueue.cpp b/src/socketengine_kqueue.cpp index fa62857c2..c58ee0817 100644 --- a/src/socketengine_kqueue.cpp +++ b/src/socketengine_kqueue.cpp @@ -2,7 +2,7 @@ * | Inspire Internet Relay Chat Daemon | * +------------------------------------+ * - * InspIRCd: (C) 2002-2008 InspIRCd Development Team + * InspIRCd: (C) 2002-2009 InspIRCd Development Team * See: http://www.inspircd.org/wiki/index.php/Credits * * This program is free but copyrighted software; see @@ -24,10 +24,10 @@ KQueueEngine::KQueueEngine(InspIRCd* Instance) : SocketEngine(Instance) EngineHandle = kqueue(); if (EngineHandle == -1) { - ServerInstance->Log(SPARSE,"ERROR: Could not initialize socket engine. Your kernel probably does not have the proper features."); - ServerInstance->Log(SPARSE,"ERROR: this is a fatal error, exiting now."); - printf("ERROR: Could not initialize socket engine. Your kernel probably does not have the proper features."); - printf("ERROR: this is a fatal error, exiting now."); + ServerInstance->Log(DEFAULT, "ERROR: Could not initialize socket engine. Your kernel probably does not have the proper features."); + ServerInstance->Log(DEFAULT, "ERROR: this is a fatal error, exiting now."); + printf("ERROR: Could not initialize socket engine. Your kernel probably does not have the proper features.\n"); + printf("ERROR: this is a fatal error, exiting now.\n"); InspIRCd::Exit(EXIT_STATUS_SOCKETENGINE); } CurrentSetSize = 0; @@ -51,15 +51,24 @@ bool KQueueEngine::AddFd(EventHandler* eh) if (ref[fd]) return false; - ref[fd] = eh; - + // We always want to read from the socket... struct kevent ke; - EV_SET(&ke, fd, eh->Readable() ? EVFILT_READ : EVFILT_WRITE, EV_ADD, 0, 0, NULL); + EV_SET(&ke, fd, EVFILT_READ, EV_ADD, 0, 0, NULL); int i = kevent(EngineHandle, &ke, 1, 0, 0, NULL); if (i == -1) + { + ServerInstance->Log(DEFAULT,"Failed to add fd: %d %s", fd, strerror(errno)); return false; + } + + if (!eh->Readable()) + { + // ...and sometimes want to write + WantWrite(eh); + } + ref[fd] = eh; CurrentSetSize++; ServerInstance->Log(DEBUG,"New file descriptor: %d", fd); @@ -71,19 +80,28 @@ bool KQueueEngine::DelFd(EventHandler* eh, bool force) int fd = eh->GetFd(); if ((fd < 0) || (fd > MAX_DESCRIPTORS)) + { + ServerInstance->Log(DEFAULT,"DelFd() on invalid fd: %d", fd); return false; + } struct kevent ke; - EV_SET(&ke, eh->GetFd(), EVFILT_READ, EV_DELETE, 0, 0, NULL); - - int i = kevent(EngineHandle, &ke, 1, 0, 0, NULL); + // First remove the write filter ignoring errors, since we can't be + // sure if there are actually any write filters registered. EV_SET(&ke, eh->GetFd(), EVFILT_WRITE, EV_DELETE, 0, 0, NULL); + kevent(EngineHandle, &ke, 1, 0, 0, NULL); + // Then remove the read filter. + EV_SET(&ke, eh->GetFd(), EVFILT_READ, EV_DELETE, 0, 0, NULL); int j = kevent(EngineHandle, &ke, 1, 0, 0, NULL); - if ((j < 0) && (i < 0) && !force) + if ((j < 0) && !force) + { + ServerInstance->Log(DEFAULT,"Failed to remove fd: %d %s", + fd, strerror(errno)); return false; + } CurrentSetSize--; ref[fd] = NULL; @@ -94,14 +112,14 @@ bool KQueueEngine::DelFd(EventHandler* eh, bool force) void KQueueEngine::WantWrite(EventHandler* eh) { - /** When changing an item in a kqueue, there is no 'modify' call - * as in epoll. Instead, we add the item again, and this overwrites - * the original setting rather than adding it twice. See man kqueue. - */ struct kevent ke; + // EV_ONESHOT since we only ever want one write event EV_SET(&ke, eh->GetFd(), EVFILT_WRITE, EV_ADD | EV_ONESHOT, 0, 0, NULL); - EV_SET(&ke, eh->GetFd(), EVFILT_READ, EV_ADD | EV_ONESHOT, 0, 0, NULL); - kevent(EngineHandle, &ke, 1, 0, 0, NULL); + int i = kevent(EngineHandle, &ke, 1, 0, 0, NULL); + if (i < 0) { + ServerInstance->Log(DEFAULT,"Failed to mark for writing: %d %s", + eh->GetFd(), strerror(errno)); + } } int KQueueEngine::GetMaxFds() @@ -118,7 +136,11 @@ int KQueueEngine::DispatchEvents() { ts.tv_nsec = 0; ts.tv_sec = 1; + int i = kevent(EngineHandle, NULL, 0, &ke_list[0], MAX_DESCRIPTORS, &ts); + + TotalEvents += i; + for (int j = 0; j < i; j++) { if (ke_list[j].flags & EV_EOF) @@ -128,23 +150,25 @@ int KQueueEngine::DispatchEvents() * Unlike smelly epoll and select, where we have to getsockopt * to get the error, this saves us time and cpu cycles. Go BSD! */ + ErrorEvents++; if (ref[ke_list[j].ident]) ref[ke_list[j].ident]->HandleEvent(EVENT_ERROR, ke_list[j].fflags); continue; } - if (ke_list[j].flags & EVFILT_WRITE) + if (ke_list[j].filter == EVFILT_WRITE) { - /* This looks wrong but its right. As above, theres no modify - * call in kqueue. See the manpage. + /* We only ever add write events with EV_ONESHOT, which + * means they are automatically removed once such a + * event fires, so nothing to do here. */ - struct kevent ke; - EV_SET(&ke, ke_list[j].ident, EVFILT_READ, EV_ADD, 0, 0, NULL); - kevent(EngineHandle, &ke, 1, 0, 0, NULL); + + WriteEvents++; if (ref[ke_list[j].ident]) ref[ke_list[j].ident]->HandleEvent(EVENT_WRITE); } - else + if (ke_list[j].filter == EVFILT_READ) { + ReadEvents++; if (ref[ke_list[j].ident]) ref[ke_list[j].ident]->HandleEvent(EVENT_READ); } -- cgit v1.3.1-10-gc9f91