]> jfr.im git - irc/quakenet/newserv.git/blame - core/events-kqueue.c
fix some format string errors and dergister some hooks, also do some (pointless)...
[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
f074aada
P
57void finihandlers() {
58 deregisterhook(HOOK_CORE_STATSREQUEST, &eventstats);
59}
60
61
2c5db955
CP
62/*
63 * checkindex():
64 * Given the number of a new file descriptor, makes sure that the array
65 * will be big enough to deal with it.
66 */
67
68void checkindex(unsigned index) {
69 int oldmax=maxfds;
70
71 if (index<maxfds) {
72 return;
73 }
74
75 while (maxfds<=index) {
76 maxfds+=GROWFDS;
77 }
78
79 eventfds=(struct kevent *)realloc((void *)eventfds,maxfds*sizeof(struct kevent));
80 memset(&eventfds[oldmax],0,(maxfds-oldmax)*sizeof(struct kevent));
81}
82
83/*
84 * registerhandler():
85 * Create a kevent structure and put it on the list to be added next
86 * time kevent() is called. If that list is full, we call kevent()
87 * to flush it first.
88 *
89 * We pass the handler in as the udata field to the kernel, this way
90 * we don't have to hunt for it when the kernel throws the kevent back
91 * at us.
92 */
93
94int registerhandler(int fd, short events, FDHandler handler) {
95 checkindex(fd);
96
97 /* Check that it's not already registered */
98 if (eventfds[fd].filter!=0) {
99 return 1;
100 }
101
102 eventfds[fd].ident=fd;
103 if (events & POLLIN) {
104 eventfds[fd].filter=EVFILT_READ;
105 } else {
106 eventfds[fd].filter=EVFILT_WRITE;
107 }
108 eventfds[fd].flags=EV_ADD;
109 eventfds[fd].fflags=0;
110 eventfds[fd].data=0;
111 eventfds[fd].udata=(void *)handler;
112
113/* Error("core",ERR_DEBUG,"Adding fd %d filter %d",fd,eventfds[fd].filter); */
114
115 if (updates>=UPDATEQUEUESIZE) {
116 kevent(kq, addqueue, updates, NULL, 0, NULL);
117 updates=0;
118 }
119
120 addqueue[updates++]=eventfds[fd];
121
122 eventadds++;
123 regfds++;
124 return 0;
125}
126
127/*
128 * deregisterhandler():
129 * Removes the fd's kevent from the kqueue. Note that if we're
130 * going to be closing the fd, it will automatically be removed
131 * from the queue so we don't have to do anything except the close().
132 */
133
134int deregisterhandler(int fd, int doclose) {
135
136 if (!doclose) {
137 if (updates>=UPDATEQUEUESIZE) {
138 kevent(kq, addqueue, updates, NULL, 0, NULL);
139 updates=0;
140 }
141
142 eventfds[fd].flags=EV_DELETE;
143 addqueue[updates++]=eventfds[fd];
144
145/* Error("core",ERR_DEBUG,"Deleting fd %d filter %d",fd,eventfds[fd].filter); */
146 } else {
147 close(fd);
148 }
149
150 regfds--;
151 eventdels++;
152 eventfds[fd].filter=0;
153
154 return 0;
155}
156
157/*
158 * handleevents():
159 * Call kevent() and handle and call appropiate handlers
160 * for any sockets that come up.
161 *
162 * This is O(n) in the number of fds returned, rather than the number
163 * of fds polled as in the poll() case.
164 */
165
166int handleevents(int timeout) {
167 int i,res;
168 struct timespec ts;
169 struct kevent theevents[100];
170 short revents;
171
172 ts.tv_sec=(timeout/1000);
173 ts.tv_nsec=(timeout%1000)*1000000;
174
175 res=kevent(kq, addqueue, updates, theevents, 100, &ts);
176 updates=0;
177
178 if (res<0) {
179 return 1;
180 }
181
182 for (i=0;i<res;i++) {
183 revents=0;
184
185 /* If EV_ERROR is set it's a failed addition of a kevent to the queue.
186 * This shouldn't happen so we flag a warning. */
187 if(theevents[i].flags & EV_ERROR) {
188 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);
189 } else {
190 /* Otherwise, translate the result into poll() format.. */
191 if(theevents[i].filter==EVFILT_READ) {
192 if (theevents[i].data>0) {
193 revents|=POLLIN;
194 }
195 } else {
196 if (theevents[i].data>0) {
197 revents|=POLLOUT;
198 }
199 }
200
201 if (theevents[i].flags & EV_EOF || theevents[i].data<0) {
202 revents|=POLLERR;
203 }
204
205 /* Call the handler */
206 ((FDHandler)(theevents[i].udata))(theevents[i].ident, revents);
207 eventexes++;
208 }
209 }
210 return 0;
211}
212
213void eventstats(int hooknum, void *arg) {
214 char buf[512];
c3db6f7e 215 long level=(long) arg;
2c5db955
CP
216
217 if (level>5) {
218 sprintf(buf,"Events :%7d fds registered, %7d fds deregistered",eventadds,eventdels);
219 triggerhook(HOOK_CORE_STATSREPLY,(void *)buf);
220 sprintf(buf,"Events :%7d events triggered, %6d fds active",eventexes,regfds);
221 triggerhook(HOOK_CORE_STATSREPLY,(void *)buf);
222 }
223}
224