]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/socketengine_kqueue.cpp
de9a78f4efdf3114eb4309addfc6f569a8bdbec5
[user/henk/code/inspircd.git] / src / socketengine_kqueue.cpp
1 /*       +------------------------------------+\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