]> git.netwichtig.de Git - user/henk/code/inspircd.git/blobdiff - src/socketengine_kqueue.cpp
OOPS! We try again, since I'm smoking craq. LF is 0x0a NOT CR.
[user/henk/code/inspircd.git] / src / socketengine_kqueue.cpp
index de9a78f4efdf3114eb4309addfc6f569a8bdbec5..7fcdae2b6a58084056cb25268e9b2e1365fb253a 100644 (file)
@@ -1 +1,158 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "exitcodes.h"\r#include <sys/types.h>\r#include <sys/event.h>\r#include <sys/time.h>\r#include "socketengine_kqueue.h"\r\r\rKQueueEngine::KQueueEngine(InspIRCd* Instance) : SocketEngine(Instance)\r{\r     EngineHandle = kqueue();\r       if (EngineHandle == -1)\r        {\r              ServerInstance->Log(SPARSE,"ERROR: Could not initialize socket engine. Your kernel probably does not have the proper features.");\r              ServerInstance->Log(SPARSE,"ERROR: this is a fatal error, exiting now.");\r              printf("ERROR: Could not initialize socket engine. Your kernel probably does not have the proper features.");\r          printf("ERROR: this is a fatal error, exiting now.");\r          InspIRCd::Exit(EXIT_STATUS_SOCKETENGINE);\r      }\r      CurrentSetSize = 0;\r}\r\rKQueueEngine::~KQueueEngine()\r{\r close(EngineHandle);\r}\r\rbool KQueueEngine::AddFd(EventHandler* eh)\r{\r   int fd = eh->GetFd();\r\r if ((fd < 0) || (fd > MAX_DESCRIPTORS))\r                return false;\r\r if (GetRemainingFds() <= 1)\r            return false;\r\r if (ref[fd])\r           return false;\r\r ref[fd] = eh;\r\r struct kevent ke;\r      EV_SET(&ke, fd, eh->Readable() ? EVFILT_READ : EVFILT_WRITE, EV_ADD, 0, 0, NULL);\r\r     int i = kevent(EngineHandle, &ke, 1, 0, 0, NULL);\r      if (i == -1)\r           return false;\r\r CurrentSetSize++;\r\r     ServerInstance->Log(DEBUG,"New file descriptor: %d", fd);\r      return true;\r}\r\rbool KQueueEngine::DelFd(EventHandler* eh, bool force)\r{\r       int fd = eh->GetFd();\r\r if ((fd < 0) || (fd > MAX_DESCRIPTORS))\r                return false;\r\r struct kevent ke;\r      EV_SET(&ke, eh->GetFd(), EVFILT_READ, EV_DELETE, 0, 0, NULL);\r\r int i = kevent(EngineHandle, &ke, 1, 0, 0, NULL);\r\r     EV_SET(&ke, eh->GetFd(), EVFILT_WRITE, EV_DELETE, 0, 0, NULL);\r\r        int j = kevent(EngineHandle, &ke, 1, 0, 0, NULL);\r\r     if ((j < 0) && (i < 0) && !force)\r              return false;\r\r CurrentSetSize--;\r      ref[fd] = NULL;\r\r       ServerInstance->Log(DEBUG,"Remove file descriptor: %d", fd);\r   return true;\r}\r\rvoid KQueueEngine::WantWrite(EventHandler* eh)\r{\r       /** When changing an item in a kqueue, there is no 'modify' call\r        * as in epoll. Instead, we add the item again, and this overwrites\r     * the original setting rather than adding it twice. See man kqueue.\r    */\r    struct kevent ke;\r      EV_SET(&ke, eh->GetFd(), EVFILT_WRITE, EV_ADD | EV_ONESHOT, 0, 0, NULL);\r       kevent(EngineHandle, &ke, 1, 0, 0, NULL);\r}\r\rint KQueueEngine::GetMaxFds()\r{\r   return MAX_DESCRIPTORS;\r}\r\rint KQueueEngine::GetRemainingFds()\r{\r       return MAX_DESCRIPTORS - CurrentSetSize;\r}\r\rint KQueueEngine::DispatchEvents()\r{\r       ts.tv_nsec = 0;\r        ts.tv_sec = 1;\r int i = kevent(EngineHandle, NULL, 0, &ke_list[0], MAX_DESCRIPTORS, &ts);\r      for (int j = 0; j < i; j++)\r    {\r              if (ke_list[j].flags & EV_EOF)\r         {\r                      /* We love you kqueue, oh yes we do *sings*!\r                    * kqueue gives us the error number directly in the EOF state!\r                  * Unlike smelly epoll and select, where we have to getsockopt\r                  * to get the error, this saves us time and cpu cycles. Go BSD!\r                         */\r                    if (ref[ke_list[j].ident])\r                             ref[ke_list[j].ident]->HandleEvent(EVENT_ERROR, ke_list[j].fflags);\r                    continue;\r              }\r              if (ke_list[j].flags & EVFILT_WRITE)\r           {\r                      /* This looks wrong but its right. As above, theres no modify\r                   * call in kqueue. See the manpage.\r                     */\r                    struct kevent ke;\r                      EV_SET(&ke, ke_list[j].ident, EVFILT_READ, EV_ADD, 0, 0, NULL);\r                        kevent(EngineHandle, &ke, 1, 0, 0, NULL);\r                      if (ref[ke_list[j].ident])\r                             ref[ke_list[j].ident]->HandleEvent(EVENT_WRITE);\r               }\r              else\r           {\r                      if (ref[ke_list[j].ident])\r                             ref[ke_list[j].ident]->HandleEvent(EVENT_READ);\r                }\r      }\r\r     return i;\r}\r\rstd::string KQueueEngine::GetName()\r{\r     return "kqueue";\r}\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "exitcodes.h"
+#include <sys/types.h>
+#include <sys/event.h>
+#include <sys/time.h>
+#include "socketengine_kqueue.h"
+
+
+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.");
+               InspIRCd::Exit(EXIT_STATUS_SOCKETENGINE);
+       }
+       CurrentSetSize = 0;
+}
+
+KQueueEngine::~KQueueEngine()
+{
+       close(EngineHandle);
+}
+
+bool KQueueEngine::AddFd(EventHandler* eh)
+{
+       int fd = eh->GetFd();
+
+       if ((fd < 0) || (fd > MAX_DESCRIPTORS))
+               return false;
+
+       if (GetRemainingFds() <= 1)
+               return false;
+
+       if (ref[fd])
+               return false;
+
+       ref[fd] = eh;
+
+       struct kevent ke;
+       EV_SET(&ke, fd, eh->Readable() ? EVFILT_READ : EVFILT_WRITE, EV_ADD, 0, 0, NULL);
+
+       int i = kevent(EngineHandle, &ke, 1, 0, 0, NULL);
+       if (i == -1)
+               return false;
+
+       CurrentSetSize++;
+
+       ServerInstance->Log(DEBUG,"New file descriptor: %d", fd);
+       return true;
+}
+
+bool KQueueEngine::DelFd(EventHandler* eh, bool force)
+{
+       int fd = eh->GetFd();
+
+       if ((fd < 0) || (fd > MAX_DESCRIPTORS))
+               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);
+
+       EV_SET(&ke, eh->GetFd(), EVFILT_WRITE, EV_DELETE, 0, 0, NULL);
+
+       int j = kevent(EngineHandle, &ke, 1, 0, 0, NULL);
+
+       if ((j < 0) && (i < 0) && !force)
+               return false;
+
+       CurrentSetSize--;
+       ref[fd] = NULL;
+
+       ServerInstance->Log(DEBUG,"Remove file descriptor: %d", fd);
+       return true;
+}
+
+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_SET(&ke, eh->GetFd(), EVFILT_WRITE, EV_ADD | EV_ONESHOT, 0, 0, NULL);
+       kevent(EngineHandle, &ke, 1, 0, 0, NULL);
+}
+
+int KQueueEngine::GetMaxFds()
+{
+       return MAX_DESCRIPTORS;
+}
+
+int KQueueEngine::GetRemainingFds()
+{
+       return MAX_DESCRIPTORS - CurrentSetSize;
+}
+
+int KQueueEngine::DispatchEvents()
+{
+       ts.tv_nsec = 0;
+       ts.tv_sec = 1;
+       int i = kevent(EngineHandle, NULL, 0, &ke_list[0], MAX_DESCRIPTORS, &ts);
+       for (int j = 0; j < i; j++)
+       {
+               if (ke_list[j].flags & EV_EOF)
+               {
+                       /* We love you kqueue, oh yes we do *sings*!
+                        * kqueue gives us the error number directly in the EOF state!
+                        * Unlike smelly epoll and select, where we have to getsockopt
+                        * to get the error, this saves us time and cpu cycles. Go BSD!
+                        */
+                       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)
+               {
+                       /* This looks wrong but its right. As above, theres no modify
+                        * call in kqueue. See the manpage.
+                        */
+                       struct kevent ke;
+                       EV_SET(&ke, ke_list[j].ident, EVFILT_READ, EV_ADD, 0, 0, NULL);
+                       kevent(EngineHandle, &ke, 1, 0, 0, NULL);
+                       if (ref[ke_list[j].ident])
+                               ref[ke_list[j].ident]->HandleEvent(EVENT_WRITE);
+               }
+               else
+               {
+                       if (ref[ke_list[j].ident])
+                               ref[ke_list[j].ident]->HandleEvent(EVENT_READ);
+               }
+       }
+
+       return i;
+}
+
+std::string KQueueEngine::GetName()
+{
+       return "kqueue";
+}