]> jfr.im git - irc/quakenet/newserv.git/blame - 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
CommitLineData
2c5db955 1/*
bc78ddf6 2 * events.c: the event handling core, epoll() version
2c5db955
CP
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
22typedef struct {
23 FDHandler handler;
24} reghandler;
25
26reghandler *eventhandlers;
27
28unsigned int maxfds;
29
30int eventadds;
31int eventdels;
32int eventexes;
33
34/* How many fds are currently registered */
35int regfds;
36int epollfd;
37
38void eventstats(int hooknum, void *arg);
39
40void 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) {
9264d86b 49 Error("events",ERR_STOP,"Unable to initialise epoll.");
2c5db955
CP
50 }
51
52 registerhook(HOOK_CORE_STATSREQUEST, &eventstats);
53}
54
f074aada
P
55void finihandlers() {
56 deregisterhook(HOOK_CORE_STATSREQUEST, &eventstats);
57 free(eventhandlers);
58}
59
2c5db955
CP
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
66void 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 */
85unsigned 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
95short 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
112int 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
149int 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
182int 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
201void eventstats(int hooknum, void *arg) {
202 char buf[512];
c3db6f7e 203 long level=(long) arg;
2c5db955
CP
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}