- gchar *win_error = g_win32_error_message (GetLastError ());
- g_set_error (error, G_THREAD_ERROR, G_THREAD_ERROR_AGAIN,
- "Error creating thread: %s", win_error);
- g_free (retval);
- g_free (win_error);
- return;
+ EnterCriticalSection (&g_private_lock);
+ impl = (UINT_PTR) key->p;
+ if (impl == 0)
+ {
+ GPrivateDestructor *destructor;
+
+ impl = TlsAlloc ();
+
+ if G_UNLIKELY (impl == 0)
+ {
+ /* Ignore TLS index 0 temporarily (as 0 is the indicator that we
+ * haven't allocated TLS yet) and alloc again;
+ * See https://gitlab.gnome.org/GNOME/glib/-/issues/2058 */
+ DWORD impl2 = TlsAlloc ();
+ TlsFree (impl);
+ impl = impl2;
+ }
+
+ if (impl == TLS_OUT_OF_INDEXES || impl == 0)
+ g_thread_abort (0, "TlsAlloc");
+
+ if (key->notify != NULL)
+ {
+ destructor = malloc (sizeof (GPrivateDestructor));
+ if G_UNLIKELY (destructor == NULL)
+ g_thread_abort (errno, "malloc");
+ destructor->index = impl;
+ destructor->notify = key->notify;
+ destructor->next = g_atomic_pointer_get (&g_private_destructors);
+
+ /* We need to do an atomic store due to the unlocked
+ * access to the destructor list from the thread exit
+ * function.
+ *
+ * It can double as a sanity check...
+ */
+ if (!g_atomic_pointer_compare_and_exchange (&g_private_destructors,
+ destructor->next,
+ destructor))
+ g_thread_abort (0, "g_private_get_impl(1)");
+ }
+
+ /* Ditto, due to the unlocked access on the fast path */
+ if (!g_atomic_pointer_compare_and_exchange (&key->p, NULL, GUINT_TO_POINTER (impl)))
+ g_thread_abort (0, "g_private_get_impl(2)");
+ }
+ LeaveCriticalSection (&g_private_lock);