upstream nginx-0.7.31
[nginx.git] / nginx / src / event / modules / ngx_select_module.c
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
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 static char *ngx_select_init_conf(ngx_cycle_t *cycle, void *conf);
22
23
24 static fd_set         master_read_fd_set;
25 static fd_set         master_write_fd_set;
26 static fd_set         work_read_fd_set;
27 static fd_set         work_write_fd_set;
28
29 #if (NGX_WIN32)
30 static ngx_uint_t     max_read;
31 static ngx_uint_t     max_write;
32 #else
33 static ngx_int_t      max_fd;
34 #endif
35
36 static ngx_uint_t     nevents;
37
38 static ngx_event_t  **event_index;
39
40
41 static ngx_str_t    select_name = ngx_string("select");
42
43 ngx_event_module_t  ngx_select_module_ctx = {
44     &select_name,
45     NULL,                                  /* create configuration */
46     ngx_select_init_conf,                  /* init configuration */
47
48     {
49         ngx_select_add_event,              /* add an event */
50         ngx_select_del_event,              /* delete an event */
51         ngx_select_add_event,              /* enable an event */
52         ngx_select_del_event,              /* disable an event */
53         NULL,                              /* add an connection */
54         NULL,                              /* delete an connection */
55         NULL,                              /* process the changes */
56         ngx_select_process_events,         /* process the events */
57         ngx_select_init,                   /* init the events */
58         ngx_select_done                    /* done the events */
59     }
60
61 };
62
63 ngx_module_t  ngx_select_module = {
64     NGX_MODULE_V1,
65     &ngx_select_module_ctx,                /* module context */
66     NULL,                                  /* module directives */
67     NGX_EVENT_MODULE,                      /* module type */
68     NULL,                                  /* init master */
69     NULL,                                  /* init module */
70     NULL,                                  /* init process */
71     NULL,                                  /* init thread */
72     NULL,                                  /* exit thread */
73     NULL,                                  /* exit process */
74     NULL,                                  /* exit master */
75     NGX_MODULE_V1_PADDING
76 };
77
78
79 static ngx_int_t
80 ngx_select_init(ngx_cycle_t *cycle, ngx_msec_t timer)
81 {
82     ngx_event_t  **index;
83
84     if (event_index == NULL) {
85         FD_ZERO(&master_read_fd_set);
86         FD_ZERO(&master_write_fd_set);
87         nevents = 0;
88     }
89
90     if (ngx_process == NGX_PROCESS_WORKER
91         || cycle->old_cycle == NULL
92         || cycle->old_cycle->connection_n < cycle->connection_n)
93     {
94         index = ngx_alloc(sizeof(ngx_event_t *) * 2 * cycle->connection_n,
95                           cycle->log);
96         if (index == NULL) {
97             return NGX_ERROR;
98         }
99
100         if (event_index) {
101             ngx_memcpy(index, event_index, sizeof(ngx_event_t *) * nevents);
102             ngx_free(event_index);
103         }
104
105         event_index = index;
106     }
107
108     ngx_io = ngx_os_io;
109
110     ngx_event_actions = ngx_select_module_ctx.actions;
111
112     ngx_event_flags = NGX_USE_LEVEL_EVENT;
113
114 #if (NGX_WIN32)
115     max_read = max_write = 0;
116 #else
117     max_fd = -1;
118 #endif
119
120     return NGX_OK;
121 }
122
123
124 static void
125 ngx_select_done(ngx_cycle_t *cycle)
126 {
127     ngx_free(event_index);
128
129     event_index = NULL;
130 }
131
132
133 static ngx_int_t
134 ngx_select_add_event(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags)
135 {
136     ngx_connection_t  *c;
137
138     c = ev->data;
139
140     ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ev->log, 0,
141                    "select add event fd:%d ev:%i", c->fd, event);
142
143     if (ev->index != NGX_INVALID_INDEX) {
144         ngx_log_error(NGX_LOG_ALERT, ev->log, 0,
145                       "select event fd:%d ev:%i is already set", c->fd, event);
146         return NGX_OK;
147     }
148
149 #if (NGX_WIN32)
150
151     if ((event == NGX_READ_EVENT) && (max_read >= FD_SETSIZE)
152         || (event == NGX_WRITE_EVENT) && (max_write >= FD_SETSIZE))
153     {
154         ngx_log_error(NGX_LOG_ERR, ev->log, 0,
155                       "maximum number of descriptors "
156                       "supported by select() is %d", FD_SETSIZE);
157         return NGX_ERROR;
158     }
159
160     if (event == NGX_READ_EVENT) {
161         FD_SET(c->fd, &master_read_fd_set);
162         max_read++;
163
164     } else if (event == NGX_WRITE_EVENT) {
165         FD_SET(c->fd, &master_write_fd_set);
166         max_write++;
167     }
168
169 #else
170
171     if (event == NGX_READ_EVENT) {
172         FD_SET(c->fd, &master_read_fd_set);
173
174     } else if (event == NGX_WRITE_EVENT) {
175         FD_SET(c->fd, &master_write_fd_set);
176     }
177
178     if (max_fd != -1 && max_fd < c->fd) {
179         max_fd = c->fd;
180     }
181
182 #endif
183
184     ev->active = 1;
185
186     event_index[nevents] = ev;
187     ev->index = nevents;
188     nevents++;
189
190     return NGX_OK;
191 }
192
193
194 static ngx_int_t
195 ngx_select_del_event(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags)
196 {
197     ngx_connection_t  *c;
198
199     c = ev->data;
200
201     ev->active = 0;
202
203     if (ev->index == NGX_INVALID_INDEX) {
204         return NGX_OK;
205     }
206
207     ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ev->log, 0,
208                    "select del event fd:%d ev:%i", c->fd, event);
209
210 #if (NGX_WIN32)
211
212     if (event == NGX_READ_EVENT) {
213         FD_CLR(c->fd, &master_read_fd_set);
214         max_read--;
215
216     } else if (event == NGX_WRITE_EVENT) {
217         FD_CLR(c->fd, &master_write_fd_set);
218         max_write--;
219     }
220
221 #else
222
223     if (event == NGX_READ_EVENT) {
224         FD_CLR(c->fd, &master_read_fd_set);
225
226     } else if (event == NGX_WRITE_EVENT) {
227         FD_CLR(c->fd, &master_write_fd_set);
228     }
229
230     if (max_fd == c->fd) {
231         max_fd = -1;
232     }
233
234 #endif
235
236     if (ev->index < --nevents) {
237         event_index[ev->index] = event_index[nevents];
238         event_index[ev->index]->index = ev->index;
239     }
240
241     ev->index = NGX_INVALID_INDEX;
242
243     return NGX_OK;
244 }
245
246
247 static ngx_int_t
248 ngx_select_process_events(ngx_cycle_t *cycle, ngx_msec_t timer,
249     ngx_uint_t flags)
250 {
251     int                 ready, nready;
252     ngx_uint_t          i, found;
253     ngx_err_t           err;
254     ngx_event_t        *ev, **queue;
255     ngx_connection_t   *c;
256     struct timeval      tv, *tp;
257
258 #if !(NGX_WIN32)
259
260     if (max_fd == -1) {
261         for (i = 0; i < nevents; i++) {
262             c = event_index[i]->data;
263             if (max_fd < c->fd) {
264                 max_fd = c->fd;
265             }
266         }
267
268         ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
269                        "change max_fd: %d", max_fd);
270     }
271
272 #endif
273
274 #if (NGX_DEBUG)
275     if (cycle->log->log_level & NGX_LOG_DEBUG_ALL) {
276         for (i = 0; i < nevents; i++) {
277             ev = event_index[i];
278             c = ev->data;
279             ngx_log_debug2(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
280                            "select event: fd:%d wr:%d", c->fd, ev->write);
281         }
282
283 #if !(NGX_WIN32)
284         ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
285                        "max_fd: %d", max_fd);
286 #endif
287     }
288 #endif
289
290     if (timer == NGX_TIMER_INFINITE) {
291         tp = NULL;
292
293     } else {
294         tv.tv_sec = (long) (timer / 1000);
295         tv.tv_usec = (long) ((timer % 1000) * 1000);
296         tp = &tv;
297     }
298
299     ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
300                    "select timer: %M", timer);
301
302     work_read_fd_set = master_read_fd_set;
303     work_write_fd_set = master_write_fd_set;
304
305 #if 1
306     ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
307                    /*
308                     * (void *) disables "dereferencing type-punned
309                     * pointer will break strict-aliasing rules
310                     */
311                    "select read fd_set: %08Xd",
312                    *(int *) (void *) &work_read_fd_set);
313 #endif
314
315 #if (NGX_WIN32)
316
317     ready = select(0, &work_read_fd_set, &work_write_fd_set, NULL, tp);
318
319 #else
320
321     ready = select(max_fd + 1, &work_read_fd_set, &work_write_fd_set, NULL, tp);
322
323 #endif
324
325     if (ready == -1) {
326         err = ngx_socket_errno;
327     } else {
328         err = 0;
329     }
330
331     if (flags & NGX_UPDATE_TIME) {
332         ngx_time_update(0, 0);
333     }
334
335     ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
336                    "select ready %d", ready);
337
338 #if (NGX_WIN32)
339
340     if (err) {
341         ngx_log_error(NGX_LOG_ALERT, cycle->log, err, "select() failed");
342         return NGX_ERROR;
343     }
344
345 #else
346
347     if (err) {
348         ngx_uint_t  level;
349
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");
364         return NGX_ERROR;
365     }
366
367 #endif
368
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;
377     }
378
379     ngx_mutex_lock(ngx_posted_events_mutex);
380
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
406             queue = (ngx_event_t **) (ev->accept ? &ngx_posted_accept_events:
407                                                    &ngx_posted_events);
408             ngx_locked_post_event(ev, queue);
409
410             nready++;
411         }
412     }
413
414     ngx_mutex_unlock(ngx_posted_events_mutex);
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
424 static char *
425 ngx_select_init_conf(ngx_cycle_t *cycle, void *conf)
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
437 #if !(NGX_WIN32)
438
439     if (cycle->connection_n > FD_SETSIZE) {
440         ngx_log_error(NGX_LOG_EMERG, cycle->log, 0,
441                       "the maximum number of files "
442                       "supported by select() is %ud", FD_SETSIZE);
443         return NGX_CONF_ERROR;
444     }
445
446 #endif
447
448 #if (NGX_THREADS) && !(NGX_WIN32)
449
450     ngx_log_error(NGX_LOG_EMERG, cycle->log, 0,
451                   "select() is not supported in the threaded mode");
452     return NGX_CONF_ERROR;
453
454 #else
455
456     return NGX_CONF_OK;
457
458 #endif
459 }