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