Change log level at g_log_remove_handler
[platform/upstream/glib.git] / glib / gthread-win32.c
index 20aca6f..58e244e 100644 (file)
@@ -5,6 +5,8 @@
  * Copyright 1998-2001 Sebastian Wilhelmi; University of Karlsruhe
  * Copyright 2001 Hans Breuer
  *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
  * License as published by the Free Software Foundation; either
@@ -307,19 +309,29 @@ static CRITICAL_SECTION g_private_lock;
 static DWORD
 g_private_get_impl (GPrivate *key)
 {
-  DWORD impl = (DWORD) key->p;
+  DWORD impl = (DWORD) GPOINTER_TO_UINT(key->p);
 
   if G_UNLIKELY (impl == 0)
     {
       EnterCriticalSection (&g_private_lock);
-      impl = (DWORD) key->p;
+      impl = (UINT_PTR) key->p;
       if (impl == 0)
         {
           GPrivateDestructor *destructor;
 
           impl = TlsAlloc ();
 
-          if (impl == TLS_OUT_OF_INDEXES)
+          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)
@@ -344,7 +356,7 @@ g_private_get_impl (GPrivate *key)
             }
 
           /* Ditto, due to the unlocked access on the fast path */
-          if (!g_atomic_pointer_compare_and_exchange (&key->p, NULL, impl))
+          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);
@@ -412,6 +424,28 @@ g_system_thread_free (GRealThread *thread)
 void
 g_system_thread_exit (void)
 {
+  /* In static compilation, DllMain doesn't exist and so DLL_THREAD_DETACH
+   * case is never called and thread destroy notifications are not triggered.
+   * To ensure that notifications are correctly triggered in static
+   * compilation mode, we call directly the "detach" function here right
+   * before terminating the thread.
+   * As all win32 threads initialized through the glib API are run through
+   * the same proxy function g_thread_win32_proxy() which calls systematically
+   * g_system_thread_exit() when finishing, we obtain the same behavior as
+   * with dynamic compilation.
+   *
+   * WARNING: unfortunately this mechanism cannot work with threads created
+   * directly from the Windows API using CreateThread() or _beginthread/ex().
+   * It only works with threads created by using the glib API with
+   * g_system_thread_new(). If users need absolutely to use a thread NOT
+   * created with glib API under Windows and in static compilation mode, they
+   * should not use glib functions within their thread or they may encounter
+   * memory leaks when the thread finishes.
+   */
+#ifdef GLIB_STATIC_COMPILATION
+  g_thread_win32_thread_detach ();
+#endif
+
   _endthreadex (0);
 }
 
@@ -429,19 +463,9 @@ g_thread_win32_proxy (gpointer data)
   return 0;
 }
 
-gboolean
-g_system_thread_get_scheduler_settings (GThreadSchedulerSettings *scheduler_settings)
-{
-  HANDLE current_thread = GetCurrentThread ();
-  scheduler_settings->thread_prio = GetThreadPriority (current_thread);
-
-  return TRUE;
-}
-
 GRealThread *
 g_system_thread_new (GThreadFunc proxy,
                      gulong stack_size,
-                     const GThreadSchedulerSettings *scheduler_settings,
                      const char *name,
                      GThreadFunc func,
                      gpointer data,
@@ -481,16 +505,10 @@ g_system_thread_new (GThreadFunc proxy,
    * On Windows, by default all new threads are created with NORMAL thread
    * priority.
    */
-
-  if (scheduler_settings)
-    {
-      thread_prio = scheduler_settings->thread_prio;
-    }
-  else
-    {
-      HANDLE current_thread = GetCurrentThread ();
-      thread_prio = GetThreadPriority (current_thread);
-    }
+  {
+    HANDLE current_thread = GetCurrentThread ();
+    thread_prio = GetThreadPriority (current_thread);
+  }
 
   if (thread_prio == THREAD_PRIORITY_ERROR_RETURN)
     {
@@ -504,7 +522,7 @@ g_system_thread_new (GThreadFunc proxy,
       goto error;
     }
 
-  if (ResumeThread (thread->handle) == -1)
+  if (ResumeThread (thread->handle) == (DWORD) -1)
     {
       message = "Error resuming new thread";
       goto error;
@@ -580,7 +598,8 @@ SetThreadName (DWORD  dwThreadID,
 #ifdef _MSC_VER
    __try
      {
-       RaiseException (EXCEPTION_SET_THREAD_NAME, 0, infosize, (DWORD *) &info);
+       RaiseException (EXCEPTION_SET_THREAD_NAME, 0, infosize,
+                       (const ULONG_PTR *) &info);
      }
    __except (EXCEPTION_EXECUTE_HANDLER)
      {
@@ -592,14 +611,66 @@ SetThreadName (DWORD  dwThreadID,
    if ((!IsDebuggerPresent ()) && (SetThreadName_VEH_handle == NULL))
      return;
 
-   RaiseException (EXCEPTION_SET_THREAD_NAME, 0, infosize, (DWORD *) &info);
+   RaiseException (EXCEPTION_SET_THREAD_NAME, 0, infosize, (const ULONG_PTR *) &info);
+#endif
+}
+
+typedef HRESULT (WINAPI *pSetThreadDescription) (HANDLE hThread,
+                                                 PCWSTR lpThreadDescription);
+static pSetThreadDescription SetThreadDescriptionFunc = NULL;
+static HMODULE kernel32_module = NULL;
+
+static gboolean
+g_thread_win32_load_library (void)
+{
+  /* FIXME: Add support for UWP app */
+#if !defined(G_WINAPI_ONLY_APP)
+  static gsize _init_once = 0;
+  if (g_once_init_enter (&_init_once))
+    {
+      kernel32_module = LoadLibraryW (L"kernel32.dll");
+      if (kernel32_module)
+        {
+          SetThreadDescriptionFunc =
+              (pSetThreadDescription) GetProcAddress (kernel32_module,
+                                                      "SetThreadDescription");
+          if (!SetThreadDescriptionFunc)
+            FreeLibrary (kernel32_module);
+        }
+      g_once_init_leave (&_init_once, 1);
+    }
 #endif
+
+  return !!SetThreadDescriptionFunc;
+}
+
+static gboolean
+g_thread_win32_set_thread_desc (const gchar *name)
+{
+  HRESULT hr;
+  wchar_t *namew;
+
+  if (!g_thread_win32_load_library () || !name)
+    return FALSE;
+
+  namew = g_utf8_to_utf16 (name, -1, NULL, NULL, NULL);
+  if (!namew)
+    return FALSE;
+
+  hr = SetThreadDescriptionFunc (GetCurrentThread (), namew);
+
+  g_free (namew);
+  return SUCCEEDED (hr);
 }
 
 void
 g_system_thread_set_name (const gchar *name)
 {
-  SetThreadName ((DWORD) -1, name);
+  /* Prefer SetThreadDescription over exception based way if available,
+   * since thread description set by SetThreadDescription will be preserved
+   * in dump file */
+  if (!g_thread_win32_set_thread_desc (name))
+    SetThreadName ((DWORD) -1, name);
 }
 
 /* {{{1 Epilogue */