1
2 /*
3 * Copyright (C) Igor Sysoev
4 * Copyright (C) Nginx, Inc.
5 */
6
7
8 #include <ngx_config.h>
9 #include <ngx_core.h>
10 #include <ngx_event.h>
11
12
13 static ngx_int_t ngx_select_init(ngx_cycle_t *cycle, ngx_msec_t timer);
14 static void ngx_select_done(ngx_cycle_t *cycle);
15 static ngx_int_t ngx_select_add_event(ngx_event_t *ev, ngx_int_t event,
16 ngx_uint_t flags);
17 static ngx_int_t ngx_select_del_event(ngx_event_t *ev, ngx_int_t event,
18 ngx_uint_t flags);
19 static ngx_int_t ngx_select_process_events(ngx_cycle_t *cycle, ngx_msec_t timer,
20 ngx_uint_t flags);
21 #if !(NGX_HAVE_FSTACK)
22 static void ngx_select_repair_fd_sets(ngx_cycle_t *cycle);
23 #endif
24 static char *ngx_select_init_conf(ngx_cycle_t *cycle, void *conf);
25
26
27 static fd_set master_read_fd_set;
28 static fd_set master_write_fd_set;
29 static fd_set work_read_fd_set;
30 static fd_set work_write_fd_set;
31
32 static ngx_int_t max_fd;
33 static ngx_uint_t nevents;
34
35 static ngx_event_t **event_index;
36
37
38 static ngx_str_t select_name = ngx_string("select");
39
40 static ngx_event_module_t ngx_select_module_ctx = {
41 &select_name,
42 NULL, /* create configuration */
43 ngx_select_init_conf, /* init configuration */
44
45 {
46 ngx_select_add_event, /* add an event */
47 ngx_select_del_event, /* delete an event */
48 ngx_select_add_event, /* enable an event */
49 ngx_select_del_event, /* disable an event */
50 NULL, /* add an connection */
51 NULL, /* delete an connection */
52 NULL, /* trigger a notify */
53 ngx_select_process_events, /* process the events */
54 ngx_select_init, /* init the events */
55 ngx_select_done /* done the events */
56 }
57
58 };
59
60 ngx_module_t ngx_select_module = {
61 NGX_MODULE_V1,
62 &ngx_select_module_ctx, /* module context */
63 NULL, /* module directives */
64 NGX_EVENT_MODULE, /* module type */
65 NULL, /* init master */
66 NULL, /* init module */
67 NULL, /* init process */
68 NULL, /* init thread */
69 NULL, /* exit thread */
70 NULL, /* exit process */
71 NULL, /* exit master */
72 NGX_MODULE_V1_PADDING
73 };
74
75
76 static ngx_int_t
ngx_select_init(ngx_cycle_t * cycle,ngx_msec_t timer)77 ngx_select_init(ngx_cycle_t *cycle, ngx_msec_t timer)
78 {
79 ngx_event_t **index;
80
81 if (event_index == NULL) {
82 FD_ZERO(&master_read_fd_set);
83 FD_ZERO(&master_write_fd_set);
84 nevents = 0;
85 }
86
87 if (ngx_process >= NGX_PROCESS_WORKER
88 || cycle->old_cycle == NULL
89 || cycle->old_cycle->connection_n < cycle->connection_n)
90 {
91 index = ngx_alloc(sizeof(ngx_event_t *) * 2 * cycle->connection_n,
92 cycle->log);
93 if (index == NULL) {
94 return NGX_ERROR;
95 }
96
97 if (event_index) {
98 ngx_memcpy(index, event_index, sizeof(ngx_event_t *) * nevents);
99 ngx_free(event_index);
100 }
101
102 event_index = index;
103 }
104
105 ngx_io = ngx_os_io;
106
107 ngx_event_actions = ngx_select_module_ctx.actions;
108
109 ngx_event_flags = NGX_USE_LEVEL_EVENT;
110
111 max_fd = -1;
112
113 return NGX_OK;
114 }
115
116
117 static void
ngx_select_done(ngx_cycle_t * cycle)118 ngx_select_done(ngx_cycle_t *cycle)
119 {
120 ngx_free(event_index);
121
122 event_index = NULL;
123 }
124
125
126 static ngx_int_t
ngx_select_add_event(ngx_event_t * ev,ngx_int_t event,ngx_uint_t flags)127 ngx_select_add_event(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags)
128 {
129 ngx_connection_t *c;
130
131 c = ev->data;
132
133 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ev->log, 0,
134 "select add event fd:%d ev:%i", c->fd, event);
135
136 if (ev->index != NGX_INVALID_INDEX) {
137 ngx_log_error(NGX_LOG_ALERT, ev->log, 0,
138 "select event fd:%d ev:%i is already set", c->fd, event);
139 return NGX_OK;
140 }
141
142 if ((event == NGX_READ_EVENT && ev->write)
143 || (event == NGX_WRITE_EVENT && !ev->write))
144 {
145 ngx_log_error(NGX_LOG_ALERT, ev->log, 0,
146 "invalid select %s event fd:%d ev:%i",
147 ev->write ? "write" : "read", c->fd, event);
148 return NGX_ERROR;
149 }
150
151 if (event == NGX_READ_EVENT) {
152 FD_SET(c->fd, &master_read_fd_set);
153
154 } else if (event == NGX_WRITE_EVENT) {
155 FD_SET(c->fd, &master_write_fd_set);
156 }
157
158 if (max_fd != -1 && max_fd < c->fd) {
159 max_fd = c->fd;
160 }
161
162 ev->active = 1;
163
164 event_index[nevents] = ev;
165 ev->index = nevents;
166 nevents++;
167
168 return NGX_OK;
169 }
170
171
172 static ngx_int_t
ngx_select_del_event(ngx_event_t * ev,ngx_int_t event,ngx_uint_t flags)173 ngx_select_del_event(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags)
174 {
175 ngx_event_t *e;
176 ngx_connection_t *c;
177
178 c = ev->data;
179
180 ev->active = 0;
181
182 if (ev->index == NGX_INVALID_INDEX) {
183 return NGX_OK;
184 }
185
186 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ev->log, 0,
187 "select del event fd:%d ev:%i", c->fd, event);
188
189 if (event == NGX_READ_EVENT) {
190 FD_CLR(c->fd, &master_read_fd_set);
191
192 } else if (event == NGX_WRITE_EVENT) {
193 FD_CLR(c->fd, &master_write_fd_set);
194 }
195
196 if (max_fd == c->fd) {
197 max_fd = -1;
198 }
199
200 if (ev->index < --nevents) {
201 e = event_index[nevents];
202 event_index[ev->index] = e;
203 e->index = ev->index;
204 }
205
206 ev->index = NGX_INVALID_INDEX;
207
208 return NGX_OK;
209 }
210
211
212 static ngx_int_t
ngx_select_process_events(ngx_cycle_t * cycle,ngx_msec_t timer,ngx_uint_t flags)213 ngx_select_process_events(ngx_cycle_t *cycle, ngx_msec_t timer,
214 ngx_uint_t flags)
215 {
216 int ready, nready;
217 ngx_err_t err;
218 ngx_uint_t i, found;
219 ngx_event_t *ev;
220 ngx_queue_t *queue;
221 struct timeval tv, *tp;
222 ngx_connection_t *c;
223
224 if (max_fd == -1) {
225 for (i = 0; i < nevents; i++) {
226 c = event_index[i]->data;
227 if (max_fd < c->fd) {
228 max_fd = c->fd;
229 }
230 }
231
232 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
233 "change max_fd: %i", max_fd);
234 }
235
236 #if (NGX_DEBUG)
237 if (cycle->log->log_level & NGX_LOG_DEBUG_ALL) {
238 for (i = 0; i < nevents; i++) {
239 ev = event_index[i];
240 c = ev->data;
241 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
242 "select event: fd:%d wr:%d", c->fd, ev->write);
243 }
244
245 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
246 "max_fd: %i", max_fd);
247 }
248 #endif
249
250 if (timer == NGX_TIMER_INFINITE) {
251 tp = NULL;
252
253 } else {
254 tv.tv_sec = (long) (timer / 1000);
255 tv.tv_usec = (long) ((timer % 1000) * 1000);
256 tp = &tv;
257 }
258
259 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
260 "select timer: %M", timer);
261
262 work_read_fd_set = master_read_fd_set;
263 work_write_fd_set = master_write_fd_set;
264
265 ready = select(max_fd + 1, &work_read_fd_set, &work_write_fd_set, NULL, tp);
266
267 err = (ready == -1) ? ngx_errno : 0;
268
269 if (flags & NGX_UPDATE_TIME || ngx_event_timer_alarm) {
270 ngx_time_update();
271 }
272
273 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
274 "select ready %d", ready);
275
276 if (err) {
277 ngx_uint_t level;
278
279 if (err == NGX_EINTR) {
280
281 if (ngx_event_timer_alarm) {
282 ngx_event_timer_alarm = 0;
283 return NGX_OK;
284 }
285
286 level = NGX_LOG_INFO;
287
288 } else {
289 level = NGX_LOG_ALERT;
290 }
291
292 ngx_log_error(level, cycle->log, err, "select() failed");
293
294 if (err == NGX_EBADF) {
295 #if !(NGX_HAVE_FSTACK)
296 ngx_select_repair_fd_sets(cycle);
297 #endif
298 }
299
300 return NGX_ERROR;
301 }
302
303 if (ready == 0) {
304 if (timer != NGX_TIMER_INFINITE) {
305 return NGX_OK;
306 }
307
308 #if !(NGX_HAVE_FSTACK)
309 ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
310 "select() returned no events without timeout");
311 #endif
312 return NGX_ERROR;
313 }
314
315 nready = 0;
316
317 for (i = 0; i < nevents; i++) {
318 ev = event_index[i];
319 c = ev->data;
320 found = 0;
321
322 if (ev->write) {
323 if (FD_ISSET(c->fd, &work_write_fd_set)) {
324 found = 1;
325 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
326 "select write %d", c->fd);
327 }
328
329 } else {
330 if (FD_ISSET(c->fd, &work_read_fd_set)) {
331 found = 1;
332 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
333 "select read %d", c->fd);
334 }
335 }
336
337 if (found) {
338 ev->ready = 1;
339
340 queue = ev->accept ? &ngx_posted_accept_events
341 : &ngx_posted_events;
342
343 ngx_post_event(ev, queue);
344
345 nready++;
346 }
347 }
348
349 if (ready != nready) {
350 ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
351 "select ready != events: %d:%d", ready, nready);
352
353 #if !(NGX_HAVE_FSTACK)
354 ngx_select_repair_fd_sets(cycle);
355 #endif
356 }
357
358 return NGX_OK;
359 }
360
361 #if !(NGX_HAVE_FSTACK)
362 static void
ngx_select_repair_fd_sets(ngx_cycle_t * cycle)363 ngx_select_repair_fd_sets(ngx_cycle_t *cycle)
364 {
365 int n;
366 socklen_t len;
367 ngx_err_t err;
368 ngx_socket_t s;
369
370 for (s = 0; s <= max_fd; s++) {
371
372 if (FD_ISSET(s, &master_read_fd_set) == 0) {
373 continue;
374 }
375
376 len = sizeof(int);
377
378 if (getsockopt(s, SOL_SOCKET, SO_TYPE, &n, &len) == -1) {
379 err = ngx_socket_errno;
380
381 ngx_log_error(NGX_LOG_ALERT, cycle->log, err,
382 "invalid descriptor #%d in read fd_set", s);
383
384 FD_CLR(s, &master_read_fd_set);
385 }
386 }
387
388 for (s = 0; s <= max_fd; s++) {
389
390 if (FD_ISSET(s, &master_write_fd_set) == 0) {
391 continue;
392 }
393
394 len = sizeof(int);
395
396 if (getsockopt(s, SOL_SOCKET, SO_TYPE, &n, &len) == -1) {
397 err = ngx_socket_errno;
398
399 ngx_log_error(NGX_LOG_ALERT, cycle->log, err,
400 "invalid descriptor #%d in write fd_set", s);
401
402 FD_CLR(s, &master_write_fd_set);
403 }
404 }
405
406 max_fd = -1;
407 }
408 #endif
409
410 static char *
ngx_select_init_conf(ngx_cycle_t * cycle,void * conf)411 ngx_select_init_conf(ngx_cycle_t *cycle, void *conf)
412 {
413 ngx_event_conf_t *ecf;
414
415 ecf = ngx_event_get_conf(cycle->conf_ctx, ngx_event_core_module);
416
417 if (ecf->use != ngx_select_module.ctx_index) {
418 return NGX_CONF_OK;
419 }
420
421 /* disable warning: the default FD_SETSIZE is 1024U in FreeBSD 5.x */
422
423 if (cycle->connection_n > FD_SETSIZE) {
424 ngx_log_error(NGX_LOG_EMERG, cycle->log, 0,
425 "the maximum number of files "
426 "supported by select() is %ud", FD_SETSIZE);
427 return NGX_CONF_ERROR;
428 }
429
430 return NGX_CONF_OK;
431 }
432