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
|
|
184 event_index[nevents] = ev;
|
|
185 ev->index = nevents;
|
|
186 nevents++;
|
|
187
|
|
188 return NGX_OK;
|
|
189 }
|
|
190
|
|
191
|
50
|
192 static ngx_int_t
|
|
193 ngx_select_del_event(ngx_event_t *ev, int event, u_int flags)
|
0
|
194 {
|
|
195 ngx_connection_t *c;
|
|
196
|
|
197 c = ev->data;
|
|
198
|
|
199 ev->active = 0;
|
|
200
|
|
201 if (ev->index == NGX_INVALID_INDEX) {
|
|
202 return NGX_OK;
|
|
203 }
|
|
204
|
|
205 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ev->log, 0,
|
|
206 "select del event fd:%d ev:%d", c->fd, event);
|
|
207
|
10
|
208 #if (NGX_WIN32)
|
0
|
209
|
|
210 if (event == NGX_READ_EVENT) {
|
|
211 FD_CLR(c->fd, &master_read_fd_set);
|
|
212 max_read--;
|
|
213
|
|
214 } else if (event == NGX_WRITE_EVENT) {
|
|
215 FD_CLR(c->fd, &master_write_fd_set);
|
|
216 max_write--;
|
|
217 }
|
|
218
|
|
219 #else
|
|
220
|
|
221 if (event == NGX_READ_EVENT) {
|
|
222 FD_CLR(c->fd, &master_read_fd_set);
|
|
223
|
|
224 } else if (event == NGX_WRITE_EVENT) {
|
|
225 FD_CLR(c->fd, &master_write_fd_set);
|
|
226 }
|
|
227
|
|
228 if (max_fd == c->fd) {
|
|
229 max_fd = -1;
|
|
230 }
|
|
231
|
|
232 #endif
|
|
233
|
|
234 if (ev->index < (u_int) --nevents) {
|
|
235 event_index[ev->index] = event_index[nevents];
|
|
236 event_index[ev->index]->index = ev->index;
|
|
237 }
|
|
238
|
|
239 ev->index = NGX_INVALID_INDEX;
|
|
240
|
|
241 return NGX_OK;
|
|
242 }
|
|
243
|
|
244
|
50
|
245 static ngx_int_t
|
112
|
246 ngx_select_process_events(ngx_cycle_t *cycle, ngx_msec_t timer,
|
|
247 ngx_uint_t flags)
|
0
|
248 {
|
112
|
249 int ready, nready;
|
|
250 ngx_uint_t i, found;
|
|
251 ngx_err_t err;
|
|
252 ngx_event_t *ev, **queue;
|
|
253 ngx_connection_t *c;
|
|
254 struct timeval tv, *tp;
|
|
255 #if !(NGX_WIN32)
|
|
256 ngx_uint_t level;
|
0
|
257 #endif
|
|
258
|
10
|
259 #if !(NGX_WIN32)
|
0
|
260
|
|
261 if (max_fd == -1) {
|
|
262 for (i = 0; i < nevents; i++) {
|
|
263 c = event_index[i]->data;
|
|
264 if (max_fd < c->fd) {
|
|
265 max_fd = c->fd;
|
|
266 }
|
|
267 }
|
|
268
|
|
269 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
|
|
270 "change max_fd: %d", max_fd);
|
|
271 }
|
|
272
|
|
273 #endif
|
|
274
|
|
275 #if (NGX_DEBUG)
|
|
276 if (cycle->log->log_level & NGX_LOG_DEBUG_ALL) {
|
|
277 for (i = 0; i < nevents; i++) {
|
|
278 ev = event_index[i];
|
|
279 c = ev->data;
|
|
280 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
|
|
281 "select event: fd:%d wr:%d", c->fd, ev->write);
|
|
282 }
|
|
283
|
10
|
284 #if !(NGX_WIN32)
|
0
|
285 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
|
|
286 "max_fd: %d", max_fd);
|
|
287 #endif
|
|
288 }
|
|
289 #endif
|
|
290
|
|
291 if (timer == NGX_TIMER_INFINITE) {
|
|
292 tp = NULL;
|
|
293
|
|
294 } else {
|
106
|
295 tv.tv_sec = (long) (timer / 1000);
|
|
296 tv.tv_usec = (long) ((timer % 1000) * 1000);
|
0
|
297 tp = &tv;
|
|
298 }
|
|
299
|
|
300 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
|
106
|
301 "select timer: %M", timer);
|
0
|
302
|
|
303 work_read_fd_set = master_read_fd_set;
|
|
304 work_write_fd_set = master_write_fd_set;
|
|
305
|
36
|
306 #if 1
|
0
|
307 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
|
36
|
308 /*
|
|
309 * (void *) disables "dereferencing type-punned
|
|
310 * pointer will break strict-aliasing rules
|
|
311 */
|
|
312 "select read fd_set: %08Xd",
|
|
313 *(int *) (void *) &work_read_fd_set);
|
|
314 #endif
|
0
|
315
|
10
|
316 #if (NGX_WIN32)
|
112
|
317
|
0
|
318 ready = select(0, &work_read_fd_set, &work_write_fd_set, NULL, tp);
|
112
|
319
|
0
|
320 #else
|
112
|
321
|
0
|
322 ready = select(max_fd + 1, &work_read_fd_set, &work_write_fd_set, NULL, tp);
|
112
|
323
|
0
|
324 #endif
|
|
325
|
|
326 if (ready == -1) {
|
|
327 err = ngx_socket_errno;
|
|
328 } else {
|
|
329 err = 0;
|
|
330 }
|
|
331
|
112
|
332 if (flags & NGX_UPDATE_TIME) {
|
|
333 ngx_time_update(0, 0);
|
|
334 }
|
0
|
335
|
|
336 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
|
|
337 "select ready %d", ready);
|
|
338
|
112
|
339 #if (NGX_WIN32)
|
|
340
|
0
|
341 if (err) {
|
|
342 ngx_log_error(NGX_LOG_ALERT, cycle->log, err, "select() failed");
|
|
343 return NGX_ERROR;
|
|
344 }
|
|
345
|
112
|
346 #else
|
0
|
347
|
112
|
348 if (err) {
|
|
349 if (err == NGX_EINTR) {
|
|
350
|
|
351 if (ngx_event_timer_alarm) {
|
|
352 ngx_event_timer_alarm = 0;
|
|
353 return NGX_OK;
|
|
354 }
|
126
|
355
|
112
|
356 level = NGX_LOG_INFO;
|
126
|
357
|
|
358 } else {
|
112
|
359 level = NGX_LOG_ALERT;
|
|
360 }
|
|
361
|
|
362 ngx_log_error(level, cycle->log, err, "select() failed");
|
0
|
363 return NGX_ERROR;
|
|
364 }
|
|
365
|
112
|
366 #endif
|
|
367
|
116
|
368 if (ready == 0) {
|
|
369 if (timer != NGX_TIMER_INFINITE) {
|
|
370 return NGX_OK;
|
|
371 }
|
|
372
|
|
373 ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
|
|
374 "select() returned no events without timeout");
|
|
375 return NGX_ERROR;
|
112
|
376 }
|
|
377
|
|
378 ngx_mutex_lock(ngx_posted_events_mutex);
|
|
379
|
0
|
380 nready = 0;
|
|
381
|
|
382 for (i = 0; i < nevents; i++) {
|
|
383 ev = event_index[i];
|
|
384 c = ev->data;
|
|
385 found = 0;
|
|
386
|
|
387 if (ev->write) {
|
|
388 if (FD_ISSET(c->fd, &work_write_fd_set)) {
|
|
389 found = 1;
|
|
390 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
|
|
391 "select write %d", c->fd);
|
|
392 }
|
|
393
|
|
394 } else {
|
|
395 if (FD_ISSET(c->fd, &work_read_fd_set)) {
|
|
396 found = 1;
|
|
397 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
|
|
398 "select read %d", c->fd);
|
|
399 }
|
|
400 }
|
|
401
|
|
402 if (found) {
|
|
403 ev->ready = 1;
|
|
404
|
112
|
405 queue = (ngx_event_t **) (ev->accept ? &ngx_posted_accept_events:
|
|
406 &ngx_posted_events);
|
126
|
407 ngx_locked_post_event(ev, queue);
|
0
|
408
|
|
409 nready++;
|
|
410 }
|
|
411 }
|
|
412
|
112
|
413 ngx_mutex_unlock(ngx_posted_events_mutex);
|
0
|
414
|
|
415 if (ready != nready) {
|
|
416 ngx_log_error(NGX_LOG_ALERT, cycle->log, 0, "select ready != events");
|
|
417 }
|
|
418
|
|
419 return NGX_OK;
|
|
420 }
|
|
421
|
|
422
|
50
|
423 static char *
|
|
424 ngx_select_init_conf(ngx_cycle_t *cycle, void *conf)
|
0
|
425 {
|
|
426 ngx_event_conf_t *ecf;
|
|
427
|
|
428 ecf = ngx_event_get_conf(cycle->conf_ctx, ngx_event_core_module);
|
|
429
|
|
430 if (ecf->use != ngx_select_module.ctx_index) {
|
|
431 return NGX_CONF_OK;
|
|
432 }
|
|
433
|
|
434 /* disable warning: the default FD_SETSIZE is 1024U in FreeBSD 5.x */
|
|
435
|
10
|
436 #if !(NGX_WIN32)
|
112
|
437
|
0
|
438 if ((unsigned) ecf->connections > FD_SETSIZE) {
|
|
439 ngx_log_error(NGX_LOG_EMERG, cycle->log, 0,
|
|
440 "the maximum number of files "
|
|
441 "supported by select() is " ngx_value(FD_SETSIZE));
|
|
442 return NGX_CONF_ERROR;
|
|
443 }
|
112
|
444
|
0
|
445 #endif
|
|
446
|
10
|
447 #if (NGX_THREADS) && !(NGX_WIN32)
|
112
|
448
|
0
|
449 ngx_log_error(NGX_LOG_EMERG, cycle->log, 0,
|
|
450 "select() is not supported in the threaded mode");
|
|
451 return NGX_CONF_ERROR;
|
112
|
452
|
0
|
453 #else
|
112
|
454
|
0
|
455 return NGX_CONF_OK;
|
112
|
456
|
0
|
457 #endif
|
|
458 }
|