Prechádzať zdrojové kódy

Support atomics for stop_flag (#861)

xtne6f 5 rokov pred
rodič
commit
3283dffa00
1 zmenil súbory, kde vykonal 45 pridanie a 35 odobranie
  1. 45 35
      src/civetweb.c

+ 45 - 35
src/civetweb.c

@@ -1113,7 +1113,7 @@ gmtime_s(const time_t *ptime, struct tm *ptm)
 }
 
 
-static int mg_atomic_inc(volatile int *addr);
+static int mg_atomic_inc(int *addr);
 static struct tm tm_array[MAX_WORKER_THREADS];
 static int tm_index = 0;
 
@@ -1246,7 +1246,7 @@ mg_global_unlock(void)
 
 FUNCTION_MAY_BE_UNUSED
 static int
-mg_atomic_inc(volatile int *addr)
+mg_atomic_inc(int *addr)
 {
 	int ret;
 #if defined(_WIN32) && !defined(NO_ATOMICS)
@@ -1269,7 +1269,7 @@ mg_atomic_inc(volatile int *addr)
 
 FUNCTION_MAY_BE_UNUSED
 static int
-mg_atomic_dec(volatile int *addr)
+mg_atomic_dec(int *addr)
 {
 	int ret;
 #if defined(_WIN32) && !defined(NO_ATOMICS)
@@ -1290,6 +1290,32 @@ mg_atomic_dec(volatile int *addr)
 }
 
 
+FUNCTION_MAY_BE_UNUSED
+static int
+mg_atomic_compare_and_swap(int *addr, int oldval, int newval)
+{
+	int ret;
+#if defined(_WIN32) && !defined(NO_ATOMICS)
+	/* Depending on the SDK, this function uses either
+	 * (volatile unsigned int *) or (volatile LONG *),
+	 * so whatever you use, the other SDK is likely to raise a warning. */
+	ret = InterlockedCompareExchange((volatile long *)addr, newval, oldval);
+#elif defined(__GNUC__)                                                        \
+    && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 0)))           \
+    && !defined(NO_ATOMICS)
+	ret = __sync_val_compare_and_swap(addr, oldval, newval);
+#else
+	mg_global_lock();
+	ret = *addr;
+	if ((ret != newval) && (ret == oldval)) {
+		*addr = newval;
+	}
+	mg_global_unlock();
+#endif
+	return ret;
+}
+
+
 #if defined(GCC_DIAGNOSTIC)
 /* Show no warning in case system functions are not used. */
 #pragma GCC diagnostic pop
@@ -2733,42 +2759,27 @@ struct mg_domain_context {
 };
 
 
-/* Stop flag can be "volatile" or require a lock */
-typedef int volatile stop_flag_t;
-
-#ifdef STOP_FLAG_NEEDS_LOCK
-static int
-STOP_FLAG_IS_ZERO(stop_flag_t *f)
-{
-	int r;
-	mg_global_lock();
-	r = ((*f) == 0);
-	mg_global_unlock();
-	return r;
-}
-
-static int
-STOP_FLAG_IS_TWO(stop_flag_t *f)
-{
-	int r;
-	mg_global_lock();
-	r = ((*f) == 2);
-	mg_global_unlock();
-	return r;
-}
+/* Stop flag can be "volatile" or require atomic access */
+#if defined(STOP_FLAG_NEEDS_ATOMICS)
+typedef int stop_flag_t;
+#define STOP_FLAG_IS_ZERO(f) (mg_atomic_compare_and_swap((f), 0, 0) == 0)
+#define STOP_FLAG_IS_TWO(f) (mg_atomic_compare_and_swap((f), 0, 0) == 2)
 
 static void
 STOP_FLAG_ASSIGN(stop_flag_t *f, int v)
 {
-	mg_global_lock();
-	(*f) = v;
-	mg_global_unlock();
+	/* This only increments *f to v, never decrements. */
+	int i;
+	for (i = 0; i < v; i++) {
+		(void)mg_atomic_compare_and_swap(f, i, i + 1);
+	}
 }
-#else /* STOP_FLAG_NEEDS_LOCK */
+#else /* STOP_FLAG_NEEDS_ATOMICS */
+typedef int volatile stop_flag_t;
 #define STOP_FLAG_IS_ZERO(f) ((*(f)) == 0)
 #define STOP_FLAG_IS_TWO(f) ((*(f)) == 2)
 #define STOP_FLAG_ASSIGN(f, v) ((*(f)) = (v))
-#endif /* STOP_FLAG_NEEDS_LOCK */
+#endif /* STOP_FLAG_NEEDS_ATOMICS */
 
 
 struct mg_context {
@@ -6378,7 +6389,7 @@ mg_poll(struct mg_pollfd *pfd,
 	do {
 		int result;
 
-		if (!STOP_FLAG_IS_ZERO(&*stop_flag)) {
+		if (!STOP_FLAG_IS_ZERO(stop_flag)) {
 			/* Shut down signal */
 			return -2;
 		}
@@ -9423,8 +9434,7 @@ connect_socket(struct mg_context *ctx /* may be NULL */,
 		struct mg_pollfd pfd[1];
 		int pollres;
 		int ms_wait = 10000; /* 10 second timeout */
-		stop_flag_t nonstop;
-		STOP_FLAG_ASSIGN(&nonstop, 0);
+		stop_flag_t nonstop = 0;
 
 		/* For a non-blocking socket, the connect sequence is:
 		 * 1) call connect (will not block)
@@ -18558,7 +18568,7 @@ consume_socket(struct mg_context *ctx, struct socket *sp, int thread_index)
 
 	(void)pthread_mutex_lock(&ctx->thread_mutex);
 	*sp = ctx->client_socks[thread_index];
-	if (ctx->stop_flag) {
+	if (!STOP_FLAG_IS_ZERO(&ctx->stop_flag)) {
 		(void)pthread_mutex_unlock(&ctx->thread_mutex);
 		if (sp->in_use == 1) {
 			/* must consume */