xref: /netbsd-src/external/gpl3/gdb/dist/gnulib/import/windows-recmutex.c (revision 4b169a6ba595ae283ca507b26b15fdff40495b1c)
18dffb485Schristos /* Plain recursive mutexes (native Windows implementation).
2*4b169a6bSchristos    Copyright (C) 2005-2022 Free Software Foundation, Inc.
38dffb485Schristos 
4*4b169a6bSchristos    This file is free software: you can redistribute it and/or modify
5*4b169a6bSchristos    it under the terms of the GNU Lesser General Public License as
6*4b169a6bSchristos    published by the Free Software Foundation; either version 2.1 of the
7*4b169a6bSchristos    License, or (at your option) any later version.
88dffb485Schristos 
9*4b169a6bSchristos    This file is distributed in the hope that it will be useful,
108dffb485Schristos    but WITHOUT ANY WARRANTY; without even the implied warranty of
118dffb485Schristos    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12*4b169a6bSchristos    GNU Lesser General Public License for more details.
138dffb485Schristos 
14*4b169a6bSchristos    You should have received a copy of the GNU Lesser General Public License
15*4b169a6bSchristos    along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
168dffb485Schristos 
178dffb485Schristos /* Written by Bruno Haible <bruno@clisp.org>, 2005.
188dffb485Schristos    Based on GCC's gthr-win32.h.  */
198dffb485Schristos 
208dffb485Schristos #include <config.h>
218dffb485Schristos 
228dffb485Schristos /* Specification.  */
238dffb485Schristos #include "windows-recmutex.h"
248dffb485Schristos 
258dffb485Schristos #include <errno.h>
268dffb485Schristos 
278dffb485Schristos void
glwthread_recmutex_init(glwthread_recmutex_t * mutex)288dffb485Schristos glwthread_recmutex_init (glwthread_recmutex_t *mutex)
298dffb485Schristos {
308dffb485Schristos   mutex->owner = 0;
318dffb485Schristos   mutex->depth = 0;
328dffb485Schristos   InitializeCriticalSection (&mutex->lock);
338dffb485Schristos   mutex->guard.done = 1;
348dffb485Schristos }
358dffb485Schristos 
368dffb485Schristos int
glwthread_recmutex_lock(glwthread_recmutex_t * mutex)378dffb485Schristos glwthread_recmutex_lock (glwthread_recmutex_t *mutex)
388dffb485Schristos {
398dffb485Schristos   if (!mutex->guard.done)
408dffb485Schristos     {
418dffb485Schristos       if (InterlockedIncrement (&mutex->guard.started) == 0)
428dffb485Schristos         /* This thread is the first one to need this mutex.  Initialize it.  */
438dffb485Schristos         glwthread_recmutex_init (mutex);
448dffb485Schristos       else
458dffb485Schristos         {
468dffb485Schristos           /* Don't let mutex->guard.started grow and wrap around.  */
478dffb485Schristos           InterlockedDecrement (&mutex->guard.started);
488dffb485Schristos           /* Yield the CPU while waiting for another thread to finish
498dffb485Schristos              initializing this mutex.  */
508dffb485Schristos           while (!mutex->guard.done)
518dffb485Schristos             Sleep (0);
528dffb485Schristos         }
538dffb485Schristos     }
548dffb485Schristos   {
558dffb485Schristos     DWORD self = GetCurrentThreadId ();
568dffb485Schristos     if (mutex->owner != self)
578dffb485Schristos       {
588dffb485Schristos         EnterCriticalSection (&mutex->lock);
598dffb485Schristos         mutex->owner = self;
608dffb485Schristos       }
618dffb485Schristos     if (++(mutex->depth) == 0) /* wraparound? */
628dffb485Schristos       {
638dffb485Schristos         mutex->depth--;
648dffb485Schristos         return EAGAIN;
658dffb485Schristos       }
668dffb485Schristos   }
678dffb485Schristos   return 0;
688dffb485Schristos }
698dffb485Schristos 
708dffb485Schristos int
glwthread_recmutex_trylock(glwthread_recmutex_t * mutex)718dffb485Schristos glwthread_recmutex_trylock (glwthread_recmutex_t *mutex)
728dffb485Schristos {
738dffb485Schristos   if (!mutex->guard.done)
748dffb485Schristos     {
758dffb485Schristos       if (InterlockedIncrement (&mutex->guard.started) == 0)
768dffb485Schristos         /* This thread is the first one to need this mutex.  Initialize it.  */
778dffb485Schristos         glwthread_recmutex_init (mutex);
788dffb485Schristos       else
798dffb485Schristos         {
808dffb485Schristos           /* Don't let mutex->guard.started grow and wrap around.  */
818dffb485Schristos           InterlockedDecrement (&mutex->guard.started);
828dffb485Schristos           /* Let another thread finish initializing this mutex, and let it also
838dffb485Schristos              lock this mutex.  */
848dffb485Schristos           return EBUSY;
858dffb485Schristos         }
868dffb485Schristos     }
878dffb485Schristos   {
888dffb485Schristos     DWORD self = GetCurrentThreadId ();
898dffb485Schristos     if (mutex->owner != self)
908dffb485Schristos       {
918dffb485Schristos         if (!TryEnterCriticalSection (&mutex->lock))
928dffb485Schristos           return EBUSY;
938dffb485Schristos         mutex->owner = self;
948dffb485Schristos       }
958dffb485Schristos     if (++(mutex->depth) == 0) /* wraparound? */
968dffb485Schristos       {
978dffb485Schristos         mutex->depth--;
988dffb485Schristos         return EAGAIN;
998dffb485Schristos       }
1008dffb485Schristos   }
1018dffb485Schristos   return 0;
1028dffb485Schristos }
1038dffb485Schristos 
1048dffb485Schristos int
glwthread_recmutex_unlock(glwthread_recmutex_t * mutex)1058dffb485Schristos glwthread_recmutex_unlock (glwthread_recmutex_t *mutex)
1068dffb485Schristos {
1078dffb485Schristos   if (mutex->owner != GetCurrentThreadId ())
1088dffb485Schristos     return EPERM;
1098dffb485Schristos   if (mutex->depth == 0)
1108dffb485Schristos     return EINVAL;
1118dffb485Schristos   if (--(mutex->depth) == 0)
1128dffb485Schristos     {
1138dffb485Schristos       mutex->owner = 0;
1148dffb485Schristos       LeaveCriticalSection (&mutex->lock);
1158dffb485Schristos     }
1168dffb485Schristos   return 0;
1178dffb485Schristos }
1188dffb485Schristos 
1198dffb485Schristos int
glwthread_recmutex_destroy(glwthread_recmutex_t * mutex)1208dffb485Schristos glwthread_recmutex_destroy (glwthread_recmutex_t *mutex)
1218dffb485Schristos {
1228dffb485Schristos   if (mutex->owner != 0)
1238dffb485Schristos     return EBUSY;
1248dffb485Schristos   DeleteCriticalSection (&mutex->lock);
1258dffb485Schristos   mutex->guard.done = 0;
1268dffb485Schristos   return 0;
1278dffb485Schristos }
128