]>
Commit | Line | Data |
---|---|---|
1 | /* | |
2 | * events.c: the event handling core, poll() version | |
3 | */ | |
4 | ||
5 | #include <stdio.h> | |
6 | #include <sys/poll.h> | |
7 | #include <stdlib.h> | |
8 | #include <unistd.h> | |
9 | #include <string.h> | |
10 | ||
11 | #include "../lib/array.h" | |
12 | #include "events.h" | |
13 | #include "error.h" | |
14 | #include "hooks.h" | |
15 | ||
16 | typedef struct { | |
17 | FDHandler handler; | |
18 | int fdarraypos; | |
19 | } reghandler; | |
20 | ||
21 | /* | |
22 | * OK, new data structure format for here to make everything | |
23 | * faster. Two fixed static arrays, one of struct pollfds | |
24 | * (for feeding to poll) in no particular order. Second array | |
25 | * has an array of reghandler structs; this is indexed by FD for | |
26 | * quick reference... | |
27 | */ | |
28 | ||
29 | struct pollfd *eventfds; | |
30 | reghandler *eventhandlers; | |
31 | ||
32 | unsigned int maxfds; | |
33 | ||
34 | int eventadds; | |
35 | int eventdels; | |
36 | int eventexes; | |
37 | ||
38 | /* How many fds are currently registered */ | |
39 | int regfds; | |
40 | ||
41 | void eventstats(int hooknum, void *arg); | |
42 | ||
43 | void inithandlers() { | |
44 | regfds=0; | |
45 | eventadds=eventdels=eventexes=0; | |
46 | maxfds=STARTFDS; | |
47 | eventfds=(struct pollfd *)malloc(maxfds*sizeof(struct pollfd)); | |
48 | memset(eventfds,0,maxfds*sizeof(struct pollfd)); | |
49 | eventhandlers=(reghandler *)malloc(maxfds*sizeof(reghandler)); | |
50 | memset(eventhandlers,0,maxfds*sizeof(reghandler)); | |
51 | registerhook(HOOK_CORE_STATSREQUEST, &eventstats); | |
52 | } | |
53 | ||
54 | void finihandlers() { | |
55 | deregisterhook(HOOK_CORE_STATSREQUEST, &eventstats); | |
56 | free(eventfds); | |
57 | free(eventhandlers); | |
58 | } | |
59 | ||
60 | /* | |
61 | * checkindex(): | |
62 | * Given the number of a new file descriptor, makes sure that the arrays | |
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 | eventfds=(struct pollfd *)realloc((void *)eventfds,maxfds*sizeof(struct pollfd)); | |
78 | memset(&eventfds[oldmax],0,(maxfds-oldmax)*sizeof(struct pollfd)); | |
79 | eventhandlers=(reghandler *)realloc((void *)eventhandlers,maxfds*sizeof(reghandler)); | |
80 | memset(&eventhandlers[oldmax],0,(maxfds-oldmax)*sizeof(reghandler)); | |
81 | } | |
82 | ||
83 | /* | |
84 | * registerhandler(): | |
85 | * Add an fd to the poll() array. | |
86 | * | |
87 | * Now O(1) | |
88 | */ | |
89 | ||
90 | int registerhandler(int fd, short events, FDHandler handler) { | |
91 | checkindex(fd); | |
92 | ||
93 | /* Check that it's not already registered */ | |
94 | if (eventhandlers[fd].handler!=NULL) { | |
95 | return 1; | |
96 | } | |
97 | ||
98 | eventhandlers[fd].handler=handler; | |
99 | eventhandlers[fd].fdarraypos=regfds; | |
100 | ||
101 | eventfds[regfds].fd=fd; | |
102 | eventfds[regfds].events=events; | |
103 | eventfds[regfds].revents=0; | |
104 | ||
105 | eventadds++; | |
106 | regfds++; | |
107 | return 0; | |
108 | } | |
109 | ||
110 | /* | |
111 | * deregisterhandler(): | |
112 | * Remove an fd from the poll() array. | |
113 | * | |
114 | * The poll() version can't save any time if doclose is set, so | |
115 | * we just do the same work and then close the socket if it's set. | |
116 | * | |
117 | * Now O(1) | |
118 | */ | |
119 | ||
120 | ||
121 | int deregisterhandler(int fd, int doclose) { | |
122 | int oldfdpos; | |
123 | int lastreggedfd; | |
124 | ||
125 | /* Check that the handler exists */ | |
126 | if (eventhandlers[fd].handler==NULL) | |
127 | return 1; | |
128 | ||
129 | /* We need to rearrange the fds array slightly to handle the delete */ | |
130 | eventdels++; | |
131 | regfds--; | |
132 | if (regfds>0) { | |
133 | oldfdpos=eventhandlers[fd].fdarraypos; | |
134 | lastreggedfd=eventfds[regfds].fd; | |
135 | if (lastreggedfd!=fd) { | |
136 | /* We need to move the "lastreggedfd" into "oldfdpos" */ | |
137 | memcpy(&eventfds[oldfdpos],&eventfds[regfds],sizeof(struct pollfd)); | |
138 | eventhandlers[lastreggedfd].fdarraypos=oldfdpos; | |
139 | } | |
140 | } | |
141 | ||
142 | eventhandlers[fd].handler=NULL; | |
143 | eventhandlers[fd].fdarraypos=-1; | |
144 | ||
145 | if (doclose) { | |
146 | close(fd); | |
147 | } | |
148 | ||
149 | return 0; | |
150 | } | |
151 | ||
152 | /* | |
153 | * handleevents(): | |
154 | * Call poll() and handle and call appropiate handlers | |
155 | * for any sockets that come up. | |
156 | * | |
157 | * Unavoidably O(n) | |
158 | */ | |
159 | ||
160 | int handleevents(int timeout) { | |
161 | int i,res; | |
162 | ||
163 | for (i=0;i<regfds;i++) { | |
164 | eventfds[i].revents=0; | |
165 | } | |
166 | ||
167 | res=poll(eventfds,regfds,timeout); | |
168 | if (res<0) { | |
169 | return 1; | |
170 | } | |
171 | ||
172 | for (i=0;i<regfds;i++) { | |
173 | if(eventfds[i].revents>0) { | |
174 | (eventhandlers[eventfds[i].fd].handler)(eventfds[i].fd, eventfds[i].revents); | |
175 | eventexes++; | |
176 | } | |
177 | } | |
178 | return 0; | |
179 | } | |
180 | ||
181 | void eventstats(int hooknum, void *arg) { | |
182 | char buf[512]; | |
183 | long level=(long) arg; | |
184 | ||
185 | if (level>5) { | |
186 | sprintf(buf,"Events :%7d fds registered, %7d fds deregistered",eventadds,eventdels); | |
187 | triggerhook(HOOK_CORE_STATSREPLY,(void *)buf); | |
188 | sprintf(buf,"Events :%7d events triggered, %6d fds active",eventexes,regfds); | |
189 | triggerhook(HOOK_CORE_STATSREPLY,(void *)buf); | |
190 | } | |
191 | } | |
192 |