]> jfr.im git - irc/quakenet/newserv.git/blame - core/events-kqueue.c
Compiler warning fixes
[irc/quakenet/newserv.git] / core / events-kqueue.c
CommitLineData
2c5db955
CP
1/*
2 * events.c: the event handling core, kqueue() version
3 */
4
5#include <stdio.h>
6#include <sys/types.h>
7#include <sys/event.h>
8#include <sys/time.h>
9#include <sys/poll.h>
10#include <stdlib.h>
11#include <unistd.h>
12#include "../lib/array.h"
13#include "events.h"
14#include "error.h"
15#include "hooks.h"
16
17/*
18 * OK, for the kqueue() version we just keep an array (indexed by fd)
19 * of what we put in the kqueue() so we can remove it later. This is only
20 * required because the deregisterhandler() call doesn't include the
21 * "events" field, thus the kqueue filter used is unknown.
22 *
23 * We have a seperate fixed array addqueue() for stuff we're adding to
24 * the queue; this gets flushed if it's full or held over until we
25 * next call handleevents().
26 */
27
28#define UPDATEQUEUESIZE 100
29
30struct kevent addqueue[UPDATEQUEUESIZE];
31struct kevent *eventfds;
32
33unsigned int maxfds;
34unsigned int updates;
35
36int kq;
37
38int eventadds;
39int eventdels;
40int eventexes;
41
42/* How many fds are currently registered */
43int regfds;
44
45void eventstats(int hooknum, void *arg);
46
47void inithandlers() {
48 regfds=0;
49 updates=0;
50 eventadds=eventdels=eventexes=0;
51 maxfds=0;
52 eventfds=NULL;
53 kq=kqueue();
54 registerhook(HOOK_CORE_STATSREQUEST, &eventstats);
55}
56
57/*
58 * checkindex():
59 * Given the number of a new file descriptor, makes sure that the array
60 * will be big enough to deal with it.
61 */
62
63void checkindex(unsigned index) {
64 int oldmax=maxfds;
65
66 if (index<maxfds) {
67 return;
68 }
69
70 while (maxfds<=index) {
71 maxfds+=GROWFDS;
72 }
73
74 eventfds=(struct kevent *)realloc((void *)eventfds,maxfds*sizeof(struct kevent));
75 memset(&eventfds[oldmax],0,(maxfds-oldmax)*sizeof(struct kevent));
76}
77
78/*
79 * registerhandler():
80 * Create a kevent structure and put it on the list to be added next
81 * time kevent() is called. If that list is full, we call kevent()
82 * to flush it first.
83 *
84 * We pass the handler in as the udata field to the kernel, this way
85 * we don't have to hunt for it when the kernel throws the kevent back
86 * at us.
87 */
88
89int registerhandler(int fd, short events, FDHandler handler) {
90 checkindex(fd);
91
92 /* Check that it's not already registered */
93 if (eventfds[fd].filter!=0) {
94 return 1;
95 }
96
97 eventfds[fd].ident=fd;
98 if (events & POLLIN) {
99 eventfds[fd].filter=EVFILT_READ;
100 } else {
101 eventfds[fd].filter=EVFILT_WRITE;
102 }
103 eventfds[fd].flags=EV_ADD;
104 eventfds[fd].fflags=0;
105 eventfds[fd].data=0;
106 eventfds[fd].udata=(void *)handler;
107
108/* Error("core",ERR_DEBUG,"Adding fd %d filter %d",fd,eventfds[fd].filter); */
109
110 if (updates>=UPDATEQUEUESIZE) {
111 kevent(kq, addqueue, updates, NULL, 0, NULL);
112 updates=0;
113 }
114
115 addqueue[updates++]=eventfds[fd];
116
117 eventadds++;
118 regfds++;
119 return 0;
120}
121
122/*
123 * deregisterhandler():
124 * Removes the fd's kevent from the kqueue. Note that if we're
125 * going to be closing the fd, it will automatically be removed
126 * from the queue so we don't have to do anything except the close().
127 */
128
129int deregisterhandler(int fd, int doclose) {
130
131 if (!doclose) {
132 if (updates>=UPDATEQUEUESIZE) {
133 kevent(kq, addqueue, updates, NULL, 0, NULL);
134 updates=0;
135 }
136
137 eventfds[fd].flags=EV_DELETE;
138 addqueue[updates++]=eventfds[fd];
139
140/* Error("core",ERR_DEBUG,"Deleting fd %d filter %d",fd,eventfds[fd].filter); */
141 } else {
142 close(fd);
143 }
144
145 regfds--;
146 eventdels++;
147 eventfds[fd].filter=0;
148
149 return 0;
150}
151
152/*
153 * handleevents():
154 * Call kevent() and handle and call appropiate handlers
155 * for any sockets that come up.
156 *
157 * This is O(n) in the number of fds returned, rather than the number
158 * of fds polled as in the poll() case.
159 */
160
161int handleevents(int timeout) {
162 int i,res;
163 struct timespec ts;
164 struct kevent theevents[100];
165 short revents;
166
167 ts.tv_sec=(timeout/1000);
168 ts.tv_nsec=(timeout%1000)*1000000;
169
170 res=kevent(kq, addqueue, updates, theevents, 100, &ts);
171 updates=0;
172
173 if (res<0) {
174 return 1;
175 }
176
177 for (i=0;i<res;i++) {
178 revents=0;
179
180 /* If EV_ERROR is set it's a failed addition of a kevent to the queue.
181 * This shouldn't happen so we flag a warning. */
182 if(theevents[i].flags & EV_ERROR) {
183 Error("core",ERR_WARNING,"Got EV_ERROR return from kqueue: fd %d filter %d error %d",theevents[i].ident,theevents[i].filter,theevents[i].data);
184 } else {
185 /* Otherwise, translate the result into poll() format.. */
186 if(theevents[i].filter==EVFILT_READ) {
187 if (theevents[i].data>0) {
188 revents|=POLLIN;
189 }
190 } else {
191 if (theevents[i].data>0) {
192 revents|=POLLOUT;
193 }
194 }
195
196 if (theevents[i].flags & EV_EOF || theevents[i].data<0) {
197 revents|=POLLERR;
198 }
199
200 /* Call the handler */
201 ((FDHandler)(theevents[i].udata))(theevents[i].ident, revents);
202 eventexes++;
203 }
204 }
205 return 0;
206}
207
208void eventstats(int hooknum, void *arg) {
209 char buf[512];
c3db6f7e 210 long level=(long) arg;
2c5db955
CP
211
212 if (level>5) {
213 sprintf(buf,"Events :%7d fds registered, %7d fds deregistered",eventadds,eventdels);
214 triggerhook(HOOK_CORE_STATSREPLY,(void *)buf);
215 sprintf(buf,"Events :%7d events triggered, %6d fds active",eventexes,regfds);
216 triggerhook(HOOK_CORE_STATSREPLY,(void *)buf);
217 }
218}
219