ngx_win32_select_module.c revision e18a033b
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
13static ngx_int_t ngx_select_init(ngx_cycle_t *cycle, ngx_msec_t timer);
14static void ngx_select_done(ngx_cycle_t *cycle);
15static ngx_int_t ngx_select_add_event(ngx_event_t *ev, ngx_int_t event,
16    ngx_uint_t flags);
17static ngx_int_t ngx_select_del_event(ngx_event_t *ev, ngx_int_t event,
18    ngx_uint_t flags);
19static ngx_int_t ngx_select_process_events(ngx_cycle_t *cycle, ngx_msec_t timer,
20    ngx_uint_t flags);
21static void ngx_select_repair_fd_sets(ngx_cycle_t *cycle);
22static char *ngx_select_init_conf(ngx_cycle_t *cycle, void *conf);
23
24
25static fd_set         master_read_fd_set;
26static fd_set         master_write_fd_set;
27static fd_set         work_read_fd_set;
28static fd_set         work_write_fd_set;
29
30static ngx_uint_t     max_read;
31static ngx_uint_t     max_write;
32static ngx_uint_t     nevents;
33
34static ngx_event_t  **event_index;
35
36
37static ngx_str_t           select_name = ngx_string("select");
38
39static ngx_event_module_t  ngx_select_module_ctx = {
40    &select_name,
41    NULL,                                  /* create configuration */
42    ngx_select_init_conf,                  /* init configuration */
43
44    {
45        ngx_select_add_event,              /* add an event */
46        ngx_select_del_event,              /* delete an event */
47        ngx_select_add_event,              /* enable an event */
48        ngx_select_del_event,              /* disable an event */
49        NULL,                              /* add an connection */
50        NULL,                              /* delete an connection */
51        NULL,                              /* trigger a notify */
52        ngx_select_process_events,         /* process the events */
53        ngx_select_init,                   /* init the events */
54        ngx_select_done                    /* done the events */
55    }
56
57};
58
59ngx_module_t  ngx_select_module = {
60    NGX_MODULE_V1,
61    &ngx_select_module_ctx,                /* module context */
62    NULL,                                  /* module directives */
63    NGX_EVENT_MODULE,                      /* module type */
64    NULL,                                  /* init master */
65    NULL,                                  /* init module */
66    NULL,                                  /* init process */
67    NULL,                                  /* init thread */
68    NULL,                                  /* exit thread */
69    NULL,                                  /* exit process */
70    NULL,                                  /* exit master */
71    NGX_MODULE_V1_PADDING
72};
73
74
75static ngx_int_t
76ngx_select_init(ngx_cycle_t *cycle, ngx_msec_t timer)
77{
78    ngx_event_t  **index;
79
80    if (event_index == NULL) {
81        FD_ZERO(&master_read_fd_set);
82        FD_ZERO(&master_write_fd_set);
83        nevents = 0;
84    }
85
86    if (ngx_process >= NGX_PROCESS_WORKER
87        || cycle->old_cycle == NULL
88        || cycle->old_cycle->connection_n < cycle->connection_n)
89    {
90        index = ngx_alloc(sizeof(ngx_event_t *) * 2 * cycle->connection_n,
91                          cycle->log);
92        if (index == NULL) {
93            return NGX_ERROR;
94        }
95
96        if (event_index) {
97            ngx_memcpy(index, event_index, sizeof(ngx_event_t *) * nevents);
98            ngx_free(event_index);
99        }
100
101        event_index = index;
102    }
103
104    ngx_io = ngx_os_io;
105
106    ngx_event_actions = ngx_select_module_ctx.actions;
107
108    ngx_event_flags = NGX_USE_LEVEL_EVENT;
109
110    max_read = 0;
111    max_write = 0;
112
113    return NGX_OK;
114}
115
116
117static void
118ngx_select_done(ngx_cycle_t *cycle)
119{
120    ngx_free(event_index);
121
122    event_index = NULL;
123}
124
125
126static ngx_int_t
127ngx_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 && 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    ev->active = 1;
170
171    event_index[nevents] = ev;
172    ev->index = nevents;
173    nevents++;
174
175    return NGX_OK;
176}
177
178
179static ngx_int_t
180ngx_select_del_event(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags)
181{
182    ngx_event_t       *e;
183    ngx_connection_t  *c;
184
185    c = ev->data;
186
187    ev->active = 0;
188
189    if (ev->index == NGX_INVALID_INDEX) {
190        return NGX_OK;
191    }
192
193    ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ev->log, 0,
194                   "select del event fd:%d ev:%i", c->fd, event);
195
196    if (event == NGX_READ_EVENT) {
197        FD_CLR(c->fd, &master_read_fd_set);
198        max_read--;
199
200    } else if (event == NGX_WRITE_EVENT) {
201        FD_CLR(c->fd, &master_write_fd_set);
202        max_write--;
203    }
204
205    if (ev->index < --nevents) {
206        e = event_index[nevents];
207        event_index[ev->index] = e;
208        e->index = ev->index;
209    }
210
211    ev->index = NGX_INVALID_INDEX;
212
213    return NGX_OK;
214}
215
216
217static ngx_int_t
218ngx_select_process_events(ngx_cycle_t *cycle, ngx_msec_t timer,
219    ngx_uint_t flags)
220{
221    int                ready, nready;
222    ngx_err_t          err;
223    ngx_uint_t         i, found;
224    ngx_event_t       *ev;
225    ngx_queue_t       *queue;
226    struct timeval     tv, *tp;
227    ngx_connection_t  *c;
228
229#if (NGX_DEBUG)
230    if (cycle->log->log_level & NGX_LOG_DEBUG_ALL) {
231        for (i = 0; i < nevents; i++) {
232            ev = event_index[i];
233            c = ev->data;
234            ngx_log_debug2(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
235                           "select event: fd:%d wr:%d", c->fd, ev->write);
236        }
237    }
238#endif
239
240    if (timer == NGX_TIMER_INFINITE) {
241        tp = NULL;
242
243    } else {
244        tv.tv_sec = (long) (timer / 1000);
245        tv.tv_usec = (long) ((timer % 1000) * 1000);
246        tp = &tv;
247    }
248
249    ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
250                   "select timer: %M", timer);
251
252    work_read_fd_set = master_read_fd_set;
253    work_write_fd_set = master_write_fd_set;
254
255    if (max_read || max_write) {
256        ready = select(0, &work_read_fd_set, &work_write_fd_set, NULL, tp);
257
258    } else {
259
260        /*
261         * Winsock select() requires that at least one descriptor set must be
262         * be non-null, and any non-null descriptor set must contain at least
263         * one handle to a socket.  Otherwise select() returns WSAEINVAL.
264         */
265
266        ngx_msleep(timer);
267
268        ready = 0;
269    }
270
271    err = (ready == -1) ? ngx_socket_errno : 0;
272
273    if (flags & NGX_UPDATE_TIME) {
274        ngx_time_update();
275    }
276
277    ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
278                   "select ready %d", ready);
279
280    if (err) {
281        ngx_log_error(NGX_LOG_ALERT, cycle->log, err, "select() failed");
282
283        if (err == WSAENOTSOCK) {
284            ngx_select_repair_fd_sets(cycle);
285        }
286
287        return NGX_ERROR;
288    }
289
290    if (ready == 0) {
291        if (timer != NGX_TIMER_INFINITE) {
292            return NGX_OK;
293        }
294
295        ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
296                      "select() returned no events without timeout");
297        return NGX_ERROR;
298    }
299
300    nready = 0;
301
302    for (i = 0; i < nevents; i++) {
303        ev = event_index[i];
304        c = ev->data;
305        found = 0;
306
307        if (ev->write) {
308            if (FD_ISSET(c->fd, &work_write_fd_set)) {
309                found = 1;
310                ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
311                               "select write %d", c->fd);
312            }
313
314        } else {
315            if (FD_ISSET(c->fd, &work_read_fd_set)) {
316                found = 1;
317                ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
318                               "select read %d", c->fd);
319            }
320        }
321
322        if (found) {
323            ev->ready = 1;
324
325            queue = ev->accept ? &ngx_posted_accept_events
326                               : &ngx_posted_events;
327
328            ngx_post_event(ev, queue);
329
330            nready++;
331        }
332    }
333
334    if (ready != nready) {
335        ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
336                      "select ready != events: %d:%d", ready, nready);
337
338        ngx_select_repair_fd_sets(cycle);
339    }
340
341    return NGX_OK;
342}
343
344
345static void
346ngx_select_repair_fd_sets(ngx_cycle_t *cycle)
347{
348    int           n;
349    u_int         i;
350    socklen_t     len;
351    ngx_err_t     err;
352    ngx_socket_t  s;
353
354    for (i = 0; i < master_read_fd_set.fd_count; i++) {
355
356        s = master_read_fd_set.fd_array[i];
357        len = sizeof(int);
358
359        if (getsockopt(s, SOL_SOCKET, SO_TYPE, (char *) &n, &len) == -1) {
360            err = ngx_socket_errno;
361
362            ngx_log_error(NGX_LOG_ALERT, cycle->log, err,
363                          "invalid descriptor #%d in read fd_set", s);
364
365            FD_CLR(s, &master_read_fd_set);
366        }
367    }
368
369    for (i = 0; i < master_write_fd_set.fd_count; i++) {
370
371        s = master_write_fd_set.fd_array[i];
372        len = sizeof(int);
373
374        if (getsockopt(s, SOL_SOCKET, SO_TYPE, (char *) &n, &len) == -1) {
375            err = ngx_socket_errno;
376
377            ngx_log_error(NGX_LOG_ALERT, cycle->log, err,
378                          "invalid descriptor #%d in write fd_set", s);
379
380            FD_CLR(s, &master_write_fd_set);
381        }
382    }
383}
384
385
386static char *
387ngx_select_init_conf(ngx_cycle_t *cycle, void *conf)
388{
389    ngx_event_conf_t  *ecf;
390
391    ecf = ngx_event_get_conf(cycle->conf_ctx, ngx_event_core_module);
392
393    if (ecf->use != ngx_select_module.ctx_index) {
394        return NGX_CONF_OK;
395    }
396
397    return NGX_CONF_OK;
398}
399