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