crt: gdtoa: Fix race conditions during initialization of dtoa lock

Use InterlockedExchange() for changing the dtoa_CS_init variable to ensure
that new value would be immediately visible in all threads.

When a thread saw `dtoa_CS_init == 0`, it was possible that another thread got
scheduled and completed initialization, so `dtoa_CS_init` became 2; and then the
current thread did `last_CS_init = InterlockedExchange (&dtoa_CS_init, 1)` and
saw `last_CS_init == 2` and restored it with `InterlockedExchange (&dtoa_CS_init, 2)`.
The value of `dtoa_CS_init` went from 2 to 1 to 2, which was an ABA pattern.

The other thread which actually completed initialization should only call
`EnterCriticalSection(&dtoa_CritSec[n])` when it saw `dtoa_CS_init == 2`. In the
middle of this ABA sequence, the call might get missed.

The fix is to update `dtoa_CS_init` to 1 with a CAS from 0 so it will not be
updated from anything else.

Co-authored-by: LIU Hao <lh_mouse@126.com>
Signed-off-by: LIU Hao <lh_mouse@126.com>
1 file changed