|  | @@ -1290,28 +1290,6 @@ mg_atomic_dec(volatile int *addr)
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -#if defined(USE_SERVER_STATS)
 | 
	
		
			
				|  |  | -static int64_t
 | 
	
		
			
				|  |  | -mg_atomic_add(volatile int64_t *addr, int64_t value)
 | 
	
		
			
				|  |  | -{
 | 
	
		
			
				|  |  | -	int64_t ret;
 | 
	
		
			
				|  |  | -#if defined(_WIN64) && !defined(NO_ATOMICS)
 | 
	
		
			
				|  |  | -	ret = InterlockedAdd64(addr, value);
 | 
	
		
			
				|  |  | -#elif defined(__GNUC__)                                                        \
 | 
	
		
			
				|  |  | -    && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 0)))           \
 | 
	
		
			
				|  |  | -    && !defined(NO_ATOMICS)
 | 
	
		
			
				|  |  | -	ret = __sync_add_and_fetch(addr, value);
 | 
	
		
			
				|  |  | -#else
 | 
	
		
			
				|  |  | -	mg_global_lock();
 | 
	
		
			
				|  |  | -	*addr += value;
 | 
	
		
			
				|  |  | -	ret = (*addr);
 | 
	
		
			
				|  |  | -	mg_global_unlock();
 | 
	
		
			
				|  |  | -#endif
 | 
	
		
			
				|  |  | -	return ret;
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | -#endif
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  |  #if defined(GCC_DIAGNOSTIC)
 | 
	
		
			
				|  |  |  /* Show no warning in case system functions are not used. */
 | 
	
		
			
				|  |  |  #pragma GCC diagnostic pop
 | 
	
	
		
			
				|  | @@ -1324,10 +1302,12 @@ mg_atomic_add(volatile int64_t *addr, int64_t value)
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  #if defined(USE_SERVER_STATS)
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +static pthread_mutex_t global_stats_mutex;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  struct mg_memory_stat {
 | 
	
		
			
				|  |  | -	volatile int64_t totalMemUsed;
 | 
	
		
			
				|  |  | -	volatile int64_t maxMemUsed;
 | 
	
		
			
				|  |  | -	volatile int blockCount;
 | 
	
		
			
				|  |  | +	int64_t totalMemUsed;
 | 
	
		
			
				|  |  | +	int64_t maxMemUsed;
 | 
	
		
			
				|  |  | +	int blockCount;
 | 
	
		
			
				|  |  |  };
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -1352,20 +1332,21 @@ mg_malloc_ex(size_t size,
 | 
	
		
			
				|  |  |  #endif
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  	if (data) {
 | 
	
		
			
				|  |  | -		int64_t mmem = mg_atomic_add(&mstat->totalMemUsed, (int64_t)size);
 | 
	
		
			
				|  |  | -		if (mmem > mstat->maxMemUsed) {
 | 
	
		
			
				|  |  | -			/* could use atomic compare exchange, but this
 | 
	
		
			
				|  |  | -			 * seems overkill for statistics data */
 | 
	
		
			
				|  |  | -			mstat->maxMemUsed = mmem;
 | 
	
		
			
				|  |  | +		(void)pthread_mutex_lock(&global_stats_mutex);
 | 
	
		
			
				|  |  | +		mstat->totalMemUsed += (int64_t)size;
 | 
	
		
			
				|  |  | +		if (mstat->totalMemUsed > mstat->maxMemUsed) {
 | 
	
		
			
				|  |  | +			mstat->maxMemUsed = mstat->totalMemUsed;
 | 
	
		
			
				|  |  |  		}
 | 
	
		
			
				|  |  | +		mstat->blockCount++;
 | 
	
		
			
				|  |  | +		(void)pthread_mutex_unlock(&global_stats_mutex);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -		mg_atomic_inc(&mstat->blockCount);
 | 
	
		
			
				|  |  |  		((uintptr_t *)data)[0] = size;
 | 
	
		
			
				|  |  |  		((uintptr_t *)data)[1] = (uintptr_t)mstat;
 | 
	
		
			
				|  |  |  		memory = (void *)(((char *)data) + 2 * sizeof(uintptr_t));
 | 
	
		
			
				|  |  |  	}
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  #if defined(MEMORY_DEBUGGING)
 | 
	
		
			
				|  |  | +	(void)pthread_mutex_lock(&global_stats_mutex);
 | 
	
		
			
				|  |  |  	sprintf(mallocStr,
 | 
	
		
			
				|  |  |  	        "MEM: %p %5lu alloc   %7lu %4lu --- %s:%u\n",
 | 
	
		
			
				|  |  |  	        memory,
 | 
	
	
		
			
				|  | @@ -1374,6 +1355,7 @@ mg_malloc_ex(size_t size,
 | 
	
		
			
				|  |  |  	        (unsigned long)mstat->blockCount,
 | 
	
		
			
				|  |  |  	        file,
 | 
	
		
			
				|  |  |  	        line);
 | 
	
		
			
				|  |  | +	(void)pthread_mutex_unlock(&global_stats_mutex);
 | 
	
		
			
				|  |  |  #if defined(_WIN32)
 | 
	
		
			
				|  |  |  	OutputDebugStringA(mallocStr);
 | 
	
		
			
				|  |  |  #else
 | 
	
	
		
			
				|  | @@ -1418,9 +1400,13 @@ mg_free_ex(void *memory, const char *file, unsigned line)
 | 
	
		
			
				|  |  |  		uintptr_t size = ((uintptr_t *)data)[0];
 | 
	
		
			
				|  |  |  		struct mg_memory_stat *mstat =
 | 
	
		
			
				|  |  |  		    (struct mg_memory_stat *)(((uintptr_t *)data)[1]);
 | 
	
		
			
				|  |  | -		mg_atomic_add(&mstat->totalMemUsed, -(int64_t)size);
 | 
	
		
			
				|  |  | -		mg_atomic_dec(&mstat->blockCount);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +		(void)pthread_mutex_lock(&global_stats_mutex);
 | 
	
		
			
				|  |  | +		mstat->totalMemUsed -= (int64_t)size;
 | 
	
		
			
				|  |  | +		mstat->blockCount--;
 | 
	
		
			
				|  |  | +		(void)pthread_mutex_unlock(&global_stats_mutex);
 | 
	
		
			
				|  |  |  #if defined(MEMORY_DEBUGGING)
 | 
	
		
			
				|  |  | +		(void)pthread_mutex_lock(&global_stats_mutex);
 | 
	
		
			
				|  |  |  		sprintf(mallocStr,
 | 
	
		
			
				|  |  |  		        "MEM: %p %5lu free    %7lu %4lu --- %s:%u\n",
 | 
	
		
			
				|  |  |  		        memory,
 | 
	
	
		
			
				|  | @@ -1429,6 +1415,7 @@ mg_free_ex(void *memory, const char *file, unsigned line)
 | 
	
		
			
				|  |  |  		        (unsigned long)mstat->blockCount,
 | 
	
		
			
				|  |  |  		        file,
 | 
	
		
			
				|  |  |  		        line);
 | 
	
		
			
				|  |  | +		(void)pthread_mutex_unlock(&global_stats_mutex);
 | 
	
		
			
				|  |  |  #if defined(_WIN32)
 | 
	
		
			
				|  |  |  		OutputDebugStringA(mallocStr);
 | 
	
		
			
				|  |  |  #else
 | 
	
	
		
			
				|  | @@ -1468,8 +1455,12 @@ mg_realloc_ex(void *memory,
 | 
	
		
			
				|  |  |  			_realloc = realloc(data, newsize + 2 * sizeof(uintptr_t));
 | 
	
		
			
				|  |  |  			if (_realloc) {
 | 
	
		
			
				|  |  |  				data = _realloc;
 | 
	
		
			
				|  |  | -				mg_atomic_add(&mstat->totalMemUsed, -(int64_t)oldsize);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +				(void)pthread_mutex_lock(&global_stats_mutex);
 | 
	
		
			
				|  |  | +				mstat->totalMemUsed -= (int64_t)oldsize;
 | 
	
		
			
				|  |  | +				(void)pthread_mutex_unlock(&global_stats_mutex);
 | 
	
		
			
				|  |  |  #if defined(MEMORY_DEBUGGING)
 | 
	
		
			
				|  |  | +				(void)pthread_mutex_lock(&global_stats_mutex);
 | 
	
		
			
				|  |  |  				sprintf(mallocStr,
 | 
	
		
			
				|  |  |  				        "MEM: %p %5lu r-free  %7lu %4lu --- %s:%u\n",
 | 
	
		
			
				|  |  |  				        memory,
 | 
	
	
		
			
				|  | @@ -1478,14 +1469,18 @@ mg_realloc_ex(void *memory,
 | 
	
		
			
				|  |  |  				        (unsigned long)mstat->blockCount,
 | 
	
		
			
				|  |  |  				        file,
 | 
	
		
			
				|  |  |  				        line);
 | 
	
		
			
				|  |  | +				(void)pthread_mutex_unlock(&global_stats_mutex);
 | 
	
		
			
				|  |  |  #if defined(_WIN32)
 | 
	
		
			
				|  |  |  				OutputDebugStringA(mallocStr);
 | 
	
		
			
				|  |  |  #else
 | 
	
		
			
				|  |  |  				DEBUG_TRACE("%s", mallocStr);
 | 
	
		
			
				|  |  |  #endif
 | 
	
		
			
				|  |  |  #endif
 | 
	
		
			
				|  |  | -				mg_atomic_add(&mstat->totalMemUsed, (int64_t)newsize);
 | 
	
		
			
				|  |  | +				(void)pthread_mutex_lock(&global_stats_mutex);
 | 
	
		
			
				|  |  | +				mstat->totalMemUsed += (int64_t)newsize;
 | 
	
		
			
				|  |  | +				(void)pthread_mutex_unlock(&global_stats_mutex);
 | 
	
		
			
				|  |  |  #if defined(MEMORY_DEBUGGING)
 | 
	
		
			
				|  |  | +				(void)pthread_mutex_lock(&global_stats_mutex);
 | 
	
		
			
				|  |  |  				sprintf(mallocStr,
 | 
	
		
			
				|  |  |  				        "MEM: %p %5lu r-alloc %7lu %4lu --- %s:%u\n",
 | 
	
		
			
				|  |  |  				        memory,
 | 
	
	
		
			
				|  | @@ -1494,6 +1489,7 @@ mg_realloc_ex(void *memory,
 | 
	
		
			
				|  |  |  				        (unsigned long)mstat->blockCount,
 | 
	
		
			
				|  |  |  				        file,
 | 
	
		
			
				|  |  |  				        line);
 | 
	
		
			
				|  |  | +				(void)pthread_mutex_unlock(&global_stats_mutex);
 | 
	
		
			
				|  |  |  #if defined(_WIN32)
 | 
	
		
			
				|  |  |  				OutputDebugStringA(mallocStr);
 | 
	
		
			
				|  |  |  #else
 | 
	
	
		
			
				|  | @@ -2829,13 +2825,14 @@ struct mg_context {
 | 
	
		
			
				|  |  |  #else
 | 
	
		
			
				|  |  |  	struct socket *squeue; /* Socket queue (sq) : accepted sockets waiting for a
 | 
	
		
			
				|  |  |  	                          worker thread */
 | 
	
		
			
				|  |  | -	volatile int sq_head;  /* Head of the socket queue */
 | 
	
		
			
				|  |  | -	volatile int sq_tail;  /* Tail of the socket queue */
 | 
	
		
			
				|  |  | +	int sq_head;           /* Head of the socket queue */
 | 
	
		
			
				|  |  | +	int sq_tail;           /* Tail of the socket queue */
 | 
	
		
			
				|  |  |  	pthread_cond_t sq_full;  /* Signaled when socket is produced */
 | 
	
		
			
				|  |  |  	pthread_cond_t sq_empty; /* Signaled when socket is consumed */
 | 
	
		
			
				|  |  | -	volatile int sq_blocked; /* Status information: sq is full */
 | 
	
		
			
				|  |  |  	int sq_size;             /* No of elements in socket queue */
 | 
	
		
			
				|  |  |  #if defined(USE_SERVER_STATS)
 | 
	
		
			
				|  |  | +	int sq_blocked;          /* Status information: sq is full */
 | 
	
		
			
				|  |  | +	int sq_filled;           /* Status information: sq_head - sq_tail */
 | 
	
		
			
				|  |  |  	int sq_max_fill;
 | 
	
		
			
				|  |  |  #endif /* USE_SERVER_STATS */
 | 
	
		
			
				|  |  |  #endif /* ALTERNATIVE_QUEUE */
 | 
	
	
		
			
				|  | @@ -18316,13 +18313,14 @@ process_new_connection(struct mg_connection *conn)
 | 
	
		
			
				|  |  |  	int reqerr, uri_type;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  #if defined(USE_SERVER_STATS)
 | 
	
		
			
				|  |  | -	int mcon = mg_atomic_inc(&(conn->phys_ctx->active_connections));
 | 
	
		
			
				|  |  | -	mg_atomic_add(&(conn->phys_ctx->total_connections), 1);
 | 
	
		
			
				|  |  | -	if (mcon > (conn->phys_ctx->max_active_connections)) {
 | 
	
		
			
				|  |  | -		/* could use atomic compare exchange, but this
 | 
	
		
			
				|  |  | -		 * seems overkill for statistics data */
 | 
	
		
			
				|  |  | -		conn->phys_ctx->max_active_connections = mcon;
 | 
	
		
			
				|  |  | +	(void)pthread_mutex_lock(&global_stats_mutex);
 | 
	
		
			
				|  |  | +	conn->phys_ctx->total_connections++;
 | 
	
		
			
				|  |  | +	if ((++conn->phys_ctx->active_connections)
 | 
	
		
			
				|  |  | +	    > (conn->phys_ctx->max_active_connections)) {
 | 
	
		
			
				|  |  | +		conn->phys_ctx->max_active_connections =
 | 
	
		
			
				|  |  | +		    conn->phys_ctx->active_connections;
 | 
	
		
			
				|  |  |  	}
 | 
	
		
			
				|  |  | +	(void)pthread_mutex_unlock(&global_stats_mutex);
 | 
	
		
			
				|  |  |  #endif
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  	init_connection(conn);
 | 
	
	
		
			
				|  | @@ -18436,10 +18434,10 @@ process_new_connection(struct mg_connection *conn)
 | 
	
		
			
				|  |  |  #if defined(USE_SERVER_STATS)
 | 
	
		
			
				|  |  |  				conn->conn_state = 5; /* processed */
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -				mg_atomic_add(&(conn->phys_ctx->total_data_read),
 | 
	
		
			
				|  |  | -				              conn->consumed_content);
 | 
	
		
			
				|  |  | -				mg_atomic_add(&(conn->phys_ctx->total_data_written),
 | 
	
		
			
				|  |  | -				              conn->num_bytes_sent);
 | 
	
		
			
				|  |  | +				(void)pthread_mutex_lock(&global_stats_mutex);
 | 
	
		
			
				|  |  | +				conn->phys_ctx->total_data_read += conn->consumed_content;
 | 
	
		
			
				|  |  | +				conn->phys_ctx->total_data_written += conn->num_bytes_sent;
 | 
	
		
			
				|  |  | +				(void)pthread_mutex_unlock(&global_stats_mutex);
 | 
	
		
			
				|  |  |  #endif
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  				DEBUG_TRACE("%s", "handle_request done");
 | 
	
	
		
			
				|  | @@ -18518,8 +18516,10 @@ process_new_connection(struct mg_connection *conn)
 | 
	
		
			
				|  |  |  	close_connection(conn);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  #if defined(USE_SERVER_STATS)
 | 
	
		
			
				|  |  | -	mg_atomic_add(&(conn->phys_ctx->total_requests), conn->handled_requests);
 | 
	
		
			
				|  |  | -	mg_atomic_dec(&(conn->phys_ctx->active_connections));
 | 
	
		
			
				|  |  | +	(void)pthread_mutex_lock(&global_stats_mutex);
 | 
	
		
			
				|  |  | +	conn->phys_ctx->total_requests += conn->handled_requests;
 | 
	
		
			
				|  |  | +	conn->phys_ctx->active_connections--;
 | 
	
		
			
				|  |  | +	(void)pthread_mutex_unlock(&global_stats_mutex);
 | 
	
		
			
				|  |  |  #endif
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -18617,6 +18617,11 @@ consume_socket(struct mg_context *ctx, struct socket *sp, int thread_index)
 | 
	
		
			
				|  |  |  			ctx->sq_tail -= ctx->sq_size;
 | 
	
		
			
				|  |  |  			ctx->sq_head -= ctx->sq_size;
 | 
	
		
			
				|  |  |  		}
 | 
	
		
			
				|  |  | +#if defined(USE_SERVER_STATS)
 | 
	
		
			
				|  |  | +		(void)pthread_mutex_lock(&global_stats_mutex);
 | 
	
		
			
				|  |  | +		ctx->sq_filled = ctx->sq_head - ctx->sq_tail;
 | 
	
		
			
				|  |  | +		(void)pthread_mutex_unlock(&global_stats_mutex);
 | 
	
		
			
				|  |  | +#endif
 | 
	
		
			
				|  |  |  	}
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  	(void)pthread_cond_signal(&ctx->sq_empty);
 | 
	
	
		
			
				|  | @@ -18639,14 +18644,17 @@ produce_socket(struct mg_context *ctx, const struct socket *sp)
 | 
	
		
			
				|  |  |  	/* If the queue is full, wait */
 | 
	
		
			
				|  |  |  	while (STOP_FLAG_IS_ZERO(&ctx->stop_flag)
 | 
	
		
			
				|  |  |  	       && (queue_filled >= ctx->sq_size)) {
 | 
	
		
			
				|  |  | -		ctx->sq_blocked = 1; /* Status information: All threads bussy */
 | 
	
		
			
				|  |  |  #if defined(USE_SERVER_STATS)
 | 
	
		
			
				|  |  | -		if (queue_filled > ctx->sq_max_fill) {
 | 
	
		
			
				|  |  | -			ctx->sq_max_fill = queue_filled;
 | 
	
		
			
				|  |  | -		}
 | 
	
		
			
				|  |  | +		(void)pthread_mutex_lock(&global_stats_mutex);
 | 
	
		
			
				|  |  | +		ctx->sq_blocked = 1; /* All threads busy */
 | 
	
		
			
				|  |  | +		(void)pthread_mutex_unlock(&global_stats_mutex);
 | 
	
		
			
				|  |  |  #endif
 | 
	
		
			
				|  |  |  		(void)pthread_cond_wait(&ctx->sq_empty, &ctx->thread_mutex);
 | 
	
		
			
				|  |  | +#if defined(USE_SERVER_STATS)
 | 
	
		
			
				|  |  | +		(void)pthread_mutex_lock(&global_stats_mutex);
 | 
	
		
			
				|  |  |  		ctx->sq_blocked = 0; /* Not blocked now */
 | 
	
		
			
				|  |  | +		(void)pthread_mutex_unlock(&global_stats_mutex);
 | 
	
		
			
				|  |  | +#endif
 | 
	
		
			
				|  |  |  		queue_filled = ctx->sq_head - ctx->sq_tail;
 | 
	
		
			
				|  |  |  	}
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -18659,9 +18667,12 @@ produce_socket(struct mg_context *ctx, const struct socket *sp)
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  	queue_filled = ctx->sq_head - ctx->sq_tail;
 | 
	
		
			
				|  |  |  #if defined(USE_SERVER_STATS)
 | 
	
		
			
				|  |  | +	(void)pthread_mutex_lock(&global_stats_mutex);
 | 
	
		
			
				|  |  | +	ctx->sq_filled = queue_filled;
 | 
	
		
			
				|  |  |  	if (queue_filled > ctx->sq_max_fill) {
 | 
	
		
			
				|  |  |  		ctx->sq_max_fill = queue_filled;
 | 
	
		
			
				|  |  |  	}
 | 
	
		
			
				|  |  | +	(void)pthread_mutex_unlock(&global_stats_mutex);
 | 
	
		
			
				|  |  |  #endif
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  	(void)pthread_cond_signal(&ctx->sq_full);
 | 
	
	
		
			
				|  | @@ -19408,7 +19419,6 @@ static
 | 
	
		
			
				|  |  |  #if !defined(ALTERNATIVE_QUEUE)
 | 
	
		
			
				|  |  |  	ok &= (0 == pthread_cond_init(&ctx->sq_empty, NULL));
 | 
	
		
			
				|  |  |  	ok &= (0 == pthread_cond_init(&ctx->sq_full, NULL));
 | 
	
		
			
				|  |  | -	ctx->sq_blocked = 0;
 | 
	
		
			
				|  |  |  #endif
 | 
	
		
			
				|  |  |  	ok &= (0 == pthread_mutex_init(&ctx->nonce_mutex, &pthread_mutex_attr));
 | 
	
		
			
				|  |  |  	if (!ok) {
 | 
	
	
		
			
				|  | @@ -20598,6 +20608,15 @@ mg_get_context_info(const struct mg_context *ctx, char *buffer, int buflen)
 | 
	
		
			
				|  |  |  	context_info_length += mg_str_append(&buffer, end, "{");
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  	if (ms) { /* <-- should be always true */
 | 
	
		
			
				|  |  | +		int blockCount;
 | 
	
		
			
				|  |  | +		int64_t totalMemUsed, maxMemUsed;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +		(void)pthread_mutex_lock(&global_stats_mutex);
 | 
	
		
			
				|  |  | +		blockCount = ms->blockCount;
 | 
	
		
			
				|  |  | +		totalMemUsed = ms->totalMemUsed;
 | 
	
		
			
				|  |  | +		maxMemUsed = ms->maxMemUsed;
 | 
	
		
			
				|  |  | +		(void)pthread_mutex_unlock(&global_stats_mutex);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  		/* Memory information */
 | 
	
		
			
				|  |  |  		mg_snprintf(NULL,
 | 
	
		
			
				|  |  |  		            NULL,
 | 
	
	
		
			
				|  | @@ -20610,11 +20629,11 @@ mg_get_context_info(const struct mg_context *ctx, char *buffer, int buflen)
 | 
	
		
			
				|  |  |  		            "}",
 | 
	
		
			
				|  |  |  		            eol,
 | 
	
		
			
				|  |  |  		            eol,
 | 
	
		
			
				|  |  | -		            ms->blockCount,
 | 
	
		
			
				|  |  | +		            blockCount,
 | 
	
		
			
				|  |  |  		            eol,
 | 
	
		
			
				|  |  | -		            ms->totalMemUsed,
 | 
	
		
			
				|  |  | +		            totalMemUsed,
 | 
	
		
			
				|  |  |  		            eol,
 | 
	
		
			
				|  |  | -		            ms->maxMemUsed,
 | 
	
		
			
				|  |  | +		            maxMemUsed,
 | 
	
		
			
				|  |  |  		            eol);
 | 
	
		
			
				|  |  |  		context_info_length += mg_str_append(&buffer, end, block);
 | 
	
		
			
				|  |  |  	}
 | 
	
	
		
			
				|  | @@ -20626,6 +20645,27 @@ mg_get_context_info(const struct mg_context *ctx, char *buffer, int buflen)
 | 
	
		
			
				|  |  |  		char now_str[64] = {0};
 | 
	
		
			
				|  |  |  		time_t start_time = ctx->start_time;
 | 
	
		
			
				|  |  |  		time_t now = time(NULL);
 | 
	
		
			
				|  |  | +		int active_connections, max_active_connections;
 | 
	
		
			
				|  |  | +		int64_t total_connections;
 | 
	
		
			
				|  |  | +		int64_t total_requests;
 | 
	
		
			
				|  |  | +		int64_t total_data_read, total_data_written;
 | 
	
		
			
				|  |  | +#if !defined(ALTERNATIVE_QUEUE)
 | 
	
		
			
				|  |  | +		int sq_filled, sq_max_fill, sq_blocked;
 | 
	
		
			
				|  |  | +#endif
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +		(void)pthread_mutex_lock(&global_stats_mutex);
 | 
	
		
			
				|  |  | +		active_connections = ctx->active_connections;
 | 
	
		
			
				|  |  | +		max_active_connections = ctx->max_active_connections;
 | 
	
		
			
				|  |  | +		total_connections = ctx->total_connections;
 | 
	
		
			
				|  |  | +		total_requests = ctx->total_requests;
 | 
	
		
			
				|  |  | +		total_data_read = ctx->total_data_read;
 | 
	
		
			
				|  |  | +		total_data_written = ctx->total_data_written;
 | 
	
		
			
				|  |  | +#if !defined(ALTERNATIVE_QUEUE)
 | 
	
		
			
				|  |  | +		sq_filled = ctx->sq_filled;
 | 
	
		
			
				|  |  | +		sq_max_fill = ctx->sq_max_fill;
 | 
	
		
			
				|  |  | +		sq_blocked = ctx->sq_blocked;
 | 
	
		
			
				|  |  | +#endif
 | 
	
		
			
				|  |  | +		(void)pthread_mutex_unlock(&global_stats_mutex);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  		/* Connections information */
 | 
	
		
			
				|  |  |  		mg_snprintf(NULL,
 | 
	
	
		
			
				|  | @@ -20639,11 +20679,11 @@ mg_get_context_info(const struct mg_context *ctx, char *buffer, int buflen)
 | 
	
		
			
				|  |  |  		            "}",
 | 
	
		
			
				|  |  |  		            eol,
 | 
	
		
			
				|  |  |  		            eol,
 | 
	
		
			
				|  |  | -		            ctx->active_connections,
 | 
	
		
			
				|  |  | +		            active_connections,
 | 
	
		
			
				|  |  |  		            eol,
 | 
	
		
			
				|  |  | -		            ctx->max_active_connections,
 | 
	
		
			
				|  |  | +		            max_active_connections,
 | 
	
		
			
				|  |  |  		            eol,
 | 
	
		
			
				|  |  | -		            ctx->total_connections,
 | 
	
		
			
				|  |  | +		            total_connections,
 | 
	
		
			
				|  |  |  		            eol);
 | 
	
		
			
				|  |  |  		context_info_length += mg_str_append(&buffer, end, block);
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -20663,11 +20703,11 @@ mg_get_context_info(const struct mg_context *ctx, char *buffer, int buflen)
 | 
	
		
			
				|  |  |  		            eol,
 | 
	
		
			
				|  |  |  		            ctx->sq_size,
 | 
	
		
			
				|  |  |  		            eol,
 | 
	
		
			
				|  |  | -		            ctx->sq_head - ctx->sq_tail,
 | 
	
		
			
				|  |  | +		            sq_filled,
 | 
	
		
			
				|  |  |  		            eol,
 | 
	
		
			
				|  |  | -		            ctx->sq_max_fill,
 | 
	
		
			
				|  |  | +		            sq_max_fill,
 | 
	
		
			
				|  |  |  		            eol,
 | 
	
		
			
				|  |  | -		            (ctx->sq_blocked ? "true" : "false"),
 | 
	
		
			
				|  |  | +		            (sq_blocked ? "true" : "false"),
 | 
	
		
			
				|  |  |  		            eol);
 | 
	
		
			
				|  |  |  		context_info_length += mg_str_append(&buffer, end, block);
 | 
	
		
			
				|  |  |  #endif
 | 
	
	
		
			
				|  | @@ -20682,7 +20722,7 @@ mg_get_context_info(const struct mg_context *ctx, char *buffer, int buflen)
 | 
	
		
			
				|  |  |  		            "}",
 | 
	
		
			
				|  |  |  		            eol,
 | 
	
		
			
				|  |  |  		            eol,
 | 
	
		
			
				|  |  | -		            ctx->total_requests,
 | 
	
		
			
				|  |  | +		            total_requests,
 | 
	
		
			
				|  |  |  		            eol);
 | 
	
		
			
				|  |  |  		context_info_length += mg_str_append(&buffer, end, block);
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -20697,9 +20737,9 @@ mg_get_context_info(const struct mg_context *ctx, char *buffer, int buflen)
 | 
	
		
			
				|  |  |  		            "}",
 | 
	
		
			
				|  |  |  		            eol,
 | 
	
		
			
				|  |  |  		            eol,
 | 
	
		
			
				|  |  | -		            ctx->total_data_read,
 | 
	
		
			
				|  |  | +		            total_data_read,
 | 
	
		
			
				|  |  |  		            eol,
 | 
	
		
			
				|  |  | -		            ctx->total_data_written,
 | 
	
		
			
				|  |  | +		            total_data_written,
 | 
	
		
			
				|  |  |  		            eol);
 | 
	
		
			
				|  |  |  		context_info_length += mg_str_append(&buffer, end, block);
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -21031,6 +21071,10 @@ mg_init_library(unsigned features)
 | 
	
		
			
				|  |  |  		pthread_mutexattr_settype(&pthread_mutex_attr, PTHREAD_MUTEX_RECURSIVE);
 | 
	
		
			
				|  |  |  #endif
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +#if defined(USE_SERVER_STATS)
 | 
	
		
			
				|  |  | +		(void)pthread_mutex_init(&global_stats_mutex, &pthread_mutex_attr);
 | 
	
		
			
				|  |  | +#endif
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  #if defined(USE_LUA)
 | 
	
		
			
				|  |  |  		lua_init_optional_libraries();
 | 
	
		
			
				|  |  |  #endif
 | 
	
	
		
			
				|  | @@ -21093,6 +21137,14 @@ mg_exit_library(void)
 | 
	
		
			
				|  |  |  		}
 | 
	
		
			
				|  |  |  #endif
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +#if defined(USE_LUA)
 | 
	
		
			
				|  |  | +		lua_exit_optional_libraries();
 | 
	
		
			
				|  |  | +#endif
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +#if defined(USE_SERVER_STATS)
 | 
	
		
			
				|  |  | +		(void)pthread_mutex_destroy(&global_stats_mutex);
 | 
	
		
			
				|  |  | +#endif
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  #if defined(_WIN32)
 | 
	
		
			
				|  |  |  		(void)pthread_mutex_destroy(&global_log_file_lock);
 | 
	
		
			
				|  |  |  #else
 | 
	
	
		
			
				|  | @@ -21101,10 +21153,6 @@ mg_exit_library(void)
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  		(void)pthread_key_delete(sTlsKey);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -#if defined(USE_LUA)
 | 
	
		
			
				|  |  | -		lua_exit_optional_libraries();
 | 
	
		
			
				|  |  | -#endif
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  |  		mg_global_unlock();
 | 
	
		
			
				|  |  |  		(void)pthread_mutex_destroy(&global_lock_mutex);
 | 
	
		
			
				|  |  |  		return 1;
 |