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