Browse Source

Protect server stats by mutex

xtne6f 5 năm trước cách đây
mục cha
commit
48d038ebdf
1 tập tin đã thay đổi với 119 bổ sung71 xóa
  1. 119 71
      src/civetweb.c

+ 119 - 71
src/civetweb.c

@@ -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;