Mercurial > hg > nginx-vendor-current
comparison src/event/modules/ngx_win32_select_module.c @ 488:829f9a66a659 NGINX_0_7_56
nginx 0.7.56
*) Feature: nginx/Windows supports IPv6 in a "listen" directive of the
HTTP module.
*) Bugfix: in ngx_http_image_filter_module.
author | Igor Sysoev <http://sysoev.ru> |
---|---|
date | Mon, 11 May 2009 00:00:00 +0400 |
parents | |
children | 86dad910eeb6 |
comparison
equal
deleted
inserted
replaced
487:e98b980b4fe7 | 488:829f9a66a659 |
---|---|
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 static ngx_int_t ngx_select_init(ngx_cycle_t *cycle, ngx_msec_t timer); | |
13 static void ngx_select_done(ngx_cycle_t *cycle); | |
14 static ngx_int_t ngx_select_add_event(ngx_event_t *ev, ngx_int_t event, | |
15 ngx_uint_t flags); | |
16 static ngx_int_t ngx_select_del_event(ngx_event_t *ev, ngx_int_t event, | |
17 ngx_uint_t flags); | |
18 static ngx_int_t ngx_select_process_events(ngx_cycle_t *cycle, ngx_msec_t timer, | |
19 ngx_uint_t flags); | |
20 static void ngx_select_repair_fd_sets(ngx_cycle_t *cycle); | |
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 static ngx_uint_t max_read; | |
30 static ngx_uint_t max_write; | |
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_read = 0; | |
110 max_write = 0; | |
111 | |
112 return NGX_OK; | |
113 } | |
114 | |
115 | |
116 static void | |
117 ngx_select_done(ngx_cycle_t *cycle) | |
118 { | |
119 ngx_free(event_index); | |
120 | |
121 event_index = NULL; | |
122 } | |
123 | |
124 | |
125 static ngx_int_t | |
126 ngx_select_add_event(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags) | |
127 { | |
128 ngx_connection_t *c; | |
129 | |
130 c = ev->data; | |
131 | |
132 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ev->log, 0, | |
133 "select add event fd:%d ev:%i", c->fd, event); | |
134 | |
135 if (ev->index != NGX_INVALID_INDEX) { | |
136 ngx_log_error(NGX_LOG_ALERT, ev->log, 0, | |
137 "select event fd:%d ev:%i is already set", c->fd, event); | |
138 return NGX_OK; | |
139 } | |
140 | |
141 if ((event == NGX_READ_EVENT && ev->write) | |
142 || (event == NGX_WRITE_EVENT && !ev->write)) | |
143 { | |
144 ngx_log_error(NGX_LOG_ALERT, ev->log, 0, | |
145 "invalid select %s event fd:%d ev:%i", | |
146 ev->write ? "write" : "read", c->fd, event); | |
147 return NGX_ERROR; | |
148 } | |
149 | |
150 if ((event == NGX_READ_EVENT) && (max_read >= FD_SETSIZE) | |
151 || (event == NGX_WRITE_EVENT) && (max_write >= FD_SETSIZE)) | |
152 { | |
153 ngx_log_error(NGX_LOG_ERR, ev->log, 0, | |
154 "maximum number of descriptors " | |
155 "supported by select() is %d", FD_SETSIZE); | |
156 return NGX_ERROR; | |
157 } | |
158 | |
159 if (event == NGX_READ_EVENT) { | |
160 FD_SET(c->fd, &master_read_fd_set); | |
161 max_read++; | |
162 | |
163 } else if (event == NGX_WRITE_EVENT) { | |
164 FD_SET(c->fd, &master_write_fd_set); | |
165 max_write++; | |
166 } | |
167 | |
168 ev->active = 1; | |
169 | |
170 event_index[nevents] = ev; | |
171 ev->index = nevents; | |
172 nevents++; | |
173 | |
174 return NGX_OK; | |
175 } | |
176 | |
177 | |
178 static ngx_int_t | |
179 ngx_select_del_event(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags) | |
180 { | |
181 ngx_event_t *e; | |
182 ngx_connection_t *c; | |
183 | |
184 c = ev->data; | |
185 | |
186 ev->active = 0; | |
187 | |
188 if (ev->index == NGX_INVALID_INDEX) { | |
189 return NGX_OK; | |
190 } | |
191 | |
192 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ev->log, 0, | |
193 "select del event fd:%d ev:%i", c->fd, event); | |
194 | |
195 if (event == NGX_READ_EVENT) { | |
196 FD_CLR(c->fd, &master_read_fd_set); | |
197 max_read--; | |
198 | |
199 } else if (event == NGX_WRITE_EVENT) { | |
200 FD_CLR(c->fd, &master_write_fd_set); | |
201 max_write--; | |
202 } | |
203 | |
204 if (ev->index < --nevents) { | |
205 e = event_index[nevents]; | |
206 event_index[ev->index] = e; | |
207 e->index = ev->index; | |
208 } | |
209 | |
210 ev->index = NGX_INVALID_INDEX; | |
211 | |
212 return NGX_OK; | |
213 } | |
214 | |
215 | |
216 static ngx_int_t | |
217 ngx_select_process_events(ngx_cycle_t *cycle, ngx_msec_t timer, | |
218 ngx_uint_t flags) | |
219 { | |
220 int ready, nready; | |
221 ngx_err_t err; | |
222 ngx_uint_t i, found; | |
223 ngx_event_t *ev, **queue; | |
224 struct timeval tv, *tp; | |
225 ngx_connection_t *c; | |
226 | |
227 #if (NGX_DEBUG) | |
228 if (cycle->log->log_level & NGX_LOG_DEBUG_ALL) { | |
229 for (i = 0; i < nevents; i++) { | |
230 ev = event_index[i]; | |
231 c = ev->data; | |
232 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, cycle->log, 0, | |
233 "select event: fd:%d wr:%d", c->fd, ev->write); | |
234 } | |
235 } | |
236 #endif | |
237 | |
238 if (timer == NGX_TIMER_INFINITE) { | |
239 tp = NULL; | |
240 | |
241 } else { | |
242 tv.tv_sec = (long) (timer / 1000); | |
243 tv.tv_usec = (long) ((timer % 1000) * 1000); | |
244 tp = &tv; | |
245 } | |
246 | |
247 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0, | |
248 "select timer: %M", timer); | |
249 | |
250 work_read_fd_set = master_read_fd_set; | |
251 work_write_fd_set = master_write_fd_set; | |
252 | |
253 if (max_read || max_write) { | |
254 ready = select(0, &work_read_fd_set, &work_write_fd_set, NULL, tp); | |
255 | |
256 } else { | |
257 | |
258 /* | |
259 * Winsock select() requires that at least one descriptor set must be | |
260 * be non-null, and any non-null descriptor set must contain at least | |
261 * one handle to a socket. Otherwise select() returns WSAEINVAL. | |
262 */ | |
263 | |
264 ngx_msleep(timer); | |
265 | |
266 ready = 0; | |
267 } | |
268 | |
269 if (ready == -1) { | |
270 err = ngx_socket_errno; | |
271 } else { | |
272 err = 0; | |
273 } | |
274 | |
275 if (flags & NGX_UPDATE_TIME) { | |
276 ngx_time_update(0, 0); | |
277 } | |
278 | |
279 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0, | |
280 "select ready %d", ready); | |
281 | |
282 if (err) { | |
283 ngx_log_error(NGX_LOG_ALERT, cycle->log, err, "select() failed"); | |
284 | |
285 if (err == WSAENOTSOCK) { | |
286 ngx_select_repair_fd_sets(cycle); | |
287 } | |
288 | |
289 return NGX_ERROR; | |
290 } | |
291 | |
292 if (ready == 0) { | |
293 if (timer != NGX_TIMER_INFINITE) { | |
294 return NGX_OK; | |
295 } | |
296 | |
297 ngx_log_error(NGX_LOG_ALERT, cycle->log, 0, | |
298 "select() returned no events without timeout"); | |
299 return NGX_ERROR; | |
300 } | |
301 | |
302 ngx_mutex_lock(ngx_posted_events_mutex); | |
303 | |
304 nready = 0; | |
305 | |
306 for (i = 0; i < nevents; i++) { | |
307 ev = event_index[i]; | |
308 c = ev->data; | |
309 found = 0; | |
310 | |
311 if (ev->write) { | |
312 if (FD_ISSET(c->fd, &work_write_fd_set)) { | |
313 found = 1; | |
314 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0, | |
315 "select write %d", c->fd); | |
316 } | |
317 | |
318 } else { | |
319 if (FD_ISSET(c->fd, &work_read_fd_set)) { | |
320 found = 1; | |
321 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0, | |
322 "select read %d", c->fd); | |
323 } | |
324 } | |
325 | |
326 if (found) { | |
327 ev->ready = 1; | |
328 | |
329 queue = (ngx_event_t **) (ev->accept ? &ngx_posted_accept_events: | |
330 &ngx_posted_events); | |
331 ngx_locked_post_event(ev, queue); | |
332 | |
333 nready++; | |
334 } | |
335 } | |
336 | |
337 ngx_mutex_unlock(ngx_posted_events_mutex); | |
338 | |
339 if (ready != nready) { | |
340 ngx_log_error(NGX_LOG_ALERT, cycle->log, 0, | |
341 "select ready != events: %d:%d", ready, nready); | |
342 | |
343 ngx_select_repair_fd_sets(cycle); | |
344 } | |
345 | |
346 return NGX_OK; | |
347 } | |
348 | |
349 | |
350 static void | |
351 ngx_select_repair_fd_sets(ngx_cycle_t *cycle) | |
352 { | |
353 int n; | |
354 u_int i; | |
355 socklen_t len; | |
356 ngx_err_t err; | |
357 ngx_socket_t s; | |
358 | |
359 for (i = 0; i < master_read_fd_set.fd_count; i++) { | |
360 | |
361 s = master_read_fd_set.fd_array[i]; | |
362 len = sizeof(int); | |
363 | |
364 if (getsockopt(s, SOL_SOCKET, SO_TYPE, (char *) &n, &len) == -1) { | |
365 err = ngx_socket_errno; | |
366 | |
367 ngx_log_error(NGX_LOG_ALERT, cycle->log, err, | |
368 "invalid descriptor #%d in read fd_set", s); | |
369 | |
370 FD_CLR(s, &master_read_fd_set); | |
371 } | |
372 } | |
373 | |
374 for (i = 0; i < master_write_fd_set.fd_count; i++) { | |
375 | |
376 s = master_write_fd_set.fd_array[i]; | |
377 len = sizeof(int); | |
378 | |
379 if (getsockopt(s, SOL_SOCKET, SO_TYPE, (char *) &n, &len) == -1) { | |
380 err = ngx_socket_errno; | |
381 | |
382 ngx_log_error(NGX_LOG_ALERT, cycle->log, err, | |
383 "invalid descriptor #%d in write fd_set", s); | |
384 | |
385 FD_CLR(s, &master_write_fd_set); | |
386 } | |
387 } | |
388 } | |
389 | |
390 | |
391 static char * | |
392 ngx_select_init_conf(ngx_cycle_t *cycle, void *conf) | |
393 { | |
394 ngx_event_conf_t *ecf; | |
395 | |
396 ecf = ngx_event_get_conf(cycle->conf_ctx, ngx_event_core_module); | |
397 | |
398 if (ecf->use != ngx_select_module.ctx_index) { | |
399 return NGX_CONF_OK; | |
400 } | |
401 | |
402 return NGX_CONF_OK; | |
403 } |