LCOV - code coverage report
Current view: top level - glib - gthread-win32.c (source / functions) Coverage Total Hit
Test: unnamed Lines: 80.4 % 276 222
Test Date: 2026-08-11 05:12:37 Functions: 93.6 % 47 44
Branches: - 0 0

             Branch data     Line data    Source code
       1                 :             : /* GLIB - Library of useful routines for C programming
       2                 :             :  * Copyright (C) 1995-1997  Peter Mattis, Spencer Kimball and Josh MacDonald
       3                 :             :  *
       4                 :             :  * gthread.c: solaris thread system implementation
       5                 :             :  * Copyright 1998-2001 Sebastian Wilhelmi; University of Karlsruhe
       6                 :             :  * Copyright 2001 Hans Breuer
       7                 :             :  *
       8                 :             :  * SPDX-License-Identifier: LGPL-2.1-or-later
       9                 :             :  *
      10                 :             :  * This library is free software; you can redistribute it and/or
      11                 :             :  * modify it under the terms of the GNU Lesser General Public
      12                 :             :  * License as published by the Free Software Foundation; either
      13                 :             :  * version 2.1 of the License, or (at your option) any later version.
      14                 :             :  *
      15                 :             :  * This library is distributed in the hope that it will be useful,
      16                 :             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      17                 :             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      18                 :             :  * Lesser General Public License for more details.
      19                 :             :  *
      20                 :             :  * You should have received a copy of the GNU Lesser General Public
      21                 :             :  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
      22                 :             :  */
      23                 :             : 
      24                 :             : /*
      25                 :             :  * Modified by the GLib Team and others 1997-2000.  See the AUTHORS
      26                 :             :  * file for a list of people on the GLib Team.  See the ChangeLog
      27                 :             :  * files for a list of changes.  These files are distributed with
      28                 :             :  * GLib at ftp://ftp.gtk.org/pub/gtk/.
      29                 :             :  */
      30                 :             : 
      31                 :             : /* The GMutex and GCond implementations in this file are some of the
      32                 :             :  * lowest-level code in GLib.  All other parts of GLib (messages,
      33                 :             :  * memory, slices, etc) assume that they can freely use these facilities
      34                 :             :  * without risking recursion.
      35                 :             :  *
      36                 :             :  * As such, these functions are NOT permitted to call any other part of
      37                 :             :  * GLib.
      38                 :             :  *
      39                 :             :  * The thread manipulation functions (create, exit, join, etc.) have
      40                 :             :  * more freedom -- they can do as they please.
      41                 :             :  */
      42                 :             : 
      43                 :             : #include "config.h"
      44                 :             : 
      45                 :             : #include "glib.h"
      46                 :             : #include "glib-init.h"
      47                 :             : #include "gthread.h"
      48                 :             : #include "gthreadprivate.h"
      49                 :             : #include "gslice.h"
      50                 :             : 
      51                 :             : #include <windows.h>
      52                 :             : 
      53                 :             : #include <process.h>
      54                 :             : #include <stdlib.h>
      55                 :             : #include <stdio.h>
      56                 :             : 
      57                 :             : static void
      58                 :           0 : g_thread_abort (gint         status,
      59                 :             :                 const gchar *function)
      60                 :             : {
      61                 :           0 :   fprintf (stderr, "GLib (gthread-win32.c): Unexpected error from C library during '%s': %s.  Aborting.\n",
      62                 :           0 :            strerror (status), function);
      63                 :           0 :   g_abort ();
      64                 :             : }
      65                 :             : 
      66                 :             : /* Starting with Vista and Windows 2008, we have access to the
      67                 :             :  * CONDITION_VARIABLE and SRWLock primitives on Windows, which are
      68                 :             :  * pretty reasonable approximations of the primitives specified in
      69                 :             :  * POSIX 2001 (pthread_cond_t and pthread_mutex_t respectively).
      70                 :             :  *
      71                 :             :  * Both of these types are structs containing a single pointer.  That
      72                 :             :  * pointer is used as an atomic bitfield to support user-space mutexes
      73                 :             :  * that only get the kernel involved in cases of contention (similar
      74                 :             :  * to how futex()-based mutexes work on Linux).  The biggest advantage
      75                 :             :  * of these new types is that they can be statically initialised to
      76                 :             :  * zero.  That means that they are completely ABI compatible with our
      77                 :             :  * GMutex and GCond APIs.
      78                 :             :  */
      79                 :             : 
      80                 :             : /* {{{1 GMutex */
      81                 :             : G_ALWAYS_INLINE static inline void
      82                 :      127821 : g_mutex_init_impl (GMutex *mutex)
      83                 :             : {
      84                 :      127821 :   InitializeSRWLock ((gpointer) mutex);
      85                 :      127821 : }
      86                 :             : 
      87                 :             : G_ALWAYS_INLINE static inline void
      88                 :      126938 : g_mutex_clear_impl (GMutex *mutex)
      89                 :             : {
      90                 :      126938 : }
      91                 :             : 
      92                 :             : G_ALWAYS_INLINE static inline void
      93                 :   264676887 : g_mutex_lock_impl (GMutex *mutex)
      94                 :             : {
      95                 :   264676887 :   AcquireSRWLockExclusive ((gpointer) mutex);
      96                 :   264676887 : }
      97                 :             : 
      98                 :             : G_ALWAYS_INLINE static inline gboolean
      99                 :     1091417 : g_mutex_trylock_impl (GMutex *mutex)
     100                 :             : {
     101                 :     1091417 :   return TryAcquireSRWLockExclusive ((gpointer) mutex);
     102                 :             : }
     103                 :             : 
     104                 :             : G_ALWAYS_INLINE static inline void
     105                 :   267368347 : g_mutex_unlock_impl (GMutex *mutex)
     106                 :             : {
     107                 :   267368347 :   ReleaseSRWLockExclusive ((gpointer) mutex);
     108                 :   267368347 : }
     109                 :             : 
     110                 :             : /* {{{1 GRecMutex */
     111                 :             : 
     112                 :             : static CRITICAL_SECTION *
     113                 :         393 : g_rec_mutex_impl_new (void)
     114                 :             : {
     115                 :             :   CRITICAL_SECTION *cs;
     116                 :             : 
     117                 :         393 :   cs = g_slice_new (CRITICAL_SECTION);
     118                 :         393 :   InitializeCriticalSection (cs);
     119                 :             : 
     120                 :         393 :   return cs;
     121                 :             : }
     122                 :             : 
     123                 :             : static void
     124                 :          20 : g_rec_mutex_impl_free (CRITICAL_SECTION *cs)
     125                 :             : {
     126                 :          20 :   DeleteCriticalSection (cs);
     127                 :          20 :   g_slice_free (CRITICAL_SECTION, cs);
     128                 :          20 : }
     129                 :             : 
     130                 :             : static CRITICAL_SECTION *
     131                 :      992681 : g_rec_mutex_get_impl (GRecMutex *mutex)
     132                 :             : {
     133                 :      992681 :   CRITICAL_SECTION *impl = mutex->p;
     134                 :             : 
     135                 :      992681 :   if G_UNLIKELY (mutex->p == NULL)
     136                 :             :     {
     137                 :         373 :       impl = g_rec_mutex_impl_new ();
     138                 :         373 :       if (InterlockedCompareExchangePointer (&mutex->p, impl, NULL) != NULL)
     139                 :           0 :         g_rec_mutex_impl_free (impl);
     140                 :         373 :       impl = mutex->p;
     141                 :         373 :     }
     142                 :             : 
     143                 :      992681 :   return impl;
     144                 :             : }
     145                 :             : 
     146                 :             : G_ALWAYS_INLINE static inline void
     147                 :          20 : g_rec_mutex_init_impl (GRecMutex *mutex)
     148                 :             : {
     149                 :          20 :   mutex->p = g_rec_mutex_impl_new ();
     150                 :          20 : }
     151                 :             : 
     152                 :             : G_ALWAYS_INLINE static inline void
     153                 :          20 : g_rec_mutex_clear_impl (GRecMutex *mutex)
     154                 :             : {
     155                 :          20 :   g_rec_mutex_impl_free (mutex->p);
     156                 :          20 : }
     157                 :             : 
     158                 :             : G_ALWAYS_INLINE static inline void
     159                 :      982700 : g_rec_mutex_lock_impl (GRecMutex *mutex)
     160                 :             : {
     161                 :      982700 :   EnterCriticalSection (g_rec_mutex_get_impl (mutex));
     162                 :      982700 : }
     163                 :             : 
     164                 :             : G_ALWAYS_INLINE static inline void
     165                 :      985123 : g_rec_mutex_unlock_impl (GRecMutex *mutex)
     166                 :             : {
     167                 :      985123 :   LeaveCriticalSection (mutex->p);
     168                 :      985123 : }
     169                 :             : 
     170                 :             : G_ALWAYS_INLINE static inline gboolean
     171                 :        9999 : g_rec_mutex_trylock_impl (GRecMutex *mutex)
     172                 :             : {
     173                 :        9999 :   return TryEnterCriticalSection (g_rec_mutex_get_impl (mutex));
     174                 :             : }
     175                 :             : 
     176                 :             : /* {{{1 GRWLock */
     177                 :             : 
     178                 :             : G_ALWAYS_INLINE static inline void
     179                 :          51 : g_rw_lock_init_impl (GRWLock *lock)
     180                 :             : {
     181                 :          51 :   InitializeSRWLock ((gpointer) lock);
     182                 :          51 : }
     183                 :             : 
     184                 :             : G_ALWAYS_INLINE static inline void
     185                 :          51 : g_rw_lock_clear_impl (GRWLock *lock)
     186                 :             : {
     187                 :          51 : }
     188                 :             : 
     189                 :             : G_ALWAYS_INLINE static inline void
     190                 :     1194353 : g_rw_lock_writer_lock_impl (GRWLock *lock)
     191                 :             : {
     192                 :     1194353 :   AcquireSRWLockExclusive ((gpointer) lock);
     193                 :     1194353 : }
     194                 :             : 
     195                 :             : G_ALWAYS_INLINE static inline gboolean
     196                 :      991493 : g_rw_lock_writer_trylock_impl (GRWLock *lock)
     197                 :             : {
     198                 :      991493 :   return TryAcquireSRWLockExclusive ((gpointer) lock);
     199                 :             : }
     200                 :             : 
     201                 :             : G_ALWAYS_INLINE static inline void
     202                 :     1437020 : g_rw_lock_writer_unlock_impl (GRWLock *lock)
     203                 :             : {
     204                 :     1437020 :   ReleaseSRWLockExclusive ((gpointer) lock);
     205                 :     1437020 : }
     206                 :             : 
     207                 :             : G_ALWAYS_INLINE static inline void
     208                 :    15097978 : g_rw_lock_reader_lock_impl (GRWLock *lock)
     209                 :             : {
     210                 :    15097978 :   AcquireSRWLockShared ((gpointer) lock);
     211                 :    15097978 : }
     212                 :             : 
     213                 :             : G_ALWAYS_INLINE static inline gboolean
     214                 :           6 : g_rw_lock_reader_trylock_impl (GRWLock *lock)
     215                 :             : {
     216                 :           6 :   return TryAcquireSRWLockShared ((gpointer) lock);
     217                 :             : }
     218                 :             : 
     219                 :             : G_ALWAYS_INLINE static inline void
     220                 :    15117824 : g_rw_lock_reader_unlock_impl (GRWLock *lock)
     221                 :             : {
     222                 :    15117824 :   ReleaseSRWLockShared ((gpointer) lock);
     223                 :    15117824 : }
     224                 :             : 
     225                 :             : /* {{{1 GCond */
     226                 :             : G_ALWAYS_INLINE static inline void
     227                 :     2605099 : g_cond_init_impl (GCond *cond)
     228                 :             : {
     229                 :     2605099 :   InitializeConditionVariable ((gpointer) cond);
     230                 :     2605099 : }
     231                 :             : 
     232                 :             : G_ALWAYS_INLINE static inline void
     233                 :     2604022 : g_cond_clear_impl (GCond *cond)
     234                 :             : {
     235                 :     2604022 : }
     236                 :             : 
     237                 :             : G_ALWAYS_INLINE static inline void
     238                 :    10861454 : g_cond_signal_impl (GCond *cond)
     239                 :             : {
     240                 :    10861454 :   WakeConditionVariable ((gpointer) cond);
     241                 :    10861454 : }
     242                 :             : 
     243                 :             : G_ALWAYS_INLINE static inline void
     244                 :      151741 : g_cond_broadcast_impl (GCond *cond)
     245                 :             : {
     246                 :      151741 :   WakeAllConditionVariable ((gpointer) cond);
     247                 :      151741 : }
     248                 :             : 
     249                 :             : G_ALWAYS_INLINE static inline void
     250                 :     5039678 : g_cond_wait_impl (GCond  *cond,
     251                 :             :                   GMutex *entered_mutex)
     252                 :             : {
     253                 :     5039678 :   SleepConditionVariableSRW ((gpointer) cond, (gpointer) entered_mutex, INFINITE, 0);
     254                 :     5039678 : }
     255                 :             : 
     256                 :             : G_ALWAYS_INLINE static inline gboolean
     257                 :         708 : g_cond_wait_until_impl (GCond  *cond,
     258                 :             :                         GMutex *entered_mutex,
     259                 :             :                         gint64  end_time)
     260                 :             : {
     261                 :             :   gint64 span, start_time;
     262                 :             :   DWORD span_millis;
     263                 :             :   gboolean signalled;
     264                 :             : 
     265                 :         708 :   start_time = g_get_monotonic_time ();
     266                 :         708 :   do
     267                 :             :     {
     268                 :         739 :       span = end_time - start_time;
     269                 :             : 
     270                 :         739 :       if G_UNLIKELY (span < 0)
     271                 :           0 :         span_millis = 0;
     272                 :         739 :       else if G_UNLIKELY (span > G_GINT64_CONSTANT (1000) * (DWORD) INFINITE)
     273                 :           0 :         span_millis = INFINITE;
     274                 :             :       else
     275                 :             :         /* Round up so we don't time out too early */
     276                 :         739 :         span_millis = (span + 1000 - 1) / 1000;
     277                 :             : 
     278                 :             :       /* We never want to wait infinitely */
     279                 :         739 :       if (span_millis >= INFINITE)
     280                 :           0 :         span_millis = INFINITE - 1;
     281                 :             : 
     282                 :         739 :       signalled = SleepConditionVariableSRW ((gpointer) cond, (gpointer) entered_mutex, span_millis, 0);
     283                 :         739 :       if (signalled)
     284                 :         445 :         break;
     285                 :             : 
     286                 :             :       /* In case we didn't wait long enough after a timeout, wait again for the
     287                 :             :        * remaining time */
     288                 :         294 :       start_time = g_get_monotonic_time ();
     289                 :         294 :     }
     290                 :         294 :   while (start_time < end_time);
     291                 :             : 
     292                 :         708 :   return signalled;
     293                 :             : }
     294                 :             : 
     295                 :             : /* {{{1 GPrivate */
     296                 :             : 
     297                 :             : typedef struct _GPrivateDestructor GPrivateDestructor;
     298                 :             : 
     299                 :             : struct _GPrivateDestructor
     300                 :             : {
     301                 :             :   DWORD               index;
     302                 :             :   GDestroyNotify      notify;
     303                 :             :   GPrivateDestructor *next;
     304                 :             : };
     305                 :             : 
     306                 :             : static GPrivateDestructor *g_private_destructors;  /* (atomic) prepend-only */
     307                 :             : static CRITICAL_SECTION g_private_lock;
     308                 :             : 
     309                 :             : static DWORD
     310                 :    17241999 : _g_private_get_impl (GPrivate *key)
     311                 :             : {
     312                 :    17241999 :   DWORD impl = (DWORD) GPOINTER_TO_UINT(key->p);
     313                 :             : 
     314                 :    17241999 :   if G_UNLIKELY (impl == 0)
     315                 :             :     {
     316                 :        1018 :       EnterCriticalSection (&g_private_lock);
     317                 :        1018 :       impl = (UINT_PTR) key->p;
     318                 :        1018 :       if (impl == 0)
     319                 :             :         {
     320                 :             :           GPrivateDestructor *destructor;
     321                 :             : 
     322                 :        1015 :           impl = TlsAlloc ();
     323                 :             : 
     324                 :        1015 :           if G_UNLIKELY (impl == 0)
     325                 :             :             {
     326                 :             :               /* Ignore TLS index 0 temporarily (as 0 is the indicator that we
     327                 :             :                * haven't allocated TLS yet) and alloc again;
     328                 :             :                * See https://gitlab.gnome.org/GNOME/glib/-/issues/2058 */
     329                 :           0 :               DWORD impl2 = TlsAlloc ();
     330                 :           0 :               TlsFree (impl);
     331                 :           0 :               impl = impl2;
     332                 :           0 :             }
     333                 :             : 
     334                 :        1015 :           if (impl == TLS_OUT_OF_INDEXES || impl == 0)
     335                 :           0 :             g_thread_abort (0, "TlsAlloc");
     336                 :             : 
     337                 :        1015 :           if (key->notify != NULL)
     338                 :             :             {
     339                 :         590 :               destructor = malloc (sizeof (GPrivateDestructor));
     340                 :         590 :               if G_UNLIKELY (destructor == NULL)
     341                 :           0 :                 g_thread_abort (errno, "malloc");
     342                 :         590 :               destructor->index = impl;
     343                 :         590 :               destructor->notify = key->notify;
     344                 :         590 :               destructor->next = g_atomic_pointer_get (&g_private_destructors);
     345                 :             : 
     346                 :             :               /* We need to do an atomic store due to the unlocked
     347                 :             :                * access to the destructor list from the thread exit
     348                 :             :                * function.
     349                 :             :                *
     350                 :             :                * It can double as a sanity check...
     351                 :             :                */
     352                 :        1180 :               if (!g_atomic_pointer_compare_and_exchange (&g_private_destructors,
     353                 :         590 :                                                           destructor->next,
     354                 :         590 :                                                           destructor))
     355                 :           0 :                 g_thread_abort (0, "g_private_get_impl(1)");
     356                 :         590 :             }
     357                 :             : 
     358                 :             :           /* Ditto, due to the unlocked access on the fast path */
     359                 :        1015 :           if (!g_atomic_pointer_compare_and_exchange (&key->p, NULL, GUINT_TO_POINTER (impl)))
     360                 :           0 :             g_thread_abort (0, "g_private_get_impl(2)");
     361                 :        1015 :         }
     362                 :        1018 :       LeaveCriticalSection (&g_private_lock);
     363                 :        1018 :     }
     364                 :             : 
     365                 :    17241999 :   return impl;
     366                 :             : }
     367                 :             : 
     368                 :             : G_ALWAYS_INLINE static inline gpointer
     369                 :    10100281 : g_private_get_impl (GPrivate *key)
     370                 :             : {
     371                 :    10100281 :   return TlsGetValue (_g_private_get_impl (key));
     372                 :             : }
     373                 :             : 
     374                 :             : G_ALWAYS_INLINE static inline void
     375                 :     7141553 : g_private_set_impl (GPrivate *key,
     376                 :             :                     gpointer  value)
     377                 :             : {
     378                 :     7141553 :   TlsSetValue (_g_private_get_impl (key), value);
     379                 :     7141553 : }
     380                 :             : 
     381                 :             : G_ALWAYS_INLINE static inline void
     382                 :         680 : g_private_replace_impl (GPrivate *key,
     383                 :             :                         gpointer  value)
     384                 :             : {
     385                 :         680 :   DWORD impl = _g_private_get_impl (key);
     386                 :             :   gpointer old;
     387                 :             : 
     388                 :         680 :   old = TlsGetValue (impl);
     389                 :         680 :   TlsSetValue (impl, value);
     390                 :         680 :   if (old && key->notify)
     391                 :          71 :     key->notify (old);
     392                 :         680 : }
     393                 :             : 
     394                 :             : /* {{{1 GThread */
     395                 :             : 
     396                 :             : #define win32_check_for_error(what) G_STMT_START{                       \
     397                 :             :   if (!(what))                                                          \
     398                 :             :     g_error ("file %s: line %d (%s): error %s during %s",             \
     399                 :             :              __FILE__, __LINE__, G_STRFUNC,                             \
     400                 :             :              g_win32_error_message (GetLastError ()), #what);           \
     401                 :             :   }G_STMT_END
     402                 :             : 
     403                 :             : #define G_MUTEX_SIZE (sizeof (gpointer))
     404                 :             : 
     405                 :             : typedef BOOL (__stdcall *GTryEnterCriticalSectionFunc) (CRITICAL_SECTION *);
     406                 :             : 
     407                 :             : typedef struct
     408                 :             : {
     409                 :             :   GRealThread thread;
     410                 :             : 
     411                 :             :   GThreadFunc proxy;
     412                 :             :   HANDLE      handle;
     413                 :             : } GThreadWin32;
     414                 :             : 
     415                 :             : void
     416                 :       28945 : g_system_thread_free (GRealThread *thread)
     417                 :             : {
     418                 :       28945 :   GThreadWin32 *wt = (GThreadWin32 *) thread;
     419                 :             : 
     420                 :       28945 :   win32_check_for_error (CloseHandle (wt->handle));
     421                 :       28945 :   g_slice_free (GThreadWin32, wt);
     422                 :       28945 : }
     423                 :             : 
     424                 :             : void
     425                 :       28940 : g_system_thread_exit (void)
     426                 :             : {
     427                 :       28940 :   _endthreadex (0);
     428                 :             : }
     429                 :             : 
     430                 :             : static guint __stdcall
     431                 :       29190 : g_thread_win32_proxy (gpointer data)
     432                 :             : {
     433                 :       29190 :   GThreadWin32 *self = data;
     434                 :             : 
     435                 :       29190 :   self->proxy (self);
     436                 :             : 
     437                 :       29190 :   g_system_thread_exit ();
     438                 :             : 
     439                 :             :   g_assert_not_reached ();
     440                 :             : 
     441                 :             :   return 0;
     442                 :             : }
     443                 :             : 
     444                 :             : GRealThread *
     445                 :       29276 : g_system_thread_new (GThreadFunc proxy,
     446                 :             :                      gulong stack_size,
     447                 :             :                      const char *name,
     448                 :             :                      GThreadFunc func,
     449                 :             :                      gpointer data,
     450                 :             :                      GError **error)
     451                 :             : {
     452                 :             :   GThreadWin32 *thread;
     453                 :             :   GRealThread *base_thread;
     454                 :             :   guint ignore;
     455                 :       29276 :   const gchar *message = NULL;
     456                 :             :   int thread_prio;
     457                 :             : 
     458                 :       29276 :   thread = g_slice_new0 (GThreadWin32);
     459                 :       29276 :   thread->proxy = proxy;
     460                 :       29276 :   thread->handle = (HANDLE) NULL;
     461                 :       29276 :   base_thread = (GRealThread*)thread;
     462                 :       29276 :   base_thread->ref_count = 2;
     463                 :       29276 :   base_thread->ours = TRUE;
     464                 :       29276 :   base_thread->thread.joinable = TRUE;
     465                 :       29276 :   base_thread->thread.func = func;
     466                 :       29276 :   base_thread->thread.data = data;
     467                 :       29276 :   if (name)
     468                 :        2392 :     g_strlcpy (base_thread->name, name, 16);
     469                 :             : 
     470                 :       29276 :   thread->handle = (HANDLE) _beginthreadex (NULL, stack_size, g_thread_win32_proxy, thread,
     471                 :             :                                             CREATE_SUSPENDED, &ignore);
     472                 :             : 
     473                 :       29276 :   if (thread->handle == NULL)
     474                 :             :     {
     475                 :           0 :       message = "Error creating thread";
     476                 :           0 :       goto error;
     477                 :             :     }
     478                 :             : 
     479                 :             :   /* For thread priority inheritance we need to manually set the thread
     480                 :             :    * priority of the new thread to the priority of the current thread. We
     481                 :             :    * also have to start the thread suspended and resume it after actually
     482                 :             :    * setting the priority here.
     483                 :             :    *
     484                 :             :    * On Windows, by default all new threads are created with NORMAL thread
     485                 :             :    * priority.
     486                 :             :    */
     487                 :             :   {
     488                 :       29276 :     HANDLE current_thread = GetCurrentThread ();
     489                 :       29276 :     thread_prio = GetThreadPriority (current_thread);
     490                 :             :   }
     491                 :             : 
     492                 :       29276 :   if (thread_prio != THREAD_PRIORITY_ERROR_RETURN)
     493                 :             :     {
     494                 :             :       /* GetThreadPriority() may return non-predefined priority level
     495                 :             :        * which is not acceptable by SetThreadPriority().
     496                 :             :        * Ignores any errors occurred here since it's not a critical
     497                 :             :        */
     498                 :       29275 :       if (!SetThreadPriority (thread->handle, thread_prio))
     499                 :             :         {
     500                 :           0 :           gchar *win_error = g_win32_error_message (GetLastError ());
     501                 :           0 :           g_debug ("SetThreadPriority with priority %d failed: %s",
     502                 :           0 :                    thread_prio, win_error);
     503                 :           0 :           g_free (win_error);
     504                 :           0 :         }
     505                 :       29275 :     }
     506                 :             : 
     507                 :       29276 :   if (ResumeThread (thread->handle) == (DWORD) -1)
     508                 :             :     {
     509                 :           0 :       message = "Error resuming new thread";
     510                 :           0 :       goto error;
     511                 :             :     }
     512                 :             : 
     513                 :       29274 :   return (GRealThread *) thread;
     514                 :             : 
     515                 :             : error:
     516                 :             :   {
     517                 :           0 :     gchar *win_error = g_win32_error_message (GetLastError ());
     518                 :           0 :     g_set_error (error, G_THREAD_ERROR, G_THREAD_ERROR_AGAIN,
     519                 :           0 :                  "%s: %s", message, win_error);
     520                 :           0 :     g_free (win_error);
     521                 :           0 :     if (thread->handle)
     522                 :           0 :       CloseHandle (thread->handle);
     523                 :           0 :     g_slice_free (GThreadWin32, thread);
     524                 :           0 :     return NULL;
     525                 :             :   }
     526                 :       29274 : }
     527                 :             : 
     528                 :             : G_ALWAYS_INLINE static inline void
     529                 :    19584091 : g_thread_yield_impl (void)
     530                 :             : {
     531                 :    19584091 :   Sleep(0);
     532                 :    19584091 : }
     533                 :             : 
     534                 :             : void
     535                 :       28698 : g_system_thread_wait (GRealThread *thread)
     536                 :             : {
     537                 :       28698 :   GThreadWin32 *wt = (GThreadWin32 *) thread;
     538                 :             : 
     539                 :       28698 :   win32_check_for_error (WAIT_FAILED != WaitForSingleObject (wt->handle, INFINITE));
     540                 :       28698 : }
     541                 :             : 
     542                 :             : #define EXCEPTION_SET_THREAD_NAME ((DWORD) 0x406D1388)
     543                 :             : 
     544                 :             : #ifndef _MSC_VER
     545                 :             : static void *SetThreadName_VEH_handle = NULL;
     546                 :             : 
     547                 :             : static LONG __stdcall
     548                 :           0 : SetThreadName_VEH (PEXCEPTION_POINTERS ExceptionInfo)
     549                 :             : {
     550                 :           0 :   if (ExceptionInfo->ExceptionRecord != NULL &&
     551                 :           0 :       ExceptionInfo->ExceptionRecord->ExceptionCode == EXCEPTION_SET_THREAD_NAME)
     552                 :           0 :     return EXCEPTION_CONTINUE_EXECUTION;
     553                 :             : 
     554                 :           0 :   return EXCEPTION_CONTINUE_SEARCH;
     555                 :           0 : }
     556                 :             : #endif
     557                 :             : 
     558                 :             : typedef struct _THREADNAME_INFO
     559                 :             : {
     560                 :             :   DWORD  dwType;        /* must be 0x1000 */
     561                 :             :   LPCSTR szName;        /* pointer to name (in user addr space) */
     562                 :             :   DWORD  dwThreadID;    /* thread ID (-1=caller thread) */
     563                 :             :   DWORD  dwFlags;       /* reserved for future use, must be zero */
     564                 :             : } THREADNAME_INFO;
     565                 :             : 
     566                 :             : static void
     567                 :           0 : SetThreadName (DWORD  dwThreadID,
     568                 :             :                LPCSTR szThreadName)
     569                 :             : {
     570                 :             :    THREADNAME_INFO info;
     571                 :             :    DWORD infosize;
     572                 :             : 
     573                 :           0 :    info.dwType = 0x1000;
     574                 :           0 :    info.szName = szThreadName;
     575                 :           0 :    info.dwThreadID = dwThreadID;
     576                 :           0 :    info.dwFlags = 0;
     577                 :             : 
     578                 :           0 :    infosize = sizeof (info) / sizeof (ULONG_PTR);
     579                 :             : 
     580                 :             : #ifdef _MSC_VER
     581                 :             :    __try
     582                 :             :      {
     583                 :             :        RaiseException (EXCEPTION_SET_THREAD_NAME, 0, infosize,
     584                 :             :                        (const ULONG_PTR *) &info);
     585                 :             :      }
     586                 :             :    __except (GetExceptionCode () == EXCEPTION_SET_THREAD_NAME ?
     587                 :             :              EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH)
     588                 :             :      {
     589                 :             :      }
     590                 :             : #else
     591                 :           0 :    if ((!IsDebuggerPresent ()) || (SetThreadName_VEH_handle == NULL))
     592                 :           0 :      return;
     593                 :             : 
     594                 :           0 :    RaiseException (EXCEPTION_SET_THREAD_NAME, 0, infosize, (const ULONG_PTR *) &info);
     595                 :             : #endif
     596                 :           0 : }
     597                 :             : 
     598                 :             : typedef HRESULT (WINAPI *pSetThreadDescription) (HANDLE hThread,
     599                 :             :                                                  PCWSTR lpThreadDescription);
     600                 :             : static pSetThreadDescription SetThreadDescriptionFunc = NULL;
     601                 :             : static HMODULE kernel32_module = NULL;
     602                 :             : 
     603                 :             : static gboolean
     604                 :        2306 : g_thread_win32_load_library (void)
     605                 :             : {
     606                 :             :   /* FIXME: Add support for UWP app */
     607                 :             : #if !defined(G_WINAPI_ONLY_APP)
     608                 :             :   static gsize _init_once = 0;
     609                 :        2306 :   if (g_once_init_enter (&_init_once))
     610                 :             :     {
     611                 :         161 :       kernel32_module = LoadLibraryW (L"kernel32.dll");
     612                 :         161 :       if (kernel32_module)
     613                 :             :         {
     614                 :         161 :           SetThreadDescriptionFunc =
     615                 :         161 :               (pSetThreadDescription) GetProcAddress (kernel32_module,
     616                 :             :                                                       "SetThreadDescription");
     617                 :         161 :           if (!SetThreadDescriptionFunc)
     618                 :           0 :             FreeLibrary (kernel32_module);
     619                 :         161 :         }
     620                 :         161 :       g_once_init_leave (&_init_once, 1);
     621                 :         161 :     }
     622                 :             : #endif
     623                 :             : 
     624                 :        2306 :   return !!SetThreadDescriptionFunc;
     625                 :             : }
     626                 :             : 
     627                 :             : static gboolean
     628                 :        2308 : g_thread_win32_set_thread_desc (const gchar *name)
     629                 :             : {
     630                 :             :   HRESULT hr;
     631                 :             :   wchar_t *namew;
     632                 :             : 
     633                 :        2308 :   if (!g_thread_win32_load_library () || !name)
     634                 :           2 :     return FALSE;
     635                 :             : 
     636                 :        2306 :   namew = g_utf8_to_utf16 (name, -1, NULL, NULL, NULL);
     637                 :        2306 :   if (!namew)
     638                 :           0 :     return FALSE;
     639                 :             : 
     640                 :        2306 :   hr = SetThreadDescriptionFunc (GetCurrentThread (), namew);
     641                 :             : 
     642                 :        2306 :   g_free (namew);
     643                 :        2306 :   return SUCCEEDED (hr);
     644                 :        2306 : }
     645                 :             : 
     646                 :             : void
     647                 :        2306 : g_system_thread_set_name (const gchar *name)
     648                 :             : {
     649                 :             :   /* Prefer SetThreadDescription over exception based way if available,
     650                 :             :    * since thread description set by SetThreadDescription will be preserved
     651                 :             :    * in dump file */
     652                 :        2306 :   if (!g_thread_win32_set_thread_desc (name))
     653                 :           0 :     SetThreadName ((DWORD) -1, name);
     654                 :        2306 : }
     655                 :             : 
     656                 :             : void
     657                 :       26883 : g_system_thread_get_name (char  *buffer,
     658                 :             :                           gsize  length)
     659                 :             : {
     660                 :             :   /* FIXME: Not implemented yet */
     661                 :       26883 :   g_assert (length >= 1);
     662                 :       26883 :   buffer[0] = '\0';
     663                 :       26883 : }
     664                 :             : 
     665                 :             : /* {{{1 Epilogue */
     666                 :             : 
     667                 :             : void
     668                 :        1217 : g_thread_win32_init (void)
     669                 :             : {
     670                 :        1217 :   InitializeCriticalSection (&g_private_lock);
     671                 :             : 
     672                 :             : #ifndef _MSC_VER
     673                 :             :   /* Set the handler as last to not interfere with ASAN runtimes.
     674                 :             :    * Many ASAN implementations (currently all three of GCC, CLANG
     675                 :             :    * and MSVC) install a Vectored Exception Handler that must be
     676                 :             :    * first in the sequence to work well
     677                 :             :    */
     678                 :        1217 :   SetThreadName_VEH_handle = AddVectoredExceptionHandler (0, &SetThreadName_VEH);
     679                 :        1217 :   if (SetThreadName_VEH_handle == NULL)
     680                 :           0 :     g_critical ("%s failed with error code %u",
     681                 :           0 :                 "AddVectoredExceptionHandler", (unsigned int) GetLastError ());
     682                 :             : #endif
     683                 :        1217 : }
     684                 :             : 
     685                 :             : void
     686                 :       29539 : g_thread_win32_thread_detach (void)
     687                 :             : {
     688                 :             :   gboolean dtors_called;
     689                 :             : 
     690                 :       29539 :   do
     691                 :             :     {
     692                 :             :       GPrivateDestructor *dtor;
     693                 :             : 
     694                 :             :       /* We go by the POSIX book on this one.
     695                 :             :        *
     696                 :             :        * If we call a destructor then there is a chance that some new
     697                 :             :        * TLS variables got set by code called in that destructor.
     698                 :             :        *
     699                 :             :        * Loop until nothing is left.
     700                 :             :        */
     701                 :       58485 :       dtors_called = FALSE;
     702                 :             : 
     703                 :      224443 :       for (dtor = g_atomic_pointer_get (&g_private_destructors); dtor; dtor = dtor->next)
     704                 :             :         {
     705                 :             :           gpointer value;
     706                 :             : 
     707                 :      165958 :           value = TlsGetValue (dtor->index);
     708                 :      165958 :           if (value != NULL && dtor->notify != NULL)
     709                 :             :             {
     710                 :             :               /* POSIX says to clear this before the call */
     711                 :       33851 :               TlsSetValue (dtor->index, NULL);
     712                 :       33851 :               dtor->notify (value);
     713                 :       33851 :               dtors_called = TRUE;
     714                 :       33851 :             }
     715                 :      165958 :         }
     716                 :       58485 :     }
     717                 :       58485 :   while (dtors_called);
     718                 :       29539 : }
     719                 :             : 
     720                 :             : void
     721                 :        1214 : g_thread_win32_process_detach (void)
     722                 :             : {
     723                 :             : #ifndef _MSC_VER
     724                 :        1214 :   if (SetThreadName_VEH_handle != NULL)
     725                 :             :     {
     726                 :        1214 :       RemoveVectoredExceptionHandler (SetThreadName_VEH_handle);
     727                 :        1214 :       SetThreadName_VEH_handle = NULL;
     728                 :        1214 :     }
     729                 :             : #endif
     730                 :        1214 : }
     731                 :             : 
     732                 :             : /* vim:set foldmethod=marker: */
        

Generated by: LCOV version 2.0-1