void ngx_buffer_cache_reset_stats(ngx_buffer_cache_t* cache) { ngx_shmtx_lock(&cache->shpool->mutex); ngx_memzero(&cache->sh->stats, sizeof(cache->sh->stats)); ngx_shmtx_unlock(&cache->shpool->mutex); }
static ngx_int_t ngx_http_vhost_traffic_status_dump_restore_add_node(ngx_event_t *ev, ngx_http_vhost_traffic_status_node_t *ovtsn, ngx_str_t *key) { size_t size; uint32_t hash; ngx_slab_pool_t *shpool; ngx_rbtree_node_t *node; ngx_http_vhost_traffic_status_ctx_t *ctx; ngx_http_vhost_traffic_status_node_t *vtsn; ctx = ev->data; if (key->len == 0) { return NGX_ERROR; } shpool = (ngx_slab_pool_t *) ctx->shm_zone->shm.addr; ngx_shmtx_lock(&shpool->mutex); /* find node */ hash = ngx_crc32_short(key->data, key->len); node = ngx_http_vhost_traffic_status_node_lookup(ctx->rbtree, key, hash); /* copy node */ if (node == NULL) { size = offsetof(ngx_rbtree_node_t, color) + offsetof(ngx_http_vhost_traffic_status_node_t, data) + key->len; node = ngx_slab_alloc_locked(shpool, size); if (node == NULL) { ngx_log_error(NGX_LOG_ALERT, ev->log, 0, "dump_restore_add_node::ngx_slab_alloc_locked() failed"); ngx_shmtx_unlock(&shpool->mutex); return NGX_ERROR; } vtsn = (ngx_http_vhost_traffic_status_node_t *) &node->color; node->key = hash; *vtsn = *ovtsn; ngx_memcpy(vtsn->data, key->data, key->len); ngx_rbtree_insert(ctx->rbtree, node); } ngx_shmtx_unlock(&shpool->mutex); return NGX_OK; }
/* * 添加缓存文件到红黑树和队列中,通过 ngx_http_file_cache_t 结构管理此节点 */ static ngx_int_t ngx_http_file_cache_add(ngx_http_file_cache_t *cache, ngx_http_cache_t *c) { ngx_http_file_cache_node_t *fcn; ngx_shmtx_lock(&cache->shpool->mutex); // 根据key在二叉树中查找,没有找到添加一个节点到cache中 fcn = ngx_http_file_cache_lookup(cache, c->key); if (fcn == NULL) { fcn = ngx_slab_alloc_locked(cache->shpool, sizeof(ngx_http_file_cache_node_t)); if (fcn == NULL) { ngx_shmtx_unlock(&cache->shpool->mutex); return NGX_ERROR; } // 设置node结点key ngx_memcpy((u_char *) &fcn->node.key, c->key, sizeof(ngx_rbtree_key_t)); ngx_memcpy(fcn->key, &c->key[sizeof(ngx_rbtree_key_t)], NGX_HTTP_CACHE_KEY_LEN - sizeof(ngx_rbtree_key_t)); // 当前结点插入到二叉树中 ngx_rbtree_insert(&cache->sh->rbtree, &fcn->node); fcn->uses = 1; fcn->count = 0; fcn->valid_msec = 0; fcn->error = 0; fcn->exists = 1; fcn->updating = 0; fcn->deleting = 0; fcn->uniq = 0; fcn->valid_sec = 0; fcn->body_start = 0; fcn->fs_size = c->fs_size; cache->sh->size += c->fs_size; } else { ngx_queue_remove(&fcn->queue); } // 设置过期时间(当前时间+不活跃时间) fcn->expire = ngx_time() + cache->inactive; // 插入到队列头部,先插入的在队列的尾部 ngx_queue_insert_head(&cache->sh->queue, &fcn->queue); ngx_shmtx_unlock(&cache->shpool->mutex); return NGX_OK; }
int ngx_tcp_lua_ffi_shdict_incr(ngx_shm_zone_t *zone, u_char *key, size_t key_len, double *value, char **err) { uint32_t hash; ngx_int_t rc; ngx_tcp_lua_shdict_ctx_t *ctx; ngx_tcp_lua_shdict_node_t *sd; double num; u_char *p; ctx = zone->data; hash = ngx_crc32_short(key, key_len); dd("looking up key %.*s in shared dict %.*s", (int) key_len, key, (int) ctx->name.len, ctx->name.data); ngx_shmtx_lock(&ctx->shpool->mutex); #if 1 ngx_tcp_lua_shdict_expire(ctx, 1); #endif rc = ngx_tcp_lua_shdict_lookup(zone, hash, key, key_len, &sd); dd("shdict lookup returned %d", (int) rc); if (rc == NGX_DECLINED || rc == NGX_DONE) { ngx_shmtx_unlock(&ctx->shpool->mutex); *err = "not found"; return NGX_ERROR; } /* rc == NGX_OK */ if (sd->value_type != LUA_TNUMBER || sd->value_len != sizeof(double)) { ngx_shmtx_unlock(&ctx->shpool->mutex); *err = "not a number"; return NGX_ERROR; } ngx_queue_remove(&sd->queue); ngx_queue_insert_head(&ctx->sh->queue, &sd->queue); dd("setting value type to %d", (int) sd->value_type); p = sd->data + key_len; num = *(double *) p; num += *value; ngx_memcpy(p, (double *) &num, sizeof(double)); ngx_shmtx_unlock(&ctx->shpool->mutex); *value = num; return NGX_OK; }
static ngx_inline void ngx_http_push_stream_process_worker_message(void) { ngx_http_push_stream_worker_msg_t *worker_msg, *sentinel; ngx_slab_pool_t *shpool = (ngx_slab_pool_t *) ngx_http_push_stream_shm_zone->shm.addr; ngx_http_push_stream_worker_data_t *workers_data = ((ngx_http_push_stream_shm_data_t *) ngx_http_push_stream_shm_zone->data)->ipc; ngx_http_push_stream_worker_data_t *thisworker_data = workers_data + ngx_process_slot; sentinel = thisworker_data->messages_queue; while ((worker_msg = (ngx_http_push_stream_worker_msg_t *) ngx_queue_next(&sentinel->queue)) != sentinel) { if (worker_msg->pid == ngx_pid) { // everything is okay ngx_http_push_stream_respond_to_subscribers(worker_msg->channel, worker_msg->subscribers_sentinel, worker_msg->msg); } else { // that's quite bad you see. a previous worker died with an undelivered message. // but all its subscribers' connections presumably got canned, too. so it's not so bad after all. ngx_http_push_stream_pid_queue_t *channel_worker_sentinel = &worker_msg->channel->workers_with_subscribers; ngx_http_push_stream_pid_queue_t *channel_worker_cur = channel_worker_sentinel; ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0, "push stream module: worker %i intercepted a message intended for another worker process (%i) that probably died", ngx_pid, worker_msg->pid); // delete that invalid sucker while ((channel_worker_cur != NULL) && (channel_worker_cur = (ngx_http_push_stream_pid_queue_t *) ngx_queue_next(&channel_worker_cur->queue)) != channel_worker_sentinel) { if (channel_worker_cur->pid == worker_msg->pid) { ngx_log_error(NGX_LOG_INFO, ngx_cycle->log, 0, "push stream module: reference to worker %i will be removed", worker_msg->pid); ngx_shmtx_lock(&shpool->mutex); ngx_queue_remove(&channel_worker_cur->queue); ngx_slab_free_locked(shpool, channel_worker_cur); ngx_shmtx_unlock(&shpool->mutex); channel_worker_cur = NULL; break; } } } // free worker_msg already sent ngx_shmtx_lock(&shpool->mutex); ngx_http_push_stream_free_worker_message_memory_locked(shpool, worker_msg); ngx_shmtx_unlock(&shpool->mutex); } }
//free memory for a message. static ngx_inline void ngx_http_push_free_message_locked(ngx_http_push_msg_t *msg, ngx_slab_pool_t *shpool) { if(msg->buf->file!=NULL) { ngx_shmtx_unlock(&shpool->mutex); ngx_close_file(msg->buf->file->fd); //again, carest thou aboutst thine errorests? ngx_delete_file(msg->buf->file->name.data); //should I care about deletion errors? ngx_shmtx_lock(&shpool->mutex); } ngx_slab_free_locked(shpool, msg->buf); //separate block, remember? ngx_slab_free_locked(shpool, msg); }
static ngx_int_t ngx_http_sla_init_zone (ngx_shm_zone_t* shm_zone, void* data) { ngx_str_t name; ngx_http_sla_pool_t* pool = shm_zone->data; ngx_http_sla_pool_t* old_pool = data; if (old_pool != NULL) { /* идет перезагрузка потомков, пытаемся сохранить старые данные, если пул не менялся */ pool->shm_pool = old_pool->shm_pool; pool->shm_ctx = old_pool->shm_ctx; ngx_shmtx_lock(&pool->shm_pool->mutex); pool->generation = pool->shm_ctx->generation; if (ngx_http_sla_compare_pools(pool, old_pool) == NGX_OK) { /* если пул не менялся, поколение не меняется */ ngx_shmtx_unlock(&pool->shm_pool->mutex); return NGX_OK; } } else { /* первый запуск, аллокация shm */ pool->shm_pool = (ngx_slab_pool_t*)shm_zone->shm.addr; pool->shm_ctx = ngx_slab_alloc(pool->shm_pool, sizeof(ngx_http_sla_pool_shm_t) * NGX_HTTP_SLA_MAX_COUNTERS_LEN); if (pool->shm_ctx == NULL) { return NGX_ERROR; } ngx_shmtx_lock(&pool->shm_pool->mutex); } /* пул изменился или первый запуск */ ngx_memzero(pool->shm_ctx, sizeof(ngx_http_sla_pool_shm_t) * NGX_HTTP_SLA_MAX_COUNTERS_LEN); ngx_str_set(&name, "all"); ngx_http_sla_add_counter(pool, &name, 0); pool->generation++; pool->shm_ctx->generation = pool->generation; ngx_shmtx_unlock(&pool->shm_pool->mutex); return NGX_OK; }
static ngx_int_t ngx_http_req_status_write_filter(ngx_http_request_t *r, off_t bsent) { off_t bytes; ngx_uint_t i; ngx_msec_t td; ngx_http_req_status_ctx_t *r_ctx; ngx_http_req_status_data_t *data; ngx_http_req_status_zone_node_t *pzn; ngx_http_req_status_main_conf_t *rmcf; r_ctx = ngx_http_get_module_ctx(r, ngx_http_req_status_module); if (r_ctx == NULL || r_ctx->req_zones.nelts == 0){ return NGX_DECLINED; } rmcf = ngx_http_get_module_main_conf(r, ngx_http_req_status_module); pzn = r_ctx->req_zones.elts; bytes = r->connection->sent - bsent; for (i = 0; i < r_ctx->req_zones.nelts; i++){ data = &pzn[i].node->data; ngx_shmtx_lock(&pzn[i].zone->shpool->mutex); data->traffic += bytes; if (ngx_current_msec > pzn[i].node->last_traffic_start){ td = ngx_current_msec - pzn[i].node->last_traffic_start; if (td >= rmcf->interval){ data->bandwidth = pzn[i].node->last_traffic * 1000 / td; if (data->bandwidth > data->max_bandwidth){ data->max_bandwidth = data->bandwidth; } pzn[i].node->last_traffic = 0; pzn[i].node->last_traffic_start = ngx_current_msec; } } pzn[i].node->last_traffic += bytes; if (ngx_current_msec > pzn[i].node->last_traffic_update){ pzn[i].node->last_traffic_update = ngx_current_msec; } ngx_shmtx_unlock(&pzn[i].zone->shpool->mutex); } return NGX_DECLINED; }
static ngx_int_t ngx_http_push_stream_registry_subscriber(ngx_http_request_t *r, ngx_http_push_stream_subscriber_t *worker_subscriber) { ngx_http_push_stream_main_conf_t *mcf = ngx_http_get_module_main_conf(r, ngx_http_push_stream_module); ngx_http_push_stream_loc_conf_t *cf = ngx_http_get_module_loc_conf(r, ngx_http_push_stream_module); ngx_http_push_stream_shm_data_t *data = mcf->shm_data; ngx_http_push_stream_worker_data_t *thisworker_data = &data->ipc[ngx_process_slot]; ngx_msec_t connection_ttl = worker_subscriber->longpolling ? cf->longpolling_connection_ttl : cf->subscriber_connection_ttl; ngx_http_push_stream_module_ctx_t *ctx = ngx_http_get_module_ctx(r, ngx_http_push_stream_module); ngx_slab_pool_t *shpool = mcf->shpool; // adding subscriber to worker list of subscribers ngx_queue_insert_tail(&thisworker_data->subscribers_queue, &worker_subscriber->worker_queue); ctx->longpolling = worker_subscriber->longpolling; ctx->subscriber = worker_subscriber; if ((connection_ttl != NGX_CONF_UNSET_MSEC) || (cf->ping_message_interval != NGX_CONF_UNSET_MSEC)) { if (connection_ttl != NGX_CONF_UNSET_MSEC) { if ((ctx->disconnect_timer = ngx_pcalloc(worker_subscriber->request->pool, sizeof(ngx_event_t))) == NULL) { return NGX_ERROR; } } if ((!ctx->longpolling) && (cf->ping_message_interval != NGX_CONF_UNSET_MSEC)) { if ((ctx->ping_timer = ngx_pcalloc(worker_subscriber->request->pool, sizeof(ngx_event_t))) == NULL) { return NGX_ERROR; } } if (ctx->disconnect_timer != NULL) { ctx->disconnect_timer->handler = ngx_http_push_stream_disconnect_timer_wake_handler; ctx->disconnect_timer->data = worker_subscriber->request; ctx->disconnect_timer->log = worker_subscriber->request->connection->log; ngx_http_push_stream_timer_reset(connection_ttl, ctx->disconnect_timer); } if (ctx->ping_timer != NULL) { ctx->ping_timer->handler = ngx_http_push_stream_ping_timer_wake_handler; ctx->ping_timer->data = worker_subscriber->request; ctx->ping_timer->log = worker_subscriber->request->connection->log; ngx_http_push_stream_timer_reset(cf->ping_message_interval, ctx->ping_timer); } } // increment global subscribers count ngx_shmtx_lock(&shpool->mutex); data->subscribers++; ngx_shmtx_unlock(&shpool->mutex); thisworker_data->subscribers++; return NGX_OK; }
static ngx_int_t ngx_http_push_handle_subscriber_concurrency(ngx_http_request_t *r, ngx_http_push_channel_t *channel, ngx_http_push_loc_conf_t *loc_conf) { ngx_int_t max_subscribers = loc_conf->max_channel_subscribers; ngx_int_t current_subscribers; ngx_shmtx_lock(&ngx_http_push_shpool->mutex); current_subscribers = channel->subscribers; ngx_shmtx_unlock(&ngx_http_push_shpool->mutex); if(current_subscribers==0) { //empty channels are always okay. return NGX_OK; } if(max_subscribers!=0 && current_subscribers >= max_subscribers) { //max_channel_subscribers setting ngx_http_push_respond_status_only(r, NGX_HTTP_FORBIDDEN, NULL); return NGX_DECLINED; } //nonzero number of subscribers present switch(loc_conf->subscriber_concurrency) { case NGX_HTTP_PUSH_SUBSCRIBER_CONCURRENCY_BROADCAST: return NGX_OK; case NGX_HTTP_PUSH_SUBSCRIBER_CONCURRENCY_LASTIN: ngx_shmtx_lock(&ngx_http_push_shpool->mutex); //send "everyone" a 409 Conflict response. //in most reasonable cases, there'll be at most one subscriber on the //channel. However, since settings are bound to locations and not //specific channels, this assumption need not hold. Hence this broadcast. ngx_int_t rc = ngx_http_push_broadcast_status_locked(channel, NGX_HTTP_NOT_FOUND, &NGX_HTTP_PUSH_HTTP_STATUS_409, r->connection->log, ngx_http_push_shpool); ngx_shmtx_unlock(&ngx_http_push_shpool->mutex); return NGX_OK; case NGX_HTTP_PUSH_SUBSCRIBER_CONCURRENCY_FIRSTIN: ngx_http_push_respond_status_only(r, NGX_HTTP_NOT_FOUND, &NGX_HTTP_PUSH_HTTP_STATUS_409); return NGX_DECLINED; default: return NGX_ERROR; } }
//free memory for a message. static ngx_inline void ngx_http_push_free_message_locked(ngx_http_push_msg_t *msg, ngx_slab_pool_t *shpool) { if(msg->buf->file!=NULL) { ngx_shmtx_unlock(&shpool->mutex); if(msg->buf->file->fd!=NGX_INVALID_FILE) { ngx_close_file(msg->buf->file->fd); } ngx_delete_file(msg->buf->file->name.data); //should I care about deletion errors? doubt it. ngx_shmtx_lock(&shpool->mutex); } ngx_slab_free_locked(shpool, msg->buf); //separate block, remember? ngx_slab_free_locked(shpool, msg); }
static void ngx_http_push_subscriber_cleanup(ngx_http_push_subscriber_cleanup_t *data) { if(data->subscriber!=NULL) { //still queued up ngx_queue_remove(&data->subscriber->queue); ngx_pfree(ngx_http_push_pool, data->subscriber); //was there an error? oh whatever. } if(data->channel!=NULL) { //we're expected to decrement the subscriber count ngx_slab_pool_t *shpool = (ngx_slab_pool_t *) ngx_http_push_shm_zone->shm.addr; ngx_shmtx_lock(&shpool->mutex); data->channel->subscribers--; ngx_shmtx_unlock(&shpool->mutex); } }
int ngx_shmap_flush_expired(ngx_shm_zone_t* zone, int attempts) { ngx_queue_t *q, *prev; ngx_shmap_node_t *sd; ngx_shmap_ctx_t *ctx; ngx_time_t *tp; int freed = 0; ngx_rbtree_node_t *node; uint64_t now; assert(zone != NULL); ctx = zone->data; ngx_shmtx_lock(&ctx->shpool->mutex); if (ngx_queue_empty(&ctx->sh->queue)) { return 0; } tp = ngx_timeofday(); now = (uint64_t) tp->sec * 1000 + tp->msec; q = ngx_queue_last(&ctx->sh->queue); while (q != ngx_queue_sentinel(&ctx->sh->queue)) { prev = ngx_queue_prev(q); sd = ngx_queue_data(q, ngx_shmap_node_t, queue); if (sd->expires != 0 && sd->expires <= now) { ngx_queue_remove(q); node = (ngx_rbtree_node_t *) ((u_char *) sd - offsetof(ngx_rbtree_node_t, color)); ngx_rbtree_delete(&ctx->sh->rbtree, node); ngx_slab_free_locked(ctx->shpool, node); freed++; if (attempts && freed == attempts) { break; } } q = prev; } ngx_shmtx_unlock(&ctx->shpool->mutex); return freed; }
static ngx_int_t ngx_http_limit_access_handler(ngx_http_request_t *r) { ngx_int_t rc; ngx_http_limit_access_ctx_t *ctx; ngx_http_limit_access_conf_t *lacf; ngx_http_limit_access_hash_t *hash; lacf = ngx_http_get_module_loc_conf(r, ngx_http_limit_access_module); ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "limit_access_handler: %p, %d", lacf->shm_zone, lacf->limit_check); if (lacf->shm_zone == NULL || !lacf->limit_check) { return NGX_DECLINED; } ctx = lacf->shm_zone->data; ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "limit_access_handler"); ngx_shmtx_lock(&ctx->shpool->mutex); hash = ctx->sh; if (!hash->valid) { ngx_shmtx_unlock(&ctx->shpool->mutex); return NGX_DECLINED; } rc = 0; if (ctx->type == HASH_IP) { rc = ngx_http_limit_access_lookup_ip(r, ctx); } if (ctx->type == HASH_VARIABLE) { rc = ngx_http_limit_access_lookup_variable(r, ctx); } ngx_shmtx_unlock(&ctx->shpool->mutex); if (rc == 1) { ngx_log_error(lacf->limit_log_level, r->connection->log, 0, "access forbidden by limit_access"); return NGX_HTTP_FORBIDDEN; } return NGX_DECLINED; }
static ngx_int_t ngx_http_push_store_delete_channel(ngx_http_push_channel_t *channel, ngx_http_request_t *r) { ngx_http_push_msg_t *msg, *sentinel; ngx_shmtx_lock(&ngx_http_push_shpool->mutex); sentinel = channel->message_queue; msg = sentinel; while((msg=(ngx_http_push_msg_t *)ngx_queue_next(&msg->queue))!=sentinel) { //force-delete all the messages ngx_http_push_force_delete_message_locked(NULL, msg, ngx_http_push_shpool); } channel->messages=0; //410 gone ngx_shmtx_unlock(&ngx_http_push_shpool->mutex); ngx_http_push_store_publish(channel, NULL, NGX_HTTP_GONE, &NGX_HTTP_PUSH_HTTP_STATUS_410, r->connection->log); ngx_shmtx_lock(&ngx_http_push_shpool->mutex); ngx_http_push_delete_channel_locked(channel); ngx_shmtx_unlock(&ngx_http_push_shpool->mutex); return NGX_OK; }
void * ngx_slab_alloc(ngx_slab_pool_t *pool, size_t size) { void *p; ngx_shmtx_lock(&pool->mutex); p = ngx_slab_alloc_locked(pool, size); ngx_shmtx_unlock(&pool->mutex); return p; }
static ngx_int_t ngx_http_push_stream_send_response_channels_info_detailed(ngx_http_request_t *r, ngx_http_push_stream_requested_channel_t *requested_channels) { ngx_str_t *text; ngx_queue_t queue_channel_info; ngx_http_push_stream_main_conf_t *mcf = ngx_http_get_module_main_conf(r, ngx_http_push_stream_module); ngx_slab_pool_t *shpool = mcf->shpool; ngx_http_push_stream_content_subtype_t *subtype = ngx_http_push_stream_match_channel_info_format_and_content_type(r, 1); ngx_http_push_stream_channel_info_t *channel_info; ngx_http_push_stream_channel_t *channel = NULL; ngx_http_push_stream_requested_channel_t *requested_channel; ngx_queue_t *cur = &requested_channels->queue; ngx_uint_t qtd_channels = 0; ngx_queue_init(&queue_channel_info); ngx_shmtx_lock(&shpool->mutex); while ((cur = ngx_queue_next(cur)) != &requested_channels->queue) { requested_channel = ngx_queue_data(cur, ngx_http_push_stream_requested_channel_t, queue); // search for a existing channel with this id channel = ngx_http_push_stream_find_channel(requested_channel->id, r->connection->log, mcf); if ((channel != NULL) && ((channel_info = ngx_pcalloc(r->pool, sizeof(ngx_http_push_stream_channel_info_t))) != NULL)) { channel_info->id.data = channel->id.data; channel_info->id.len = channel->id.len; channel_info->published_messages = channel->last_message_id; channel_info->stored_messages = channel->stored_messages; channel_info->subscribers = channel->subscribers; ngx_queue_insert_tail(&queue_channel_info, &channel_info->queue); qtd_channels++; } } ngx_shmtx_unlock(&shpool->mutex); if (qtd_channels == 0) { return ngx_http_push_stream_send_only_header_response(r, NGX_HTTP_NOT_FOUND, NULL); } if (qtd_channels == 1) { channel_info = ngx_queue_data(ngx_queue_head(&queue_channel_info), ngx_http_push_stream_channel_info_t, queue); text = ngx_http_push_stream_channel_info_formatted(r->pool, subtype->format_item, &channel_info->id, channel_info->published_messages, channel_info->stored_messages, channel_info->subscribers); if (text == NULL) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "Failed to allocate response buffer."); return NGX_HTTP_INTERNAL_SERVER_ERROR; } return ngx_http_push_stream_send_response(r, text, subtype->content_type, NGX_HTTP_OK); } return ngx_http_push_stream_send_response_channels_info(r, &queue_channel_info); }
static ngx_int_t ngx_http_file_cache_add(ngx_http_file_cache_t *cache, ngx_http_cache_t *c) { ngx_http_file_cache_node_t *fcn; ngx_shmtx_lock(&cache->shpool->mutex); fcn = ngx_http_file_cache_lookup(cache, c->key); if (fcn == NULL) { fcn = ngx_slab_alloc_locked(cache->shpool, sizeof(ngx_http_file_cache_node_t)); if (fcn == NULL) { ngx_shmtx_unlock(&cache->shpool->mutex); return NGX_ERROR; } ngx_memcpy((u_char *) &fcn->node.key, c->key, sizeof(ngx_rbtree_key_t)); ngx_memcpy(fcn->key, &c->key[sizeof(ngx_rbtree_key_t)], NGX_HTTP_CACHE_KEY_LEN - sizeof(ngx_rbtree_key_t)); ngx_rbtree_insert(&cache->sh->rbtree, &fcn->node); fcn->uses = 1; fcn->count = 0; fcn->valid_msec = c->valid_msec; fcn->error = 0; fcn->exists = 1; fcn->updating = 0; fcn->deleting = 0; fcn->uniq = c->uniq; fcn->valid_sec = c->valid_sec; fcn->body_start = c->body_start; fcn->fs_size = c->fs_size; cache->sh->size += c->fs_size; } else { ngx_queue_remove(&fcn->queue); } fcn->expire = ngx_time() + cache->inactive; ngx_queue_insert_head(&cache->sh->queue, &fcn->queue); ngx_shmtx_unlock(&cache->shpool->mutex); return NGX_OK; }
void ngx_http_session_shm_free(void *p) { ngx_http_session_list_t *session_list; session_list = ngx_http_session_shm_zone->data; ngx_shmtx_lock(&session_list->shpool->mutex); ngx_slab_free_locked(session_list->shpool, p); ngx_shmtx_unlock(&session_list->shpool->mutex); return; }
static ngx_int_t ngx_http_session_manager(void) { ngx_http_session_t *session; ngx_http_session_list_t *session_list; session_list = ngx_http_session_shm_zone->data; ngx_shmtx_lock(&session_list->shpool->mutex); session = session_list->new_chain_head; if (!session) { goto out; } while (session) { /* add timer to session */ session->ev.handler = ngx_http_session_timeout_handler; session->ev.data = session; session->ev.log = session_list->log; if (session->timeout == 0) { session->timeout = 60; } session->timeout = session->timeout - (ngx_time() - session->est) * 1000; if (session->ev.timer_set) { ngx_del_timer(&session->ev); } ngx_add_timer(&session->ev, session->timeout); session_list->new_chain_head = session->new_chain_next; session->new_chain_next = NULL; session->wait = 0; session->reset = 0; session = session_list->new_chain_head; } session_list->new_chain_head = session_list->new_chain_tail = NULL; out: ngx_shmtx_unlock(&session_list->shpool->mutex); return NGX_OK; }
static ngx_int_t ngx_http_file_cache_lock(ngx_http_request_t *r, ngx_http_cache_t *c) { ngx_msec_t now, timer; ngx_http_file_cache_t *cache; if (!c->lock) { return NGX_DECLINED; } cache = c->file_cache; ngx_shmtx_lock(&cache->shpool->mutex); if (!c->node->updating) { c->node->updating = 1; c->updating = 1; } ngx_shmtx_unlock(&cache->shpool->mutex); ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http file cache lock u:%d wt:%M", c->updating, c->wait_time); if (c->updating) { return NGX_DECLINED; } c->waiting = 1; now = ngx_current_msec; if (c->wait_time == 0) { c->wait_time = now + c->lock_timeout; c->wait_event.handler = ngx_http_file_cache_lock_wait_handler; c->wait_event.data = r; c->wait_event.log = r->connection->log; } timer = c->wait_time - now; ngx_add_timer(&c->wait_event, (timer > 500) ? 500 : timer); r->main->blocked++; return NGX_AGAIN; }
static void ngx_http_limit_traffic_rate_filter_cleanup(void *data) { ngx_http_limit_traffic_rate_filter_cleanup_t *lircln = data; ngx_slab_pool_t *shpool; ngx_rbtree_node_t *node; ngx_http_limit_traffic_rate_filter_ctx_t *ctx; ngx_http_limit_traffic_rate_filter_node_t *lir; ctx = lircln->shm_zone->data; shpool = (ngx_slab_pool_t *) lircln->shm_zone->shm.addr; node = lircln->node; lir = (ngx_http_limit_traffic_rate_filter_node_t *) &node->color; ngx_shmtx_lock(&shpool->mutex); ngx_log_debug2(NGX_LOG_DEBUG_HTTP, lircln->shm_zone->shm.log, 0, "limit traffic rate cleanup: %08XD %d", node->key, lir->conn); lir->conn--; if (lir->conn == 0) { ngx_queue_t *p = lir->rq_top.next; ngx_queue_t *c; ngx_http_limit_traffic_rate_filter_request_queue_t * tr; for(; p; ){ c = p; p = ngx_queue_next(p); if(ngx_queue_next(c) && ngx_queue_prev(c)){ ngx_queue_remove(c); } tr = ngx_queue_data(c, ngx_http_limit_traffic_rate_filter_request_queue_t, rq); if (!tr->r){ ngx_slab_free_locked(shpool, tr); } if(ngx_queue_last(&lir->rq_top) == p){ break; } } ngx_rbtree_delete(ctx->rbtree, node); ngx_slab_free_locked(shpool, node); } ngx_shmtx_unlock(&shpool->mutex); }
ngx_flag_t ngx_buffer_cache_fetch( ngx_buffer_cache_t* cache, u_char* key, ngx_str_t* buffer, uint32_t* token) { ngx_buffer_cache_entry_t* entry; ngx_buffer_cache_sh_t *sh = cache->sh; ngx_flag_t result = 0; uint32_t hash; hash = ngx_crc32_short(key, BUFFER_CACHE_KEY_SIZE); ngx_shmtx_lock(&cache->shpool->mutex); if (!sh->reset) { entry = ngx_buffer_cache_rbtree_lookup(&sh->rbtree, key, hash); if (entry != NULL && entry->state == CES_READY && (cache->expiration == 0 || ngx_time() < (time_t)(entry->write_time + cache->expiration))) { result = 1; // update stats sh->stats.fetch_hit++; sh->stats.fetch_bytes += entry->buffer_size; // copy buffer pointer and size buffer->data = entry->start_offset; buffer->len = entry->buffer_size; *token = entry->write_time; // Note: setting the access time of the entry and cache to prevent it // from being freed while the caller uses the buffer sh->access_time = entry->access_time = ngx_time(); (void)ngx_atomic_fetch_add(&entry->ref_count, 1); } else { // update stats sh->stats.fetch_miss++; } } ngx_shmtx_unlock(&cache->shpool->mutex); return result; }
void * ngx_http_session_shm_alloc(size_t size) { ngx_http_session_list_t *session_list; void *p; session_list = ngx_http_session_shm_zone->data; ngx_shmtx_lock(&session_list->shpool->mutex); p = ngx_slab_alloc_locked(session_list->shpool, size); ngx_shmtx_unlock(&session_list->shpool->mutex); return p; }
static void ngx_http_file_cache_delete(ngx_http_file_cache_t *cache, ngx_queue_t *q, u_char *name) { u_char *p; size_t len; ngx_path_t *path; ngx_http_file_cache_node_t *fcn; fcn = ngx_queue_data(q, ngx_http_file_cache_node_t, queue); if (fcn->exists) { cache->sh->size -= fcn->fs_size; path = cache->path; p = name + path->name.len + 1 + path->len; p = ngx_hex_dump(p, (u_char *) &fcn->node.key, sizeof(ngx_rbtree_key_t)); len = NGX_HTTP_CACHE_KEY_LEN - sizeof(ngx_rbtree_key_t); p = ngx_hex_dump(p, fcn->key, len); *p = '\0'; fcn->count++; fcn->deleting = 1; ngx_shmtx_unlock(&cache->shpool->mutex); len = path->name.len + 1 + path->len + 2 * NGX_HTTP_CACHE_KEY_LEN; ngx_create_hashed_filename(path, name, len); ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, "http file cache expire: \"%s\"", name); if (ngx_delete_file(name) == NGX_FILE_ERROR) { ngx_log_error(NGX_LOG_CRIT, ngx_cycle->log, ngx_errno, ngx_delete_file_n " \"%s\" failed", name); } ngx_shmtx_lock(&cache->shpool->mutex); fcn->count--; fcn->deleting = 0; } if (fcn->count == 0) { ngx_queue_remove(q); ngx_rbtree_delete(&cache->sh->rbtree, &fcn->node); ngx_slab_free_locked(cache->shpool, fcn); } }
static ngx_int_t ngx_http_push_broadcast_locked(ngx_http_push_channel_t *channel, ngx_http_push_msg_t *msg, ngx_int_t status_code, const ngx_str_t *status_line, ngx_log_t *log, ngx_slab_pool_t *shpool) { //subscribers are queued up in a local pool. Queue heads, however, are located //in shared memory, identified by pid. ngx_http_push_pid_queue_t *sentinel = &channel->workers_with_subscribers; ngx_http_push_pid_queue_t *cur = sentinel; ngx_int_t received; received = channel->subscribers > 0 ? NGX_HTTP_PUSH_MESSAGE_RECEIVED : NGX_HTTP_PUSH_MESSAGE_QUEUED; if(msg!=NULL && received==NGX_HTTP_PUSH_MESSAGE_RECEIVED) { ngx_http_push_reserve_message_locked(channel, msg); } while((cur=(ngx_http_push_pid_queue_t *)ngx_queue_next(&cur->queue))!=sentinel) { pid_t worker_pid = cur->pid; ngx_int_t worker_slot = cur->slot; ngx_http_push_subscriber_t *subscriber_sentinel= cur->subscriber_sentinel; ngx_shmtx_unlock(&shpool->mutex); if(worker_pid == ngx_pid) { //my subscribers ngx_http_push_respond_to_subscribers(channel, subscriber_sentinel, msg, status_code, status_line); } else { //some other worker's subscribers //interprocess communication breakdown if(ngx_http_push_send_worker_message(channel, subscriber_sentinel, worker_pid, worker_slot, msg, status_code, log) != NGX_ERROR) { ngx_http_push_alert_worker(worker_pid, worker_slot, log); } else { ngx_log_error(NGX_LOG_ERR, log, 0, "push module: error communicating with some other worker process"); } } ngx_shmtx_lock(&shpool->mutex); /* each time all of a worker's subscribers are removed, so is the sentinel. this is done to make garbage collection easier. Assuming we want to avoid placing the sentinel in shared memory (for now -- it's a little tricky to debug), the owner of the worker pool must be the one to free said sentinel. But channels may be deleted by different worker processes, and it seems unwieldy (for now) to do IPC just to delete one stinkin' sentinel. Hence a new sentinel is used every time the subscriber queue is emptied. */ cur->subscriber_sentinel = NULL; //think about it it terms of garbage collection. it'll make sense. sort of. } return received; }
void ngx_buffer_cache_get_stats( ngx_buffer_cache_t* cache, ngx_buffer_cache_stats_t* stats) { ngx_buffer_cache_sh_t *sh = cache->sh; ngx_shmtx_lock(&cache->shpool->mutex); memcpy(stats, &sh->stats, sizeof(sh->stats)); stats->entries = sh->entries_end - sh->entries_start; stats->data_size = sh->buffers_end - sh->buffers_start; ngx_shmtx_unlock(&cache->shpool->mutex); }
void ngx_http_file_cache_free(ngx_http_request_t *r, ngx_temp_file_t *tf) { ngx_http_cache_t *c; ngx_http_file_cache_t *cache; c = r->cache; if (c->updated) { return; } c->updated = 1; cache = c->file_cache; ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http file cache free"); ngx_shmtx_lock(&cache->shpool->mutex); c->node->count--; if (c->error) { c->node->valid_sec = c->valid_sec; c->node->valid_msec = c->valid_msec; c->node->error = c->error; } c->node->updating = 0; ngx_shmtx_unlock(&cache->shpool->mutex); if (c->temp_file) { if (tf && tf->file.fd != NGX_INVALID_FILE) { ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http file cache incomplete: \"%s\"", tf->file.name.data); if (ngx_delete_file(tf->file.name.data) == NGX_FILE_ERROR) { ngx_log_error(NGX_LOG_CRIT, r->connection->log, ngx_errno, ngx_delete_file_n " \"%s\" failed", tf->file.name.data); } } } }
static void ngx_http_file_cache_lock_wait_handler(ngx_event_t *ev) { ngx_uint_t wait; ngx_msec_t timer; ngx_http_cache_t *c; ngx_http_request_t *r; ngx_http_file_cache_t *cache; r = ev->data; c = r->cache; ngx_log_debug2(NGX_LOG_DEBUG_HTTP, ev->log, 0, "http file cache wait handler wt:%M cur:%M", c->wait_time, ngx_current_msec); timer = c->wait_time - ngx_current_msec; if ((ngx_msec_int_t) timer <= 0) { ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ev->log, 0, "http file cache lock timeout"); c->lock = 0; goto wakeup; } cache = c->file_cache; wait = 0; ngx_shmtx_lock(&cache->shpool->mutex); if (c->node->updating) { wait = 1; } ngx_shmtx_unlock(&cache->shpool->mutex); if (wait) { ngx_add_timer(ev, (timer > 500) ? 500 : timer); return; } wakeup: c->waiting = 0; r->main->blocked--; r->connection->write->handler(r->connection->write); }
static ngx_int_t setup_default_servers(ngx_http_request_t *r, ngx_http_upstream_srv_conf_t *us) { ngx_http_upstream_available_capacity_srv_conf_t *conf = ngx_http_conf_upstream_srv_conf(us, ngx_http_upstream_available_capacity_module); if (conf->server_list) return NGX_OK; ngx_slab_pool_t *shpool = (ngx_slab_pool_t *)us->shm_zone->shm.addr; ngx_shmtx_lock(&shpool->mutex); ngx_http_upstream_available_capacity_server_t *prev_server_conf = NULL; size_t i = 0; for (i = 0; i < us->servers->nelts; ++i) { ngx_http_upstream_server_t *servers = us->servers->elts; ngx_http_upstream_available_capacity_server_t *server_conf = ngx_slab_calloc_locked(shpool, sizeof(ngx_http_upstream_available_capacity_server_t)); server_conf->server = &servers[i]; server_conf->capacity = 1; ngx_str_t server_address = ngx_string(server_conf->server->name.data); ngx_url_t url; ngx_memzero(&url, sizeof(ngx_url_t)); size_t server_address_size = strlen((char *)server_address.data); url.url.len = server_address_size; url.url.data = ngx_slab_alloc_locked(shpool, server_address_size); url.default_port = 80; ngx_cpystrn(url.url.data, server_address.data, server_address_size + 1); if (ngx_parse_url_slab(shpool, &url) != NGX_OK) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "cannot parse url : %s", server_address.data); return NGX_DECLINED; } server_conf->addr = *url.addrs; server_conf->next = NULL; if (prev_server_conf) { prev_server_conf->next = server_conf; } else { conf->server_list = server_conf; } prev_server_conf = server_conf; } conf->server_num = us->servers->nelts; conf->search_start_peer = conf->server_list; ngx_shmtx_unlock(&shpool->mutex); return NGX_OK; }