]> jfr.im git - irc/quakenet/newserv.git/blob - core/events-epoll.c
fix some format string errors and dergister some hooks, also do some (pointless)...
[irc/quakenet/newserv.git] / core / events-epoll.c
1 /*
2 * events.c: the event handling core, epoll() version
3 */
4
5 #include <stdio.h>
6 #include <sys/poll.h>
7 #include <sys/epoll.h>
8 #include <stdlib.h>
9 #include <unistd.h>
10 #include <string.h>
11 #include <errno.h>
12
13 #include "../lib/array.h"
14 #include "events.h"
15 #include "error.h"
16 #include "hooks.h"
17
18 /* We need to track the handler for each fd - epoll() can
19 * return an fd or a pointer but not both :(. We'll keep the
20 * fd in the epoll_data structure for simplicity. */
21
22 typedef struct {
23 FDHandler handler;
24 } reghandler;
25
26 reghandler *eventhandlers;
27
28 unsigned int maxfds;
29
30 int eventadds;
31 int eventdels;
32 int eventexes;
33
34 /* How many fds are currently registered */
35 int regfds;
36 int epollfd;
37
38 void eventstats(int hooknum, void *arg);
39
40 void inithandlers() {
41 regfds=0;
42 eventadds=eventdels=eventexes=0;
43 maxfds=STARTFDS;
44 eventhandlers=(reghandler *)malloc(maxfds*sizeof(reghandler));
45 memset(eventhandlers,0,maxfds*sizeof(reghandler));
46
47 /* Get an epoll FD */
48 if ((epollfd=epoll_create(STARTFDS))<0) {
49 Error("events",ERR_STOP,"Unable to initialise epoll.");
50 }
51
52 registerhook(HOOK_CORE_STATSREQUEST, &eventstats);
53 }
54
55 void finihandlers() {
56 deregisterhook(HOOK_CORE_STATSREQUEST, &eventstats);
57 free(eventhandlers);
58 }
59
60 /*
61 * checkindex():
62 * Given the number of a new file descriptor, makes sure that the array
63 * will be big enough to deal with it.
64 */
65
66 void checkindex(unsigned index) {
67 int oldmax=maxfds;
68
69 if (index<maxfds) {
70 return;
71 }
72
73 while (maxfds<=index) {
74 maxfds+=GROWFDS;
75 }
76
77 eventhandlers=(reghandler *)realloc((void *)eventhandlers,maxfds*sizeof(reghandler));
78 memset(&eventhandlers[oldmax],0,(maxfds-oldmax)*sizeof(reghandler));
79 }
80
81 /*
82 * polltoepoll():
83 * Converts a poll-style event variable to an epoll one.
84 */
85 unsigned int polltoepoll(short events) {
86 unsigned int epe=EPOLLERR|EPOLLHUP; /* Default event mask */
87
88 if (events & POLLIN) epe |= EPOLLIN;
89 if (events & POLLOUT) epe |= EPOLLOUT;
90 if (events & POLLPRI) epe |= EPOLLPRI;
91
92 return epe;
93 }
94
95 short epolltopoll(unsigned int events) {
96 short e=0;
97
98 if (events & EPOLLIN) e |= POLLIN;
99 if (events & EPOLLOUT) e |= POLLOUT;
100 if (events & EPOLLERR) e |= POLLERR;
101 if (events & EPOLLPRI) e |= POLLPRI;
102 if (events & EPOLLHUP) e |= POLLHUP;
103
104 return e;
105 }
106
107 /*
108 * registerhandler():
109 * Add an fd to the epoll array.
110 */
111
112 int registerhandler(int fd, short events, FDHandler handler) {
113 struct epoll_event epe;
114
115 checkindex(fd);
116
117 /* Check that it's not already registered */
118 if (eventhandlers[fd].handler!=NULL) {
119 Error("events",ERR_WARNING,"Attempting to register already-registered fd %d.",fd);
120 return 1;
121 }
122
123 eventhandlers[fd].handler=handler;
124
125 epe.data.fd=fd;
126 epe.events=polltoepoll(events);
127
128 if (epoll_ctl(epollfd, EPOLL_CTL_ADD, fd, &epe)) {
129 Error("events",ERR_WARNING,"Error %d adding fd %d to epoll (events=%d)",errno,fd,epe.events);
130 return 1;
131 }
132
133 eventadds++;
134 regfds++;
135 return 0;
136 }
137
138 /*
139 * deregisterhandler():
140 * Remove an fd from the poll() array.
141 *
142 * The poll() version can't save any time if doclose is set, so
143 * we just do the same work and then close the socket if it's set.
144 *
145 * Now O(1)
146 */
147
148
149 int deregisterhandler(int fd, int doclose) {
150 struct epoll_event epe;
151
152 checkindex(fd);
153
154 /* Check that the handler exists */
155 if (eventhandlers[fd].handler==NULL) {
156 Error("events",ERR_WARNING,"Attempt to deregister unregistered fd: %d",fd);
157 return 1;
158 }
159
160 eventhandlers[fd].handler=NULL;
161
162 if (epoll_ctl(epollfd, EPOLL_CTL_DEL, fd, &epe)) {
163 Error("events",ERR_WARNING,"Error deleting FD %d from epoll: %d",fd,errno);
164 }
165
166 if (doclose) {
167 close(fd);
168 }
169
170 eventdels++;
171 regfds--;
172
173 return 0;
174 }
175
176 /*
177 * handleevents():
178 * Call epoll_wait() and handle and call appropiate handlers
179 * for any sockets that come up.
180 */
181
182 int handleevents(int timeout) {
183 int i,res;
184 struct epoll_event epes[100];
185
186 res=epoll_wait(epollfd, epes, 100, timeout);
187
188 if (res<0) {
189 Error("events",ERR_WARNING,"Error in epoll_wait(): %d",errno);
190 return 1;
191 }
192
193 for (i=0;i<res;i++) {
194 (eventhandlers[epes[i].data.fd].handler)(epes[i].data.fd, epolltopoll(epes[i].events));
195 eventexes++;
196 }
197
198 return 0;
199 }
200
201 void eventstats(int hooknum, void *arg) {
202 char buf[512];
203 long level=(long) arg;
204
205 if (level>5) {
206 sprintf(buf,"Events :%7d fds registered, %7d fds deregistered",eventadds,eventdels);
207 triggerhook(HOOK_CORE_STATSREPLY,(void *)buf);
208 sprintf(buf,"Events :%7d events triggered, %6d fds active",eventexes,regfds);
209 triggerhook(HOOK_CORE_STATSREPLY,(void *)buf);
210 }
211 }