From 561dca3b9510464600b4da8d1397e7762f523568 Mon Sep 17 00:00:00 2001
From: Jelte Fennema <jelte.fennema@microsoft.com>
Date: Fri, 13 Jan 2023 16:52:17 +0100
Subject: [PATCH v7 3/4] Make mutexes easier to use in libpq

For process global mutexes windows requires some different setup than
other OSes. This abstracts away that logic into the newly added pglock
and pgunlock functions. The main reason to do this refactoring is to
prepare for a new global mutex that will be added in a follow up commit.
---
 src/interfaces/libpq/fe-connect.c        | 58 +++++++++++++++---------
 src/interfaces/libpq/fe-secure-openssl.c | 33 +++-----------
 src/interfaces/libpq/libpq-int.h         | 21 +++++++++
 3 files changed, 64 insertions(+), 48 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 18a07d810dc..69ed891703a 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -7424,36 +7424,17 @@ pqGetHomeDirectory(char *buf, int bufsize)
 static void
 default_threadlock(int acquire)
 {
-#ifdef ENABLE_THREAD_SAFETY
-#ifndef WIN32
-	static pthread_mutex_t singlethread_lock = PTHREAD_MUTEX_INITIALIZER;
-#else
-	static pthread_mutex_t singlethread_lock = NULL;
-	static long mutex_initlock = 0;
-
-	if (singlethread_lock == NULL)
-	{
-		while (InterlockedExchange(&mutex_initlock, 1) == 1)
-			 /* loop, another thread own the lock */ ;
-		if (singlethread_lock == NULL)
-		{
-			if (pthread_mutex_init(&singlethread_lock, NULL))
-				Assert(false);
-		}
-		InterlockedExchange(&mutex_initlock, 0);
-	}
-#endif
+	static pglock_t singlethread_lock = PGLOCK_INITIALIZER;
 	if (acquire)
 	{
-		if (pthread_mutex_lock(&singlethread_lock))
+		if (!pglock(&singlethread_lock))
 			Assert(false);
 	}
 	else
 	{
-		if (pthread_mutex_unlock(&singlethread_lock))
+		if (!pgunlock(&singlethread_lock))
 			Assert(false);
 	}
-#endif
 }
 
 pgthreadlock_t
@@ -7468,3 +7449,36 @@ PQregisterThreadLock(pgthreadlock_t newhandler)
 
 	return prev;
 }
+
+bool
+pglock(pglock_t * lock)
+{
+#ifdef WIN32
+	if (lock->mutex == NULL)
+	{
+		while (InterlockedExchange(&lock->mutex_initlock, 1) == 1)
+			 /* loop, another thread own the lock */ ;
+		if (lock->mutex == NULL)
+		{
+			if (pthread_mutex_init(&lock->mutex, NULL))
+				return false;
+		}
+		InterlockedExchange(&lock->mutex_initlock, 0);
+	}
+#endif
+	if (pthread_mutex_lock(&lock->mutex))
+	{
+		return false;
+	}
+	return true;
+}
+
+bool
+pgunlock(pglock_t * lock)
+{
+	if (pthread_mutex_unlock(&lock->mutex))
+	{
+		return false;
+	}
+	return true;
+}
diff --git a/src/interfaces/libpq/fe-secure-openssl.c b/src/interfaces/libpq/fe-secure-openssl.c
index ab2cbf045b8..c52c2ccf217 100644
--- a/src/interfaces/libpq/fe-secure-openssl.c
+++ b/src/interfaces/libpq/fe-secure-openssl.c
@@ -94,12 +94,7 @@ static bool ssl_lib_initialized = false;
 #ifdef ENABLE_THREAD_SAFETY
 static long crypto_open_connections = 0;
 
-#ifndef WIN32
-static pthread_mutex_t ssl_config_mutex = PTHREAD_MUTEX_INITIALIZER;
-#else
-static pthread_mutex_t ssl_config_mutex = NULL;
-static long win32_ssl_create_mutex = 0;
-#endif
+static pglock_t ssl_config_lock = PGLOCK_INITIALIZER;
 #endif							/* ENABLE_THREAD_SAFETY */
 
 static PQsslKeyPassHook_OpenSSL_type PQsslKeyPassHook = NULL;
@@ -744,21 +739,7 @@ int
 pgtls_init(PGconn *conn, bool do_ssl, bool do_crypto)
 {
 #ifdef ENABLE_THREAD_SAFETY
-#ifdef WIN32
-	/* Also see similar code in fe-connect.c, default_threadlock() */
-	if (ssl_config_mutex == NULL)
-	{
-		while (InterlockedExchange(&win32_ssl_create_mutex, 1) == 1)
-			 /* loop, another thread own the lock */ ;
-		if (ssl_config_mutex == NULL)
-		{
-			if (pthread_mutex_init(&ssl_config_mutex, NULL))
-				return -1;
-		}
-		InterlockedExchange(&win32_ssl_create_mutex, 0);
-	}
-#endif
-	if (pthread_mutex_lock(&ssl_config_mutex))
+	if (!pglock(&ssl_config_lock))
 		return -1;
 
 #ifdef HAVE_CRYPTO_LOCK
@@ -775,7 +756,7 @@ pgtls_init(PGconn *conn, bool do_ssl, bool do_crypto)
 			pq_lockarray = malloc(sizeof(pthread_mutex_t) * CRYPTO_num_locks());
 			if (!pq_lockarray)
 			{
-				pthread_mutex_unlock(&ssl_config_mutex);
+				pgunlock(&ssl_config_lock);
 				return -1;
 			}
 			for (i = 0; i < CRYPTO_num_locks(); i++)
@@ -784,7 +765,7 @@ pgtls_init(PGconn *conn, bool do_ssl, bool do_crypto)
 				{
 					free(pq_lockarray);
 					pq_lockarray = NULL;
-					pthread_mutex_unlock(&ssl_config_mutex);
+					pgunlock(&ssl_config_lock);
 					return -1;
 				}
 			}
@@ -827,7 +808,7 @@ pgtls_init(PGconn *conn, bool do_ssl, bool do_crypto)
 	}
 
 #ifdef ENABLE_THREAD_SAFETY
-	pthread_mutex_unlock(&ssl_config_mutex);
+	pgunlock(&ssl_config_lock);
 #endif
 	return 0;
 }
@@ -849,7 +830,7 @@ destroy_ssl_system(void)
 {
 #if defined(ENABLE_THREAD_SAFETY) && defined(HAVE_CRYPTO_LOCK)
 	/* Mutex is created in pgtls_init() */
-	if (pthread_mutex_lock(&ssl_config_mutex))
+	if (!pglock(&ssl_config_lock))
 		return;
 
 	if (pq_init_crypto_lib && crypto_open_connections > 0)
@@ -875,7 +856,7 @@ destroy_ssl_system(void)
 		 */
 	}
 
-	pthread_mutex_unlock(&ssl_config_mutex);
+	pgunlock(&ssl_config_lock);
 #endif
 }
 
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 86dd1d6d405..01dd4190f33 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -672,7 +672,28 @@ extern pgthreadlock_t pg_g_threadlock;
 
 #define pglock_thread()		pg_g_threadlock(true)
 #define pgunlock_thread()	pg_g_threadlock(false)
+
+typedef struct pglock_t
+{
+	pthread_mutex_t mutex;
+#ifdef WIN32
+	long		mutex_initlock;
+#endif
+}			pglock_t;
+
+#ifdef WIN32
+#define PGLOCK_INITIALIZER { NULL, 0 }
+#else
+#define PGLOCK_INITIALIZER { PTHREAD_MUTEX_INITIALIZER }
+#endif
+
+extern bool pglock(pglock_t * lock);
+extern bool pgunlock(pglock_t * lock);
 #else
+#define pglock_t bool;
+#define PGLOCK_INITIALIZER false;
+#define pglock(lock)	((void) true)
+#define pgunlock(lock)	((void) true)
 #define pglock_thread()		((void) 0)
 #define pgunlock_thread()	((void) 0)
 #endif
-- 
2.34.1

