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>
diff --git a/mingw-w64-crt/gdtoa/misc.c b/mingw-w64-crt/gdtoa/misc.c
index adc955e..74a2ca6 100644
--- a/mingw-w64-crt/gdtoa/misc.c
+++ b/mingw-w64-crt/gdtoa/misc.c
@@ -76,16 +76,13 @@
 		return;
 	}
 	else if (0 == dtoa_CS_init) {
-		long last_CS_init = InterlockedExchange (&dtoa_CS_init, 1);
-		if (0 == last_CS_init) {
+		if (0 == InterlockedCompareExchange (&dtoa_CS_init, 1, 0)) {
 			int i;
 			for (i = 0; i < NLOCKS;  i++)
 				InitializeCriticalSection (&dtoa_CritSec[i]);
 			atexit (dtoa_lock_cleanup);
-			dtoa_CS_init = 2;
+			(void)InterlockedExchange (&dtoa_CS_init, 2);
 		}
-		else if (2 == last_CS_init)
-			dtoa_CS_init = 2;
 	}
 	/*  Another thread is initializing. Wait. */
 	while (1 == dtoa_CS_init)