Пример #1
0
int ngx_tcp_io_update_in(long int in, ngx_http_request_t *r)
{
    ngx_tcp_io *data = statu_io_info;
	ngx_tcp_io *tcp_io_data = NULL;

    if (r == NULL || data == NULL)
    {
        return NGX_ERROR;
    }

#ifdef _TEMP_LOG_
    ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                "ngx_tcp_io_update_in %d#%d#%d#%s",
                getpid(), data->in, in, r->headers_in.host->value.data);
#endif

	ngx_atomic_fetch_add(&data->in, in);
	ngx_atomic_fetch_add(&data->requests, 1);

	tcp_io_data = ngx_status_get_momerybyhost_brtree(r);
	if (tcp_io_data)
	{
		ngx_atomic_fetch_add(&tcp_io_data->in, in);
		ngx_atomic_fetch_add(&tcp_io_data->requests, 1);
	}
	
	return data->in;
}
void 
ngx_tcp_lua_finalize_light_session(ngx_tcp_session_t* s)
{
    ngx_connection_t         *c;
    ngx_tcp_lua_ctx_t        *ctx;
    
    c = s->connection;
    ctx = s->ctx;
    //ngx_log_debug0(NGX_LOG_DEBUG_TCP, c->log, 0,
    //               "lua req calling wait_next_request() method");
   
#if (NGX_STAT_STUB)

    if (s->stat_reading) {
        (void) ngx_atomic_fetch_add(ngx_stat_reading, -1);
        s->stat_reading = 0;
    }

    if (s->stat_writing) {
        (void) ngx_atomic_fetch_add(ngx_stat_writing, -1);
        s->stat_writing = 0;
    }

#endif

    ngx_tcp_lua_log_session(s);
    
    ngx_reset_pool(s->pool);

    ctx->buf_in = NULL;
    ctx->buf_out = NULL;
}
Пример #3
0
void
ngx_reusable_connection(ngx_connection_t *c, ngx_uint_t reusable)
{
    ngx_log_debug1(NGX_LOG_DEBUG_CORE, c->log, 0,
                   "reusable connection: %ui", reusable);

    // 一旦一个keepalive的连接正常处理了,就将其从reusable队列中移除
    if (c->reusable) {
        ngx_queue_remove(&c->queue);

#if (NGX_STAT_STUB)
        (void) ngx_atomic_fetch_add(ngx_stat_waiting, -1);
#endif
    }

    // 在ngx_http_set_keepalive中会将reusable置为1,reusable为1的直接效果  
    // 就是将该连接插到reusable_connections_queue中 
    c->reusable = reusable;

    // 当reusable为0时,意味着该keepalive被正常的处理掉了,不应该被再次添加  
    // 到reusable队列中了。
    if (reusable) {
        /* need cast as ngx_cycle is volatile */

        // 这里使用头插法,较新的连接靠近头部,时间越久未被处理的连接越靠尾
        ngx_queue_insert_head(
            (ngx_queue_t *) &ngx_cycle->reusable_connections_queue, &c->queue);

#if (NGX_STAT_STUB)
        (void) ngx_atomic_fetch_add(ngx_stat_waiting, 1);
#endif
    }
}
void 
ngx_tcp_lua_close_session(ngx_tcp_session_t *s)
{
    ngx_connection_t  *c;
    ngx_tcp_cleanup_t *cln;

#if (NGX_STAT_STUB)
    if (s->stat_reading) {
        (void) ngx_atomic_fetch_add(ngx_stat_reading, -1);
    }

    if (s->stat_writing) {
        (void) ngx_atomic_fetch_add(ngx_stat_writing, -1);
    }
#endif


    c = s->connection;

    ngx_log_debug0(NGX_LOG_DEBUG_TCP, c->log, 0, "ngx_tcp_lua_close_session");

    for (cln = s->cleanup; cln; cln = cln->next) {
        if (cln->handler) {
            cln->handler(cln->data);
            cln->handler = NULL;
        }
    }

    ngx_destroy_pool(s->pool);
    ngx_tcp_close_connection(c);

    return;
}
Пример #5
0
void
ngx_reusable_connection(ngx_connection_t *c, ngx_uint_t reusable)
{
    ngx_log_debug1(NGX_LOG_DEBUG_CORE, c->log, 0,
                   "reusable connection: %ui", reusable);

    if (c->reusable) {
        ngx_queue_remove(&c->queue);

#if (NGX_STAT_STUB)
        (void) ngx_atomic_fetch_add(ngx_stat_waiting, -1);
#endif
    }

    c->reusable = reusable;

    if (reusable) {
        /* need cast as ngx_cycle is volatile */

        ngx_queue_insert_head(
            (ngx_queue_t *) &ngx_cycle->reusable_connections_queue, &c->queue);

#if (NGX_STAT_STUB)
        (void) ngx_atomic_fetch_add(ngx_stat_waiting, 1);
#endif
    }
}
Пример #6
0
// 发生了错误,关闭一个连接
static void
ngx_close_accepted_connection(ngx_connection_t *c)
{
    ngx_socket_t  fd;

    // 释放连接,加入空闲链表
    // in core/ngx_connection.c
    ngx_free_connection(c);

    // 连接的描述符置为无效
    fd = c->fd;
    c->fd = (ngx_socket_t) -1;

    // 关闭socket
    if (!c->shared && ngx_close_socket(fd) == -1) {
        ngx_log_error(NGX_LOG_ALERT, c->log, ngx_socket_errno,
                      ngx_close_socket_n " failed");
    }

    // 释放连接相关的所有内存
    if (c->pool) {
        ngx_destroy_pool(c->pool);
    }

#if (NGX_STAT_STUB)
    (void) ngx_atomic_fetch_add(ngx_stat_active, -1);
#endif
}
Пример #7
0
void
ngx_buffer_cache_release(
	ngx_buffer_cache_t* cache,
	u_char* key,
	uint32_t token)
{
	ngx_buffer_cache_entry_t* entry;
	ngx_buffer_cache_sh_t *sh = cache->sh;
	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 && (uint32_t)entry->write_time == token)
		{
			(void)ngx_atomic_fetch_add(&entry->ref_count, -1);
		}
	}

	ngx_shmtx_unlock(&cache->shpool->mutex);
}
static ngx_int_t
ngx_http_status_log_handler(ngx_http_request_t *r)
{
    ngx_time_t                *tp;
    ngx_msec_int_t             ms;
    struct timeval             tv;
    ngx_http_core_loc_conf_t  *clcf;

    clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
    if (clcf->request_time_cache) {
        tp = ngx_timeofday();

        ms = (ngx_msec_int_t)
                 ((tp->sec - r->start_sec) * 1000 + (tp->msec - r->start_msec));
    } else {
        ngx_gettimeofday(&tv);

        ms = (ngx_msec_int_t) ((tv.tv_sec - r->start_sec) * 1000
                 + (tv.tv_usec / 1000 - r->start_msec));
    }

    ms = ngx_max(ms, 0);
    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                   "http status: request_time %d", ms);

    (void) ngx_atomic_fetch_add(ngx_stat_request_time, ms);

    return NGX_OK;
}
static void
ngx_log_memory_writer(ngx_log_t *log, ngx_uint_t level, u_char *buf,
    size_t len)
{
    u_char                *p;
    size_t                 avail, written;
    ngx_log_memory_buf_t  *mem;

    mem = log->wdata;

    if (mem == NULL) {
        return;
    }

    written = ngx_atomic_fetch_add(&mem->written, len);

    p = mem->pos + written % (mem->end - mem->pos);

    avail = mem->end - p;

    if (avail >= len) {
        ngx_memcpy(p, buf, len);

    } else {
        ngx_memcpy(p, buf, avail);
        ngx_memcpy(mem->pos, buf + avail, len - avail);
    }
}
Пример #10
0
void
ngx_mail_close_connection(ngx_connection_t *c)
{
    ngx_pool_t  *pool;

    ngx_log_debug1(NGX_LOG_DEBUG_MAIL, c->log, 0,
                   "close mail connection: %d", c->fd);

#if (NGX_MAIL_SSL)

    if (c->ssl) {
        if (ngx_ssl_shutdown(c) == NGX_AGAIN) {
            c->ssl->handler = ngx_mail_close_connection;
            return;
        }
    }

#endif

#if (NGX_STAT_STUB)
    ngx_atomic_fetch_add(ngx_stat_active, -1);
#endif

    c->destroyed = 1;

    pool = c->pool;

    ngx_close_connection(c);

    ngx_destroy_pool(pool);
}
Пример #11
0
// 关闭stream连接,销毁线程池
void
ngx_stream_close_connection(ngx_connection_t *c)
{
    ngx_pool_t  *pool;

    ngx_log_debug1(NGX_LOG_DEBUG_STREAM, c->log, 0,
                   "close stream connection: %d", c->fd);

#if (NGX_STREAM_SSL)

    if (c->ssl) {
        if (ngx_ssl_shutdown(c) == NGX_AGAIN) {
            c->ssl->handler = ngx_stream_close_connection;
            return;
        }
    }

#endif

#if (NGX_STAT_STUB)
    (void) ngx_atomic_fetch_add(ngx_stat_active, -1);
#endif

    // 暂时保留内存池
    pool = c->pool;

    // 关闭连接
    ngx_close_connection(c);

    // 最后再销毁内存池
    ngx_destroy_pool(pool);
}
void
ngx_http_reqstat_count(void *data, off_t offset, ngx_int_t incr)
{
    ngx_http_reqstat_rbnode_t    *node = data;

    (void) ngx_atomic_fetch_add(NGX_HTTP_REQSTAT_REQ_FIELD(node, offset), incr);
}
Пример #13
0
static
ngx_int_t ngx_http_aio_log_header_filter(ngx_http_request_t *r)
{
    ngx_http_vesb_aio_log_main_conf_t				*valcf;
    ngx_http_vesb_aio_log_loc_conf_t				*vallcf;
    int												timeuse;
    struct timeval									endinvoketime;

    valcf = ngx_http_get_module_main_conf(r, ngx_http_vesb_aio_log_module);
    vallcf = ngx_http_get_module_loc_conf(r, ngx_http_vesb_aio_log_module);

    gettimeofday( &endinvoketime, NULL );
    timeuse = 1000000 * ( endinvoketime.tv_sec - r->esb_start_process_time.tv_sec )
              + endinvoketime.tv_usec - r->esb_start_process_time.tv_usec;

    /*esb: ngx_stat_proxy_request*/
    (void) ngx_atomic_fetch_add(ngx_stat_proxy_request, 1);

    /*esb:write invoke record*/
    ngx_http_proxy_write_client_invoke_record(r, valcf,vallcf,timeuse);


    if(valcf->mongodb_enable >0 && vallcf->enable_tracking >0)
    {
        ngx_wirte_tracking_into_mongodb(r,valcf,vallcf,timeuse);
    }


    return ngx_http_next_header_filter(r);
}
Пример #14
0
static void receive_subscribe_reply(ngx_int_t sender, subscribe_data_t *d) {
  memstore_channel_head_t      *head;
  store_channel_head_shm_t     *old_shared;
  DBG("received subscribe reply for channel %V", d->shm_chid);
  //we have the chanhead address, but are too afraid to use it.
  
  if(!d->shared_channel_data && !d->d.subscriber) {
    ERR("failed to subscribe");
    return;
  }
  
  if((head = nchan_memstore_get_chanhead_no_ipc_sub(d->shm_chid, d->cf)) == NULL) {
    ERR("Error regarding an aspect of life or maybe freshly fallen cookie crumbles");
    return;
  }
  
  old_shared = head->shared;
  if(old_shared) {
    assert(old_shared == d->shared_channel_data);
  }
  DBG("receive subscribe proceed to do ipc_sub stuff");
  head->shared = d->shared_channel_data;
  
  if(old_shared == NULL) {
    //ERR("%V local total_sub_count %i, internal_sub_count %i", &head->id,  head->sub_count, head->internal_sub_count);
    assert(head->total_sub_count >= head->internal_sub_count);
    ngx_atomic_fetch_add(&head->shared->sub_count, head->total_sub_count - head->internal_sub_count);
    ngx_atomic_fetch_add(&head->shared->internal_sub_count, head->internal_sub_count);
  }
  else {
    ERR("%V sub count already shared, don't update", &head->id);
  }
  
  assert(head->shared != NULL);
  if(head->foreign_owner_ipc_sub) {
    assert(head->foreign_owner_ipc_sub == d->d.subscriber);
  }
  else {
    head->foreign_owner_ipc_sub = d->d.subscriber;
  }
  
  memstore_ready_chanhead_unless_stub(head);
  
  str_shm_free(d->shm_chid);
}
ngx_int_t
ngx_http_status_code_count_handler(ngx_http_request_t *r)
{
  if (r->headers_out.status >= NGX_HTTP_OK && r->headers_out.status < NGX_HTTP_LAST_LEVEL_500) {
    ngx_atomic_fetch_add(&ngx_http_metrics_status_codes[r->headers_out.status - NGX_HTTP_OK], 1);
  }

  return NGX_OK;
}
Пример #16
0
static void change_sub_count(nchan_store_channel_head_t *ch, ngx_int_t n) {
  ch->sub_count += n;
  ch->channel.subscribers += n;
  if(ch->shared) {
    ngx_atomic_fetch_add(&ch->shared->sub_count, n);
  }
  if(ch->use_redis) {
    memstore_fakesub_add(ch, n);
  }
}
Пример #17
0
ngx_atomic_uint_t
ngx_next_temp_number(ngx_uint_t collision)
{
    ngx_atomic_uint_t  n, add;

    add = collision ? ngx_random_number : 1;

    n = ngx_atomic_fetch_add(ngx_temp_number, add);

    return n + add;
}
Пример #18
0
ngx_connection_t *nchan_create_fake_connection(ngx_pool_t *pool) {
    ngx_log_t               *log;
    ngx_connection_t        *c;
    ngx_connection_t        *saved_c = NULL;

    /* (we temporarily use a valid fd (0) to make ngx_get_connection happy) */
    if (ngx_cycle->files) {
        saved_c = ngx_cycle->files[0];
    }

    c = ngx_get_connection(0, ngx_cycle->log);

    if (ngx_cycle->files) {
        ngx_cycle->files[0] = saved_c;
    }

    if (c == NULL) {
        return NULL;
    }

    c->fd = (ngx_socket_t) -1;
    c->number = ngx_atomic_fetch_add(ngx_connection_counter, 1);

    if (pool) {
        c->pool = pool;
    }
    else {
        c->pool = ngx_create_pool(128, c->log);
        if (c->pool == NULL) {
            goto failed;
        }
    }

    log = ngx_pcalloc(c->pool, sizeof(ngx_log_t));
    if (log == NULL) {
        goto failed;
    }

    c->log = log;
    c->log->connection = c->number;
    c->log->action = NULL;
    c->log->data = NULL;

    c->log_error = NGX_ERROR_INFO;

    c->error = 1;

    return c;

failed:

    nchan_close_fake_connection(c);
    return NULL;
}
Пример #19
0
static void
ngx_close_udp_connection(ngx_connection_t *c)
{
    ngx_free_connection(c);

    if (c->pool) {
        ngx_destroy_pool(c->pool);
    }

#if (NGX_STAT_STUB)
    (void) ngx_atomic_fetch_add(ngx_stat_active, -1);
#endif
}
ngx_int_t
ngx_tcp_lua_init_light_session(ngx_tcp_session_t* s)
{
    ngx_connection_t         *c;
    ngx_time_t               *tp;
    
    c = s->connection;

    c->requests++;

#if (NGX_STAT_STUB)
    (void) ngx_atomic_fetch_add(ngx_stat_reading, 1);
    s->stat_reading = 1;
    (void) ngx_atomic_fetch_add(ngx_stat_requests, 1);
#endif

    tp = ngx_timeofday();
    s->start_sec = tp->sec;
    s->start_msec = tp->msec;
          
    return NGX_OK;
}
Пример #21
0
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;
}
static void
ngx_rtmp_close_connection(ngx_connection_t *c)
{
    ngx_pool_t                         *pool;

    ngx_log_debug0(NGX_LOG_DEBUG_RTMP, c->log, 0, "close connection");

#if (NGX_STAT_STUB)
    (void) ngx_atomic_fetch_add(ngx_stat_active, -1);
#endif

    pool = c->pool;
    ngx_close_connection(c);
    ngx_destroy_pool(pool);
}
Пример #23
0
int ngx_tcp_http_status_update_ex(long int out, ngx_http_request_t *r)
{
	ngx_tcp_io *tcp_io_data = NULL;
	ngx_tcp_io *data = statu_io_info;
	if (r == NULL)
		return NGX_ERROR;
	
	ngx_tcp_http_status_update(r, data);

	tcp_io_data = ngx_status_get_momerybyhost_brtree(r);
	if (tcp_io_data)
	{
		ngx_tcp_http_status_update(r, tcp_io_data);
		ngx_atomic_fetch_add(&tcp_io_data->out, out);
	}
	return NGX_OK;
}
Пример #24
0
void
ngx_tcp_close_connection(ngx_connection_t *c)
{
    ngx_pool_t           *pool;
    ngx_tcp_session_t    *s;

    ngx_log_error(NGX_LOG_NOTICE, c->log, 0, 
        "ngx_tcp_close_connection|client=%V|fd=%d\n", 
            &c->addr_text, c->fd);

    s = c->data;
    if (s != NULL) {
        ngx_tcp_core_srv_conf_t  *cscf;
    
        cscf = ngx_tcp_get_module_srv_conf(s, ngx_tcp_core_module);
        if (cscf->protocol != NULL && cscf->protocol->finit_session != NULL) {
            cscf->protocol->finit_session(s);
        }
    }

#if (NGX_TCP_SSL)

    if (c->ssl) {
        if (ngx_ssl_shutdown(c) == NGX_AGAIN) {
            c->ssl->handler = ngx_tcp_close_connection;
            return;
        }
    }

#endif

#if (NGX_STAT_STUB)
    (void) ngx_atomic_fetch_add(ngx_stat_active, -1);
#endif

    c->destroyed = 1;

    pool = c->pool;

    ngx_close_connection(c);

    ngx_destroy_pool(pool);
}
Пример #25
0
int ngx_tcp_io_update_out(long int out, ngx_http_request_t *r)
{
    ngx_tcp_io *data = statu_io_info;
	
    if (data == NULL || r==NULL)
    {
        return NGX_ERROR;
    }

#ifdef _TEMP_LOG_
    ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                "ngx_tcp_io_update_out %d#%d#%d#%s",
                getpid(), data->out, out, r->headers_in.host->value.data);
#endif
	ngx_atomic_fetch_add(&data->out, out);
	ngx_tcp_http_status_update_ex(out, r);
	
	return data->out;
}
Пример #26
0
ngx_int_t msg_release(nchan_msg_t *msg, char *lbl) {
  nchan_msg_t    *parent = msg->parent;
  if(parent) {
    assert(msg->storage != NCHAN_MSG_SHARED);
#if NCHAN_MSG_RESERVE_DEBUG
    nchan_msg_release_debug(msg, lbl);
#endif
    msg->refcount--;
    assert(msg->refcount >= 0);
    
    if(msg->refcount == 0) {
      switch(msg->storage) {
        case NCHAN_MSG_POOL:
          //free the id, the rest of the msg will be cleaned with the pool
          nchan_free_msg_id(&msg->id);
          break;
          
        case NCHAN_MSG_HEAP:
          nchan_free_msg_id(&msg->id);
          ngx_free(msg);
          break;
          
        default:
          break;
          //do nothing for NCHAN_MSG_STACK. NCHAN_MSG_SHARED should never be seen here.
      }
    }
    return msg_release(parent, lbl);
  }
  assert(!parent);
  
#if NCHAN_MSG_RESERVE_DEBUG
  nchan_msg_release_debug(msg, lbl);
#endif
  assert(msg->refcount > 0);
  ngx_atomic_fetch_add((ngx_atomic_uint_t *)&msg->refcount, -1);
  //DBG("msg %p released (%i) %s", msg, msg->refcount, lbl);
  return NGX_OK;
}
static void
ngx_limit_tcp_cleanup(void *data)
{
    ngx_limit_tcp_clean_ctx_t  *cctx = data;

    ngx_limit_tcp_node_t  *node;
    ngx_connection_t      *c;

    node = cctx->node;
    c = cctx->connection;

    if (c->write->timer_set) {
        ngx_log_debug0(NGX_LOG_DEBUG_CORE, c->log, 0,
                       "delete connection timer");
        ngx_del_timer(c->write);
    }

    ngx_log_debug2(NGX_LOG_DEBUG_CORE, c->log, 0,
                   "limit tcp cleanup connection count: [%ui] %p",
                   node->count, c);

    (void) ngx_atomic_fetch_add(&node->count, -1);
}
Пример #28
0
static void
ngx_close_accepted_connection(ngx_connection_t *c)
{
    ngx_socket_t  fd;

    ngx_free_connection(c);

    fd = c->fd;
    c->fd = (ngx_socket_t) -1;

    if (ngx_close_socket(fd) == -1) {
        ngx_log_error(NGX_LOG_ALERT, c->log, ngx_socket_errno,
                      ngx_close_socket_n " failed");
    }

    if (c->pool) {
        ngx_destroy_pool(c->pool);
    }

#if (NGX_STAT_STUB)
    (void) ngx_atomic_fetch_add(ngx_stat_active, -1);
#endif
}
Пример #29
0
ngx_int_t msg_reserve(nchan_msg_t *msg, char *lbl) {
  if(msg->parent) {
    assert(msg->storage != NCHAN_MSG_SHARED);
    msg->refcount++;
#if NCHAN_MSG_RESERVE_DEBUG
    nchan_msg_reserve_debug(msg, lbl);
#endif
    return msg_reserve(msg->parent, lbl);
  }
  assert(!msg->parent);
  
  ngx_atomic_fetch_add((ngx_atomic_uint_t *)&msg->refcount, 1);
  assert(msg->refcount >= 0);
  if(msg->refcount < 0) {
    msg->refcount = MSG_REFCOUNT_INVALID;
    return NGX_ERROR;
  }
#if NCHAN_MSG_RESERVE_DEBUG  
  nchan_msg_reserve_debug(msg, lbl);
#endif

  //DBG("msg %p reserved (%i) %s", msg, msg->refcount, lbl);
  return NGX_OK;
}
Пример #30
0
void
ngx_http_stats_server_dec(ngx_http_statistics_server_t *server,
        ngx_uint_t type, ngx_uint_t slot)
{
    ngx_uint_t *slots;

    if (server == NULL) {
        return;
    }

    switch (type) {
        case NGX_HTTP_STATS_TYPE_ATTACK:
            slots = server->attacks;
            break;
        case NGX_HTTP_STATS_TYPE_TRAFFIC:
            slots = server->traffic;
            break;
        default:
            /* invalid type */
            return;
    }

    ngx_atomic_fetch_add(&slots[slot], -1);
}