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