Re: [PATCH v1] Fix races in Windows pthread emulation - Mailing list pgsql-hackers

From Heikki Linnakangas
Subject Re: [PATCH v1] Fix races in Windows pthread emulation
Date
Msg-id e39c8c80-5554-4bc1-a232-aaa552e556d9@iki.fi
Whole thread
Responses Re: [PATCH v1] Fix races in Windows pthread emulation
List pgsql-hackers
On 20/08/2026 15:09, Nazir Bilal Yavuz wrote:
> On Fri, 24 Jul 2026 at 10:07, Harrison Booth <harrisontbooth@gmail.com> wrote:
>>
>> On native Windows ARM64, the ECPG thread/alloc test could hang until
>> Meson's 1000-second timeout. The cause was a race in the Windows pthread
>> mutex emulation.
> 
> I ran into this exact issue today [1] and found your thread.

Is there some memory ordering reason why this only happens on ARM64? 
AFAICS, it could happen on x86 too.

>> The mutex initialization path used InterlockedExchange to set initstate to
>> 2. A waiting thread could therefore change the fully initialized state from
>> 1 back to 2. pthread_mutex_unlock would then see a state other than 1,
>> return EINVAL, and leave the critical section locked.
> 
> I tried to understand the problem and the related Windows thread
> functions, please correct my understanding:
> 
> 1- In pthread_mutex_lock(), calling
> InterlockedExchange(&mp->initstate, 2) writes unconditionally,
> clobbering an initialized state 1 back to 2.
> 2- The thread enters the critical section while mp->initstate = 2.
> 3- Later, when pthread_mutex_unlock() is called, if (mp->initstate !=
> 1) evaluates to true, causing the function to return EINVAL without
> releasing the underlying critical section, leading to a deadlock.
> 
> And your patch fixes this problem with
> InterlockedCompareExchange(&mp->initstate, 2, 0), because now you
> check the initial value so that you can't overwrite 1 with 2.

That works, but an InterlockedCompareExchange is more expensive than a 
plain unlocked read. I presume the reason it didn't use 
InterlockedCompareExchange in the first place. I think you could salvage 
it by doing an unlocked check first (with a memory barrier?), and using 
InterLockedCompareExchange only if the initialization is needed.

I don't think we need to care too much about performance of ecpg on 
Windows -- I doubt anyone's doing anything that performance sensitive 
with that combo -- but nevertheless.

> -typedef bool pthread_once_t;
> +typedef LONG pthread_once_t;

Is that safe to backpatch?

- Heikki




pgsql-hackers by date:

Previous
From: shihao zhong
Date:
Subject: Re: REPACK (CONCURRENTLY) might keep dropped-column data
Next
From: Masahiko Sawada
Date:
Subject: Re: parallel autovacuum: Propagate track_cost_delay_timing to parallel workers