From 2e1281762b56bb6e62f71124611505e5e29e5627 Mon Sep 17 00:00:00 2001
From: Thomas Munro <thomas.munro@gmail.com>
Date: Fri, 9 Jun 2023 13:27:42 +1200
Subject: [PATCH 5/5] Replace various ad hoc abstractions with pg_threads.h.

Several places had their own macros and functions to abstract POSIX and
Windows threading APIs.  Use the new centralized API instead.
---
 src/bin/pgbench/pgbench.c                     | 67 +++----------
 src/interfaces/ecpg/ecpglib/connect.c         | 43 ++++----
 src/interfaces/ecpg/ecpglib/descriptor.c      | 14 +--
 src/interfaces/ecpg/ecpglib/memory.c          | 14 +--
 src/interfaces/ecpg/ecpglib/misc.c            | 68 ++++---------
 src/interfaces/ecpg/ecpglib/sqlda.c           |  1 -
 .../ecpg/include/ecpg-pthread-win32.h         | 55 -----------
 src/interfaces/ecpg/include/ecpg_config.h.in  |  3 +
 src/interfaces/ecpg/include/meson.build       |  1 +
 .../ecpg/test/expected/thread-alloc.c         | 73 +++++---------
 .../ecpg/test/expected/thread-descriptor.c    | 52 +++-------
 .../ecpg/test/expected/thread-prep.c          | 99 +++++++------------
 .../ecpg/test/expected/thread-thread.c        | 92 +++++++----------
 .../test/expected/thread-thread_implicit.c    | 92 +++++++----------
 src/interfaces/ecpg/test/thread/alloc.pgc     | 39 +-------
 .../ecpg/test/thread/descriptor.pgc           | 38 +------
 src/interfaces/ecpg/test/thread/prep.pgc      | 37 +------
 src/interfaces/ecpg/test/thread/thread.pgc    | 38 ++-----
 .../ecpg/test/thread/thread_implicit.pgc      | 38 ++-----
 src/interfaces/libpq/Makefile                 |  1 -
 src/interfaces/libpq/fe-connect.c             | 39 +++-----
 src/interfaces/libpq/fe-secure-openssl.c      | 63 +++++-------
 src/interfaces/libpq/fe-secure.c              |  4 +-
 src/interfaces/libpq/libpq-int.h              |  5 -
 src/interfaces/libpq/meson.build              |  4 +-
 src/interfaces/libpq/pthread-win32.c          | 60 -----------
 src/port/pthread-win32.h                      | 22 -----
 src/tools/pginclude/cpluspluscheck            |  1 -
 src/tools/pginclude/headerscheck              |  1 -
 29 files changed, 285 insertions(+), 779 deletions(-)
 delete mode 100644 src/interfaces/ecpg/include/ecpg-pthread-win32.h
 delete mode 100644 src/interfaces/libpq/pthread-win32.c
 delete mode 100644 src/port/pthread-win32.h

diff --git a/src/bin/pgbench/pgbench.c b/src/bin/pgbench/pgbench.c
index 683fc5860f..57e3b5fb46 100644
--- a/src/bin/pgbench/pgbench.c
+++ b/src/bin/pgbench/pgbench.c
@@ -66,6 +66,7 @@
 #include "libpq-fe.h"
 #include "pgbench.h"
 #include "port/pg_bitutils.h"
+#include "port/pg_threads.h"
 #include "portability/instr_time.h"
 
 /* X/Open (XSI) requires <math.h> to provide M_PI, but core POSIX does not */
@@ -113,49 +114,6 @@ typedef struct socket_set
 
 #endif							/* POLL_USING_SELECT */
 
-/*
- * Multi-platform thread implementations
- */
-
-#ifdef WIN32
-/* Use Windows threads */
-#include <windows.h>
-#define GETERRNO() (_dosmaperr(GetLastError()), errno)
-#define THREAD_T HANDLE
-#define THREAD_FUNC_RETURN_TYPE unsigned
-#define THREAD_FUNC_RETURN return 0
-#define THREAD_FUNC_CC __stdcall
-#define THREAD_CREATE(handle, function, arg) \
-	((*(handle) = (HANDLE) _beginthreadex(NULL, 0, (function), (arg), 0, NULL)) == 0 ? errno : 0)
-#define THREAD_JOIN(handle) \
-	(WaitForSingleObject(handle, INFINITE) != WAIT_OBJECT_0 ? \
-	GETERRNO() : CloseHandle(handle) ? 0 : GETERRNO())
-#define THREAD_BARRIER_T SYNCHRONIZATION_BARRIER
-#define THREAD_BARRIER_INIT(barrier, n) \
-	(InitializeSynchronizationBarrier((barrier), (n), 0) ? 0 : GETERRNO())
-#define THREAD_BARRIER_WAIT(barrier) \
-	EnterSynchronizationBarrier((barrier), \
-								SYNCHRONIZATION_BARRIER_FLAGS_BLOCK_ONLY)
-#define THREAD_BARRIER_DESTROY(barrier)
-#else
-/* Use POSIX threads */
-#include "port/pg_pthread.h"
-#define THREAD_T pthread_t
-#define THREAD_FUNC_RETURN_TYPE void *
-#define THREAD_FUNC_RETURN return NULL
-#define THREAD_FUNC_CC
-#define THREAD_CREATE(handle, function, arg) \
-	pthread_create((handle), NULL, (function), (arg))
-#define THREAD_JOIN(handle) \
-	pthread_join((handle), NULL)
-#define THREAD_BARRIER_T pthread_barrier_t
-#define THREAD_BARRIER_INIT(barrier, n) \
-	pthread_barrier_init((barrier), NULL, (n))
-#define THREAD_BARRIER_WAIT(barrier) pthread_barrier_wait((barrier))
-#define THREAD_BARRIER_DESTROY(barrier) pthread_barrier_destroy((barrier))
-#endif
-
-
 /********************************************************************
  * some configurable parameters */
 
@@ -477,7 +435,7 @@ typedef enum TStatus
 static pg_prng_state base_random_sequence;
 
 /* Synchronization barrier for start and connection */
-static THREAD_BARRIER_T barrier;
+static pg_thrd_barrier_t barrier;
 
 /*
  * Connection state machine states.
@@ -644,7 +602,7 @@ typedef struct
 typedef struct
 {
 	int			tid;			/* thread id */
-	THREAD_T	thread;			/* thread handle */
+	pg_thrd_t	thread;			/* thread handle */
 	CState	   *state;			/* array of CState */
 	int			nstate;			/* length of state[] */
 
@@ -825,7 +783,7 @@ static void doLog(TState *thread, CState *st,
 static void processXactStats(TState *thread, CState *st, pg_time_usec_t *now,
 							 bool skipped, StatsData *agg);
 static void addScript(const ParsedScript *script);
-static THREAD_FUNC_RETURN_TYPE THREAD_FUNC_CC threadRun(void *arg);
+static int threadRun(void *arg);
 static void finishCon(CState *st);
 static void setalarm(int seconds);
 static socket_set *alloc_socket_set(int count);
@@ -7218,7 +7176,7 @@ main(int argc, char **argv)
 	if (duration > 0)
 		setalarm(duration);
 
-	errno = THREAD_BARRIER_INIT(&barrier, nthreads);
+	errno = pg_thrd_barrier_init(&barrier, nthreads);
 	if (errno != 0)
 		pg_fatal("could not initialize barrier: %m");
 
@@ -7228,7 +7186,7 @@ main(int argc, char **argv)
 		TState	   *thread = &threads[i];
 
 		thread->create_time = pg_time_now();
-		errno = THREAD_CREATE(&thread->thread, threadRun, thread);
+		errno = pg_thrd_create(&thread->thread, threadRun, thread);
 
 		if (errno != 0)
 			pg_fatal("could not create thread: %m");
@@ -7251,7 +7209,7 @@ main(int argc, char **argv)
 		TState	   *thread = &threads[i];
 
 		if (i > 0)
-			THREAD_JOIN(thread->thread);
+			pg_thrd_join(thread->thread, NULL);
 
 		for (int j = 0; j < thread->nstate; j++)
 			if (thread->state[j].state != CSTATE_FINISHED)
@@ -7291,7 +7249,7 @@ main(int argc, char **argv)
 	printResults(&stats, pg_time_now() - bench_start, conn_total_duration,
 				 bench_start - start_time, latency_late);
 
-	THREAD_BARRIER_DESTROY(&barrier);
+	pg_thrd_barrier_destroy(&barrier);
 
 	if (exit_code != 0)
 		pg_log_error("Run was aborted; the above results are incomplete.");
@@ -7299,7 +7257,7 @@ main(int argc, char **argv)
 	return exit_code;
 }
 
-static THREAD_FUNC_RETURN_TYPE THREAD_FUNC_CC
+static int
 threadRun(void *arg)
 {
 	TState	   *thread = (TState *) arg;
@@ -7336,7 +7294,7 @@ threadRun(void *arg)
 		state[i].state = CSTATE_CHOOSE_SCRIPT;
 
 	/* READY */
-	THREAD_BARRIER_WAIT(&barrier);
+	pg_thrd_barrier_wait(&barrier);
 
 	thread_start = pg_time_now();
 	thread->started_time = thread_start;
@@ -7360,7 +7318,7 @@ threadRun(void *arg)
 	}
 
 	/* GO */
-	THREAD_BARRIER_WAIT(&barrier);
+	pg_thrd_barrier_wait(&barrier);
 
 	start = pg_time_now();
 	thread->bench_start = start;
@@ -7572,7 +7530,8 @@ done:
 		thread->logfile = NULL;
 	}
 	free_socket_set(sockets);
-	THREAD_FUNC_RETURN;
+
+	return 0;
 }
 
 static void
diff --git a/src/interfaces/ecpg/ecpglib/connect.c b/src/interfaces/ecpg/ecpglib/connect.c
index 8afb1f0a26..61ca9a0829 100644
--- a/src/interfaces/ecpg/ecpglib/connect.c
+++ b/src/interfaces/ecpg/ecpglib/connect.c
@@ -2,8 +2,8 @@
 
 #define POSTGRES_ECPG_INTERNAL
 #include "postgres_fe.h"
+#include "port/pg_threads.h"
 
-#include "ecpg-pthread-win32.h"
 #include "ecpgerrno.h"
 #include "ecpglib.h"
 #include "ecpglib_extern.h"
@@ -14,22 +14,23 @@
 locale_t	ecpg_clocale = (locale_t) 0;
 #endif
 
-static pthread_mutex_t connections_mutex = PTHREAD_MUTEX_INITIALIZER;
-static pthread_key_t actual_connection_key;
-static pthread_once_t actual_connection_key_once = PTHREAD_ONCE_INIT;
+static pg_mtx_t connections_mutex;
+static pg_tss_t actual_connection_key;
+static pg_once_flag actual_connection_key_once = PG_ONCE_FLAG_INIT;
 static struct connection *actual_connection = NULL;
 static struct connection *all_connections = NULL;
 
 static void
 ecpg_actual_connection_init(void)
 {
-	pthread_key_create(&actual_connection_key, NULL);
+	pg_mtx_init(&connections_mutex, pg_mtx_plain);
+	pg_tss_create(&actual_connection_key, NULL);
 }
 
 void
 ecpg_pthreads_init(void)
 {
-	pthread_once(&actual_connection_key_once, ecpg_actual_connection_init);
+	pg_call_once(&actual_connection_key_once, ecpg_actual_connection_init);
 }
 
 static struct connection *
@@ -41,7 +42,7 @@ ecpg_get_connection_nr(const char *connection_name)
 	{
 		ecpg_pthreads_init();	/* ensure actual_connection_key is valid */
 
-		ret = pthread_getspecific(actual_connection_key);
+		ret = pg_tss_get(actual_connection_key);
 
 		/*
 		 * if no connection in TSD for this thread, get the global default
@@ -76,7 +77,7 @@ ecpg_get_connection(const char *connection_name)
 	{
 		ecpg_pthreads_init();	/* ensure actual_connection_key is valid */
 
-		ret = pthread_getspecific(actual_connection_key);
+		ret = pg_tss_get(actual_connection_key);
 
 		/*
 		 * if no connection in TSD for this thread, get the global default
@@ -89,11 +90,11 @@ ecpg_get_connection(const char *connection_name)
 	}
 	else
 	{
-		pthread_mutex_lock(&connections_mutex);
+		pg_mtx_lock(&connections_mutex);
 
 		ret = ecpg_get_connection_nr(connection_name);
 
-		pthread_mutex_unlock(&connections_mutex);
+		pg_mtx_unlock(&connections_mutex);
 	}
 
 	return ret;
@@ -127,8 +128,8 @@ ecpg_finish(struct connection *act)
 				con->next = act->next;
 		}
 
-		if (pthread_getspecific(actual_connection_key) == act)
-			pthread_setspecific(actual_connection_key, all_connections);
+		if (pg_tss_get(actual_connection_key) == act)
+			pg_tss_set(actual_connection_key, all_connections);
 		if (actual_connection == act)
 			actual_connection = all_connections;
 
@@ -194,7 +195,7 @@ ECPGsetconn(int lineno, const char *connection_name)
 	if (!ecpg_init(con, connection_name, lineno))
 		return false;
 
-	pthread_setspecific(actual_connection_key, con);
+	pg_tss_set(actual_connection_key, con);
 	return true;
 }
 
@@ -481,7 +482,7 @@ ECPGconnect(int lineno, int c, const char *name, const char *user, const char *p
 	}
 
 	/* add connection to our list */
-	pthread_mutex_lock(&connections_mutex);
+	pg_mtx_lock(&connections_mutex);
 
 	/*
 	 * ... but first, make certain we have created ecpg_clocale.  Rely on
@@ -493,7 +494,7 @@ ECPGconnect(int lineno, int c, const char *name, const char *user, const char *p
 		ecpg_clocale = newlocale(LC_NUMERIC_MASK, "C", (locale_t) 0);
 		if (!ecpg_clocale)
 		{
-			pthread_mutex_unlock(&connections_mutex);
+			pg_mtx_unlock(&connections_mutex);
 			ecpg_raise(lineno, ECPG_OUT_OF_MEMORY,
 					   ECPG_SQLSTATE_ECPG_OUT_OF_MEMORY, NULL);
 			if (host)
@@ -530,7 +531,7 @@ ECPGconnect(int lineno, int c, const char *name, const char *user, const char *p
 		this->next = all_connections;
 
 	all_connections = this;
-	pthread_setspecific(actual_connection_key, all_connections);
+	pg_tss_set(actual_connection_key, all_connections);
 	actual_connection = all_connections;
 
 	ecpg_log("ECPGconnect: opening database %s on %s port %s %s%s %s%s\n",
@@ -648,7 +649,7 @@ ECPGconnect(int lineno, int c, const char *name, const char *user, const char *p
 		ecpg_log("ECPGconnect: %s", errmsg);
 
 		ecpg_finish(this);
-		pthread_mutex_unlock(&connections_mutex);
+		pg_mtx_unlock(&connections_mutex);
 
 		ecpg_raise(lineno, ECPG_CONNECT, ECPG_SQLSTATE_SQLCLIENT_UNABLE_TO_ESTABLISH_SQLCONNECTION, db);
 		if (realname)
@@ -660,7 +661,7 @@ ECPGconnect(int lineno, int c, const char *name, const char *user, const char *p
 	if (realname)
 		ecpg_free(realname);
 
-	pthread_mutex_unlock(&connections_mutex);
+	pg_mtx_unlock(&connections_mutex);
 
 	this->autocommit = autocommit;
 
@@ -682,7 +683,7 @@ ECPGdisconnect(int lineno, const char *connection_name)
 		return false;
 	}
 
-	pthread_mutex_lock(&connections_mutex);
+	pg_mtx_lock(&connections_mutex);
 
 	if (strcmp(connection_name, "ALL") == 0)
 	{
@@ -701,14 +702,14 @@ ECPGdisconnect(int lineno, const char *connection_name)
 
 		if (!ecpg_init(con, connection_name, lineno))
 		{
-			pthread_mutex_unlock(&connections_mutex);
+			pg_mtx_unlock(&connections_mutex);
 			return false;
 		}
 		else
 			ecpg_finish(con);
 	}
 
-	pthread_mutex_unlock(&connections_mutex);
+	pg_mtx_unlock(&connections_mutex);
 
 	return true;
 }
diff --git a/src/interfaces/ecpg/ecpglib/descriptor.c b/src/interfaces/ecpg/ecpglib/descriptor.c
index ad279e245c..b57e065672 100644
--- a/src/interfaces/ecpg/ecpglib/descriptor.c
+++ b/src/interfaces/ecpg/ecpglib/descriptor.c
@@ -7,11 +7,11 @@
 #include "postgres_fe.h"
 
 #include "catalog/pg_type_d.h"
-#include "ecpg-pthread-win32.h"
 #include "ecpgerrno.h"
 #include "ecpglib.h"
 #include "ecpglib_extern.h"
 #include "ecpgtype.h"
+#include "port/pg_threads.h"
 #include "sql3types.h"
 #include "sqlca.h"
 #include "sqlda.h"
@@ -19,8 +19,8 @@
 static void descriptor_free(struct descriptor *desc);
 
 /* We manage descriptors separately for each thread. */
-static pthread_key_t descriptor_key;
-static pthread_once_t descriptor_once = PTHREAD_ONCE_INIT;
+static pg_tss_t descriptor_key;
+static pg_once_flag descriptor_once = PG_ONCE_FLAG_INIT;
 
 static void descriptor_deallocate_all(struct descriptor *list);
 
@@ -33,20 +33,20 @@ descriptor_destructor(void *arg)
 static void
 descriptor_key_init(void)
 {
-	pthread_key_create(&descriptor_key, descriptor_destructor);
+	pg_tss_create(&descriptor_key, descriptor_destructor);
 }
 
 static struct descriptor *
 get_descriptors(void)
 {
-	pthread_once(&descriptor_once, descriptor_key_init);
-	return (struct descriptor *) pthread_getspecific(descriptor_key);
+	pg_call_once(&descriptor_once, descriptor_key_init);
+	return (struct descriptor *) pg_tss_get(descriptor_key);
 }
 
 static void
 set_descriptors(struct descriptor *value)
 {
-	pthread_setspecific(descriptor_key, value);
+	pg_tss_set(descriptor_key, value);
 }
 
 /* old internal convenience function that might go away later */
diff --git a/src/interfaces/ecpg/ecpglib/memory.c b/src/interfaces/ecpg/ecpglib/memory.c
index a83637ac75..985f05087d 100644
--- a/src/interfaces/ecpg/ecpglib/memory.c
+++ b/src/interfaces/ecpg/ecpglib/memory.c
@@ -3,11 +3,11 @@
 #define POSTGRES_ECPG_INTERNAL
 #include "postgres_fe.h"
 
-#include "ecpg-pthread-win32.h"
 #include "ecpgerrno.h"
 #include "ecpglib.h"
 #include "ecpglib_extern.h"
 #include "ecpgtype.h"
+#include "port/pg_threads.h"
 
 void
 ecpg_free(void *ptr)
@@ -68,8 +68,8 @@ struct auto_mem
 	struct auto_mem *next;
 };
 
-static pthread_key_t auto_mem_key;
-static pthread_once_t auto_mem_once = PTHREAD_ONCE_INIT;
+static pg_tss_t auto_mem_key;
+static pg_once_flag auto_mem_once = PG_ONCE_FLAG_INIT;
 
 static void
 auto_mem_destructor(void *arg)
@@ -81,20 +81,20 @@ auto_mem_destructor(void *arg)
 static void
 auto_mem_key_init(void)
 {
-	pthread_key_create(&auto_mem_key, auto_mem_destructor);
+	pg_tss_create(&auto_mem_key, auto_mem_destructor);
 }
 
 static struct auto_mem *
 get_auto_allocs(void)
 {
-	pthread_once(&auto_mem_once, auto_mem_key_init);
-	return (struct auto_mem *) pthread_getspecific(auto_mem_key);
+	pg_call_once(&auto_mem_once, auto_mem_key_init);
+	return (struct auto_mem *) pg_tss_get(auto_mem_key);
 }
 
 static void
 set_auto_allocs(struct auto_mem *am)
 {
-	pthread_setspecific(auto_mem_key, am);
+	pg_tss_set(auto_mem_key, am);
 }
 
 char *
diff --git a/src/interfaces/ecpg/ecpglib/misc.c b/src/interfaces/ecpg/ecpglib/misc.c
index 2b78caeaf5..b3d997e749 100644
--- a/src/interfaces/ecpg/ecpglib/misc.c
+++ b/src/interfaces/ecpg/ecpglib/misc.c
@@ -6,7 +6,6 @@
 #include <limits.h>
 #include <unistd.h>
 
-#include "ecpg-pthread-win32.h"
 #include "ecpgerrno.h"
 #include "ecpglib.h"
 #include "ecpglib_extern.h"
@@ -16,6 +15,7 @@
 #include "pgtypes_interval.h"
 #include "pgtypes_numeric.h"
 #include "pgtypes_timestamp.h"
+#include "port/pg_threads.h"
 #include "sqlca.h"
 
 #ifndef LONG_LONG_MIN
@@ -55,11 +55,10 @@ static struct sqlca_t sqlca_init =
 	}
 };
 
-static pthread_key_t sqlca_key;
-static pthread_once_t sqlca_key_once = PTHREAD_ONCE_INIT;
-
-static pthread_mutex_t debug_mutex = PTHREAD_MUTEX_INITIALIZER;
-static pthread_mutex_t debug_init_mutex = PTHREAD_MUTEX_INITIALIZER;
+static pg_tss_t sqlca_key;
+static pg_once_flag ecpg_once = PG_ONCE_FLAG_INIT;
+static pg_mtx_t debug_mutex;
+static pg_mtx_t debug_init_mutex;
 static int	simple_debug = 0;
 static FILE *debugstream = NULL;
 
@@ -99,9 +98,11 @@ ecpg_sqlca_key_destructor(void *arg)
 }
 
 static void
-ecpg_sqlca_key_init(void)
+ecpg_init_once(void)
 {
-	pthread_key_create(&sqlca_key, ecpg_sqlca_key_destructor);
+	pg_tss_create(&sqlca_key, ecpg_sqlca_key_destructor);
+	pg_mtx_init(&debug_mutex, pg_mtx_plain);
+	pg_mtx_init(&debug_init_mutex, pg_mtx_plain);
 }
 
 struct sqlca_t *
@@ -109,16 +110,16 @@ ECPGget_sqlca(void)
 {
 	struct sqlca_t *sqlca;
 
-	pthread_once(&sqlca_key_once, ecpg_sqlca_key_init);
+	pg_call_once(&ecpg_once, ecpg_init_once);
 
-	sqlca = pthread_getspecific(sqlca_key);
+	sqlca = pg_tss_get(sqlca_key);
 	if (sqlca == NULL)
 	{
 		sqlca = malloc(sizeof(struct sqlca_t));
 		if (sqlca == NULL)
 			return NULL;
 		ecpg_init_sqlca(sqlca);
-		pthread_setspecific(sqlca_key, sqlca);
+		pg_tss_set(sqlca_key, sqlca);
 	}
 	return sqlca;
 }
@@ -203,7 +204,9 @@ ECPGtrans(int lineno, const char *connection_name, const char *transaction)
 void
 ECPGdebug(int n, FILE *dbgs)
 {
-	pthread_mutex_lock(&debug_init_mutex);
+	pg_call_once(&ecpg_once, ecpg_init_once);
+
+	pg_mtx_lock(&debug_init_mutex);
 
 	if (n > 100)
 	{
@@ -217,7 +220,7 @@ ECPGdebug(int n, FILE *dbgs)
 
 	ecpg_log("ECPGdebug: set to %d\n", simple_debug);
 
-	pthread_mutex_unlock(&debug_init_mutex);
+	pg_mtx_unlock(&debug_init_mutex);
 }
 
 void
@@ -249,7 +252,9 @@ ecpg_log(const char *format,...)
 	else
 		snprintf(fmt, bufsize, "[%d]: %s", (int) getpid(), intl_format);
 
-	pthread_mutex_lock(&debug_mutex);
+	pg_call_once(&ecpg_once, ecpg_init_once);
+
+	pg_mtx_lock(&debug_mutex);
 
 	va_start(ap, format);
 	vfprintf(debugstream, fmt, ap);
@@ -264,7 +269,7 @@ ecpg_log(const char *format,...)
 
 	fflush(debugstream);
 
-	pthread_mutex_unlock(&debug_mutex);
+	pg_mtx_unlock(&debug_mutex);
 
 	free(fmt);
 }
@@ -405,39 +410,6 @@ ECPGis_noind_null(enum ECPGttype type, const void *ptr)
 	return false;
 }
 
-#ifdef WIN32
-
-void
-win32_pthread_mutex(volatile pthread_mutex_t *mutex)
-{
-	if (mutex->handle == NULL)
-	{
-		while (InterlockedExchange((LONG *) &mutex->initlock, 1) == 1)
-			Sleep(0);
-		if (mutex->handle == NULL)
-			mutex->handle = CreateMutex(NULL, FALSE, NULL);
-		InterlockedExchange((LONG *) &mutex->initlock, 0);
-	}
-}
-
-static pthread_mutex_t win32_pthread_once_lock = PTHREAD_MUTEX_INITIALIZER;
-
-void
-win32_pthread_once(volatile pthread_once_t *once, void (*fn) (void))
-{
-	if (!*once)
-	{
-		pthread_mutex_lock(&win32_pthread_once_lock);
-		if (!*once)
-		{
-			fn();
-			*once = true;
-		}
-		pthread_mutex_unlock(&win32_pthread_once_lock);
-	}
-}
-#endif							/* WIN32 */
-
 #ifdef ENABLE_NLS
 
 char *
diff --git a/src/interfaces/ecpg/ecpglib/sqlda.c b/src/interfaces/ecpg/ecpglib/sqlda.c
index 081e32666f..7231cc4a6f 100644
--- a/src/interfaces/ecpg/ecpglib/sqlda.c
+++ b/src/interfaces/ecpg/ecpglib/sqlda.c
@@ -11,7 +11,6 @@
 
 #include "catalog/pg_type_d.h"
 #include "decimal.h"
-#include "ecpg-pthread-win32.h"
 #include "ecpgerrno.h"
 #include "ecpglib.h"
 #include "ecpglib_extern.h"
diff --git a/src/interfaces/ecpg/include/ecpg-pthread-win32.h b/src/interfaces/ecpg/include/ecpg-pthread-win32.h
deleted file mode 100644
index 8252a17809..0000000000
--- a/src/interfaces/ecpg/include/ecpg-pthread-win32.h
+++ /dev/null
@@ -1,55 +0,0 @@
-/* src/interfaces/ecpg/include/ecpg-pthread-win32.h */
-/*
- * pthread mapping macros for win32 native thread implementation
- */
-#ifndef _ECPG_PTHREAD_WIN32_H
-#define _ECPG_PTHREAD_WIN32_H
-
-#ifndef WIN32
-
-#include <pthread.h>
-#else
-
-typedef struct pthread_mutex_t
-{
-	HANDLE		handle;
-	LONG		initlock;
-} pthread_mutex_t;
-
-typedef DWORD pthread_key_t;
-typedef bool pthread_once_t;
-
-#define PTHREAD_MUTEX_INITIALIZER	{ NULL, 0 }
-#define PTHREAD_ONCE_INIT			false
-
-void		win32_pthread_mutex(volatile pthread_mutex_t *mutex);
-void		win32_pthread_once(volatile pthread_once_t *once, void (*fn) (void));
-
-#define pthread_mutex_lock(mutex) \
-	do { \
-		if ((mutex)->handle == NULL) \
-			win32_pthread_mutex((mutex)); \
-		WaitForSingleObject((mutex)->handle, INFINITE); \
-	} while(0)
-
-#define pthread_mutex_unlock(mutex) \
-	ReleaseMutex((mutex)->handle)
-
-#define pthread_getspecific(key) \
-	TlsGetValue((key))
-
-#define pthread_setspecific(key, value) \
-	TlsSetValue((key), (value))
-
-/* FIXME: destructor is never called in Win32. */
-#define pthread_key_create(key, destructor) \
-	do { *(key) = TlsAlloc(); ((void)(destructor)); } while(0)
-
-#define pthread_once(once, fn) \
-	do { \
-		if (!*(once)) \
-			win32_pthread_once((once), (fn)); \
-	} while(0)
-#endif							/* WIN32 */
-
-#endif							/* _ECPG_PTHREAD_WIN32_H */
diff --git a/src/interfaces/ecpg/include/ecpg_config.h.in b/src/interfaces/ecpg/include/ecpg_config.h.in
index 6d01608a49..e693c9074f 100644
--- a/src/interfaces/ecpg/include/ecpg_config.h.in
+++ b/src/interfaces/ecpg/include/ecpg_config.h.in
@@ -10,5 +10,8 @@
 /* Define to 1 if `long long int' works and is 64 bits. */
 #undef HAVE_LONG_LONG_INT_64
 
+/* Define to 1 if you have the `pthread_barrier_wait' function. */
+#undef HAVE_PTHREAD_BARRIER_WAIT
+
 /* Define to 1 to use <stdbool.h> to define type bool. */
 #undef PG_USE_STDBOOL
diff --git a/src/interfaces/ecpg/include/meson.build b/src/interfaces/ecpg/include/meson.build
index 543e48fd6e..2e93efde98 100644
--- a/src/interfaces/ecpg/include/meson.build
+++ b/src/interfaces/ecpg/include/meson.build
@@ -6,6 +6,7 @@ ecpg_conf_keys = [
   'HAVE_INT64',
   'HAVE_LONG_INT_64',
   'HAVE_LONG_LONG_INT_64',
+  'HAVE_PTHREAD_BARRIER_WAIT',
   'PG_USE_STDBOOL',
 ]
 
diff --git a/src/interfaces/ecpg/test/expected/thread-alloc.c b/src/interfaces/ecpg/test/expected/thread-alloc.c
index 3b31d27fd3..97ed928ef1 100644
--- a/src/interfaces/ecpg/test/expected/thread-alloc.c
+++ b/src/interfaces/ecpg/test/expected/thread-alloc.c
@@ -10,16 +10,7 @@
 #include <stdint.h>
 #include <stdlib.h>
 #include "ecpg_config.h"
-
-#ifdef WIN32
-#define WIN32_LEAN_AND_MEAN
-#include <windows.h>
-#include <process.h>
-#include <locale.h>
-#else
-#include <pthread.h>
-#endif
-#include <stdio.h>
+#include "port/pg_threads.h"
 
 #define THREADS		16
 #define REPEATS		50
@@ -93,7 +84,7 @@ struct sqlca_t *ECPGget_sqlca(void);
 
 #endif
 
-#line 18 "alloc.pgc"
+#line 9 "alloc.pgc"
 
 
 #line 1 "regression.h"
@@ -103,21 +94,17 @@ struct sqlca_t *ECPGget_sqlca(void);
 
 
 
-#line 19 "alloc.pgc"
+#line 10 "alloc.pgc"
 
 
 /* exec sql whenever sqlerror  sqlprint ; */
-#line 21 "alloc.pgc"
+#line 12 "alloc.pgc"
 
 /* exec sql whenever not found  sqlprint ; */
-#line 22 "alloc.pgc"
+#line 13 "alloc.pgc"
 
 
-#ifdef WIN32
-static unsigned __stdcall fn(void* arg)
-#else
-static void* fn(void* arg)
-#endif
+static int fn(void* arg)
 {
 	int i;
 
@@ -126,54 +113,54 @@ static void* fn(void* arg)
 	 
 	   
 	
-#line 33 "alloc.pgc"
+#line 20 "alloc.pgc"
  int value ;
  
-#line 34 "alloc.pgc"
+#line 21 "alloc.pgc"
  char name [ 100 ] ;
  
-#line 35 "alloc.pgc"
+#line 22 "alloc.pgc"
  char ** r = NULL ;
 /* exec sql end declare section */
-#line 36 "alloc.pgc"
+#line 23 "alloc.pgc"
 
 
 	value = (intptr_t) arg;
 	sprintf(name, "Connection: %d", value);
 
 	{ ECPGconnect(__LINE__, 0, "ecpg1_regression" , NULL, NULL , name, 0); 
-#line 41 "alloc.pgc"
+#line 28 "alloc.pgc"
 
 if (sqlca.sqlcode < 0) sqlprint();}
-#line 41 "alloc.pgc"
+#line 28 "alloc.pgc"
 
 	{ ECPGsetcommit(__LINE__, "on", NULL);
-#line 42 "alloc.pgc"
+#line 29 "alloc.pgc"
 
 if (sqlca.sqlcode < 0) sqlprint();}
-#line 42 "alloc.pgc"
+#line 29 "alloc.pgc"
 
 	for (i = 1; i <= REPEATS; ++i)
 	{
 		{ ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "select relname from pg_class where relname = 'pg_class'", ECPGt_EOIT, 
 	ECPGt_char,&(r),(long)0,(long)0,(1)*sizeof(char), 
 	ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EORT);
-#line 45 "alloc.pgc"
+#line 32 "alloc.pgc"
 
 if (sqlca.sqlcode == ECPG_NOT_FOUND) sqlprint();
-#line 45 "alloc.pgc"
+#line 32 "alloc.pgc"
 
 if (sqlca.sqlcode < 0) sqlprint();}
-#line 45 "alloc.pgc"
+#line 32 "alloc.pgc"
 
 		free(r);
 		r = NULL;
 	}
 	{ ECPGdisconnect(__LINE__, name);
-#line 49 "alloc.pgc"
+#line 36 "alloc.pgc"
 
 if (sqlca.sqlcode < 0) sqlprint();}
-#line 49 "alloc.pgc"
+#line 36 "alloc.pgc"
 
 
 	return 0;
@@ -182,28 +169,12 @@ if (sqlca.sqlcode < 0) sqlprint();}
 int main ()
 {
 	intptr_t i;
-#ifdef WIN32
-	HANDLE threads[THREADS];
-#else
-	pthread_t threads[THREADS];
-#endif
-
-#ifdef WIN32
-	for (i = 0; i < THREADS; ++i)
-	{
-		unsigned id;
-		threads[i] = (HANDLE)_beginthreadex(NULL, 0, fn, (void*)i, 0, &id);
-	}
+	pg_thrd_t threads[THREADS];
 
-	WaitForMultipleObjects(THREADS, threads, TRUE, INFINITE);
 	for (i = 0; i < THREADS; ++i)
-		CloseHandle(threads[i]);
-#else
+		pg_thrd_create(&threads[i], fn, (void *) i);
 	for (i = 0; i < THREADS; ++i)
-		pthread_create(&threads[i], NULL, fn, (void *) i);
-	for (i = 0; i < THREADS; ++i)
-		pthread_join(threads[i], NULL);
-#endif
+		pg_thrd_join(threads[i], NULL);
 
 	return 0;
 }
diff --git a/src/interfaces/ecpg/test/expected/thread-descriptor.c b/src/interfaces/ecpg/test/expected/thread-descriptor.c
index e34f4708d1..50cdbf1b2f 100644
--- a/src/interfaces/ecpg/test/expected/thread-descriptor.c
+++ b/src/interfaces/ecpg/test/expected/thread-descriptor.c
@@ -7,15 +7,7 @@
 #define ECPGdebug(X,Y) ECPGdebug((X)+100,(Y))
 
 #line 1 "descriptor.pgc"
-#ifdef WIN32
-#define WIN32_LEAN_AND_MEAN
-#include <windows.h>
-#include <process.h>
-#include <locale.h>
-#else
-#include <pthread.h>
-#endif
-#include <stdio.h>
+#include "port/pg_threads.h"
 
 #define THREADS		16
 #define REPEATS		50000
@@ -89,36 +81,32 @@ struct sqlca_t *ECPGget_sqlca(void);
 
 #endif
 
-#line 14 "descriptor.pgc"
+#line 6 "descriptor.pgc"
 
 /* exec sql whenever sqlerror  sqlprint ; */
-#line 15 "descriptor.pgc"
+#line 7 "descriptor.pgc"
 
 /* exec sql whenever not found  sqlprint ; */
-#line 16 "descriptor.pgc"
+#line 8 "descriptor.pgc"
 
 
-#if defined(WIN32)
-static unsigned __stdcall fn(void* arg)
-#else
-static void* fn(void* arg)
-#endif
+static int fn(void* arg)
 {
 	int i;
 
 	for (i = 1; i <= REPEATS; ++i)
 	{
 		ECPGallocate_desc(__LINE__, "mydesc");
-#line 28 "descriptor.pgc"
+#line 16 "descriptor.pgc"
 
 if (sqlca.sqlcode < 0) sqlprint();
-#line 28 "descriptor.pgc"
+#line 16 "descriptor.pgc"
 
 		ECPGdeallocate_desc(__LINE__, "mydesc");
-#line 29 "descriptor.pgc"
+#line 17 "descriptor.pgc"
 
 if (sqlca.sqlcode < 0) sqlprint();
-#line 29 "descriptor.pgc"
+#line 17 "descriptor.pgc"
 
 	}
 
@@ -128,28 +116,12 @@ if (sqlca.sqlcode < 0) sqlprint();
 int main ()
 {
 	int i;
-#ifdef WIN32
-	HANDLE threads[THREADS];
-#else
-	pthread_t threads[THREADS];
-#endif
-
-#ifdef WIN32
-	for (i = 0; i < THREADS; ++i)
-	{
-		unsigned id;
-		threads[i] = (HANDLE)_beginthreadex(NULL, 0, fn, NULL, 0, &id);
-	}
+	pg_thrd_t threads[THREADS];
 
-	WaitForMultipleObjects(THREADS, threads, TRUE, INFINITE);
-	for (i = 0; i < THREADS; ++i)
-		CloseHandle(threads[i]);
-#else
 	for (i = 0; i < THREADS; ++i)
-		pthread_create(&threads[i], NULL, fn, NULL);
+		pg_thrd_create(&threads[i], fn, NULL);
 	for (i = 0; i < THREADS; ++i)
-		pthread_join(threads[i], NULL);
-#endif
+		pg_thrd_join(threads[i], NULL);
 
 	return 0;
 }
diff --git a/src/interfaces/ecpg/test/expected/thread-prep.c b/src/interfaces/ecpg/test/expected/thread-prep.c
index 052e27b634..c5b60d18cb 100644
--- a/src/interfaces/ecpg/test/expected/thread-prep.c
+++ b/src/interfaces/ecpg/test/expected/thread-prep.c
@@ -10,15 +10,8 @@
 #include <stdint.h>
 #include <stdlib.h>
 #include "ecpg_config.h"
+#include "port/pg_threads.h"
 
-#ifdef WIN32
-#define WIN32_LEAN_AND_MEAN
-#include <windows.h>
-#include <process.h>
-#include <locale.h>
-#else
-#include <pthread.h>
-#endif
 #include <stdio.h>
 
 #define THREADS		16
@@ -93,7 +86,7 @@ struct sqlca_t *ECPGget_sqlca(void);
 
 #endif
 
-#line 18 "prep.pgc"
+#line 11 "prep.pgc"
 
 
 #line 1 "regression.h"
@@ -103,21 +96,17 @@ struct sqlca_t *ECPGget_sqlca(void);
 
 
 
-#line 19 "prep.pgc"
+#line 12 "prep.pgc"
 
 
 /* exec sql whenever sqlerror  sqlprint ; */
-#line 21 "prep.pgc"
+#line 14 "prep.pgc"
 
 /* exec sql whenever not found  sqlprint ; */
-#line 22 "prep.pgc"
+#line 15 "prep.pgc"
 
 
-#ifdef WIN32
-static unsigned __stdcall fn(void* arg)
-#else
-static void* fn(void* arg)
-#endif
+static int fn(void* arg)
 {
 	int i;
 
@@ -126,64 +115,64 @@ static void* fn(void* arg)
 	 
 	   
 	
-#line 33 "prep.pgc"
+#line 22 "prep.pgc"
  int value ;
  
-#line 34 "prep.pgc"
+#line 23 "prep.pgc"
  char name [ 100 ] ;
  
-#line 35 "prep.pgc"
+#line 24 "prep.pgc"
  char query [ 256 ] = "INSERT INTO T VALUES ( ? )" ;
 /* exec sql end declare section */
-#line 36 "prep.pgc"
+#line 25 "prep.pgc"
 
 
 	value = (intptr_t) arg;
 	sprintf(name, "Connection: %d", value);
 
 	{ ECPGconnect(__LINE__, 0, "ecpg1_regression" , NULL, NULL , name, 0); 
-#line 41 "prep.pgc"
+#line 30 "prep.pgc"
 
 if (sqlca.sqlcode < 0) sqlprint();}
-#line 41 "prep.pgc"
+#line 30 "prep.pgc"
 
 	{ ECPGsetcommit(__LINE__, "on", NULL);
-#line 42 "prep.pgc"
+#line 31 "prep.pgc"
 
 if (sqlca.sqlcode < 0) sqlprint();}
-#line 42 "prep.pgc"
+#line 31 "prep.pgc"
 
 	for (i = 1; i <= REPEATS; ++i)
 	{
 		{ ECPGprepare(__LINE__, NULL, 0, "i", query);
-#line 45 "prep.pgc"
+#line 34 "prep.pgc"
 
 if (sqlca.sqlcode < 0) sqlprint();}
-#line 45 "prep.pgc"
+#line 34 "prep.pgc"
 
 		{ ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_execute, "i", 
 	ECPGt_int,&(value),(long)1,(long)1,sizeof(int), 
 	ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EOIT, ECPGt_EORT);
-#line 46 "prep.pgc"
+#line 35 "prep.pgc"
 
 if (sqlca.sqlcode == ECPG_NOT_FOUND) sqlprint();
-#line 46 "prep.pgc"
+#line 35 "prep.pgc"
 
 if (sqlca.sqlcode < 0) sqlprint();}
-#line 46 "prep.pgc"
+#line 35 "prep.pgc"
 
 	}
 	{ ECPGdeallocate(__LINE__, 0, NULL, "i");
-#line 48 "prep.pgc"
+#line 37 "prep.pgc"
 
 if (sqlca.sqlcode < 0) sqlprint();}
-#line 48 "prep.pgc"
+#line 37 "prep.pgc"
 
 	{ ECPGdisconnect(__LINE__, name);
-#line 49 "prep.pgc"
+#line 38 "prep.pgc"
 
 if (sqlca.sqlcode < 0) sqlprint();}
-#line 49 "prep.pgc"
+#line 38 "prep.pgc"
 
 
 	return 0;
@@ -192,59 +181,43 @@ if (sqlca.sqlcode < 0) sqlprint();}
 int main ()
 {
 	intptr_t i;
-#ifdef WIN32
-	HANDLE threads[THREADS];
-#else
-	pthread_t threads[THREADS];
-#endif
+	pg_thrd_t threads[THREADS];
 
 	{ ECPGconnect(__LINE__, 0, "ecpg1_regression" , NULL, NULL , NULL, 0); 
-#line 63 "prep.pgc"
+#line 48 "prep.pgc"
 
 if (sqlca.sqlcode < 0) sqlprint();}
-#line 63 "prep.pgc"
+#line 48 "prep.pgc"
 
 	{ ECPGsetcommit(__LINE__, "on", NULL);
-#line 64 "prep.pgc"
+#line 49 "prep.pgc"
 
 if (sqlca.sqlcode < 0) sqlprint();}
-#line 64 "prep.pgc"
+#line 49 "prep.pgc"
 
 	{ ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "drop table if exists T", ECPGt_EOIT, ECPGt_EORT);
-#line 65 "prep.pgc"
+#line 50 "prep.pgc"
 
 if (sqlca.sqlcode < 0) sqlprint();}
-#line 65 "prep.pgc"
+#line 50 "prep.pgc"
 
 	{ ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "create table T ( i int )", ECPGt_EOIT, ECPGt_EORT);
-#line 66 "prep.pgc"
+#line 51 "prep.pgc"
 
 if (sqlca.sqlcode < 0) sqlprint();}
-#line 66 "prep.pgc"
+#line 51 "prep.pgc"
 
 	{ ECPGdisconnect(__LINE__, "CURRENT");
-#line 67 "prep.pgc"
+#line 52 "prep.pgc"
 
 if (sqlca.sqlcode < 0) sqlprint();}
-#line 67 "prep.pgc"
+#line 52 "prep.pgc"
 
 
-#ifdef WIN32
 	for (i = 0; i < THREADS; ++i)
-	{
-		unsigned id;
-		threads[i] = (HANDLE)_beginthreadex(NULL, 0, fn, (void*)i, 0, &id);
-	}
-
-	WaitForMultipleObjects(THREADS, threads, TRUE, INFINITE);
+		pg_thrd_create(&threads[i], fn, (void *) i);
 	for (i = 0; i < THREADS; ++i)
-		CloseHandle(threads[i]);
-#else
-	for (i = 0; i < THREADS; ++i)
-		pthread_create(&threads[i], NULL, fn, (void *) i);
-	for (i = 0; i < THREADS; ++i)
-		pthread_join(threads[i], NULL);
-#endif
+		pg_thrd_join(threads[i], NULL);
 
 	return 0;
 }
diff --git a/src/interfaces/ecpg/test/expected/thread-thread.c b/src/interfaces/ecpg/test/expected/thread-thread.c
index 95faa223c2..03c7169995 100644
--- a/src/interfaces/ecpg/test/expected/thread-thread.c
+++ b/src/interfaces/ecpg/test/expected/thread-thread.c
@@ -14,13 +14,7 @@
 #include <stdint.h>
 #include <stdlib.h>
 #include "ecpg_config.h"
-
-#ifndef WIN32
-#include <pthread.h>
-#else
-#include <windows.h>
-#include <locale.h>
-#endif
+#include "port/pg_threads.h"
 
 
 #line 1 "regression.h"
@@ -30,29 +24,25 @@
 
 
 
-#line 16 "thread.pgc"
+#line 10 "thread.pgc"
 
 
-void *test_thread(void *arg);
+int test_thread(void *arg);
 
 int nthreads   = 10;
 int iterations = 20;
 
 int main()
 {
-#ifndef WIN32
-  pthread_t *threads;
-#else
-  HANDLE *threads;
-#endif
+  pg_thrd_t *threads;
   intptr_t n;
   /* exec sql begin declare section */
    
   
-#line 32 "thread.pgc"
+#line 22 "thread.pgc"
  int l_rows ;
 /* exec sql end declare section */
-#line 33 "thread.pgc"
+#line 23 "thread.pgc"
 
 
  /* Do not switch on debug output for regression tests. The threads get executed in
@@ -61,22 +51,22 @@ int main()
 
   /* setup test_thread table */
   { ECPGconnect(__LINE__, 0, "ecpg1_regression" , NULL, NULL , NULL, 0); }
-#line 40 "thread.pgc"
+#line 30 "thread.pgc"
 
   { ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "drop table test_thread", ECPGt_EOIT, ECPGt_EORT);}
-#line 41 "thread.pgc"
+#line 31 "thread.pgc"
  /* DROP might fail */
   { ECPGtrans(__LINE__, NULL, "commit");}
-#line 42 "thread.pgc"
+#line 32 "thread.pgc"
 
   { ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "create table test_thread ( tstamp timestamp not null default cast ( timeofday ( ) as timestamp ) , thread text not null , iteration integer not null , primary key ( thread , iteration ) )", ECPGt_EOIT, ECPGt_EORT);}
-#line 47 "thread.pgc"
+#line 37 "thread.pgc"
 
   { ECPGtrans(__LINE__, NULL, "commit");}
-#line 48 "thread.pgc"
+#line 38 "thread.pgc"
 
   { ECPGdisconnect(__LINE__, "CURRENT");}
-#line 49 "thread.pgc"
+#line 39 "thread.pgc"
 
 
   /* create, and start, threads */
@@ -87,39 +77,27 @@ int main()
       return 1;
     }
   for( n = 0; n < nthreads; n++ )
-    {
-#ifndef WIN32
-      pthread_create(&threads[n], NULL, test_thread, (void *) (n + 1));
-#else
-      threads[n] = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) (void (*) (void)) test_thread, (void *) (n + 1), 0, NULL);
-#endif
-    }
+      pg_thrd_create(&threads[n], test_thread, (void *) (n + 1));
 
   /* wait for thread completion */
-#ifndef WIN32
   for( n = 0; n < nthreads; n++ )
-    {
-      pthread_join(threads[n], NULL);
-    }
-#else
-  WaitForMultipleObjects(nthreads, threads, TRUE, INFINITE);
-#endif
+      pg_thrd_join(threads[n], NULL);
   free(threads);
 
   /* and check results */
   { ECPGconnect(__LINE__, 0, "ecpg1_regression" , NULL, NULL , NULL, 0); }
-#line 79 "thread.pgc"
+#line 57 "thread.pgc"
 
   { ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "select count ( * ) from test_thread", ECPGt_EOIT, 
 	ECPGt_int,&(l_rows),(long)1,(long)1,sizeof(int), 
 	ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EORT);}
-#line 80 "thread.pgc"
+#line 58 "thread.pgc"
 
   { ECPGtrans(__LINE__, NULL, "commit");}
-#line 81 "thread.pgc"
+#line 59 "thread.pgc"
 
   { ECPGdisconnect(__LINE__, "CURRENT");}
-#line 82 "thread.pgc"
+#line 60 "thread.pgc"
 
   if( l_rows == (nthreads * iterations) )
     printf("Success.\n");
@@ -129,7 +107,7 @@ int main()
   return 0;
 }
 
-void *test_thread(void *arg)
+int test_thread(void *arg)
 {
   long threadnum = (intptr_t) arg;
 
@@ -137,13 +115,13 @@ void *test_thread(void *arg)
     
    
   
-#line 96 "thread.pgc"
+#line 74 "thread.pgc"
  int l_i ;
  
-#line 97 "thread.pgc"
+#line 75 "thread.pgc"
  char l_connection [ 128 ] ;
 /* exec sql end declare section */
-#line 98 "thread.pgc"
+#line 76 "thread.pgc"
 
 
   /* build up connection name, and connect to database */
@@ -153,24 +131,24 @@ void *test_thread(void *arg)
   _snprintf(l_connection, sizeof(l_connection), "thread_%03ld", threadnum);
 #endif
   /* exec sql whenever sqlerror  sqlprint ; */
-#line 106 "thread.pgc"
+#line 84 "thread.pgc"
 
   { ECPGconnect(__LINE__, 0, "ecpg1_regression" , NULL, NULL , l_connection, 0); 
-#line 107 "thread.pgc"
+#line 85 "thread.pgc"
 
 if (sqlca.sqlcode < 0) sqlprint();}
-#line 107 "thread.pgc"
+#line 85 "thread.pgc"
 
   if( sqlca.sqlcode != 0 )
     {
       printf("%s: ERROR: cannot connect to database!\n", l_connection);
-      return NULL;
+      return 0;
     }
   { ECPGtrans(__LINE__, l_connection, "begin");
-#line 113 "thread.pgc"
+#line 91 "thread.pgc"
 
 if (sqlca.sqlcode < 0) sqlprint();}
-#line 113 "thread.pgc"
+#line 91 "thread.pgc"
 
 
   /* insert into test_thread table */
@@ -181,10 +159,10 @@ if (sqlca.sqlcode < 0) sqlprint();}
 	ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, 
 	ECPGt_int,&(l_i),(long)1,(long)1,sizeof(int), 
 	ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EOIT, ECPGt_EORT);
-#line 118 "thread.pgc"
+#line 96 "thread.pgc"
 
 if (sqlca.sqlcode < 0) sqlprint();}
-#line 118 "thread.pgc"
+#line 96 "thread.pgc"
 
       if( sqlca.sqlcode != 0 )
 	printf("%s: ERROR: insert failed!\n", l_connection);
@@ -192,16 +170,16 @@ if (sqlca.sqlcode < 0) sqlprint();}
 
   /* all done */
   { ECPGtrans(__LINE__, l_connection, "commit");
-#line 124 "thread.pgc"
+#line 102 "thread.pgc"
 
 if (sqlca.sqlcode < 0) sqlprint();}
-#line 124 "thread.pgc"
+#line 102 "thread.pgc"
 
   { ECPGdisconnect(__LINE__, l_connection);
-#line 125 "thread.pgc"
+#line 103 "thread.pgc"
 
 if (sqlca.sqlcode < 0) sqlprint();}
-#line 125 "thread.pgc"
+#line 103 "thread.pgc"
 
-  return NULL;
+  return 0;
 }
diff --git a/src/interfaces/ecpg/test/expected/thread-thread_implicit.c b/src/interfaces/ecpg/test/expected/thread-thread_implicit.c
index 7ac0297a23..c859012f50 100644
--- a/src/interfaces/ecpg/test/expected/thread-thread_implicit.c
+++ b/src/interfaces/ecpg/test/expected/thread-thread_implicit.c
@@ -14,13 +14,7 @@
 #include <stdint.h>
 #include <stdlib.h>
 #include "ecpg_config.h"
-
-#ifndef WIN32
-#include <pthread.h>
-#else
-#include <windows.h>
-#include <locale.h>
-#endif
+#include "port/pg_threads.h"
 
 
 #line 1 "regression.h"
@@ -30,29 +24,25 @@
 
 
 
-#line 16 "thread_implicit.pgc"
+#line 10 "thread_implicit.pgc"
 
 
-void *test_thread(void *arg);
+int test_thread(void *arg);
 
 int nthreads   = 10;
 int iterations = 20;
 
 int main()
 {
-#ifndef WIN32
-  pthread_t *threads;
-#else
-  HANDLE *threads;
-#endif
+  pg_thrd_t *threads;
   intptr_t n;
   /* exec sql begin declare section */
    
   
-#line 32 "thread_implicit.pgc"
+#line 22 "thread_implicit.pgc"
  int l_rows ;
 /* exec sql end declare section */
-#line 33 "thread_implicit.pgc"
+#line 23 "thread_implicit.pgc"
 
 
  /* Do not switch on debug output for regression tests. The threads get executed in
@@ -61,22 +51,22 @@ int main()
 
   /* setup test_thread table */
   { ECPGconnect(__LINE__, 0, "ecpg1_regression" , NULL, NULL , NULL, 0); }
-#line 40 "thread_implicit.pgc"
+#line 30 "thread_implicit.pgc"
 
   { ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "drop table test_thread", ECPGt_EOIT, ECPGt_EORT);}
-#line 41 "thread_implicit.pgc"
+#line 31 "thread_implicit.pgc"
  /* DROP might fail */
   { ECPGtrans(__LINE__, NULL, "commit");}
-#line 42 "thread_implicit.pgc"
+#line 32 "thread_implicit.pgc"
 
   { ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "create table test_thread ( tstamp timestamp not null default cast ( timeofday ( ) as timestamp ) , thread text not null , iteration integer not null , primary key ( thread , iteration ) )", ECPGt_EOIT, ECPGt_EORT);}
-#line 47 "thread_implicit.pgc"
+#line 37 "thread_implicit.pgc"
 
   { ECPGtrans(__LINE__, NULL, "commit");}
-#line 48 "thread_implicit.pgc"
+#line 38 "thread_implicit.pgc"
 
   { ECPGdisconnect(__LINE__, "CURRENT");}
-#line 49 "thread_implicit.pgc"
+#line 39 "thread_implicit.pgc"
 
 
   /* create, and start, threads */
@@ -87,39 +77,27 @@ int main()
       return 1;
     }
   for( n = 0; n < nthreads; n++ )
-    {
-#ifndef WIN32
-      pthread_create(&threads[n], NULL, test_thread, (void *) (n + 1));
-#else
-      threads[n] = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) (void (*) (void)) test_thread, (void *) (n+1), 0, NULL);
-#endif
-    }
+      pg_thrd_create(&threads[n], test_thread, (void *) (n + 1));
 
   /* wait for thread completion */
-#ifndef WIN32
   for( n = 0; n < nthreads; n++ )
-    {
-      pthread_join(threads[n], NULL);
-    }
-#else
-  WaitForMultipleObjects(nthreads, threads, TRUE, INFINITE);
-#endif
+      pg_thrd_join(threads[n], NULL);
   free(threads);
 
   /* and check results */
   { ECPGconnect(__LINE__, 0, "ecpg1_regression" , NULL, NULL , NULL, 0); }
-#line 79 "thread_implicit.pgc"
+#line 57 "thread_implicit.pgc"
 
   { ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "select count ( * ) from test_thread", ECPGt_EOIT, 
 	ECPGt_int,&(l_rows),(long)1,(long)1,sizeof(int), 
 	ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EORT);}
-#line 80 "thread_implicit.pgc"
+#line 58 "thread_implicit.pgc"
 
   { ECPGtrans(__LINE__, NULL, "commit");}
-#line 81 "thread_implicit.pgc"
+#line 59 "thread_implicit.pgc"
 
   { ECPGdisconnect(__LINE__, "CURRENT");}
-#line 82 "thread_implicit.pgc"
+#line 60 "thread_implicit.pgc"
 
   if( l_rows == (nthreads * iterations) )
     printf("Success.\n");
@@ -129,7 +107,7 @@ int main()
   return 0;
 }
 
-void *test_thread(void *arg)
+int test_thread(void *arg)
 {
   long threadnum = (intptr_t) arg;
 
@@ -137,13 +115,13 @@ void *test_thread(void *arg)
     
    
   
-#line 96 "thread_implicit.pgc"
+#line 74 "thread_implicit.pgc"
  int l_i ;
  
-#line 97 "thread_implicit.pgc"
+#line 75 "thread_implicit.pgc"
  char l_connection [ 128 ] ;
 /* exec sql end declare section */
-#line 98 "thread_implicit.pgc"
+#line 76 "thread_implicit.pgc"
 
 
   /* build up connection name, and connect to database */
@@ -153,24 +131,24 @@ void *test_thread(void *arg)
   _snprintf(l_connection, sizeof(l_connection), "thread_%03ld", threadnum);
 #endif
   /* exec sql whenever sqlerror  sqlprint ; */
-#line 106 "thread_implicit.pgc"
+#line 84 "thread_implicit.pgc"
 
   { ECPGconnect(__LINE__, 0, "ecpg1_regression" , NULL, NULL , l_connection, 0); 
-#line 107 "thread_implicit.pgc"
+#line 85 "thread_implicit.pgc"
 
 if (sqlca.sqlcode < 0) sqlprint();}
-#line 107 "thread_implicit.pgc"
+#line 85 "thread_implicit.pgc"
 
   if( sqlca.sqlcode != 0 )
     {
       printf("%s: ERROR: cannot connect to database!\n", l_connection);
-      return NULL;
+      return 0;
     }
   { ECPGtrans(__LINE__, NULL, "begin");
-#line 113 "thread_implicit.pgc"
+#line 91 "thread_implicit.pgc"
 
 if (sqlca.sqlcode < 0) sqlprint();}
-#line 113 "thread_implicit.pgc"
+#line 91 "thread_implicit.pgc"
 
 
   /* insert into test_thread table */
@@ -181,10 +159,10 @@ if (sqlca.sqlcode < 0) sqlprint();}
 	ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, 
 	ECPGt_int,&(l_i),(long)1,(long)1,sizeof(int), 
 	ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EOIT, ECPGt_EORT);
-#line 118 "thread_implicit.pgc"
+#line 96 "thread_implicit.pgc"
 
 if (sqlca.sqlcode < 0) sqlprint();}
-#line 118 "thread_implicit.pgc"
+#line 96 "thread_implicit.pgc"
 
       if( sqlca.sqlcode != 0 )
 	printf("%s: ERROR: insert failed!\n", l_connection);
@@ -192,16 +170,16 @@ if (sqlca.sqlcode < 0) sqlprint();}
 
   /* all done */
   { ECPGtrans(__LINE__, NULL, "commit");
-#line 124 "thread_implicit.pgc"
+#line 102 "thread_implicit.pgc"
 
 if (sqlca.sqlcode < 0) sqlprint();}
-#line 124 "thread_implicit.pgc"
+#line 102 "thread_implicit.pgc"
 
   { ECPGdisconnect(__LINE__, l_connection);
-#line 125 "thread_implicit.pgc"
+#line 103 "thread_implicit.pgc"
 
 if (sqlca.sqlcode < 0) sqlprint();}
-#line 125 "thread_implicit.pgc"
+#line 103 "thread_implicit.pgc"
 
-  return NULL;
+  return 0;
 }
diff --git a/src/interfaces/ecpg/test/thread/alloc.pgc b/src/interfaces/ecpg/test/thread/alloc.pgc
index d3d35493bf..248a29447c 100644
--- a/src/interfaces/ecpg/test/thread/alloc.pgc
+++ b/src/interfaces/ecpg/test/thread/alloc.pgc
@@ -1,16 +1,7 @@
 #include <stdint.h>
 #include <stdlib.h>
 #include "ecpg_config.h"
-
-#ifdef WIN32
-#define WIN32_LEAN_AND_MEAN
-#include <windows.h>
-#include <process.h>
-#include <locale.h>
-#else
-#include <pthread.h>
-#endif
-#include <stdio.h>
+#include "port/pg_threads.h"
 
 #define THREADS		16
 #define REPEATS		50
@@ -21,11 +12,7 @@ exec sql include ../regression;
 exec sql whenever sqlerror sqlprint;
 exec sql whenever not found sqlprint;
 
-#ifdef WIN32
-static unsigned __stdcall fn(void* arg)
-#else
-static void* fn(void* arg)
-#endif
+static int fn(void* arg)
 {
 	int i;
 
@@ -54,28 +41,12 @@ static void* fn(void* arg)
 int main ()
 {
 	intptr_t i;
-#ifdef WIN32
-	HANDLE threads[THREADS];
-#else
-	pthread_t threads[THREADS];
-#endif
-
-#ifdef WIN32
-	for (i = 0; i < THREADS; ++i)
-	{
-		unsigned id;
-		threads[i] = (HANDLE)_beginthreadex(NULL, 0, fn, (void*)i, 0, &id);
-	}
+	pg_thrd_t threads[THREADS];
 
-	WaitForMultipleObjects(THREADS, threads, TRUE, INFINITE);
-	for (i = 0; i < THREADS; ++i)
-		CloseHandle(threads[i]);
-#else
 	for (i = 0; i < THREADS; ++i)
-		pthread_create(&threads[i], NULL, fn, (void *) i);
+		pg_thrd_create(&threads[i], fn, (void *) i);
 	for (i = 0; i < THREADS; ++i)
-		pthread_join(threads[i], NULL);
-#endif
+		pg_thrd_join(threads[i], NULL);
 
 	return 0;
 }
diff --git a/src/interfaces/ecpg/test/thread/descriptor.pgc b/src/interfaces/ecpg/test/thread/descriptor.pgc
index 30bce7c87b..faa9a0a656 100644
--- a/src/interfaces/ecpg/test/thread/descriptor.pgc
+++ b/src/interfaces/ecpg/test/thread/descriptor.pgc
@@ -1,12 +1,4 @@
-#ifdef WIN32
-#define WIN32_LEAN_AND_MEAN
-#include <windows.h>
-#include <process.h>
-#include <locale.h>
-#else
-#include <pthread.h>
-#endif
-#include <stdio.h>
+#include "port/pg_threads.h"
 
 #define THREADS		16
 #define REPEATS		50000
@@ -15,11 +7,7 @@ EXEC SQL include sqlca;
 EXEC SQL whenever sqlerror sqlprint;
 EXEC SQL whenever not found sqlprint;
 
-#if defined(WIN32)
-static unsigned __stdcall fn(void* arg)
-#else
-static void* fn(void* arg)
-#endif
+static int fn(void* arg)
 {
 	int i;
 
@@ -35,28 +23,12 @@ static void* fn(void* arg)
 int main ()
 {
 	int i;
-#ifdef WIN32
-	HANDLE threads[THREADS];
-#else
-	pthread_t threads[THREADS];
-#endif
+	pg_thrd_t threads[THREADS];
 
-#ifdef WIN32
 	for (i = 0; i < THREADS; ++i)
-	{
-		unsigned id;
-		threads[i] = (HANDLE)_beginthreadex(NULL, 0, fn, NULL, 0, &id);
-	}
-
-	WaitForMultipleObjects(THREADS, threads, TRUE, INFINITE);
-	for (i = 0; i < THREADS; ++i)
-		CloseHandle(threads[i]);
-#else
-	for (i = 0; i < THREADS; ++i)
-		pthread_create(&threads[i], NULL, fn, NULL);
+		pg_thrd_create(&threads[i], fn, NULL);
 	for (i = 0; i < THREADS; ++i)
-		pthread_join(threads[i], NULL);
-#endif
+		pg_thrd_join(threads[i], NULL);
 
 	return 0;
 }
diff --git a/src/interfaces/ecpg/test/thread/prep.pgc b/src/interfaces/ecpg/test/thread/prep.pgc
index f61b31ce10..f5a875cc28 100644
--- a/src/interfaces/ecpg/test/thread/prep.pgc
+++ b/src/interfaces/ecpg/test/thread/prep.pgc
@@ -1,15 +1,8 @@
 #include <stdint.h>
 #include <stdlib.h>
 #include "ecpg_config.h"
+#include "port/pg_threads.h"
 
-#ifdef WIN32
-#define WIN32_LEAN_AND_MEAN
-#include <windows.h>
-#include <process.h>
-#include <locale.h>
-#else
-#include <pthread.h>
-#endif
 #include <stdio.h>
 
 #define THREADS		16
@@ -21,11 +14,7 @@ exec sql include ../regression;
 exec sql whenever sqlerror sqlprint;
 exec sql whenever not found sqlprint;
 
-#ifdef WIN32
-static unsigned __stdcall fn(void* arg)
-#else
-static void* fn(void* arg)
-#endif
+static int fn(void* arg)
 {
 	int i;
 
@@ -54,11 +43,7 @@ static void* fn(void* arg)
 int main ()
 {
 	intptr_t i;
-#ifdef WIN32
-	HANDLE threads[THREADS];
-#else
-	pthread_t threads[THREADS];
-#endif
+	pg_thrd_t threads[THREADS];
 
 	EXEC SQL CONNECT TO REGRESSDB1;
 	EXEC SQL SET AUTOCOMMIT TO ON;
@@ -66,22 +51,10 @@ int main ()
 	EXEC SQL CREATE TABLE T ( i int );
 	EXEC SQL DISCONNECT;
 
-#ifdef WIN32
 	for (i = 0; i < THREADS; ++i)
-	{
-		unsigned id;
-		threads[i] = (HANDLE)_beginthreadex(NULL, 0, fn, (void*)i, 0, &id);
-	}
-
-	WaitForMultipleObjects(THREADS, threads, TRUE, INFINITE);
-	for (i = 0; i < THREADS; ++i)
-		CloseHandle(threads[i]);
-#else
-	for (i = 0; i < THREADS; ++i)
-		pthread_create(&threads[i], NULL, fn, (void *) i);
+		pg_thrd_create(&threads[i], fn, (void *) i);
 	for (i = 0; i < THREADS; ++i)
-		pthread_join(threads[i], NULL);
-#endif
+		pg_thrd_join(threads[i], NULL);
 
 	return 0;
 }
diff --git a/src/interfaces/ecpg/test/thread/thread.pgc b/src/interfaces/ecpg/test/thread/thread.pgc
index b9b9ebb441..bc967b9da8 100644
--- a/src/interfaces/ecpg/test/thread/thread.pgc
+++ b/src/interfaces/ecpg/test/thread/thread.pgc
@@ -5,28 +5,18 @@
 #include <stdint.h>
 #include <stdlib.h>
 #include "ecpg_config.h"
-
-#ifndef WIN32
-#include <pthread.h>
-#else
-#include <windows.h>
-#include <locale.h>
-#endif
+#include "port/pg_threads.h"
 
 exec sql include ../regression;
 
-void *test_thread(void *arg);
+int test_thread(void *arg);
 
 int nthreads   = 10;
 int iterations = 20;
 
 int main()
 {
-#ifndef WIN32
-  pthread_t *threads;
-#else
-  HANDLE *threads;
-#endif
+  pg_thrd_t *threads;
   intptr_t n;
   EXEC SQL BEGIN DECLARE SECTION;
   int l_rows;
@@ -56,23 +46,11 @@ int main()
       return 1;
     }
   for( n = 0; n < nthreads; n++ )
-    {
-#ifndef WIN32
-      pthread_create(&threads[n], NULL, test_thread, (void *) (n + 1));
-#else
-      threads[n] = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) (void (*) (void)) test_thread, (void *) (n + 1), 0, NULL);
-#endif
-    }
+      pg_thrd_create(&threads[n], test_thread, (void *) (n + 1));
 
   /* wait for thread completion */
-#ifndef WIN32
   for( n = 0; n < nthreads; n++ )
-    {
-      pthread_join(threads[n], NULL);
-    }
-#else
-  WaitForMultipleObjects(nthreads, threads, TRUE, INFINITE);
-#endif
+      pg_thrd_join(threads[n], NULL);
   free(threads);
 
   /* and check results */
@@ -88,7 +66,7 @@ int main()
   return 0;
 }
 
-void *test_thread(void *arg)
+int test_thread(void *arg)
 {
   long threadnum = (intptr_t) arg;
 
@@ -108,7 +86,7 @@ void *test_thread(void *arg)
   if( sqlca.sqlcode != 0 )
     {
       printf("%s: ERROR: cannot connect to database!\n", l_connection);
-      return NULL;
+      return 0;
     }
   EXEC SQL AT :l_connection BEGIN;
 
@@ -123,5 +101,5 @@ void *test_thread(void *arg)
   /* all done */
   EXEC SQL AT :l_connection COMMIT;
   EXEC SQL DISCONNECT :l_connection;
-  return NULL;
+  return 0;
 }
diff --git a/src/interfaces/ecpg/test/thread/thread_implicit.pgc b/src/interfaces/ecpg/test/thread/thread_implicit.pgc
index ff9b12a943..7a793dc7f8 100644
--- a/src/interfaces/ecpg/test/thread/thread_implicit.pgc
+++ b/src/interfaces/ecpg/test/thread/thread_implicit.pgc
@@ -5,28 +5,18 @@
 #include <stdint.h>
 #include <stdlib.h>
 #include "ecpg_config.h"
-
-#ifndef WIN32
-#include <pthread.h>
-#else
-#include <windows.h>
-#include <locale.h>
-#endif
+#include "port/pg_threads.h"
 
 exec sql include ../regression;
 
-void *test_thread(void *arg);
+int test_thread(void *arg);
 
 int nthreads   = 10;
 int iterations = 20;
 
 int main()
 {
-#ifndef WIN32
-  pthread_t *threads;
-#else
-  HANDLE *threads;
-#endif
+  pg_thrd_t *threads;
   intptr_t n;
   EXEC SQL BEGIN DECLARE SECTION;
   int l_rows;
@@ -56,23 +46,11 @@ int main()
       return 1;
     }
   for( n = 0; n < nthreads; n++ )
-    {
-#ifndef WIN32
-      pthread_create(&threads[n], NULL, test_thread, (void *) (n + 1));
-#else
-      threads[n] = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) (void (*) (void)) test_thread, (void *) (n+1), 0, NULL);
-#endif
-    }
+      pg_thrd_create(&threads[n], test_thread, (void *) (n + 1));
 
   /* wait for thread completion */
-#ifndef WIN32
   for( n = 0; n < nthreads; n++ )
-    {
-      pthread_join(threads[n], NULL);
-    }
-#else
-  WaitForMultipleObjects(nthreads, threads, TRUE, INFINITE);
-#endif
+      pg_thrd_join(threads[n], NULL);
   free(threads);
 
   /* and check results */
@@ -88,7 +66,7 @@ int main()
   return 0;
 }
 
-void *test_thread(void *arg)
+int test_thread(void *arg)
 {
   long threadnum = (intptr_t) arg;
 
@@ -108,7 +86,7 @@ void *test_thread(void *arg)
   if( sqlca.sqlcode != 0 )
     {
       printf("%s: ERROR: cannot connect to database!\n", l_connection);
-      return NULL;
+      return 0;
     }
   EXEC SQL BEGIN;
 
@@ -123,5 +101,5 @@ void *test_thread(void *arg)
   /* all done */
   EXEC SQL COMMIT;
   EXEC SQL DISCONNECT :l_connection;
-  return NULL;
+  return 0;
 }
diff --git a/src/interfaces/libpq/Makefile b/src/interfaces/libpq/Makefile
index 46653682b0..62269ddbf4 100644
--- a/src/interfaces/libpq/Makefile
+++ b/src/interfaces/libpq/Makefile
@@ -69,7 +69,6 @@ endif
 
 ifeq ($(PORTNAME), win32)
 OBJS += \
-	pthread-win32.o \
 	win32.o
 endif
 
diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 837c5321aa..7806f67879 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -32,6 +32,7 @@
 #include "mb/pg_wchar.h"
 #include "pg_config_paths.h"
 #include "port/pg_bswap.h"
+#include "port/pg_threads.h"
 
 #ifdef WIN32
 #include "win32.h"
@@ -52,12 +53,6 @@
 #include <netinet/tcp.h>
 #endif
 
-#ifdef WIN32
-#include "pthread-win32.h"
-#else
-#include <pthread.h>
-#endif
-
 #ifdef USE_LDAP
 #ifdef WIN32
 #include <winldap.h>
@@ -7779,35 +7774,29 @@ pqGetHomeDirectory(char *buf, int bufsize)
  * the field.
  */
 
+static pg_mtx_t singlethread_lock;
+
+static void
+singlethread_lock_init(void)
+{
+	pg_mtx_init(&singlethread_lock, pg_mtx_plain);
+}
+
 static void
 default_threadlock(int acquire)
 {
-#ifndef WIN32
-	static pthread_mutex_t singlethread_lock = PTHREAD_MUTEX_INITIALIZER;
-#else
-	static pthread_mutex_t singlethread_lock = NULL;
-	static long mutex_initlock = 0;
+	static pg_once_flag singlethread_lock_once = PG_ONCE_FLAG_INIT;
+
+	pg_call_once(&singlethread_lock_once, singlethread_lock_init);
 
-	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
 	if (acquire)
 	{
-		if (pthread_mutex_lock(&singlethread_lock))
+		if (pg_mtx_lock(&singlethread_lock) != pg_thrd_success)
 			Assert(false);
 	}
 	else
 	{
-		if (pthread_mutex_unlock(&singlethread_lock))
+		if (pg_mtx_unlock(&singlethread_lock) != pg_thrd_success)
 			Assert(false);
 	}
 }
diff --git a/src/interfaces/libpq/fe-secure-openssl.c b/src/interfaces/libpq/fe-secure-openssl.c
index 4976d963a2..dcbab932ee 100644
--- a/src/interfaces/libpq/fe-secure-openssl.c
+++ b/src/interfaces/libpq/fe-secure-openssl.c
@@ -30,6 +30,7 @@
 #include "fe-auth.h"
 #include "fe-secure-common.h"
 #include "libpq-int.h"
+#include "port/pg_threads.h"
 
 #ifdef WIN32
 #include "win32.h"
@@ -44,12 +45,6 @@
 
 #include <sys/stat.h>
 
-#ifdef WIN32
-#include "pthread-win32.h"
-#else
-#include <pthread.h>
-#endif
-
 /*
  * These SSL-related #includes must come after all system-provided headers.
  * This ensures that OpenSSL can take care of conflicts with Windows'
@@ -91,12 +86,8 @@ static bool ssl_lib_initialized = false;
 
 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 pg_mtx_t ssl_config_mutex;
+static pg_once_flag ssl_config_mutex_once = PG_ONCE_FLAG_INIT;
 
 static PQsslKeyPassHook_OpenSSL_type PQsslKeyPassHook = NULL;
 static int	ssl_protocol_version_to_openssl(const char *protocol);
@@ -726,14 +717,14 @@ static unsigned long
 pq_threadidcallback(void)
 {
 	/*
-	 * This is not standards-compliant.  pthread_self() returns pthread_t, and
+	 * This is not standards-compliant.  thrd_currnt() returns thrd_t, and
 	 * shouldn't be cast to unsigned long, but CRYPTO_set_id_callback requires
 	 * it, so we have to do it.
 	 */
-	return (unsigned long) pthread_self();
+	return (unsigned long) thrd_current();
 }
 
-static pthread_mutex_t *pq_lockarray;
+static pg_mtx_t *pq_lockarray;
 
 static void
 pq_lockingcallback(int mode, int n, const char *file, int line)
@@ -745,17 +736,23 @@ pq_lockingcallback(int mode, int n, const char *file, int line)
 	 */
 	if (mode & CRYPTO_LOCK)
 	{
-		if (pthread_mutex_lock(&pq_lockarray[n]))
+		if (pg_mtx_lock(&pq_lockarray[n]) != pg_thrd_success)
 			Assert(false);
 	}
 	else
 	{
-		if (pthread_mutex_unlock(&pq_lockarray[n]))
+		if (pg_mtx_unlock(&pq_lockarray[n]) != pg_thrd_success)
 			Assert(false);
 	}
 }
 #endif							/* HAVE_CRYPTO_LOCK */
 
+static void
+ssl_config_mutex_init(void)
+{
+	pg_mtx_init(&ssl_config_mutex, pg_mtx_plain);
+}
+
 /*
  * Initialize SSL library.
  *
@@ -769,21 +766,9 @@ pq_lockingcallback(int mode, int n, const char *file, int line)
 int
 pgtls_init(PGconn *conn, bool do_ssl, bool do_crypto)
 {
-#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))
+	pg_call_once(&ssl_config_mutex_once, ssl_config_mutex_init);
+
+	if (pg_mtx_lock(&ssl_config_mutex) != pg_thrd_success)
 		return -1;
 
 #ifdef HAVE_CRYPTO_LOCK
@@ -797,19 +782,19 @@ pgtls_init(PGconn *conn, bool do_ssl, bool do_crypto)
 		{
 			int			i;
 
-			pq_lockarray = malloc(sizeof(pthread_mutex_t) * CRYPTO_num_locks());
+			pq_lockarray = malloc(sizeof(pg_mtx_t) * CRYPTO_num_locks());
 			if (!pq_lockarray)
 			{
-				pthread_mutex_unlock(&ssl_config_mutex);
+				pg_mtx_unlock(&ssl_config_mutex);
 				return -1;
 			}
 			for (i = 0; i < CRYPTO_num_locks(); i++)
 			{
-				if (pthread_mutex_init(&pq_lockarray[i], NULL))
+				if (pg_mtx_init(&pq_lockarray[i], NULL) != pg_thrd_success)
 				{
 					free(pq_lockarray);
 					pq_lockarray = NULL;
-					pthread_mutex_unlock(&ssl_config_mutex);
+					pg_mtx_unlock(&ssl_config_mutex);
 					return -1;
 				}
 			}
@@ -850,7 +835,7 @@ pgtls_init(PGconn *conn, bool do_ssl, bool do_crypto)
 		ssl_lib_initialized = true;
 	}
 
-	pthread_mutex_unlock(&ssl_config_mutex);
+	pg_mtx_unlock(&ssl_config_mutex);
 	return 0;
 }
 
@@ -871,7 +856,7 @@ destroy_ssl_system(void)
 {
 #if defined(HAVE_CRYPTO_LOCK)
 	/* Mutex is created in pgtls_init() */
-	if (pthread_mutex_lock(&ssl_config_mutex))
+	if (pg_mtx_lock(&ssl_config_mutex) != pg_thrd_success)
 		return;
 
 	if (pq_init_crypto_lib && crypto_open_connections > 0)
@@ -897,7 +882,7 @@ destroy_ssl_system(void)
 		 */
 	}
 
-	pthread_mutex_unlock(&ssl_config_mutex);
+	pg_mtx_unlock(&ssl_config_mutex);
 #endif
 }
 
diff --git a/src/interfaces/libpq/fe-secure.c b/src/interfaces/libpq/fe-secure.c
index bd72a87bbb..804b5e30aa 100644
--- a/src/interfaces/libpq/fe-secure.c
+++ b/src/interfaces/libpq/fe-secure.c
@@ -35,9 +35,7 @@
 
 #include <sys/stat.h>
 
-#ifdef WIN32
-#include "pthread-win32.h"
-#else
+#ifndef WIN32
 #include <pthread.h>
 #endif
 
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 10f20c1175..870db73841 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -31,11 +31,6 @@
 #include <sys/time.h>
 #endif
 
-#ifdef WIN32
-#include "pthread-win32.h"
-#else
-#include <pthread.h>
-#endif
 #include <signal.h>
 
 /* include stuff common to fe and be */
diff --git a/src/interfaces/libpq/meson.build b/src/interfaces/libpq/meson.build
index 80e6a15adf..6aa0276209 100644
--- a/src/interfaces/libpq/meson.build
+++ b/src/interfaces/libpq/meson.build
@@ -21,7 +21,7 @@ libpq_sources = files(
 libpq_so_sources = [] # for shared lib, in addition to the above
 
 if host_system == 'windows'
-  libpq_sources += files('pthread-win32.c', 'win32.c')
+  libpq_sources += files('win32.c')
   libpq_so_sources += rc_lib_gen.process(win32ver_rc, extra_args: [
     '--NAME', 'libpq',
     '--FILEDESC', 'PostgreSQL Access Library',])
@@ -43,7 +43,7 @@ export_file = custom_target('libpq.exports',
   kwargs: gen_export_kwargs,
 )
 
-# port needs to be in include path due to pthread-win32.h
+# XXX why do we need this?
 libpq_inc = include_directories('.', '../../port')
 libpq_c_args = ['-DSO_MAJOR_VERSION=5']
 
diff --git a/src/interfaces/libpq/pthread-win32.c b/src/interfaces/libpq/pthread-win32.c
deleted file mode 100644
index 8e65637387..0000000000
--- a/src/interfaces/libpq/pthread-win32.c
+++ /dev/null
@@ -1,60 +0,0 @@
-/*-------------------------------------------------------------------------
-*
-* pthread-win32.c
-*	 partial pthread implementation for win32
-*
-* Copyright (c) 2004-2023, PostgreSQL Global Development Group
-* IDENTIFICATION
-*	src/interfaces/libpq/pthread-win32.c
-*
-*-------------------------------------------------------------------------
-*/
-
-#include "postgres_fe.h"
-
-#include "pthread-win32.h"
-
-DWORD
-pthread_self(void)
-{
-	return GetCurrentThreadId();
-}
-
-void
-pthread_setspecific(pthread_key_t key, void *val)
-{
-}
-
-void *
-pthread_getspecific(pthread_key_t key)
-{
-	return NULL;
-}
-
-int
-pthread_mutex_init(pthread_mutex_t *mp, void *attr)
-{
-	*mp = (CRITICAL_SECTION *) malloc(sizeof(CRITICAL_SECTION));
-	if (!*mp)
-		return 1;
-	InitializeCriticalSection(*mp);
-	return 0;
-}
-
-int
-pthread_mutex_lock(pthread_mutex_t *mp)
-{
-	if (!*mp)
-		return 1;
-	EnterCriticalSection(*mp);
-	return 0;
-}
-
-int
-pthread_mutex_unlock(pthread_mutex_t *mp)
-{
-	if (!*mp)
-		return 1;
-	LeaveCriticalSection(*mp);
-	return 0;
-}
diff --git a/src/port/pthread-win32.h b/src/port/pthread-win32.h
deleted file mode 100644
index 97ccc17a12..0000000000
--- a/src/port/pthread-win32.h
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * src/port/pthread-win32.h
- */
-#ifndef __PTHREAD_H
-#define __PTHREAD_H
-
-typedef ULONG pthread_key_t;
-typedef CRITICAL_SECTION *pthread_mutex_t;
-typedef int pthread_once_t;
-
-DWORD		pthread_self(void);
-
-void		pthread_setspecific(pthread_key_t, void *);
-void	   *pthread_getspecific(pthread_key_t);
-
-int			pthread_mutex_init(pthread_mutex_t *, void *attr);
-int			pthread_mutex_lock(pthread_mutex_t *);
-
-/* blocking */
-int			pthread_mutex_unlock(pthread_mutex_t *);
-
-#endif
diff --git a/src/tools/pginclude/cpluspluscheck b/src/tools/pginclude/cpluspluscheck
index 4e09c4686b..121c7a2684 100755
--- a/src/tools/pginclude/cpluspluscheck
+++ b/src/tools/pginclude/cpluspluscheck
@@ -79,7 +79,6 @@ do
 	test "$f" = src/include/port/win32_msvc/dirent.h && continue
 	test "$f" = src/include/port/win32_msvc/utime.h && continue
 	test "$f" = src/include/port/win32ntdll.h && continue
-	test "$f" = src/port/pthread-win32.h && continue
 
 	# Likewise, these files are platform-specific, and the one
 	# relevant to our platform will be included by atomics.h.
diff --git a/src/tools/pginclude/headerscheck b/src/tools/pginclude/headerscheck
index 8dee1b5670..b42467dfc6 100755
--- a/src/tools/pginclude/headerscheck
+++ b/src/tools/pginclude/headerscheck
@@ -74,7 +74,6 @@ do
 	test "$f" = src/include/port/win32_msvc/dirent.h && continue
 	test "$f" = src/include/port/win32_msvc/utime.h && continue
 	test "$f" = src/include/port/win32ntdll.h && continue
-	test "$f" = src/port/pthread-win32.h && continue
 
 	# Likewise, these files are platform-specific, and the one
 	# relevant to our platform will be included by atomics.h.
-- 
2.39.2

