]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/socketengine_kqueue.cpp
Un-static InspIRCd::Exit and use SignalHandler instead.
[user/henk/code/inspircd.git] / src / socketengine_kqueue.cpp
1 /*       +------------------------------------+
2  *       | Inspire Internet Relay Chat Daemon |
3  *       +------------------------------------+
4  *
5  *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
6  * See: http://www.inspircd.org/wiki/index.php/Credits
7  *
8  * This program is free but copyrighted software; see
9  *            the file COPYING for details.
10  *
11  * ---------------------------------------------------
12  */
13
14 #include "inspircd.h"
15 #include "exitcodes.h"
16 #include <sys/types.h>
17 #include <sys/event.h>
18 #include <sys/time.h>
19 #include "socketengine_kqueue.h"
20
21
22 KQueueEngine::KQueueEngine(InspIRCd* Instance) : SocketEngine(Instance)
23 {
24         EngineHandle = kqueue();
25         if (EngineHandle == -1)
26         {
27                 ServerInstance->Log(SPARSE,"ERROR: Could not initialize socket engine. Your kernel probably does not have the proper features.");
28                 ServerInstance->Log(SPARSE,"ERROR: this is a fatal error, exiting now.");
29                 printf("ERROR: Could not initialize socket engine. Your kernel probably does not have the proper features.");
30                 printf("ERROR: this is a fatal error, exiting now.");
31                 ServerInstance->Exit(EXIT_STATUS_SOCKETENGINE);
32         }
33         CurrentSetSize = 0;
34 }
35
36 KQueueEngine::~KQueueEngine()
37 {
38         close(EngineHandle);
39 }
40
41 bool KQueueEngine::AddFd(EventHandler* eh)
42 {
43         int fd = eh->GetFd();
44
45         if ((fd < 0) || (fd > MAX_DESCRIPTORS))
46                 return false;
47
48         if (GetRemainingFds() <= 1)
49                 return false;
50
51         if (ref[fd])
52                 return false;
53
54         ref[fd] = eh;
55
56         struct kevent ke;
57         EV_SET(&ke, fd, eh->Readable() ? EVFILT_READ : EVFILT_WRITE, EV_ADD, 0, 0, NULL);
58
59         int i = kevent(EngineHandle, &ke, 1, 0, 0, NULL);
60         if (i == -1)
61                 return false;
62
63         CurrentSetSize++;
64
65         ServerInstance->Log(DEBUG,"New file descriptor: %d", fd);
66         return true;
67 }
68
69 bool KQueueEngine::DelFd(EventHandler* eh, bool force)
70 {
71         int fd = eh->GetFd();
72
73         if ((fd < 0) || (fd > MAX_DESCRIPTORS))
74                 return false;
75
76         struct kevent ke;
77         EV_SET(&ke, eh->GetFd(), EVFILT_READ, EV_DELETE, 0, 0, NULL);
78
79         int i = kevent(EngineHandle, &ke, 1, 0, 0, NULL);
80
81         EV_SET(&ke, eh->GetFd(), EVFILT_WRITE, EV_DELETE, 0, 0, NULL);
82
83         int j = kevent(EngineHandle, &ke, 1, 0, 0, NULL);
84
85         if ((j < 0) && (i < 0) && !force)
86                 return false;
87
88         CurrentSetSize--;
89         ref[fd] = NULL;
90
91         ServerInstance->Log(DEBUG,"Remove file descriptor: %d", fd);
92         return true;
93 }
94
95 void KQueueEngine::WantWrite(EventHandler* eh)
96 {
97         /** When changing an item in a kqueue, there is no 'modify' call
98          * as in epoll. Instead, we add the item again, and this overwrites
99          * the original setting rather than adding it twice. See man kqueue.
100          */
101         struct kevent ke;
102         EV_SET(&ke, eh->GetFd(), EVFILT_WRITE, EV_ADD | EV_ONESHOT, 0, 0, NULL);
103         kevent(EngineHandle, &ke, 1, 0, 0, NULL);
104 }
105
106 int KQueueEngine::GetMaxFds()
107 {
108         return MAX_DESCRIPTORS;
109 }
110
111 int KQueueEngine::GetRemainingFds()
112 {
113         return MAX_DESCRIPTORS - CurrentSetSize;
114 }
115
116 int KQueueEngine::DispatchEvents()
117 {
118         ts.tv_nsec = 0;
119         ts.tv_sec = 1;
120         int i = kevent(EngineHandle, NULL, 0, &ke_list[0], MAX_DESCRIPTORS, &ts);
121         for (int j = 0; j < i; j++)
122         {
123                 if (ke_list[j].flags & EV_EOF)
124                 {
125                         /* We love you kqueue, oh yes we do *sings*!
126                          * kqueue gives us the error number directly in the EOF state!
127                          * Unlike smelly epoll and select, where we have to getsockopt
128                          * to get the error, this saves us time and cpu cycles. Go BSD!
129                          */
130                         if (ref[ke_list[j].ident])
131                                 ref[ke_list[j].ident]->HandleEvent(EVENT_ERROR, ke_list[j].fflags);
132                         continue;
133                 }
134                 if (ke_list[j].flags & EVFILT_WRITE)
135                 {
136                         /* This looks wrong but its right. As above, theres no modify
137                          * call in kqueue. See the manpage.
138                          */
139                         struct kevent ke;
140                         EV_SET(&ke, ke_list[j].ident, EVFILT_READ, EV_ADD, 0, 0, NULL);
141                         kevent(EngineHandle, &ke, 1, 0, 0, NULL);
142                         if (ref[ke_list[j].ident])
143                                 ref[ke_list[j].ident]->HandleEvent(EVENT_WRITE);
144                 }
145                 else
146                 {
147                         if (ref[ke_list[j].ident])
148                                 ref[ke_list[j].ident]->HandleEvent(EVENT_READ);
149                 }
150         }
151
152         return i;
153 }
154
155 std::string KQueueEngine::GetName()
156 {
157         return "kqueue";
158 }