static int ngx_lcb_event_update(lcb_io_opt_t io, lcb_socket_t sock, void *event, short flags, void *data, ngx_lcb_handler_pt handler) { ngx_lcb_context_t *ctx = from_socket(sock); ngx_int_t f; ctx->handler = handler; ctx->handler_mask = flags; ctx->handler_data = data; if (ngx_event_flags & NGX_USE_CLEAR_EVENT) { /* kqueue */ f = NGX_CLEAR_EVENT; } else { /* select, poll, /dev/poll */ f = NGX_LEVEL_EVENT; } /* FIXME check return value */ if (flags & LCB_WRITE_EVENT) { ngx_add_event(ctx->peer->connection->write, NGX_WRITE_EVENT, f); } if (flags & LCB_READ_EVENT) { ngx_add_event(ctx->peer->connection->read, NGX_READ_EVENT, f); } (void)io; (void)event; return 0; }
ngx_int_t ngx_handle_read_event(ngx_event_t *rev, ngx_uint_t flags) { if (ngx_event_flags & NGX_USE_CLEAR_EVENT) { /* kqueue, epoll */ if (!rev->active && !rev->ready) { if (ngx_add_event(rev, NGX_READ_EVENT, NGX_CLEAR_EVENT) == NGX_ERROR) { return NGX_ERROR; } } return NGX_OK; } else if (ngx_event_flags & NGX_USE_LEVEL_EVENT) { /* select, poll, /dev/poll */ if (!rev->active && !rev->ready) { if (ngx_add_event(rev, NGX_READ_EVENT, NGX_LEVEL_EVENT) == NGX_ERROR) { return NGX_ERROR; } return NGX_OK; } if (rev->active && (rev->ready || (flags & NGX_CLOSE_EVENT))) { if (ngx_del_event(rev, NGX_READ_EVENT, NGX_LEVEL_EVENT | flags) == NGX_ERROR) { return NGX_ERROR; } return NGX_OK; } } else if (ngx_event_flags & NGX_USE_EVENTPORT_EVENT) { /* event ports */ if (!rev->active && !rev->ready) { if (ngx_add_event(rev, NGX_READ_EVENT, 0) == NGX_ERROR) { return NGX_ERROR; } return NGX_OK; } if (rev->oneshot && !rev->ready) { if (ngx_del_event(rev, NGX_READ_EVENT, 0) == NGX_ERROR) { return NGX_ERROR; } return NGX_OK; } } /* aio, iocp, rtsig */ return NGX_OK; }
static ngx_int_t ngx_enable_accept_events(ngx_cycle_t *cycle) { ngx_uint_t i; ngx_listening_t *ls; ngx_connection_t *c; ls = cycle->listening.elts; for (i = 0; i < cycle->listening.nelts; i++) { c = ls[i].connection; if (c->read->active) { continue; } if (ngx_add_event(c->read, NGX_READ_EVENT, 0) == NGX_ERROR) { return NGX_ERROR; } } return NGX_OK; }
void ngx_http_upstream_dbd_init(ngx_http_request_t *r) { ngx_connection_t *c; c = r->connection; ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, "http init upstream, client timer: %d", c->read->timer_set); if (c->read->timer_set) { ngx_del_timer(c->read); } if (ngx_event_flags & NGX_USE_CLEAR_EVENT) { if (!c->write->active) { if (ngx_add_event(c->write, NGX_WRITE_EVENT, NGX_CLEAR_EVENT) == NGX_ERROR) { ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); return; } } } ngx_http_upstream_dbd_init_request(r); }
// 遍历监听端口列表,加入epoll连接事件,开始接受请求 static ngx_int_t ngx_enable_accept_events(ngx_cycle_t *cycle) { ngx_uint_t i; ngx_listening_t *ls; ngx_connection_t *c; // 遍历监听端口列表 ls = cycle->listening.elts; for (i = 0; i < cycle->listening.nelts; i++) { c = ls[i].connection; // 如果连接已经监听(读事件激活)那么就跳过 // rtsig在nginx 1.9.x已经删除 if (c == NULL || c->read->active) { continue; } // #define ngx_add_event ngx_event_actions.add // 加入读事件,即接受连接事件 if (ngx_add_event(c->read, NGX_READ_EVENT, 0) == NGX_ERROR) { return NGX_ERROR; } } return NGX_OK; }
static ngx_int_t ngx_enable_accept_events(ngx_cycle_t *cycle) { ngx_uint_t i; ngx_listening_t *ls; ngx_connection_t *c; ls = cycle->listening.elts; for (i = 0; i < cycle->listening.nelts; i++) { c = ls[i].connection; if (ngx_event_flags & NGX_USE_RTSIG_EVENT) { if (ngx_add_conn(c) == NGX_ERROR) { return NGX_ERROR; } } else { if (ngx_add_event(c->read, NGX_READ_EVENT, 0) == NGX_ERROR) { return NGX_ERROR; } } } return NGX_OK; }
static void ngx_lcb_upstream_init(ngx_http_request_t *r) { ngx_http_core_loc_conf_t *clcf; ngx_lcb_connection_t *conn; ngx_connection_t *c; c = r->connection; if (c->read->timer_set) { ngx_del_timer(c->read); } if (ngx_event_flags & NGX_USE_CLEAR_EVENT) { if (!c->write->active) { if (ngx_add_event(c->write, NGX_WRITE_EVENT, NGX_CLEAR_EVENT) == NGX_ERROR) { ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); return; } } } clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); conn = ngx_http_get_couchbase_connection(clcf->name); if (conn == NULL) { ngx_log_error(NGX_LOG_ERR, c->log, 0, "couchbase: connection not found: \"%V\"", &clcf->name); ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); return; } if (conn->connected) { /* the instance has been connected */ ngx_log_debug3(NGX_LOG_DEBUG_HTTP, c->log, 0, "couchbase(%p): connection to \"%s:%s\" ready. process request", (void *)conn->lcb, lcb_get_host(conn->lcb), lcb_get_port(conn->lcb)); ngx_lcb_process(r); } else { lcb_error_t err; ngx_http_request_t **rp; rp = ngx_array_push(&conn->backlog); if (rp == NULL) { ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); return; } *rp = r; if (!conn->connect_scheduled) { ngx_log_debug3(NGX_LOG_DEBUG_HTTP, c->log, 0, "couchbase(%p): connecting to \"%s:%s\"", (void *)conn->lcb, lcb_get_host(conn->lcb), lcb_get_port(conn->lcb)); err = lcb_connect(conn->lcb); if (err != LCB_SUCCESS) { ngx_log_error(NGX_LOG_EMERG, c->log, 0, "couchbase(%p): failed to initiate connection: 0x%02xd \"%s\"", conn->lcb, err, lcb_strerror(NULL, err)); ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); return; } conn->connect_scheduled = 1; } } }
static void ngx_http_push_channel_handler(ngx_event_t *ev) { //copypasta from os/unix/ngx_process_cycle.c (ngx_channel_handler) ngx_int_t n; ngx_channel_t ch; ngx_connection_t *c; if (ev->timedout) { ev->timedout = 0; return; } c = ev->data; while(1) { n = ngx_read_channel(c->fd, &ch, sizeof(ch), ev->log); if (n == NGX_ERROR) { if (ngx_event_flags & NGX_USE_EPOLL_EVENT) { ngx_del_conn(c, 0); } ngx_close_connection(c); return; } if ((ngx_event_flags & NGX_USE_EVENTPORT_EVENT) && (ngx_add_event(ev, NGX_READ_EVENT, 0) == NGX_ERROR)) { return; } if (n == NGX_AGAIN) { return; } //ngx_log_debug1(NGX_LOG_DEBUG_CORE, ev->log, 0, "push module: channel command: %d", ch.command); if (ch.command==NGX_CMD_HTTP_PUSH_CHECK_MESSAGES) { ngx_http_push_store->receive_worker_message(); } } }
static void ngx_open_file_add_event(ngx_open_file_cache_t *cache, ngx_cached_open_file_t *file, ngx_open_file_info_t *of, ngx_log_t *log) { ngx_open_file_cache_event_t *fev; if (!(ngx_event_flags & NGX_USE_VNODE_EVENT) || !of->events || file->event || of->fd == NGX_INVALID_FILE || file->uses < of->min_uses) { return; } file->event = ngx_calloc(sizeof(ngx_event_t), log); if (file->event== NULL) { return; } fev = ngx_alloc(sizeof(ngx_open_file_cache_event_t), log); if (fev == NULL) { ngx_free(file->event); file->event = NULL; return; } fev->fd = of->fd; fev->file = file; fev->cache = cache; file->event->handler = ngx_open_file_cache_remove; file->event->data = fev; /* * although vnode event may be called while ngx_cycle->poll * destruction, however, cleanup procedures are run before any * memory freeing and events will be canceled. */ file->event->log = ngx_cycle->log; if (ngx_add_event(file->event, NGX_VNODE_EVENT, NGX_ONESHOT_EVENT) != NGX_OK) { ngx_free(file->event->data); ngx_free(file->event); file->event = NULL; return; } /* * we do not file->use_event here because there may be a race * condition between opening file and adding event, so we rely * upon event notification only after first file revalidation */ return; }
void redis_nginx_add_write(void *privdata) { ngx_connection_t *connection = (ngx_connection_t *) privdata; if (!connection->write->active && redis_nginx_fd_is_valid(connection->fd)) { connection->write->handler = redis_nginx_write_event; connection->write->log = connection->log; if (ngx_add_event(connection->write, NGX_WRITE_EVENT, NGX_CLEAR_EVENT) == NGX_ERROR) { ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0, "redis_nginx_adapter: could not add write event to redis"); } } }
ngx_int_t ngx_add_channel_event(ngx_cycle_t *cycle, ngx_fd_t fd, ngx_int_t event, ngx_event_handler_pt handler) { syslog(LOG_INFO, "[%s:%s:%d]\n", __FILE__, __func__, __LINE__); ngx_event_t *ev, *rev, *wev; ngx_connection_t *c; c = ngx_get_connection(fd, cycle->log); if (c == NULL) { return NGX_ERROR; } c->pool = cycle->pool; rev = c->read; wev = c->write; rev->log = cycle->log; wev->log = cycle->log; #if (NGX_THREADS) rev->lock = &c->lock; wev->lock = &c->lock; rev->own_lock = &c->lock; wev->own_lock = &c->lock; #endif rev->channel = 1; wev->channel = 1; ev = (event == NGX_READ_EVENT) ? rev : wev; ev->handler = handler; if (ngx_add_conn && (ngx_event_flags & NGX_USE_EPOLL_EVENT) == 0) { if (ngx_add_conn(c) == NGX_ERROR) { ngx_free_connection(c); return NGX_ERROR; } } else { if (ngx_add_event(ev, event, 0) == NGX_ERROR) { ngx_free_connection(c); return NGX_ERROR; } } return NGX_OK; }
ngx_http_cache_add_file_event(ngx_http_cache_hash_t *hash, ngx_http_cache_t *cache) { ngx_event_t *ev; ngx_http_cache_event_ctx_t *ctx; ev = &ngx_cycle->read_events[fd]; ngx_memzero(ev, sizeof(ngx_event_t); ev->data = data; ev->event_handler = ngx_http_cache_invalidate; return ngx_add_event(ev, NGX_VNODE_EVENT, 0); }
static ngx_connection_t* init_dummy_conn(void *data, int fd, ngx_event_handler_pt readhandler) { ngx_connection_t *c = calloc(1,sizeof(ngx_connection_t)); if (c == NULL) { ngx_log_error(NGX_LOG_ERR, pcycle->log, 0, "calloc ngx_connection_t failed"); return NULL; } c->read = calloc(1,sizeof(ngx_event_t)); if (c->read == NULL) { ngx_log_error(NGX_LOG_ERR, pcycle->log, 0, "calloc ngx_event_t failed"); free(c); return NULL; } c->write = calloc(1,sizeof(ngx_event_t)); if (c->write == NULL) { ngx_log_error(NGX_LOG_ERR, pcycle->log, 0, "calloc ngx_event_t failed"); free(c->read); free(c); return NULL; } if (ngx_nonblocking(fd) == -1) { ngx_log_error(NGX_LOG_ALERT, pcycle->log, errno, "init_dummy_conn ngx_nonblocking failed"); } c->fd = fd; c->data = data; c->log = pcycle->log; c->read->data = c; c->read->log = pcycle->log; c->read->handler = readhandler; c->write->data = c; c->write->log = pcycle->log; c->write->handler = dummy_write_handler; if (ngx_add_event(c->read, NGX_READ_EVENT, 0) == NGX_ERROR) { ngx_log_error(NGX_LOG_INFO, pcycle->log, 0, "add dummy conn read event failed"); free(c->read); free(c->write); free(c); return NULL; } return c; }
/* Make sure the event handlers are activated. */ static ngx_int_t ngx_http_gettoken_restore_handlers(ngx_connection_t *conn) { ngx_int_t rc; ngx_log_debug2(NGX_LOG_DEBUG_HTTP, conn->log, 0, "http_gettoken: Restoring event handlers. read=%d write=%d", conn->read->active, conn->write->active); if (!conn->read->active) { rc = ngx_add_event(conn->read, NGX_READ_EVENT, 0); if (rc != NGX_OK) { return rc; } } if (!conn->write->active && (conn->write->handler != ngx_http_gettoken_dummy_write_handler)) { rc = ngx_add_event(conn->write, NGX_WRITE_EVENT, 0); if (rc != NGX_OK) { return rc; } } return NGX_OK; }
ngx_int_t ngx_add_channel_event(ngx_cycle_t *cycle, ngx_fd_t fd, ngx_int_t event, ngx_event_handler_pt handler) { ngx_event_t *ev, *rev, *wev; ngx_connection_t *c; c = ngx_get_connection(fd, cycle->log); if (c == NULL) { return NGX_ERROR; } c->pool = cycle->pool; rev = c->read; wev = c->write; rev->log = cycle->log; wev->log = cycle->log; rev->channel = 1; wev->channel = 1; ev = (event == NGX_READ_EVENT) ? rev : wev; ev->handler = handler; if (ngx_add_conn && (ngx_event_flags & NGX_USE_EPOLL_EVENT) == 0) { if (ngx_add_conn(c) == NGX_ERROR) { ngx_free_connection(c); return NGX_ERROR; } } else { if (ngx_add_event(ev, event, 0) == NGX_ERROR) { ngx_free_connection(c); return NGX_ERROR; } } return NGX_OK; }
static void ngx_http_push_stream_channel_handler(ngx_event_t *ev) { // copypaste from os/unix/ngx_process_cycle.c (ngx_channel_handler) ngx_int_t n; ngx_channel_t ch; ngx_connection_t *c; if (ev->timedout) { ev->timedout = 0; return; } c = ev->data; while (1) { n = ngx_read_channel(c->fd, &ch, sizeof(ch), ev->log); if (n == NGX_ERROR) { if (ngx_event_flags & NGX_USE_EPOLL_EVENT) { ngx_del_conn(c, 0); } ngx_close_connection(c); return; } if ((ngx_event_flags & NGX_USE_EVENTPORT_EVENT) && (ngx_add_event(ev, NGX_READ_EVENT, 0) == NGX_ERROR)) { return; } if (n == NGX_AGAIN) { return; } if (ch.command == NGX_CMD_HTTP_PUSH_STREAM_CHECK_MESSAGES.command) { ngx_http_push_stream_process_worker_message(); } else if (ch.command == NGX_CMD_HTTP_PUSH_STREAM_CENSUS_SUBSCRIBERS.command) { ngx_http_push_stream_census_worker_subscribers(); } else if (ch.command == NGX_CMD_HTTP_PUSH_STREAM_DELETE_CHANNEL.command) { ngx_http_push_stream_delete_worker_channel(); } } }
ngx_int_t ipc_register_worker(ipc_t *ipc, ngx_cycle_t *cycle) { int i; ngx_connection_t *c; ipc_process_t *proc; for(i=0; i< NGX_MAX_PROCESSES; i++) { proc = &ipc->process[i]; if(!proc->active) continue; assert(proc->pipe[0] != NGX_INVALID_FILE); assert(proc->pipe[1] != NGX_INVALID_FILE); if(i==ngx_process_slot) { //set up read connection c = ngx_get_connection(proc->pipe[0], cycle->log); c->data = ipc; c->read->handler = ipc_read_handler; c->read->log = cycle->log; c->write->handler = NULL; ngx_add_event(c->read, NGX_READ_EVENT, 0); proc->c=c; } else { //set up write connection c = ngx_get_connection(proc->pipe[1], cycle->log); c->data = proc; c->read->handler = NULL; c->write->log = cycle->log; c->write->handler = ipc_write_handler; proc->c=c; } } return NGX_OK; }
/* 将监听socket连接的读事件加入到监听事件中 */ static ngx_int_t ngx_enable_accept_events(ngx_cycle_t *cycle) { ngx_uint_t i; ngx_listening_t *ls; ngx_connection_t *c; /* 获取监听数组的首地址 */ ls = cycle->listening.elts; /* 遍历整个监听数组 */ for (i = 0; i < cycle->listening.nelts; i++) { /* 获取当前监听socket所对应的连接 */ c = ls[i].connection; /* 当前连接的读事件是否处于active活跃状态 */ if (c->read->active) { /* 若是处于active状态,表示该连接的读事件已经在事件监控对象中 */ continue; } /* 若当前连接没有加入到事件监控对象中,则将该链接注册到事件监控中 */ if (ngx_event_flags & NGX_USE_RTSIG_EVENT) { if (ngx_add_conn(c) == NGX_ERROR) { return NGX_ERROR; } } else { /* 若当前连接的读事件不在事件监控对象中,则将其加入 */ if (ngx_add_event(c->read, NGX_READ_EVENT, 0) == NGX_ERROR) { return NGX_ERROR; } } } return NGX_OK; }
static ngx_int_t ngx_enable_accept_events(ngx_cycle_t *cycle) { ngx_uint_t i; ngx_listening_t *ls; ngx_connection_t *c; ls = cycle->listening.elts; /* 注意:这里的循环会把所有的listening加入到了epoll中,那不是每个进程都会把所有的listening加入到epoll中吗,不是有惊群了吗? 答案:实际上在本进程ngx_enable_accept_events把所有listen加入本进程epoll中后,本进程获取到ngx_accept_mutex锁后,在执行accept事件的 过程中如果如果其他进程也开始ngx_trylock_accept_mutex,如果之前已经获取到锁,并把所有的listen添加到了epoll中,这时会因为没法获取到 accept锁,而把之前加入到本进程,但没有accept过的时间全部清除。和ngx_disable_accept_events配合使用 最终只有一个进程能accept到同一个客户端连接 */ for (i = 0; i < cycle->listening.nelts; i++) { c = ls[i].connection; //后面的ngx_add_event->ngx_epoll_add_event中把listening中的c->read->active置1, ngx_epoll_del_event中把listening中置read->active置0 if (c == NULL || c->read->active) { //之前本进程已经accept成功的连接,不用再加入epoll事件中,避免重复 continue; } char tmpbuf[256]; snprintf(tmpbuf, sizeof(tmpbuf), "<%25s, %5d> epoll NGX_READ_EVENT(et) read add", NGX_FUNC_LINE); ngx_log_debug0(NGX_LOG_DEBUG_EVENT, cycle->log, 0, tmpbuf); if (ngx_add_event(c->read, NGX_READ_EVENT, 0) == NGX_ERROR) { //ngx_epoll_add_event return NGX_ERROR; } } return NGX_OK; }
ngx_int_t ngx_zeromq_connect(ngx_peer_connection_t *pc) { ngx_connection_t *c; ngx_event_t *rev, *wev; void *zmq; int fd, zero; size_t fdsize; zmq = zmq_socket(zmq_context, ZMQ_REQ); if (zmq == NULL) { ngx_zeromq_log_error(pc->log, "zmq_socket(ZMQ_REQ)"); return NGX_ERROR; } fdsize = sizeof(int); if (zmq_getsockopt(zmq, ZMQ_FD, &fd, &fdsize) == -1) { ngx_zeromq_log_error(pc->log, "zmq_getsockopt(ZMQ_FD)"); goto failed_zmq; } zero = 0; if (zmq_setsockopt(zmq, ZMQ_LINGER, &zero, sizeof(int)) == -1) { ngx_zeromq_log_error(pc->log, "zmq_setsockopt(ZMQ_LINGER)"); goto failed_zmq; } c = ngx_get_connection(fd, pc->log); if (c == NULL) { goto failed_zmq; } c->data = zmq; c->recv = ngx_zeromq_recv; c->send = ngx_zeromq_send; c->recv_chain = ngx_zeromq_recv_chain; c->send_chain = ngx_zeromq_send_chain; /* This won't fly with ZeroMQ */ c->sendfile = 0; c->tcp_nopush = NGX_TCP_NOPUSH_DISABLED; c->tcp_nodelay = NGX_TCP_NODELAY_DISABLED; c->log_error = pc->log_error; rev = c->read; wev = c->write; rev->log = pc->log; wev->log = pc->log; pc->connection = c; c->number = ngx_atomic_fetch_add(ngx_connection_counter, 1); if (pc->local) { ngx_log_error(NGX_LOG_WARN, pc->log, 0, "zmq_connect: binding to local address is not supported"); } if (zmq_connect(zmq, (const char *) pc->data) == -1) { ngx_zeromq_log_error(pc->log, "zmq_connect()"); goto failed; } ngx_log_debug4(NGX_LOG_DEBUG_EVENT, pc->log, 0, "zmq_connect: lazily connected to tcp://%V," " zmq:%p fd:%d #%d", pc->name, zmq, fd, c->number); if (ngx_add_conn) { /* rtsig */ if (ngx_add_conn(c) == NGX_ERROR) { goto failed; } } else { if (ngx_event_flags & NGX_USE_CLEAR_EVENT) { /* kqueue, epoll */ if (ngx_add_event(rev, NGX_READ_EVENT, NGX_CLEAR_EVENT) != NGX_OK) { goto failed; } } else { /* select, poll, /dev/poll */ if (ngx_add_event(rev, NGX_READ_EVENT, NGX_LEVEL_EVENT) != NGX_OK) { goto failed; } } } /* * ZeroMQ assumes that new socket is read-ready (but it really isn't) * and it won't notify us about any new events if we don't fail to read * from it first. Sigh. */ rev->ready = 1; wev->ready = 1; return NGX_OK; failed: ngx_free_connection(c); c->fd = (ngx_socket_t) -1; failed_zmq: if (zmq_close(zmq) == -1) { ngx_zeromq_log_error(pc->log, "zmq_close()"); } return NGX_ERROR; }
static ngx_int_t ngx_event_process_init(ngx_cycle_t *cycle) { ngx_uint_t m, i; ngx_event_t *rev, *wev; ngx_listening_t *ls; ngx_connection_t *c, *next, *old; ngx_core_conf_t *ccf; ngx_event_conf_t *ecf; ngx_event_module_t *module; ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module); ecf = ngx_event_get_conf(cycle->conf_ctx, ngx_event_core_module); if (ccf->master && ccf->worker_processes > 1 && ecf->accept_mutex) { ngx_use_accept_mutex = 1; ngx_accept_mutex_held = 0; ngx_accept_mutex_delay = ecf->accept_mutex_delay; } else { ngx_use_accept_mutex = 0; } #if (NGX_WIN32) /* * disable accept mutex on win32 as it may cause deadlock if * grabbed by a process which can't accept connections */ ngx_use_accept_mutex = 0; #endif #if (NGX_THREADS) ngx_posted_events_mutex = ngx_mutex_init(cycle->log, 0); if (ngx_posted_events_mutex == NULL) { return NGX_ERROR; } #endif if (ngx_event_timer_init(cycle->log) == NGX_ERROR) { return NGX_ERROR; } for (m = 0; ngx_modules[m]; m++) { if (ngx_modules[m]->type != NGX_EVENT_MODULE) { continue; } if (ngx_modules[m]->ctx_index != ecf->use) { continue; } module = ngx_modules[m]->ctx; if (module->actions.init(cycle, ngx_timer_resolution) != NGX_OK) { /* fatal */ exit(2); } break; } #if !(NGX_WIN32) if (ngx_timer_resolution && !(ngx_event_flags & NGX_USE_TIMER_EVENT)) { struct sigaction sa; struct itimerval itv; ngx_memzero(&sa, sizeof(struct sigaction)); sa.sa_handler = ngx_timer_signal_handler; sigemptyset(&sa.sa_mask); if (sigaction(SIGALRM, &sa, NULL) == -1) { ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, "sigaction(SIGALRM) failed"); return NGX_ERROR; } itv.it_interval.tv_sec = ngx_timer_resolution / 1000; itv.it_interval.tv_usec = (ngx_timer_resolution % 1000) * 1000; itv.it_value.tv_sec = ngx_timer_resolution / 1000; itv.it_value.tv_usec = (ngx_timer_resolution % 1000 ) * 1000; if (setitimer(ITIMER_REAL, &itv, NULL) == -1) { ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, "setitimer() failed"); } } if (ngx_event_flags & NGX_USE_FD_EVENT) { struct rlimit rlmt; if (getrlimit(RLIMIT_NOFILE, &rlmt) == -1) { ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, "getrlimit(RLIMIT_NOFILE) failed"); return NGX_ERROR; } cycle->files_n = (ngx_uint_t) rlmt.rlim_cur; cycle->files = ngx_calloc(sizeof(ngx_connection_t *) * cycle->files_n, cycle->log); if (cycle->files == NULL) { return NGX_ERROR; } } #endif cycle->connections = ngx_alloc(sizeof(ngx_connection_t) * cycle->connection_n, cycle->log); if (cycle->connections == NULL) { return NGX_ERROR; } c = cycle->connections; cycle->read_events = ngx_alloc(sizeof(ngx_event_t) * cycle->connection_n, cycle->log); if (cycle->read_events == NULL) { return NGX_ERROR; } rev = cycle->read_events; for (i = 0; i < cycle->connection_n; i++) { rev[i].closed = 1; rev[i].instance = 1; #if (NGX_THREADS) rev[i].lock = &c[i].lock; rev[i].own_lock = &c[i].lock; #endif } cycle->write_events = ngx_alloc(sizeof(ngx_event_t) * cycle->connection_n, cycle->log); if (cycle->write_events == NULL) { return NGX_ERROR; } wev = cycle->write_events; for (i = 0; i < cycle->connection_n; i++) { wev[i].closed = 1; #if (NGX_THREADS) wev[i].lock = &c[i].lock; wev[i].own_lock = &c[i].lock; #endif } i = cycle->connection_n; next = NULL; do { i--; c[i].data = next; c[i].read = &cycle->read_events[i]; c[i].write = &cycle->write_events[i]; c[i].fd = (ngx_socket_t) -1; next = &c[i]; #if (NGX_THREADS) c[i].lock = 0; #endif } while (i); cycle->free_connections = next; cycle->free_connection_n = cycle->connection_n; /* for each listening socket */ ls = cycle->listening.elts; for (i = 0; i < cycle->listening.nelts; i++) { c = ngx_get_connection(ls[i].fd, cycle->log); if (c == NULL) { return NGX_ERROR; } c->log = &ls[i].log; c->listening = &ls[i]; ls[i].connection = c; rev = c->read; rev->log = c->log; rev->accept = 1; #if (NGX_HAVE_DEFERRED_ACCEPT) rev->deferred_accept = ls[i].deferred_accept; #endif if (!(ngx_event_flags & NGX_USE_IOCP_EVENT)) { if (ls[i].previous) { /* * delete the old accept events that were bound to * the old cycle read events array */ old = ls[i].previous->connection; if (ngx_del_event(old->read, NGX_READ_EVENT, NGX_CLOSE_EVENT) == NGX_ERROR) { return NGX_ERROR; } old->fd = (ngx_socket_t) -1; } } #if (NGX_WIN32) if (ngx_event_flags & NGX_USE_IOCP_EVENT) { ngx_iocp_conf_t *iocpcf; rev->handler = ngx_event_acceptex; if (ngx_use_accept_mutex) { continue; } if (ngx_add_event(rev, 0, NGX_IOCP_ACCEPT) == NGX_ERROR) { return NGX_ERROR; } ls[i].log.handler = ngx_acceptex_log_error; iocpcf = ngx_event_get_conf(cycle->conf_ctx, ngx_iocp_module); if (ngx_event_post_acceptex(&ls[i], iocpcf->post_acceptex) == NGX_ERROR) { return NGX_ERROR; } } else { rev->handler = ngx_event_accept; if (ngx_use_accept_mutex) { continue; } if (ngx_add_event(rev, NGX_READ_EVENT, 0) == NGX_ERROR) { return NGX_ERROR; } } #else rev->handler = ngx_event_accept; if (ngx_use_accept_mutex) { continue; } if (ngx_event_flags & NGX_USE_RTSIG_EVENT) { if (ngx_add_conn(c) == NGX_ERROR) { return NGX_ERROR; } } else { if (ngx_add_event(rev, NGX_READ_EVENT, 0) == NGX_ERROR) { return NGX_ERROR; } } #endif } return NGX_OK; }
ngx_int_t ngx_event_connect_peer(ngx_peer_connection_t *pc) { int rc, type; #if (NGX_HAVE_IP_BIND_ADDRESS_NO_PORT || NGX_LINUX) in_port_t port; #endif ngx_int_t event; ngx_err_t err; ngx_uint_t level; ngx_socket_t s; ngx_event_t *rev, *wev; ngx_connection_t *c; rc = pc->get(pc, pc->data); if (rc != NGX_OK) { return rc; } type = (pc->type ? pc->type : SOCK_STREAM); s = ngx_socket(pc->sockaddr->sa_family, type, 0); ngx_log_debug2(NGX_LOG_DEBUG_EVENT, pc->log, 0, "%s socket %d", (type == SOCK_STREAM) ? "stream" : "dgram", s); if (s == (ngx_socket_t) -1) { ngx_log_error(NGX_LOG_ALERT, pc->log, ngx_socket_errno, ngx_socket_n " failed"); return NGX_ERROR; } c = ngx_get_connection(s, pc->log); if (c == NULL) { if (ngx_close_socket(s) == -1) { ngx_log_error(NGX_LOG_ALERT, pc->log, ngx_socket_errno, ngx_close_socket_n "failed"); } return NGX_ERROR; } c->type = type; if (pc->rcvbuf) { if (setsockopt(s, SOL_SOCKET, SO_RCVBUF, (const void *) &pc->rcvbuf, sizeof(int)) == -1) { ngx_log_error(NGX_LOG_ALERT, pc->log, ngx_socket_errno, "setsockopt(SO_RCVBUF) failed"); goto failed; } } if (ngx_nonblocking(s) == -1) { ngx_log_error(NGX_LOG_ALERT, pc->log, ngx_socket_errno, ngx_nonblocking_n " failed"); goto failed; } if (pc->local) { #if (NGX_HAVE_TRANSPARENT_PROXY) if (pc->transparent) { if (ngx_event_connect_set_transparent(pc, s) != NGX_OK) { goto failed; } } #endif #if (NGX_HAVE_IP_BIND_ADDRESS_NO_PORT || NGX_LINUX) port = ngx_inet_get_port(pc->local->sockaddr); #endif #if (NGX_HAVE_IP_BIND_ADDRESS_NO_PORT) if (pc->sockaddr->sa_family != AF_UNIX && port == 0) { static int bind_address_no_port = 1; if (bind_address_no_port) { if (setsockopt(s, IPPROTO_IP, IP_BIND_ADDRESS_NO_PORT, (const void *) &bind_address_no_port, sizeof(int)) == -1) { err = ngx_socket_errno; if (err != NGX_EOPNOTSUPP && err != NGX_ENOPROTOOPT) { ngx_log_error(NGX_LOG_ALERT, pc->log, err, "setsockopt(IP_BIND_ADDRESS_NO_PORT) " "failed, ignored"); } else { bind_address_no_port = 0; } } } } #endif #if (NGX_LINUX) if (pc->type == SOCK_DGRAM && port != 0) { int reuse_addr = 1; if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (const void *) &reuse_addr, sizeof(int)) == -1) { ngx_log_error(NGX_LOG_ALERT, pc->log, ngx_socket_errno, "setsockopt(SO_REUSEADDR) failed"); goto failed; } } #endif if (bind(s, pc->local->sockaddr, pc->local->socklen) == -1) { ngx_log_error(NGX_LOG_CRIT, pc->log, ngx_socket_errno, "bind(%V) failed", &pc->local->name); goto failed; } } if (type == SOCK_STREAM) { c->recv = ngx_recv; c->send = ngx_send; c->recv_chain = ngx_recv_chain; c->send_chain = ngx_send_chain; c->sendfile = 1; if (pc->sockaddr->sa_family == AF_UNIX) { c->tcp_nopush = NGX_TCP_NOPUSH_DISABLED; c->tcp_nodelay = NGX_TCP_NODELAY_DISABLED; #if (NGX_SOLARIS) /* Solaris's sendfilev() supports AF_NCA, AF_INET, and AF_INET6 */ c->sendfile = 0; #endif } } else { /* type == SOCK_DGRAM */ c->recv = ngx_udp_recv; c->send = ngx_send; c->send_chain = ngx_udp_send_chain; } c->log_error = pc->log_error; rev = c->read; wev = c->write; rev->log = pc->log; wev->log = pc->log; pc->connection = c; c->number = ngx_atomic_fetch_add(ngx_connection_counter, 1); if (ngx_add_conn) { if (ngx_add_conn(c) == NGX_ERROR) { goto failed; } } ngx_log_debug3(NGX_LOG_DEBUG_EVENT, pc->log, 0, "connect to %V, fd:%d #%uA", pc->name, s, c->number); rc = connect(s, pc->sockaddr, pc->socklen); if (rc == -1) { err = ngx_socket_errno; if (err != NGX_EINPROGRESS #if (NGX_WIN32) /* Winsock returns WSAEWOULDBLOCK (NGX_EAGAIN) */ && err != NGX_EAGAIN #endif ) { if (err == NGX_ECONNREFUSED #if (NGX_LINUX) /* * Linux returns EAGAIN instead of ECONNREFUSED * for unix sockets if listen queue is full */ || err == NGX_EAGAIN #endif || err == NGX_ECONNRESET || err == NGX_ENETDOWN || err == NGX_ENETUNREACH || err == NGX_EHOSTDOWN || err == NGX_EHOSTUNREACH) { level = NGX_LOG_ERR; } else { level = NGX_LOG_CRIT; } ngx_log_error(level, c->log, err, "connect() to %V failed", pc->name); ngx_close_connection(c); pc->connection = NULL; return NGX_DECLINED; } } if (ngx_add_conn) { if (rc == -1) { /* NGX_EINPROGRESS */ return NGX_AGAIN; } ngx_log_debug0(NGX_LOG_DEBUG_EVENT, pc->log, 0, "connected"); wev->ready = 1; return NGX_OK; } if (ngx_event_flags & NGX_USE_IOCP_EVENT) { ngx_log_debug1(NGX_LOG_DEBUG_EVENT, pc->log, ngx_socket_errno, "connect(): %d", rc); if (ngx_blocking(s) == -1) { ngx_log_error(NGX_LOG_ALERT, pc->log, ngx_socket_errno, ngx_blocking_n " failed"); goto failed; } /* * FreeBSD's aio allows to post an operation on non-connected socket. * NT does not support it. * * TODO: check in Win32, etc. As workaround we can use NGX_ONESHOT_EVENT */ rev->ready = 1; wev->ready = 1; return NGX_OK; } if (ngx_event_flags & NGX_USE_CLEAR_EVENT) { /* kqueue */ event = NGX_CLEAR_EVENT; } else { /* select, poll, /dev/poll */ event = NGX_LEVEL_EVENT; } if (ngx_add_event(rev, NGX_READ_EVENT, event) != NGX_OK) { goto failed; } if (rc == -1) { /* NGX_EINPROGRESS */ if (ngx_add_event(wev, NGX_WRITE_EVENT, event) != NGX_OK) { goto failed; } return NGX_AGAIN; } ngx_log_debug0(NGX_LOG_DEBUG_EVENT, pc->log, 0, "connected"); wev->ready = 1; return NGX_OK; failed: ngx_close_connection(c); pc->connection = NULL; return NGX_ERROR; }
/* * [analy] 加入读事件到epoll事件处理队列中(根据触发模式有不通的处理方式) */ ngx_int_t ngx_handle_read_event(ngx_event_t *rev, ngx_uint_t flags) { if (ngx_event_flags & NGX_USE_CLEAR_EVENT) { /* [analy] 使用edge triggered */ /* kqueue, epoll */ if (!rev->active && !rev->ready) { // 当此事件处于非活跃状态时(即没有被添加到epoll事件监控队列中时), rev->ready是此连接没有读事件到来 if (ngx_add_event(rev, NGX_READ_EVENT, NGX_CLEAR_EVENT) /* [analy] 调用ngx_epoll_add_event(), 当使用epoll时,宏NGX_CLEAR_EVENT被定义成 EPOLLET */ == NGX_ERROR) { return NGX_ERROR; } } return NGX_OK; } else if (ngx_event_flags & NGX_USE_LEVEL_EVENT) { /* [analy] 使用level triggered */ /* select, poll, /dev/poll */ if (!rev->active && !rev->ready) { if (ngx_add_event(rev, NGX_READ_EVENT, NGX_LEVEL_EVENT) == NGX_ERROR) { return NGX_ERROR; } return NGX_OK; } if (rev->active && (rev->ready || (flags & NGX_CLOSE_EVENT))) { if (ngx_del_event(rev, NGX_READ_EVENT, NGX_LEVEL_EVENT | flags) == NGX_ERROR) { return NGX_ERROR; } return NGX_OK; } } else if (ngx_event_flags & NGX_USE_EVENTPORT_EVENT) { /* event ports */ if (!rev->active && !rev->ready) { if (ngx_add_event(rev, NGX_READ_EVENT, 0) == NGX_ERROR) { return NGX_ERROR; } return NGX_OK; } if (rev->oneshot && !rev->ready) { if (ngx_del_event(rev, NGX_READ_EVENT, 0) == NGX_ERROR) { return NGX_ERROR; } return NGX_OK; } } /* aio, iocp, rtsig */ return NGX_OK; }
/* * [analy] 将写事件添加到事件处理队列中 * 参数 lowat: 如果大于0,将设置发送缓冲区的低潮阀值 */ ngx_int_t ngx_handle_write_event(ngx_event_t *wev, size_t lowat) { ngx_connection_t *c; if (lowat) { // 设置发送缓冲区的低潮阀值 c = wev->data; if (ngx_send_lowat(c, lowat) == NGX_ERROR) { return NGX_ERROR; } } if (ngx_event_flags & NGX_USE_CLEAR_EVENT) { // 使用edge triggered 模式 /* kqueue, epoll */ // 此事件未加入epoll事件队列中时,将添加写事件。 if (!wev->active && !wev->ready) { if (ngx_add_event(wev, NGX_WRITE_EVENT, NGX_CLEAR_EVENT | (lowat ? NGX_LOWAT_EVENT : 0)) // NGX_CLEAR_EVENT = EPOLLET == NGX_ERROR) { return NGX_ERROR; } } return NGX_OK; } else if (ngx_event_flags & NGX_USE_LEVEL_EVENT) { // 使用level triggerred模式 /* select, poll, /dev/poll */ if (!wev->active && !wev->ready) { if (ngx_add_event(wev, NGX_WRITE_EVENT, NGX_LEVEL_EVENT) == NGX_ERROR) { return NGX_ERROR; } return NGX_OK; } if (wev->active && wev->ready) { if (ngx_del_event(wev, NGX_WRITE_EVENT, NGX_LEVEL_EVENT) == NGX_ERROR) { return NGX_ERROR; } return NGX_OK; } } else if (ngx_event_flags & NGX_USE_EVENTPORT_EVENT) { /* event ports */ if (!wev->active && !wev->ready) { if (ngx_add_event(wev, NGX_WRITE_EVENT, 0) == NGX_ERROR) { return NGX_ERROR; } return NGX_OK; } if (wev->oneshot && wev->ready) { if (ngx_del_event(wev, NGX_WRITE_EVENT, 0) == NGX_ERROR) { return NGX_ERROR; } return NGX_OK; } } /* aio, iocp, rtsig */ return NGX_OK; }
static void ngx_channel_handler(ngx_event_t *ev) { ngx_int_t n; ngx_channel_t ch; ngx_connection_t *c; if (ev->timedout) { ev->timedout = 0; return; } c = ev->data; ngx_log_debug0(NGX_LOG_DEBUG_CORE, ev->log, 0, "channel handler"); for ( ;; ) { n = ngx_read_channel(c->fd, &ch, sizeof(ngx_channel_t), ev->log); ngx_log_debug1(NGX_LOG_DEBUG_CORE, ev->log, 0, "channel: %i", n); if (n == NGX_ERROR) { if (ngx_event_flags & NGX_USE_EPOLL_EVENT) { ngx_del_conn(c, 0); } ngx_close_connection(c); return; } if (ngx_event_flags & NGX_USE_EVENTPORT_EVENT) { if (ngx_add_event(ev, NGX_READ_EVENT, 0) == NGX_ERROR) { return; } } if (n == NGX_AGAIN) { return; } ngx_log_debug1(NGX_LOG_DEBUG_CORE, ev->log, 0, "channel command: %d", ch.command); switch (ch.command) { case NGX_CMD_QUIT: ngx_quit = 1; break; case NGX_CMD_TERMINATE: ngx_terminate = 1; break; case NGX_CMD_REOPEN: ngx_reopen = 1; break; case NGX_CMD_OPEN_CHANNEL: ngx_log_debug3(NGX_LOG_DEBUG_CORE, ev->log, 0, "get channel s:%i pid:%P fd:%d", ch.slot, ch.pid, ch.fd); ngx_processes[ch.slot].pid = ch.pid; ngx_processes[ch.slot].channel[0] = ch.fd; break; case NGX_CMD_CLOSE_CHANNEL: ngx_log_debug4(NGX_LOG_DEBUG_CORE, ev->log, 0, "close channel s:%i pid:%P our:%P fd:%d", ch.slot, ch.pid, ngx_processes[ch.slot].pid, ngx_processes[ch.slot].channel[0]); if (close(ngx_processes[ch.slot].channel[0]) == -1) { ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_errno, "close() channel failed"); } ngx_processes[ch.slot].channel[0] = -1; break; } } }
static ngx_int_t ngx_http_lua_udp_connect(ngx_udp_connection_t *uc) { int rc; ngx_int_t event; ngx_event_t *rev, *wev; ngx_socket_t s; ngx_connection_t *c; s = ngx_socket(uc->sockaddr->sa_family, SOCK_DGRAM, 0); ngx_log_debug1(NGX_LOG_DEBUG_EVENT, &uc->log, 0, "UDP socket %d", s); if (s == -1) { ngx_log_error(NGX_LOG_ALERT, &uc->log, ngx_socket_errno, ngx_socket_n " failed"); return NGX_ERROR; } c = ngx_get_connection(s, &uc->log); if (c == NULL) { if (ngx_close_socket(s) == -1) { ngx_log_error(NGX_LOG_ALERT, &uc->log, ngx_socket_errno, ngx_close_socket_n "failed"); } return NGX_ERROR; } if (ngx_nonblocking(s) == -1) { ngx_log_error(NGX_LOG_ALERT, &uc->log, ngx_socket_errno, ngx_nonblocking_n " failed"); ngx_free_connection(c); if (ngx_close_socket(s) == -1) { ngx_log_error(NGX_LOG_ALERT, &uc->log, ngx_socket_errno, ngx_close_socket_n " failed"); } return NGX_ERROR; } rev = c->read; wev = c->write; rev->log = &uc->log; wev->log = &uc->log; uc->connection = c; c->number = ngx_atomic_fetch_add(ngx_connection_counter, 1); #if (NGX_THREADS) /* TODO: lock event when call completion handler */ rev->lock = &c->lock; wev->lock = &c->lock; rev->own_lock = &c->lock; wev->own_lock = &c->lock; #endif #if (NGX_HTTP_LUA_HAVE_SO_PASSCRED) if (uc->sockaddr->sa_family == AF_UNIX) { struct sockaddr addr; addr.sa_family = AF_UNIX; /* just to make valgrind happy */ ngx_memzero(addr.sa_data, sizeof(addr.sa_data)); ngx_log_debug0(NGX_LOG_DEBUG_EVENT, &uc->log, 0, "datagram unix " "domain socket autobind"); if (bind(uc->connection->fd, &addr, sizeof(sa_family_t)) != 0) { ngx_log_error(NGX_LOG_CRIT, &uc->log, ngx_socket_errno, "bind() failed"); return NGX_ERROR; } } #endif ngx_log_debug3(NGX_LOG_DEBUG_EVENT, &uc->log, 0, "connect to %V, fd:%d #%d", &uc->server, s, c->number); rc = connect(s, uc->sockaddr, uc->socklen); /* TODO: aio, iocp */ if (rc == -1) { ngx_log_error(NGX_LOG_CRIT, &uc->log, ngx_socket_errno, "connect() failed"); return NGX_ERROR; } /* UDP sockets are always ready to write */ wev->ready = 1; if (ngx_add_event) { event = (ngx_event_flags & NGX_USE_CLEAR_EVENT) ? /* kqueue, epoll */ NGX_CLEAR_EVENT: /* select, poll, /dev/poll */ NGX_LEVEL_EVENT; /* eventport event type has no meaning: oneshot only */ if (ngx_add_event(rev, NGX_READ_EVENT, event) != NGX_OK) { return NGX_ERROR; } } else { /* rtsig */ if (ngx_add_conn(c) == NGX_ERROR) { return NGX_ERROR; } } return NGX_OK; }
static ngx_int_t ngx_rtmp_exec_run(ngx_rtmp_exec_t *e) { #if !(NGX_WIN32) ngx_pid_t pid; int fd, maxfd; int pipefd[2]; int ret; ngx_rtmp_exec_conf_t *ec; ngx_str_t *arg, a; char **args; ngx_uint_t n; ec = e->conf; ngx_log_debug1(NGX_LOG_DEBUG_RTMP, e->log, 0, "exec: starting child '%V'", &ec->cmd); if (e->active) { ngx_log_debug1(NGX_LOG_DEBUG_RTMP, e->log, 0, "exec: already active '%V'", &ec->cmd); return NGX_OK; } if (pipe(pipefd) == -1) { ngx_log_error(NGX_LOG_INFO, e->log, ngx_errno, "exec: pipe failed"); return NGX_ERROR; } /* make pipe write end survive through exec */ ret = fcntl(pipefd[1], F_GETFD); if (ret != -1) { ret &= ~FD_CLOEXEC; ret = fcntl(pipefd[1], F_SETFD, ret); } if (ret == -1) { close(pipefd[0]); close(pipefd[1]); ngx_log_error(NGX_LOG_INFO, e->log, ngx_errno, "exec: fcntl failed"); return NGX_ERROR; } pid = fork(); switch (pid) { case -1: close(pipefd[0]); close(pipefd[1]); ngx_log_error(NGX_LOG_INFO, e->log, ngx_errno, "exec: fork failed"); return NGX_ERROR; case 0: /* child */ #if (NGX_LINUX) prctl(PR_SET_PDEATHSIG, e->kill_signal, 0, 0, 0); #endif /* close all descriptors but pipe write end */ maxfd = sysconf(_SC_OPEN_MAX); for (fd = 0; fd < maxfd; ++fd) { if (fd == pipefd[1]) { continue; } close(fd); } fd = open("/dev/null", O_RDWR); dup2(fd, STDIN_FILENO); dup2(fd, STDOUT_FILENO); dup2(fd, STDERR_FILENO); args = ngx_alloc((ec->args.nelts + 2) * sizeof(char *), e->log); if (args == NULL) { exit(1); } arg = ec->args.elts; args[0] = (char *) ec->cmd.data; for (n = 0; n < ec->args.nelts; ++n, ++arg) { if (e->session == NULL) { a = *arg; } else { ngx_rtmp_eval(e->session, arg, ngx_rtmp_exec_eval_p, &a); } args[n + 1] = (char *) a.data; } args[n + 1] = NULL; if (execvp((char *) ec->cmd.data, args) == -1) { exit(1); } break; default: /* parent */ close(pipefd[1]); e->active = 1; e->pid = pid; e->pipefd = pipefd[0]; if (e->save_pid) { *e->save_pid = pid; } e->dummy_conn.fd = e->pipefd; e->dummy_conn.data = e; e->dummy_conn.read = &e->read_evt; e->dummy_conn.write = &e->write_evt; e->read_evt.data = &e->dummy_conn; e->write_evt.data = &e->dummy_conn; e->read_evt.log = e->log; e->read_evt.handler = ngx_rtmp_exec_child_dead; if (ngx_add_event(&e->read_evt, NGX_READ_EVENT, 0) != NGX_OK) { ngx_log_error(NGX_LOG_INFO, e->log, ngx_errno, "exec: failed to add child control event"); } ngx_log_debug2(NGX_LOG_DEBUG_RTMP, e->log, 0, "exec: child '%V' started pid=%i", &ec->cmd, (ngx_int_t) pid); break; } #endif /* NGX_WIN32 */ return NGX_OK; }
static ngx_int_t ngx_event_process_init(ngx_cycle_t *cycle) { ngx_uint_t m, i; ngx_event_t *rev, *wev; ngx_listening_t *ls; ngx_connection_t *c, *next, *old; ngx_core_conf_t *ccf; ngx_event_conf_t *ecf; ngx_event_module_t *module; ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module); ecf = ngx_event_get_conf(cycle->conf_ctx, ngx_event_core_module); /* [analy] ngx_use_accept_mutex表示是否需要通过对accept加锁来解决惊群问题。 当nginx worker进程数>1时且配置文件中打开accept_mutex时,这个标志置为1 */ if (ccf->master && ccf->worker_processes > 1 && ecf->accept_mutex) { ngx_use_accept_mutex = 1; ngx_accept_mutex_held = 0; ngx_accept_mutex_delay = ecf->accept_mutex_delay; } else { ngx_use_accept_mutex = 0; } #if (NGX_THREADS) ngx_posted_events_mutex = ngx_mutex_init(cycle->log, 0); if (ngx_posted_events_mutex == NULL) { return NGX_ERROR; } #endif /* [analy] ??????????? */ if (ngx_event_timer_init(cycle->log) == NGX_ERROR) { return NGX_ERROR; } /* [analy] 调用事件处理模块(epoll)初始化函数 */ for (m = 0; ngx_modules[m]; m++) { if (ngx_modules[m]->type != NGX_EVENT_MODULE) { continue; } if (ngx_modules[m]->ctx_index != ecf->use) { continue; } /* [analy] 由于Nginx实现了很多的事件模块,比如:epoll,poll,select, kqueue,aio (这些模块位于src/event/modules目录中)等等,所以Nginx对事件模块进行 了一层抽象,方便在不同的系统上使用不同的事件模型,也便于扩展新的事件 模型 此处的init回调,其实就是调用了ngx_epoll_init函数。module->actions结构 封装了epoll的所有接口函数。Nginx就是通过actions结构将epoll注册到事件 抽象层中。actions的类型是ngx_event_actions_t */ module = ngx_modules[m]->ctx; if (module->actions.init(cycle, ngx_timer_resolution) != NGX_OK) { /* fatal */ exit(2); } break; } #if !(NGX_WIN32) /* * timer_resolution指令指定了时间,并且未指定NGX_USE_TIMER_EVENT标记时, * 根据 timer_resolution 指令指定的时间设置一个定时器 */ if (ngx_timer_resolution && !(ngx_event_flags & NGX_USE_TIMER_EVENT)) { struct sigaction sa; struct itimerval itv; ngx_memzero(&sa, sizeof(struct sigaction)); sa.sa_handler = ngx_timer_signal_handler; sigemptyset(&sa.sa_mask); if (sigaction(SIGALRM, &sa, NULL) == -1) { ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, "sigaction(SIGALRM) failed"); return NGX_ERROR; } itv.it_interval.tv_sec = ngx_timer_resolution / 1000; itv.it_interval.tv_usec = (ngx_timer_resolution % 1000) * 1000; itv.it_value.tv_sec = ngx_timer_resolution / 1000; itv.it_value.tv_usec = (ngx_timer_resolution % 1000 ) * 1000; if (setitimer(ITIMER_REAL, &itv, NULL) == -1) { ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, "setitimer() failed"); } } if (ngx_event_flags & NGX_USE_FD_EVENT) { /* [analy] epoll模块不使用 */ struct rlimit rlmt; if (getrlimit(RLIMIT_NOFILE, &rlmt) == -1) { ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, "getrlimit(RLIMIT_NOFILE) failed"); return NGX_ERROR; } cycle->files_n = (ngx_uint_t) rlmt.rlim_cur; cycle->files = ngx_calloc(sizeof(ngx_connection_t *) * cycle->files_n, cycle->log); if (cycle->files == NULL) { return NGX_ERROR; } } #endif /* [analy] 为连接池申请空间,由于此处在worker进程初始化时进行的,所以 每个worker都会拥有一个自己的connections连接池 根据配置worker_connections指令指定的个数申请 */ cycle->connections = ngx_alloc(sizeof(ngx_connection_t) * cycle->connection_n, cycle->log); if (cycle->connections == NULL) { return NGX_ERROR; } c = cycle->connections; /* [analy] 为读事件队列申请空间 */ cycle->read_events = ngx_alloc(sizeof(ngx_event_t) * cycle->connection_n, cycle->log); if (cycle->read_events == NULL) { return NGX_ERROR; } rev = cycle->read_events; for (i = 0; i < cycle->connection_n; i++) { rev[i].closed = 1; rev[i].instance = 1; #if (NGX_THREADS) rev[i].lock = &c[i].lock; rev[i].own_lock = &c[i].lock; #endif } /* [analy] 为写事件队列申请空间 */ cycle->write_events = ngx_alloc(sizeof(ngx_event_t) * cycle->connection_n, cycle->log); if (cycle->write_events == NULL) { return NGX_ERROR; } wev = cycle->write_events; for (i = 0; i < cycle->connection_n; i++) { wev[i].closed = 1; #if (NGX_THREADS) wev[i].lock = &c[i].lock; wev[i].own_lock = &c[i].lock; #endif } /* [analy] 初始化connections数组 data字段指向下一个元素 read事件指针指向read_events对应下标的元素 write事件指针指向write_events对应下标的元素 fd初始化-1 */ i = cycle->connection_n; next = NULL; do { i--; c[i].data = next; c[i].read = &cycle->read_events[i]; /* [analy] 将连接池中connections的read事件与read_events数组中的对应下标的元素关联 */ c[i].write = &cycle->write_events[i]; /* [analy] 将连接池中connections的write事件与write_events数组中对应下标元素关联 */ c[i].fd = (ngx_socket_t) -1; next = &c[i]; #if (NGX_THREADS) c[i].lock = 0; #endif } while (i); /* 初始化free_connections空闲连接池和空闲连接个数;指向connections连接池首地址 */ cycle->free_connections = next; cycle->free_connection_n = cycle->connection_n; /* [analy] 为每一个套接口分配一个空闲的连接 */ /* for each listening socket */ ls = cycle->listening.elts; for (i = 0; i < cycle->listening.nelts; i++) { c = ngx_get_connection(ls[i].fd, cycle->log); if (c == NULL) { return NGX_ERROR; } c->log = &ls[i].log; c->listening = &ls[i]; /* [analy] connection的listening指针指向cycle->listening[n] */ ls[i].connection = c; /* [analy] cycle->listening[n]->connection指针指向了申请的空闲connection */ rev = c->read; rev->log = c->log; rev->accept = 1; // 设置监听套接字标识 #if (NGX_HAVE_DEFERRED_ACCEPT) rev->deferred_accept = ls[i].deferred_accept; #endif if (!(ngx_event_flags & NGX_USE_IOCP_EVENT)) { if (ls[i].previous) { /* * delete the old accept events that were bound to * the old cycle read events array */ old = ls[i].previous->connection; if (ngx_del_event(old->read, NGX_READ_EVENT, NGX_CLOSE_EVENT) == NGX_ERROR) { return NGX_ERROR; } old->fd = (ngx_socket_t) -1; } } #if (NGX_WIN32) if (ngx_event_flags & NGX_USE_IOCP_EVENT) { ngx_iocp_conf_t *iocpcf; rev->handler = ngx_event_acceptex; if (ngx_use_accept_mutex) { continue; } if (ngx_add_event(rev, 0, NGX_IOCP_ACCEPT) == NGX_ERROR) { return NGX_ERROR; } ls[i].log.handler = ngx_acceptex_log_error; iocpcf = ngx_event_get_conf(cycle->conf_ctx, ngx_iocp_module); if (ngx_event_post_acceptex(&ls[i], iocpcf->post_acceptex) == NGX_ERROR) { return NGX_ERROR; } } else { rev->handler = ngx_event_accept; if (ngx_use_accept_mutex) { continue; } if (ngx_add_event(rev, NGX_READ_EVENT, 0) == NGX_ERROR) { return NGX_ERROR; } } #else rev->handler = ngx_event_accept; /* [analy] 设置accpet回调处理函数 */ if (ngx_use_accept_mutex) { continue; } if (ngx_event_flags & NGX_USE_RTSIG_EVENT) { if (ngx_add_conn(c) == NGX_ERROR) { return NGX_ERROR; } } else { if (ngx_add_event(rev, NGX_READ_EVENT, 0) == NGX_ERROR) { /* [analy] 将event送进epoll队列中 */ return NGX_ERROR; } } #endif } return NGX_OK; }
ngx_int_t ngx_handle_write_event(ngx_event_t *wev, size_t lowat) { ngx_connection_t *c; if (lowat) { c = wev->data; if (ngx_send_lowat(c, lowat) == NGX_ERROR) { return NGX_ERROR; } } if (ngx_event_flags & NGX_USE_CLEAR_EVENT) { /* kqueue, epoll */ if (!wev->active && !wev->ready) { if (ngx_add_event(wev, NGX_WRITE_EVENT, NGX_CLEAR_EVENT | (lowat ? NGX_LOWAT_EVENT : 0)) == NGX_ERROR) { return NGX_ERROR; } } return NGX_OK; } else if (ngx_event_flags & NGX_USE_LEVEL_EVENT) { /* select, poll, /dev/poll */ if (!wev->active && !wev->ready) { if (ngx_add_event(wev, NGX_WRITE_EVENT, NGX_LEVEL_EVENT) == NGX_ERROR) { return NGX_ERROR; } return NGX_OK; } if (wev->active && wev->ready) { if (ngx_del_event(wev, NGX_WRITE_EVENT, NGX_LEVEL_EVENT) == NGX_ERROR) { return NGX_ERROR; } return NGX_OK; } } else if (ngx_event_flags & NGX_USE_EVENTPORT_EVENT) { /* event ports */ if (!wev->active && !wev->ready) { if (ngx_add_event(wev, NGX_WRITE_EVENT, 0) == NGX_ERROR) { return NGX_ERROR; } return NGX_OK; } if (wev->oneshot && wev->ready) { if (ngx_del_event(wev, NGX_WRITE_EVENT, 0) == NGX_ERROR) { return NGX_ERROR; } return NGX_OK; } } /* aio, iocp, rtsig */ return NGX_OK; }
ngx_int_t ngx_event_connect_peer(ngx_peer_connection_t *pc) { //Here,we initilize a connection!!! int rc; ngx_int_t event; ngx_err_t err; ngx_uint_t level; ngx_socket_t s; ngx_event_t *rev, *wev; ngx_connection_t *c; //Here,very important, this handler is use to get a select handler!! /* For ip_hash module,will set the get handler!!! r->upstream->peer.get = ngx_http_upstream_get_round_robin_peer; r->upstream->peer.free = ngx_http_upstream_free_round_robin_peer; */ //will stored the really backend ip_addr in the pc!! rc = pc->get(pc, pc->data); if (rc != NGX_OK) { return rc; } //Here,Do the socket operation! alloc a socket_fd s = ngx_socket(pc->sockaddr->sa_family, SOCK_STREAM, 0); ngx_log_debug1(NGX_LOG_DEBUG_EVENT, pc->log, 0, "socket %d", s); if (s == -1) { ngx_log_error(NGX_LOG_ALERT, pc->log, ngx_socket_errno, ngx_socket_n " failed"); return NGX_ERROR; } c = ngx_get_connection(s, pc->log); if (c == NULL) { if (ngx_close_socket(s) == -1) { ngx_log_error(NGX_LOG_ALERT, pc->log, ngx_socket_errno, ngx_close_socket_n "failed"); } return NGX_ERROR; } if (pc->rcvbuf) { if (setsockopt(s, SOL_SOCKET, SO_RCVBUF, (const void *) &pc->rcvbuf, sizeof(int)) == -1) { ngx_log_error(NGX_LOG_ALERT, pc->log, ngx_socket_errno, "setsockopt(SO_RCVBUF) failed"); goto failed; } } if (ngx_nonblocking(s) == -1) { ngx_log_error(NGX_LOG_ALERT, pc->log, ngx_socket_errno, ngx_nonblocking_n " failed"); goto failed; } if (pc->local) { if (bind(s, pc->local->sockaddr, pc->local->socklen) == -1) { ngx_log_error(NGX_LOG_CRIT, pc->log, ngx_socket_errno, "bind(%V) failed", &pc->local->name); goto failed; } } //########################### Here set the connection data's read write handler!!! c->recv = ngx_recv; c->send = ngx_send; c->recv_chain = ngx_recv_chain; c->send_chain = ngx_send_chain; c->sendfile = 1; c->log_error = pc->log_error; if (pc->sockaddr->sa_family != AF_INET) { c->tcp_nopush = NGX_TCP_NOPUSH_DISABLED; c->tcp_nodelay = NGX_TCP_NODELAY_DISABLED; #if (NGX_SOLARIS) /* Solaris's sendfilev() supports AF_NCA, AF_INET, and AF_INET6 */ c->sendfile = 0; #endif } rev = c->read; wev = c->write; rev->log = pc->log; wev->log = pc->log; pc->connection = c; c->number = ngx_atomic_fetch_add(ngx_connection_counter, 1); #if (NGX_THREADS) /* TODO: lock event when call completion handler */ rev->lock = pc->lock; wev->lock = pc->lock; rev->own_lock = &c->lock; wev->own_lock = &c->lock; #endif if (ngx_add_conn) { if (ngx_add_conn(c) == NGX_ERROR) { goto failed; } } ngx_log_debug3(NGX_LOG_DEBUG_EVENT, pc->log, 0, "connect to %V, fd:%d #%d", pc->name, s, c->number); //########################## Here,doing the really connect operation rc = connect(s, pc->sockaddr, pc->socklen); if (rc == -1) { err = ngx_socket_errno; if (err != NGX_EINPROGRESS #if (NGX_WIN32) /* Winsock returns WSAEWOULDBLOCK (NGX_EAGAIN) */ && err != NGX_EAGAIN #endif ) { if (err == NGX_ECONNREFUSED #if (NGX_LINUX) /* * Linux returns EAGAIN instead of ECONNREFUSED * for unix sockets if listen queue is full */ || err == NGX_EAGAIN #endif || err == NGX_ECONNRESET || err == NGX_ENETDOWN || err == NGX_ENETUNREACH || err == NGX_EHOSTDOWN || err == NGX_EHOSTUNREACH) { level = NGX_LOG_ERR; } else { level = NGX_LOG_CRIT; } ngx_log_error(level, c->log, err, "connect() to %V failed", pc->name); return NGX_DECLINED; } } if (ngx_add_conn) { if (rc == -1) { /* NGX_EINPROGRESS */ return NGX_AGAIN; } ngx_log_debug0(NGX_LOG_DEBUG_EVENT, pc->log, 0, "connected"); wev->ready = 1;// return NGX_OK; } if (ngx_event_flags & NGX_USE_AIO_EVENT) { ngx_log_debug1(NGX_LOG_DEBUG_EVENT, pc->log, ngx_socket_errno, "connect(): %d", rc); /* aio, iocp */ if (ngx_blocking(s) == -1) { ngx_log_error(NGX_LOG_ALERT, pc->log, ngx_socket_errno, ngx_blocking_n " failed"); goto failed; } /* * FreeBSD's aio allows to post an operation on non-connected socket. * NT does not support it. * * TODO: check in Win32, etc. As workaround we can use NGX_ONESHOT_EVENT */ rev->ready = 1; wev->ready = 1; return NGX_OK; } if (ngx_event_flags & NGX_USE_CLEAR_EVENT) { /* kqueue */ event = NGX_CLEAR_EVENT; } else { /* select, poll, /dev/poll */ event = NGX_LEVEL_EVENT; } //##########################################Very important! //##########################################add the connection read event!! if (ngx_add_event(rev, NGX_READ_EVENT, event) != NGX_OK) { goto failed; } if (rc == -1) { /* NGX_EINPROGRESS */ if (ngx_add_event(wev, NGX_WRITE_EVENT, event) != NGX_OK) { goto failed; } return NGX_AGAIN; } ngx_log_debug0(NGX_LOG_DEBUG_EVENT, pc->log, 0, "connected"); wev->ready = 1; //Means the connection is ready to write! return NGX_OK; failed: ngx_free_connection(c); if (ngx_close_socket(s) == -1) { ngx_log_error(NGX_LOG_ALERT, pc->log, ngx_socket_errno, ngx_close_socket_n " failed"); } return NGX_ERROR; }