static void nchan_msg_reserve_debug(nchan_msg_t *msg, char *lbl) { msg_rsv_dbg_t *rsv; int shared = msg->storage == NCHAN_MSG_SHARED; if(shared) shmtx_lock(nchan_store_memory_shmem); if(shared) rsv=shm_locked_calloc(nchan_store_memory_shmem, sizeof(*rsv) + ngx_strlen(lbl) + 1, "msgdebug"); else rsv=ngx_calloc(sizeof(*rsv) + ngx_strlen(lbl) + 1, ngx_cycle->log); rsv->lbl = (char *)(&rsv[1]); ngx_memcpy(rsv->lbl, lbl, ngx_strlen(lbl)); if(msg->rsv == NULL) { msg->rsv = rsv; rsv->prev = NULL; rsv->next = NULL; } else { msg->rsv->prev = rsv; rsv->next = msg->rsv; rsv->prev = NULL; msg->rsv = rsv; } if(shared) shmtx_unlock(nchan_store_memory_shmem); }
static ngx_int_t spool_add_subscriber(subscriber_pool_t *self, subscriber_t *sub, uint8_t enqueue) { spooled_subscriber_t *ssub; ssub = ngx_calloc(sizeof(*ssub), ngx_cycle->log); //DBG("add sub %p to spool %p", sub, self); if(ssub == NULL) { ERR("failed to allocate new sub for spool"); return NGX_ERROR; } ssub->next = self->first; ssub->prev = NULL; if(self->first != NULL) { self->first->prev = ssub; } self->first = ssub; self->sub_count++; ssub->dequeue_callback_data.ssub = ssub; ssub->dequeue_callback_data.spool = self; if(enqueue) { sub->fn->enqueue(sub); } sub->fn->set_dequeue_callback(sub, spool_sub_dequeue_callback, &ssub->dequeue_callback_data); ssub->sub = sub; return NGX_OK; }
static ngx_int_t ngx_statsd_init_endpoint(ngx_conf_t *cf, ngx_udp_endpoint_t *endpoint) { ngx_pool_cleanup_t *cln; ngx_udp_connection_t *uc; ngx_log_debug0(NGX_LOG_DEBUG_HTTP, cf->log, 0, "statsd: initting endpoint"); cln = ngx_pool_cleanup_add(cf->pool, 0); if(cln == NULL) { return NGX_ERROR; } cln->handler = ngx_statsd_updater_cleanup; cln->data = endpoint; uc = ngx_calloc(sizeof(ngx_udp_connection_t), cf->log); if (uc == NULL) { return NGX_ERROR; } endpoint->udp_connection = uc; uc->sockaddr = endpoint->peer_addr.sockaddr; uc->socklen = endpoint->peer_addr.socklen; uc->server = endpoint->peer_addr.name; endpoint->log = &cf->cycle->new_log; return NGX_OK; }
static ngx_int_t ngx_fluentd_init_endpoint(ngx_conf_t *cf, ngx_udp_endpoint_t *endpoint) { ngx_pool_cleanup_t *cln; ngx_udp_connection_t *uc; cln = ngx_pool_cleanup_add(cf->pool, 0); if(cln == NULL) { return NGX_ERROR; } cln->handler = ngx_fluentd_cleanup; cln->data = endpoint; uc = ngx_calloc(sizeof(ngx_udp_connection_t), cf->log); if (uc == NULL) { return NGX_ERROR; } endpoint->udp_connection = uc; uc->sockaddr = endpoint->peer_addr.sockaddr; uc->socklen = endpoint->peer_addr.socklen; uc->server = endpoint->peer_addr.name; #if defined nginx_version && ( nginx_version >= 7054 && nginx_version < 8055 ) uc->log = cf->cycle->new_log; #else uc->log = cf->cycle->new_log; #if defined nginx_version && nginx_version >= 8032 uc->log.handler = NULL; uc->log.data = NULL; uc->log.action = "logging"; #endif #endif return NGX_OK; }
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; }
subscriber_t *longpoll_subscriber_create(ngx_http_request_t *r, nchan_msg_id_t *msg_id) { DBG("create for req %p", r); full_subscriber_t *fsub; //TODO: allocate from pool (but not the request's pool) if((fsub = ngx_alloc(sizeof(*fsub), ngx_cycle->log)) == NULL) { ERR("Unable to allocate"); assert(0); return NULL; } nchan_subscriber_init(&fsub->sub, &new_longpoll_sub, r, msg_id); fsub->privdata = NULL; fsub->data.cln = NULL; fsub->data.finalize_request = 1; fsub->data.holding = 0; fsub->data.act_as_intervalpoll = 0; nchan_subscriber_init_timeout_timer(&fsub->sub, &fsub->data.timeout_ev); fsub->data.dequeue_handler = empty_handler; fsub->data.dequeue_handler_data = NULL; fsub->data.already_responded = 0; fsub->data.awaiting_destruction = 0; if(fsub->sub.cf->longpoll_multimsg) { nchan_request_ctx_t *ctx = ngx_http_get_module_ctx(r, ngx_nchan_module); fsub->sub.dequeue_after_response = 0; ctx->bcp = ngx_palloc(r->pool, sizeof(nchan_bufchain_pool_t)); nchan_bufchain_pool_init(ctx->bcp, r->pool); } fsub->data.multimsg_first = NULL; fsub->data.multimsg_last = NULL; #if NCHAN_SUBSCRIBER_LEAK_DEBUG subscriber_debug_add(&fsub->sub); //set debug label fsub->sub.lbl = ngx_calloc(r->uri.len+1, ngx_cycle->log); ngx_memcpy(fsub->sub.lbl, r->uri.data, r->uri.len); #endif //http request sudden close cleanup if((fsub->data.cln = ngx_http_cleanup_add(r, 0)) == NULL) { ERR("Unable to add request cleanup for longpoll subscriber"); assert(0); return NULL; } fsub->data.cln->data = fsub; fsub->data.cln->handler = (ngx_http_cleanup_pt )sudden_abort_handler; DBG("%p created for request %p", &fsub->sub, r); return &fsub->sub; }
nchan_fakereq_subrequest_data_t *nchan_subscriber_subrequest(subscriber_t *sub, nchan_requestmachine_request_params_t *params) { if(sub->upstream_requestmachine == NULL) { sub->upstream_requestmachine = ngx_calloc(sizeof(nchan_requestmachine_t), ngx_cycle->log); if(sub->upstream_requestmachine == NULL) { nchan_log_error("failed to allocate upstream_requestmachine for subscriber %p", sub); return NULL; } else { nchan_requestmachine_initialize(sub->upstream_requestmachine, sub->request); } } return nchan_requestmachine_request(sub->upstream_requestmachine, params); }
static ngx_int_t spool_add_subscriber(subscriber_pool_t *self, subscriber_t *sub, uint8_t enqueue) { spooled_subscriber_t *ssub; ssub = ngx_calloc(sizeof(*ssub), ngx_cycle->log); //DBG("add sub %p to spool %p", sub, self); if(ssub == NULL) { ERR("failed to allocate new sub for spool"); return NGX_ERROR; } ssub->next = self->first; ssub->prev = NULL; if(self->first != NULL) { self->first->prev = ssub; } self->first = ssub; self->sub_count++; if(sub->type != INTERNAL) { self->non_internal_sub_count++; } ssub->dequeue_callback_data.ssub = ssub; ssub->dequeue_callback_data.spool = self; if(enqueue) { sub->fn->enqueue(sub); } if(sub->type != INTERNAL && self->spooler->publish_events) { nchan_maybe_send_channel_event_message(sub->request, SUB_ENQUEUE); } sub->fn->set_dequeue_callback(sub, spool_sub_dequeue_callback, &ssub->dequeue_callback_data); ssub->sub = sub; return NGX_OK; }
static ngx_int_t ngx_http_upstream_init_chash(ngx_conf_t *cf, ngx_http_upstream_srv_conf_t *us) { u_char hash_buf[256]; ngx_int_t j, weight; ngx_uint_t sid, id, hash_len; ngx_uint_t i, n, *number, rnindex; ngx_http_upstream_rr_peer_t *peer; ngx_http_upstream_rr_peers_t *peers; ngx_http_upstream_chash_server_t *server; ngx_http_upstream_chash_srv_conf_t *ucscf; if (ngx_http_upstream_init_round_robin(cf, us) == NGX_ERROR) { return NGX_ERROR; } ucscf = ngx_http_conf_upstream_srv_conf(us, ngx_http_upstream_consistent_hash_module); if (ucscf == NULL) { return NGX_ERROR; } us->peer.init = ngx_http_upstream_init_chash_peer; peers = (ngx_http_upstream_rr_peers_t *) us->peer.data; if (peers == NULL) { return NGX_ERROR; } n = peers->number; ucscf->number = 0; ucscf->real_node = ngx_pcalloc(cf->pool, n * sizeof(ngx_http_upstream_chash_server_t**)); if (ucscf->real_node == NULL) { return NGX_ERROR; } for (i = 0; i < n; i++) { ucscf->number += peers->peer[i].weight * NGX_CHASH_VIRTUAL_NODE_NUMBER; ucscf->real_node[i] = ngx_pcalloc(cf->pool, (peers->peer[i].weight * NGX_CHASH_VIRTUAL_NODE_NUMBER + 1) * sizeof(ngx_http_upstream_chash_server_t*)); if (ucscf->real_node[i] == NULL) { return NGX_ERROR; } } ucscf->servers = ngx_pcalloc(cf->pool, (ucscf->number + 1) * sizeof(ngx_http_upstream_chash_server_t)); if (ucscf->servers == NULL) { return NGX_ERROR; } ucscf->d_servers = ngx_pcalloc(cf->pool, (ucscf->number + 1) * sizeof(ngx_http_upstream_chash_down_server_t)); if (ucscf->d_servers == NULL) { return NGX_ERROR; } ucscf->number = 0; for (i = 0; i < n; i++) { peer = &peers->peer[i]; sid = (ngx_uint_t) ngx_atoi(peer->id.data, peer->id.len); if (sid == (ngx_uint_t) NGX_ERROR || sid > 65535) { ngx_log_debug1(NGX_LOG_DEBUG_HTTP, cf->log, 0, "server id %d", sid); ngx_snprintf(hash_buf, 256, "%V%Z", &peer->name); hash_len = ngx_strlen(hash_buf); sid = ngx_murmur_hash2(hash_buf, hash_len); } weight = peer->weight * NGX_CHASH_VIRTUAL_NODE_NUMBER; if (weight >= 1 << 14) { ngx_log_error(NGX_LOG_WARN, cf->log, 0, "weigth[%d] is too large, is must be less than %d", weight / NGX_CHASH_VIRTUAL_NODE_NUMBER, (1 << 14) / NGX_CHASH_VIRTUAL_NODE_NUMBER); weight = 1 << 14; } for (j = 0; j < weight; j++) { server = &ucscf->servers[++ucscf->number]; server->peer = peer; server->rnindex = i; id = sid * 256 * 16 + j; server->hash = ngx_murmur_hash2((u_char *) (&id), 4); } } ngx_qsort(ucscf->servers + 1, ucscf->number, sizeof(ngx_http_upstream_chash_server_t), (const void *)ngx_http_upstream_chash_cmp); number = ngx_calloc(n * sizeof(ngx_uint_t), cf->log); if (number == NULL) { return NGX_ERROR; } for (i = 1; i <= ucscf->number; i++) { ucscf->servers[i].index = i; ucscf->d_servers[i].id = i; rnindex = ucscf->servers[i].rnindex; ucscf->real_node[rnindex][number[rnindex]] = &ucscf->servers[i]; number[rnindex]++; } ngx_free(number); ucscf->tree = ngx_pcalloc(cf->pool, sizeof(ngx_segment_tree_t)); if (ucscf->tree == NULL) { return NGX_ERROR; } ngx_segment_tree_init(ucscf->tree, ucscf->number, cf->pool); ucscf->tree->build(ucscf->tree, 1, 1, ucscf->number); ngx_queue_init(&ucscf->down_servers); return NGX_OK; }
ngx_resolver_t * ngx_resolver_create(ngx_conf_t *cf, ngx_str_t *names, ngx_uint_t n) { ngx_str_t s; ngx_url_t u; ngx_uint_t i; ngx_resolver_t *r; ngx_pool_cleanup_t *cln; ngx_udp_connection_t *uc; cln = ngx_pool_cleanup_add(cf->pool, 0); if (cln == NULL) { return NULL; } cln->handler = ngx_resolver_cleanup; r = ngx_calloc(sizeof(ngx_resolver_t), cf->log); if (r == NULL) { return NULL; } if (n) { if (ngx_array_init(&r->udp_connections, cf->pool, n, sizeof(ngx_udp_connection_t)) != NGX_OK) { return NULL; } } cln->data = r; r->event = ngx_calloc(sizeof(ngx_event_t), cf->log); if (r->event == NULL) { return NULL; } ngx_rbtree_init(&r->name_rbtree, &r->name_sentinel, ngx_resolver_rbtree_insert_value); ngx_rbtree_init(&r->addr_rbtree, &r->addr_sentinel, ngx_rbtree_insert_value); ngx_queue_init(&r->name_resend_queue); ngx_queue_init(&r->addr_resend_queue); ngx_queue_init(&r->name_expire_queue); ngx_queue_init(&r->addr_expire_queue); r->event->handler = ngx_resolver_resend_handler; r->event->data = r; r->event->log = &cf->cycle->new_log; r->ident = -1; r->resend_timeout = 5; r->expire = 30; r->valid = 0; r->log = &cf->cycle->new_log; r->log_level = NGX_LOG_ERR; for (i = 0; i < n; i++) { if (ngx_strncmp(names[i].data, "valid=", 6) == 0) { s.len = names[i].len - 6; s.data = names[i].data + 6; r->valid = ngx_parse_time(&s, 1); if (r->valid == NGX_ERROR) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid parameter: %V", &names[i]); return NULL; } continue; } ngx_memzero(&u, sizeof(ngx_url_t)); u.host = names[i]; u.port = 53; if (ngx_inet_resolve_host(cf->pool, &u) != NGX_OK) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "%V: %s", &u.host, u.err); return NULL; } uc = ngx_array_push(&r->udp_connections); if (uc == NULL) { return NULL; } ngx_memzero(uc, sizeof(ngx_udp_connection_t)); uc->sockaddr = u.addrs->sockaddr; uc->socklen = u.addrs->socklen; uc->server = u.addrs->name; uc->log = cf->cycle->new_log; uc->log.handler = ngx_resolver_log_error; uc->log.data = uc; uc->log.action = "resolving"; } return r; }
/* 事件驱动模块初始化,也就是worker进程初始化时会调用到这里 */ 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 /* 初始化两个时间接收队列 */ ngx_queue_init(&ngx_posted_accept_events); ngx_queue_init(&ngx_posted_events); /* 事件模型的时钟初始化 */ 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; /* RLIMIT_NOFILE表示一个进程能打开的最大文件数 */ 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; } } #else if (ngx_timer_resolution && !(ngx_event_flags & NGX_USE_TIMER_EVENT)) { ngx_log_error(NGX_LOG_WARN, cycle->log, 0, "the \"timer_resolution\" directive is not supported " "with the configured event method, ignored"); ngx_timer_resolution = 0; } #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; } /* 分配和连接个数相同的写事件 */ 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; } 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]; } while (i); /* 刚开始设置所有的连接为空闲连接 */ cycle->free_connections = next; cycle->free_connection_n = cycle->connection_n; /* for each listening socket */ ls = cycle->listening.elts; /* 循环处理监听套接字,也就是监听套接字的事件处理为ngx_event_accept函数 */ for (i = 0; i < cycle->listening.nelts; i++) { #if (NGX_HAVE_REUSEPORT) if (ls[i].reuseport && ls[i].worker != ngx_worker) { continue; } #endif /* 获取每个监听套接字对应的连接 */ 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 #if (NGX_HAVE_REUSEPORT) && !ls[i].reuseport #endif ) { continue; } if (ngx_add_event(rev, NGX_READ_EVENT, 0) == NGX_ERROR) { return NGX_ERROR; } #endif } return NGX_OK; }
static ngx_thread_value_t ngx_worker_thread_cycle(void *data) { ngx_thread_t *thr = data; sigset_t set; ngx_err_t err; ngx_core_tls_t *tls; ngx_cycle_t *cycle; cycle = (ngx_cycle_t *) ngx_cycle; sigemptyset(&set); sigaddset(&set, ngx_signal_value(NGX_RECONFIGURE_SIGNAL)); sigaddset(&set, ngx_signal_value(NGX_REOPEN_SIGNAL)); sigaddset(&set, ngx_signal_value(NGX_CHANGEBIN_SIGNAL)); err = ngx_thread_sigmask(SIG_BLOCK, &set, NULL); if (err) { ngx_log_error(NGX_LOG_ALERT, cycle->log, err, ngx_thread_sigmask_n " failed"); return (ngx_thread_value_t) 1; } ngx_log_debug1(NGX_LOG_DEBUG_CORE, cycle->log, 0, "thread " NGX_TID_T_FMT " started", ngx_thread_self()); ngx_setthrtitle("worker thread"); tls = ngx_calloc(sizeof(ngx_core_tls_t), cycle->log); if (tls == NULL) { return (ngx_thread_value_t) 1; } err = ngx_thread_set_tls(ngx_core_tls_key, tls); if (err != 0) { ngx_log_error(NGX_LOG_ALERT, cycle->log, err, ngx_thread_set_tls_n " failed"); return (ngx_thread_value_t) 1; } ngx_mutex_lock(ngx_posted_events_mutex); for ( ;; ) { thr->state = NGX_THREAD_FREE; if (ngx_cond_wait(thr->cv, ngx_posted_events_mutex) == NGX_ERROR) { return (ngx_thread_value_t) 1; } if (ngx_terminate) { thr->state = NGX_THREAD_EXIT; ngx_mutex_unlock(ngx_posted_events_mutex); ngx_log_debug1(NGX_LOG_DEBUG_CORE, cycle->log, 0, "thread " NGX_TID_T_FMT " is done", ngx_thread_self()); return (ngx_thread_value_t) 0; } thr->state = NGX_THREAD_BUSY; if (ngx_event_thread_process_posted(cycle) == NGX_ERROR) { return (ngx_thread_value_t) 1; } if (ngx_event_thread_process_posted(cycle) == NGX_ERROR) { return (ngx_thread_value_t) 1; } if (ngx_process_changes) { if (ngx_process_changes(cycle, 1) == NGX_ERROR) { return (ngx_thread_value_t) 1; } } } }
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_worker_process_init 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); /* 当打开accept_mutex负载均衡锁,同时使用了master模式并且worker迸程数量大于1时,才正式确定了进程将使用accept_mutex负载均衡锁。 因此,即使我们在配置文件中指定打开accept_mutex锁,如果没有使用master模式或者worker进程数量等于1,进程在运行时还是不会使用 负载均衡锁(既然不存在多个进程去抢一个监听端口上的连接的情况,那么自然不需要均衡多个worker进程的负载)。 这时会将ngx_use_accept_mutex全局变量置为1,ngx_accept_mutex_held标志设为0,ngx_accept_mutex_delay则设为在配置文件中指定的最大延迟时间。 这3个变量的意义可参见9.8节中关于负载均衡锁的说明。 */ 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 ngx_queue_init(&ngx_posted_accept_events); ngx_queue_init(&ngx_posted_events); //初始化红黑树实现的定时器。关于定时器的实现细节可参见9.6节。 if (ngx_event_timer_init(cycle->log) == NGX_ERROR) { return NGX_ERROR; } //在调用use配置项指定的事件模块中,在ngx_event_module_t接口下,ngx_event_actions_t中的init方法进行这个事件模块的初始化工作。 for (m = 0; ngx_modules[m]; m++) { if (ngx_modules[m]->type != NGX_EVENT_MODULE) { continue; } if (ngx_modules[m]->ctx_index != ecf->use) { //找到epoll或者select的module模块 continue; } module = ngx_modules[m]->ctx; if (module->actions.init(cycle, ngx_timer_resolution) != NGX_OK) { //执行epoll module中的ngx_epoll_init /* fatal */ exit(2); } break; /*跳出循环,只可能使用一个具体的事件模型*/ } #if !(NGX_WIN32) /* 如果nginx.conf配置文件中设置了timer_resolution酡置项,即表明需要控制时间精度,这时会调用setitimer方法,设置时间间隔 为timer_resolution毫秒来回调ngx_timer_signal_handler方法 */ if (ngx_timer_resolution && !(ngx_event_flags & NGX_USE_TIMER_EVENT)) { struct sigaction sa; struct itimerval itv; //设置定时器 /* 在ngx_event_ actions t的process_events方法中,每一个事件驱动模块都需要在ngx_event_timer_alarm为1时调 用ngx_time_update方法(参见9.7.1节)更新系统时间,在更新系统结束后需要将ngx_event_timer_alarm设为0。 */ ngx_memzero(&sa, sizeof(struct sigaction)); //每隔ngx_timer_resolution ms会超时执行handle 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"); } } /* 如果使用了epoll事件驱动模式,那么会为ngx_cycle_t结构体中的files成员预分配旬柄。 */ 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; } 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; } i = cycle->connection_n; next = NULL; /* 接照序号,将上述3个数组相应的读/写事件设置到每一个ngx_connection_t连接对象中,同时把这些连接以ngx_connection_t中的data成员 作为next指针串联成链表,为下一步设置空闲连接链表做好准备 */ 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]; } while (i); /* 将ngx_cycle_t结构体中的空闲连接链表free_connections指向connections数组的最后1个元素,也就是第10步所有ngx_connection_t连 接通过data成员组成的单链表的首部。 */ cycle->free_connections = next; cycle->free_connection_n = cycle->connection_n; /* for each listening socket */ /* 在刚刚建立好的连接池中,为所有ngx_listening_t监听对象中的connection成员分配连接,同时对监听端口的读事件设置处理方法 为ngx_event_accept,也就是说,有新连接事件时将调用ngx_event_accept方法建立新连接(详见9.8节中关于如何建立新连接的内容)。 */ ls = cycle->listening.elts; for (i = 0; i < cycle->listening.nelts; i++) { #if (NGX_HAVE_REUSEPORT) if (ls[i].reuseport && ls[i].worker != ngx_worker) { continue; } #endif c = ngx_get_connection(ls[i].fd, cycle->log); //从连接池中获取一个ngx_connection_t if (c == NULL) { return NGX_ERROR; } c->log = &ls[i].log; c->listening = &ls[i]; //把解析到listen配置项信息赋值给ngx_connection_s中的listening中 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 /* 对监听端口的读事件设置处理方法 为ngx_event_accept,也就是说,有新连接事件时将调用ngx_event_accept方法建立新连接(详见9.8节中关于如何建立新连接的内容)。 */ rev->handler = ngx_event_accept; /* 使用了accept_mutex,暂时不将监听套接字放入epoll中, 而是等到worker抢到accept互斥体后,再放入epoll,避免惊群的发生。 */ //在建连接的时候,为了避免惊群,在accept的时候,只有获取到该原子锁,才把accept添加到epoll事件中,见ngx_process_events_and_timers->ngx_trylock_accept_mutex if (ngx_use_accept_mutex #if (NGX_HAVE_REUSEPORT) && !ls[i].reuseport #endif ) //如果是单进程方式 { continue; } /* 将监听对象连接的读事件添加到事件驱动模块中,这样,epoll等事件模块就开始检测监听服务,并开始向用户提供服务了。 */ //如果ngx_use_accept_mutex为0也就是未开启accept_mutex锁,则在ngx_worker_process_init->ngx_event_process_init 中把accept连接读事件统计到epoll中 //否则在ngx_process_events_and_timers->ngx_process_events_and_timers->ngx_trylock_accept_mutex中把accept连接读事件统计到epoll中 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(rev, NGX_READ_EVENT, 0) == NGX_ERROR) { //如果是epoll则为ngx_epoll_add_event return NGX_ERROR; } #endif } return NGX_OK; }
//每一个worker进程开始初始化的函数 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); //accept_mutex为1时才会使用互斥体 if (ccf->master && ccf->worker_processes > 1 && ecf->accept_mutex) { //当工作进程数目大于1时,用于开启负载均衡情况下,才设置该变量 ngx_use_accept_mutex = 1; //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 //初始化定时器,这里将会初始化一个红黑树来管理 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) { //不是use配置项指定的事件跳过 continue; } module = ngx_modules[m]->ctx; //调用具体事件模块的函数,如epoll机制的ngx_epoll_init if (module->actions.init(cycle, ngx_timer_resolution) != NGX_OK) { /* fatal */ exit(2); } break; } #if !(NGX_WIN32) //如果设置了timer_resolution配置项,表明要控制时间精度,调用setitimer 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; //file成员 cycle->files = ngx_calloc(sizeof(ngx_connection_t *) * cycle->files_n, cycle->log); if (cycle->files == NULL) { return NGX_ERROR; } } #endif //创建一个connections数组,直接通过malloc 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; //初始化整个connections数组 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; //指向一个可用的slot cycle->free_connection_n = cycle->connection_n; /* for each listening socket */ //为每一个监听套接字分配一个connection ls = cycle->listening.elts; for (i = 0; i < cycle->listening.nelts; i++) { c = ngx_get_connection(ls[i].fd, cycle->log); //获得一个可用的connection //对于每一个监听套接口创建对应的connection连接对象 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 //ngx_process_events_and_timers 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 { //没有使用accept_mutex时,就将监听套接字放入到epoll中 if (ngx_add_event(rev, NGX_READ_EVENT, 0) == NGX_ERROR) { return NGX_ERROR; } } #endif } return NGX_OK; }
// 这篇文章写得很清晰http://www.tbdata.org/archives/1245 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); // 判断是否使用mutex锁,主要是为了控制负载均衡。ccf->master主要确定下是否是master-worker模式。单进程模式就不需要进行下面操作了。 if (ccf->master && ccf->worker_processes > 1 && ecf->accept_mutex) { //使用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 //定时器初始化 if (ngx_event_timer_init(cycle->log) == NGX_ERROR) { return NGX_ERROR; } //event module的初始化 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 //创建连接池。现在已经是在worker中了,所以每个worker都有自己的connection数组 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; //防止stale event 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; //每一个连接的读写事件对应cycle的读写事件 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); //设置free 连接 cycle->free_connections = next; cycle->free_connection_n = cycle->connection_n; /* for each listening socket */ //下面这段初始化listen 事件 ,创建socket句柄,绑定事件回调,然后加入到事件驱动中 ls = cycle->listening.elts; // 为每一个监听套接字从connection数组中分配一个连接,即一个slot //开始遍历listen 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; // 注册监听套接读事件的回调函数ngx_event_accept if (ngx_use_accept_mutex) { continue; } if (ngx_add_event(rev, NGX_READ_EVENT, 0) == NGX_ERROR) { return NGX_ERROR; } } #else //设置listen句柄的事件回调,这个回调里面会accept,然后进行后续处理,这个函数是nginx事件驱动的第一个函数 rev->handler = ngx_event_accept; //如果默认使用mutex,则会继续下面操作 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 { //加可读事件到事件处理,如果没有使用accept互斥体,那么就在此处将监听套接字放入 if (ngx_add_event(rev, NGX_READ_EVENT, 0) == NGX_ERROR) { return NGX_ERROR; } } #endif } return NGX_OK; }
// fork之后,worker进程初始化时调用,即每个worker里都会执行 // 初始化两个延后处理的事件队列,初始化定时器红黑树 // 发送定时信号,更新时间用 // 初始化cycle里的连接和事件数组 // 设置接受连接的回调函数为ngx_event_accept,可以接受连接 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; // core模块的配置结构体 ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module); // event_core模块的配置结构体 ecf = ngx_event_get_conf(cycle->conf_ctx, ngx_event_core_module); // 使用master/worker多进程,使用负载均衡 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 // 初始化两个延后处理的事件队列 ngx_queue_init(&ngx_posted_accept_events); ngx_queue_init(&ngx_posted_events); // 初始化定时器红黑树 if (ngx_event_timer_init(cycle->log) == NGX_ERROR) { return NGX_ERROR; } // 遍历事件模块,但只执行实际使用的事件模块对应初始化函数 for (m = 0; cycle->modules[m]; m++) { if (cycle->modules[m]->type != NGX_EVENT_MODULE) { continue; } // 找到use指令使用的事件模型,或者是默认事件模型 if (cycle->modules[m]->ctx_index != ecf->use) { continue; } module = cycle->modules[m]->ctx; // 调用事件模块的事件初始化函数 // // 调用epoll_create初始化epoll机制 // 参数size=cycle->connection_n / 2,但并无实际意义 // 设置全局变量,操作系统提供的底层数据收发接口 // 初始化全局的事件模块访问接口,指向epoll的函数 // 默认使用et模式,边缘触发,高速 if (module->actions.init(cycle, ngx_timer_resolution) != NGX_OK) { /* fatal */ exit(2); } break; } // unix代码, 发送定时信号,更新时间用 #if !(NGX_WIN32) // NGX_USE_TIMER_EVENT标志量只有eventport/kqueue,epoll无此标志位 // ngx_timer_resolution = ccf->timer_resolution;默认值是0 // 所以只有使用了timer_resolution指令才会发信号 if (ngx_timer_resolution && !(ngx_event_flags & NGX_USE_TIMER_EVENT)) { struct sigaction sa; struct itimerval itv; // 设置信号掩码,sigalarm 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; } // 设置信号发送的时间间隔,也就是nginx的时间精度 // 收到信号会设置设置ngx_event_timer_alarm变量 // 在epoll的ngx_epoll_process_events里检查,更新时间的标志 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; } } #else if (ngx_timer_resolution && !(ngx_event_flags & NGX_USE_TIMER_EVENT)) { ngx_log_error(NGX_LOG_WARN, cycle->log, 0, "the \"timer_resolution\" directive is not supported " "with the configured event method, ignored"); ngx_timer_resolution = 0; } #endif // 创建连接池数组,大小是cycle->connection_n // 直接使用malloc分配内存,没有使用内存池 cycle->connections = ngx_alloc(sizeof(ngx_connection_t) * cycle->connection_n, cycle->log); if (cycle->connections == NULL) { return NGX_ERROR; } c = cycle->connections; // 创建读事件池数组,大小是cycle->connection_n 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; } // 创建写事件池数组,大小是cycle->connection_n 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; } // i是数组的末尾 i = cycle->connection_n; next = NULL; // 把连接对象与读写事件关联起来 // 注意i是数组的末尾,从最后遍历 do { i--; // 使用data成员,把连接对象串成链表 c[i].data = next; // 读写事件 c[i].read = &cycle->read_events[i]; c[i].write = &cycle->write_events[i]; // 连接的描述符是-1,表示无效 c[i].fd = (ngx_socket_t) -1; // next指针指向数组的前一个元素 next = &c[i]; } while (i); // 连接对象已经串成链表,现在设置空闲链表指针 // 此时next指向连接对象数组的第一个元素 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++) { #if (NGX_HAVE_REUSEPORT) if (ls[i].reuseport && ls[i].worker != ngx_worker) { continue; } #endif // 获取一个空闲连接 c = ngx_get_connection(ls[i].fd, cycle->log); if (c == NULL) { return NGX_ERROR; } c->type = ls[i].type; c->log = &ls[i].log; c->listening = &ls[i]; ls[i].connection = c; rev = c->read; rev->log = c->log; // 设置accept标志,接受连接 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 // 重要!! // 设置接受连接的回调函数为ngx_event_accept // 监听端口上收到连接请求时的回调函数,即事件handler // 从cycle的连接池里获取连接 // 关键操作 ls->handler(c);调用其他模块的业务handler // 1.10使用ngx_event_recvmsg接收udp rev->handler = (c->type == SOCK_STREAM) ? ngx_event_accept : ngx_event_recvmsg; // 如果使用负载均衡,不向epoll添加事件,只有抢到锁才添加 if (ngx_use_accept_mutex #if (NGX_HAVE_REUSEPORT) && !ls[i].reuseport #endif ) { // 对一个监听端口的处理结束,只设置了回调函数 continue; } // nginx 1.9.x不再使用rtsig // 单进程、未明确指定负载均衡,不使用负载均衡 // 直接加入epoll事件,开始监听,可以接受请求 if (ngx_add_event(rev, NGX_READ_EVENT, 0) == NGX_ERROR) { return NGX_ERROR; } #endif } // 为每个监听端口分配一个连接对象循环结束 return NGX_OK; }
static void * ngx_http_js_calloc(void *mem, size_t size) { return ngx_calloc(size, ngx_cycle->log); }
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; }
//Here,This function very important! 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; //Means we used a multi worker!!!! 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 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) {//Here,find the used event scheme!!!! continue; } module = ngx_modules[m]->ctx; if (module->actions.init(cycle, ngx_timer_resolution) != NGX_OK) {//Here,we set the global ngx_event_actions!!!!! /* 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 //Here,we alloction the connection pool!! cycle->connections = ngx_alloc(sizeof(ngx_connection_t) * cycle->connection_n, cycle->log); if (cycle->connections == NULL) { return NGX_ERROR; } c = cycle->connections; //Here,alloction the read_events pool 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 } //Here,alloction the write_events pool 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; //Here,make a pair!!! on connection,to one rev and one wev!!! do { i--; c[i].data = next;//point to the next free connection!!!! 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;// //-------------->very important!!! //-------------->start to initilize a connection for every listening socket!!! for (i = 0; i < cycle->listening.nelts; i++) { c = ngx_get_connection(ls[i].fd, cycle->log);//Get a free connection! if (c == NULL) { return NGX_ERROR; } c->log = &ls[i].log; c->listening = &ls[i];//Means this connection bind to this listen socket!!! ls[i].connection = c; rev = c->read; rev->log = c->log; rev->accept = 1; //Means mark that this rev use to accept request,It is a special read_event!!! //This read_event handler should be call be for release the ngx_accept_mutex #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 //Here,set the read_handler!!! 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_init_threads(int n, size_t size, ngx_cycle_t *cycle) { char *red_zone, *zone; size_t len; ngx_int_t i; struct sigaction sa; max_threads = n + 1; for (i = 0; i < n; i++) { ngx_memzero(&sa, sizeof(struct sigaction)); sa.sa_handler = SIG_IGN; sigemptyset(&sa.sa_mask); if (sigaction(NGX_CV_SIGNAL, &sa, NULL) == -1) { ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, "sigaction(%d, SIG_IGN) failed", NGX_CV_SIGNAL); return NGX_ERROR; } } len = sizeof(ngx_freebsd_kern_usrstack); if (sysctlbyname("kern.usrstack", &ngx_freebsd_kern_usrstack, &len, NULL, 0) == -1) { ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, "sysctlbyname(kern.usrstack) failed"); return NGX_ERROR; } /* the main thread stack red zone */ rz_size = ngx_pagesize; red_zone = ngx_freebsd_kern_usrstack - (size + rz_size); ngx_log_debug2(NGX_LOG_DEBUG_CORE, cycle->log, 0, "usrstack: %p red zone: %p", ngx_freebsd_kern_usrstack, red_zone); zone = mmap(red_zone, rz_size, PROT_NONE, MAP_ANON, -1, 0); if (zone == MAP_FAILED) { ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, "mmap(%p:%uz, PROT_NONE, MAP_ANON) red zone failed", red_zone, rz_size); return NGX_ERROR; } if (zone != red_zone) { ngx_log_error(NGX_LOG_ALERT, cycle->log, 0, "red zone %p address was changed to %p", red_zone, zone); return NGX_ERROR; } /* create the thread errno' array */ errnos = ngx_calloc(n * sizeof(int), cycle->log); if (errnos == NULL) { return NGX_ERROR; } /* create the thread tids array */ tids = ngx_calloc((n + 1) * sizeof(ngx_tid_t), cycle->log); if (tids == NULL) { return NGX_ERROR; } tids[0] = ngx_pid; /* create the thread tls' array */ ngx_tls = ngx_calloc(NGX_THREAD_KEYS_MAX * (n + 1) * sizeof(void *), cycle->log); if (ngx_tls == NULL) { return NGX_ERROR; } nthreads = 1; last_stack = zone + rz_size; usable_stack_size = size; ngx_thread_stack_size = size + rz_size; /* allow the spinlock in libc malloc() */ __isthreaded = 1; ngx_threaded = 1; return NGX_OK; }
ngx_resolver_t * ngx_resolver_create(ngx_conf_t *cf, ngx_addr_t *addr) { ngx_resolver_t *r; ngx_pool_cleanup_t *cln; ngx_udp_connection_t *uc; cln = ngx_pool_cleanup_add(cf->pool, 0); if (cln == NULL) { return NULL; } cln->handler = ngx_resolver_cleanup; r = ngx_calloc(sizeof(ngx_resolver_t), cf->log); if (r == NULL) { return NULL; } cln->data = r; r->event = ngx_calloc(sizeof(ngx_event_t), cf->log); if (r->event == NULL) { return NULL; } ngx_rbtree_init(&r->name_rbtree, &r->name_sentinel, ngx_resolver_rbtree_insert_value); ngx_rbtree_init(&r->addr_rbtree, &r->addr_sentinel, ngx_rbtree_insert_value); ngx_queue_init(&r->name_resend_queue); ngx_queue_init(&r->addr_resend_queue); ngx_queue_init(&r->name_expire_queue); ngx_queue_init(&r->addr_expire_queue); r->event->handler = ngx_resolver_resend_handler; r->event->data = r; r->event->log = &cf->cycle->new_log; r->ident = -1; r->resend_timeout = 5; r->expire = 30; r->valid = 300; r->log = &cf->cycle->new_log; r->log_level = NGX_LOG_ALERT; if (addr) { uc = ngx_calloc(sizeof(ngx_udp_connection_t), cf->log); if (uc == NULL) { return NULL; } r->udp_connection = uc; uc->sockaddr = addr->sockaddr; uc->socklen = addr->socklen; uc->server = addr->name; uc->log = cf->cycle->new_log; uc->log.handler = ngx_resolver_log_error; uc->log.data = uc; uc->log.action = "resolving"; } return r; }
subscriber_t *longpoll_subscriber_create(ngx_http_request_t *r, nchan_msg_id_t *msg_id) { DBG("create for req %p", r); full_subscriber_t *fsub; nchan_request_ctx_t *ctx = ngx_http_get_module_ctx(r, nchan_module); //TODO: allocate from pool (but not the request's pool) if((fsub = ngx_alloc(sizeof(*fsub), ngx_cycle->log)) == NULL) { ERR("Unable to allocate"); assert(0); return NULL; } ngx_memcpy(&fsub->sub, &new_longpoll_sub, sizeof(new_longpoll_sub)); fsub->sub.request = r; fsub->data.cln = NULL; fsub->data.finalize_request = 1; fsub->data.holding = 0; fsub->data.act_as_intervalpoll = 0; fsub->sub.cf = ngx_http_get_module_loc_conf(r, nchan_module); ngx_memzero(&fsub->data.timeout_ev, sizeof(fsub->data.timeout_ev)); fsub->data.timeout_handler = empty_handler; fsub->data.timeout_handler_data = NULL; fsub->data.dequeue_handler = empty_handler; fsub->data.dequeue_handler_data = NULL; fsub->data.already_responded = 0; fsub->data.awaiting_destruction = 0; fsub->sub.reserved = 0; fsub->sub.enqueued = 0; if(fsub->sub.cf->longpoll_multimsg) { fsub->sub.dequeue_after_response = 0; } fsub->data.multimsg_first = NULL; fsub->data.multimsg_last = NULL; #if NCHAN_SUBSCRIBER_LEAK_DEBUG subscriber_debug_add(&fsub->sub); //set debug label fsub->sub.lbl = ngx_calloc(r->uri.len+1, ngx_cycle->log); ngx_memcpy(fsub->sub.lbl, r->uri.data, r->uri.len); #endif if(msg_id) { nchan_copy_new_msg_id(&fsub->sub.last_msgid, msg_id); } else { fsub->sub.last_msgid.time = 0; fsub->sub.last_msgid.tag.fixed[0] = 0; fsub->sub.last_msgid.tagcount = 1; } ctx->prev_msg_id = fsub->sub.last_msgid; fsub->data.owner = memstore_slot(); //http request sudden close cleanup if((fsub->data.cln = ngx_http_cleanup_add(r, 0)) == NULL) { ERR("Unable to add request cleanup for longpoll subscriber"); assert(0); return NULL; } fsub->data.cln->data = fsub; fsub->data.cln->handler = (ngx_http_cleanup_pt )sudden_abort_handler; DBG("%p created for request %p", &fsub->sub, r); if(ctx) { ctx->sub = &fsub->sub; ctx->subscriber_type = fsub->sub.name; } return &fsub->sub; }
//初始化事件处理函数 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; //是否获得accept互斥锁 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 //初始化accept请求队列(使用accept锁) ngx_queue_init(&ngx_posted_accept_events); ngx_queue_init(&ngx_posted_events); if (ngx_event_timer_init(cycle->log) == NGX_ERROR) { return NGX_ERROR; } //初始化事件驱动模块 for (m = 0; cycle->modules[m]; m++) { /*循环事件驱动模块,跳过模块类型为非NGX_EVENT_MODULE类型的模块*/ //调用event/modules/*.c if (cycle->modules[m]->type != NGX_EVENT_MODULE) { continue; } //如果非当前使用的模块则跳过( ngx_event_core_init_conf 定义) if (cycle->modules[m]->ctx_index != ecf->use) { continue; } module = cycle->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; } } #else if (ngx_timer_resolution && !(ngx_event_flags & NGX_USE_TIMER_EVENT)) { ngx_log_error(NGX_LOG_WARN, cycle->log, 0, "the \"timer_resolution\" directive is not supported " "with the configured event method, ignored"); ngx_timer_resolution = 0; } #endif //创建connections数组,保存连接信息 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; } //创建写事件数组 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; } 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]; } while (i); //初始化完成后,free_connections指向 cycle->connections第一个元素 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++) { #if (NGX_HAVE_REUSEPORT) if (ls[i].reuseport && ls[i].worker != ngx_worker) { continue; } #endif c = ngx_get_connection(ls[i].fd, cycle->log); if (c == NULL) { return NGX_ERROR; } c->type = ls[i].type; 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 = (c->type == SOCK_STREAM) ? ngx_event_accept : ngx_event_recvmsg; if (ngx_use_accept_mutex #if (NGX_HAVE_REUSEPORT) && !ls[i].reuseport #endif ) { continue; } //添加事件 if (ngx_add_event(rev, NGX_READ_EVENT, 0) == NGX_ERROR) { return NGX_ERROR; } #endif } return NGX_OK; }