Skip to content

Commit 9440d23

Browse files
committed
Clean up Windows-specific mutex code in libpq and ecpglib.
Fix pthread-win32.h and pthread-win32.c to provide a more complete emulation of POSIX pthread mutexes: define PTHREAD_MUTEX_INITIALIZER and make sure that pthread_mutex_lock() can operate on a mutex object that's been initialized that way. Then we don't need the duplicative platform-specific logic in default_threadlock() and pgtls_init(), which we'd otherwise need yet a third copy of for an upcoming bug fix. Also, since default_threadlock() supposes that pthread_mutex_lock() cannot fail, try to ensure that that's actually true, by getting rid of the malloc call that was formerly involved in initializing an emulated mutex. We can define an extra state for the spinlock field instead. Also, replace the similar code in ecpglib/misc.c with this version. While ecpglib's version at least had a POSIX-compliant API, it also had the potential of failing during mutex init (but here, because of CreateMutex failure rather than malloc failure). Since all of misc.c's callers ignore failures, it seems like a wise idea to avoid failures here too. A further improvement in this area could be to unify libpq's and ecpglib's implementations into a src/port/pthread-win32.c file. But that doesn't seem like a bug fix, so I'll desist for now. In preparation for the aforementioned bug fix, back-patch to all supported branches. Discussion: https://postgr.es/m/264860.1707163416@sss.pgh.pa.us
1 parent e3e05ad commit 9440d23

File tree

6 files changed

+63
-69
lines changed

6 files changed

+63
-69
lines changed

src/interfaces/ecpg/ecpglib/misc.c

Lines changed: 29 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -453,17 +453,38 @@ ECPGis_noind_null(enum ECPGttype type, const void *ptr)
453453
#ifdef WIN32
454454
#ifdef ENABLE_THREAD_SAFETY
455455

456-
void
457-
win32_pthread_mutex(volatile pthread_mutex_t *mutex)
456+
int
457+
pthread_mutex_init(pthread_mutex_t *mp, void *attr)
458+
{
459+
mp->initstate = 0;
460+
return 0;
461+
}
462+
463+
int
464+
pthread_mutex_lock(pthread_mutex_t *mp)
458465
{
459-
if (mutex->handle == NULL)
466+
/* Initialize the csection if not already done */
467+
if (mp->initstate != 1)
460468
{
461-
while (InterlockedExchange((LONG *) &mutex->initlock, 1) == 1)
462-
Sleep(0);
463-
if (mutex->handle == NULL)
464-
mutex->handle = CreateMutex(NULL, FALSE, NULL);
465-
InterlockedExchange((LONG *) &mutex->initlock, 0);
469+
LONG istate;
470+
471+
while ((istate = InterlockedExchange(&mp->initstate, 2)) == 2)
472+
Sleep(0); /* wait, another thread is doing this */
473+
if (istate != 1)
474+
InitializeCriticalSection(&mp->csection);
475+
InterlockedExchange(&mp->initstate, 1);
466476
}
477+
EnterCriticalSection(&mp->csection);
478+
return 0;
479+
}
480+
481+
int
482+
pthread_mutex_unlock(pthread_mutex_t *mp)
483+
{
484+
if (mp->initstate != 1)
485+
return EINVAL;
486+
LeaveCriticalSection(&mp->csection);
487+
return 0;
467488
}
468489

469490
static pthread_mutex_t win32_pthread_once_lock = PTHREAD_MUTEX_INITIALIZER;

src/interfaces/ecpg/include/ecpg-pthread-win32.h

Lines changed: 8 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -14,28 +14,22 @@
1414

1515
typedef struct pthread_mutex_t
1616
{
17-
HANDLE handle;
18-
LONG initlock;
17+
/* initstate = 0: not initialized; 1: init done; 2: init in progress */
18+
LONG initstate;
19+
CRITICAL_SECTION csection;
1920
} pthread_mutex_t;
2021

2122
typedef DWORD pthread_key_t;
2223
typedef bool pthread_once_t;
2324

24-
#define PTHREAD_MUTEX_INITIALIZER { NULL, 0 }
25+
#define PTHREAD_MUTEX_INITIALIZER { 0 }
2526
#define PTHREAD_ONCE_INIT false
2627

27-
void win32_pthread_mutex(volatile pthread_mutex_t *mutex);
28-
void win32_pthread_once(volatile pthread_once_t *once, void (*fn) (void));
28+
int pthread_mutex_init(pthread_mutex_t *, void *attr);
29+
int pthread_mutex_lock(pthread_mutex_t *);
30+
int pthread_mutex_unlock(pthread_mutex_t *);
2931

30-
#define pthread_mutex_lock(mutex) \
31-
do { \
32-
if ((mutex)->handle == NULL) \
33-
win32_pthread_mutex((mutex)); \
34-
WaitForSingleObject((mutex)->handle, INFINITE); \
35-
} while(0)
36-
37-
#define pthread_mutex_unlock(mutex) \
38-
ReleaseMutex((mutex)->handle)
32+
void win32_pthread_once(volatile pthread_once_t *once, void (*fn) (void));
3933

4034
#define pthread_getspecific(key) \
4135
TlsGetValue((key))

src/interfaces/libpq/fe-connect.c

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -7785,24 +7785,8 @@ static void
77857785
default_threadlock(int acquire)
77867786
{
77877787
#ifdef ENABLE_THREAD_SAFETY
7788-
#ifndef WIN32
77897788
static pthread_mutex_t singlethread_lock = PTHREAD_MUTEX_INITIALIZER;
7790-
#else
7791-
static pthread_mutex_t singlethread_lock = NULL;
7792-
static long mutex_initlock = 0;
77937789

7794-
if (singlethread_lock == NULL)
7795-
{
7796-
while (InterlockedExchange(&mutex_initlock, 1) == 1)
7797-
/* loop, another thread own the lock */ ;
7798-
if (singlethread_lock == NULL)
7799-
{
7800-
if (pthread_mutex_init(&singlethread_lock, NULL))
7801-
Assert(false);
7802-
}
7803-
InterlockedExchange(&mutex_initlock, 0);
7804-
}
7805-
#endif
78067790
if (acquire)
78077791
{
78087792
if (pthread_mutex_lock(&singlethread_lock))

src/interfaces/libpq/fe-secure-openssl.c

Lines changed: 0 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -94,12 +94,7 @@ static bool ssl_lib_initialized = false;
9494
#ifdef ENABLE_THREAD_SAFETY
9595
static long crypto_open_connections = 0;
9696

97-
#ifndef WIN32
9897
static pthread_mutex_t ssl_config_mutex = PTHREAD_MUTEX_INITIALIZER;
99-
#else
100-
static pthread_mutex_t ssl_config_mutex = NULL;
101-
static long win32_ssl_create_mutex = 0;
102-
#endif
10398
#endif /* ENABLE_THREAD_SAFETY */
10499

105100
static PQsslKeyPassHook_OpenSSL_type PQsslKeyPassHook = NULL;
@@ -783,20 +778,6 @@ int
783778
pgtls_init(PGconn *conn, bool do_ssl, bool do_crypto)
784779
{
785780
#ifdef ENABLE_THREAD_SAFETY
786-
#ifdef WIN32
787-
/* Also see similar code in fe-connect.c, default_threadlock() */
788-
if (ssl_config_mutex == NULL)
789-
{
790-
while (InterlockedExchange(&win32_ssl_create_mutex, 1) == 1)
791-
/* loop, another thread own the lock */ ;
792-
if (ssl_config_mutex == NULL)
793-
{
794-
if (pthread_mutex_init(&ssl_config_mutex, NULL))
795-
return -1;
796-
}
797-
InterlockedExchange(&win32_ssl_create_mutex, 0);
798-
}
799-
#endif
800781
if (pthread_mutex_lock(&ssl_config_mutex))
801782
return -1;
802783

@@ -887,7 +868,6 @@ static void
887868
destroy_ssl_system(void)
888869
{
889870
#if defined(ENABLE_THREAD_SAFETY) && defined(HAVE_CRYPTO_LOCK)
890-
/* Mutex is created in pgtls_init() */
891871
if (pthread_mutex_lock(&ssl_config_mutex))
892872
return;
893873

src/interfaces/libpq/pthread-win32.c

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -34,27 +34,33 @@ pthread_getspecific(pthread_key_t key)
3434
int
3535
pthread_mutex_init(pthread_mutex_t *mp, void *attr)
3636
{
37-
*mp = (CRITICAL_SECTION *) malloc(sizeof(CRITICAL_SECTION));
38-
if (!*mp)
39-
return 1;
40-
InitializeCriticalSection(*mp);
37+
mp->initstate = 0;
4138
return 0;
4239
}
4340

4441
int
4542
pthread_mutex_lock(pthread_mutex_t *mp)
4643
{
47-
if (!*mp)
48-
return 1;
49-
EnterCriticalSection(*mp);
44+
/* Initialize the csection if not already done */
45+
if (mp->initstate != 1)
46+
{
47+
LONG istate;
48+
49+
while ((istate = InterlockedExchange(&mp->initstate, 2)) == 2)
50+
Sleep(0); /* wait, another thread is doing this */
51+
if (istate != 1)
52+
InitializeCriticalSection(&mp->csection);
53+
InterlockedExchange(&mp->initstate, 1);
54+
}
55+
EnterCriticalSection(&mp->csection);
5056
return 0;
5157
}
5258

5359
int
5460
pthread_mutex_unlock(pthread_mutex_t *mp)
5561
{
56-
if (!*mp)
57-
return 1;
58-
LeaveCriticalSection(*mp);
62+
if (mp->initstate != 1)
63+
return EINVAL;
64+
LeaveCriticalSection(&mp->csection);
5965
return 0;
6066
}

src/port/pthread-win32.h

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,16 @@
55
#define __PTHREAD_H
66

77
typedef ULONG pthread_key_t;
8-
typedef CRITICAL_SECTION *pthread_mutex_t;
8+
9+
typedef struct pthread_mutex_t
10+
{
11+
/* initstate = 0: not initialized; 1: init done; 2: init in progress */
12+
LONG initstate;
13+
CRITICAL_SECTION csection;
14+
} pthread_mutex_t;
15+
16+
#define PTHREAD_MUTEX_INITIALIZER { 0 }
17+
918
typedef int pthread_once_t;
1019

1120
DWORD pthread_self(void);

0 commit comments

Comments
 (0)