(root)/
m4-1.4.19/
lib/
windows-recmutex.c
       1  /* Plain recursive mutexes (native Windows implementation).
       2     Copyright (C) 2005-2021 Free Software Foundation, Inc.
       3  
       4     This program is free software; you can redistribute it and/or modify
       5     it under the terms of the GNU General Public License as published by
       6     the Free Software Foundation; either version 3, or (at your option)
       7     any later version.
       8  
       9     This program is distributed in the hope that it will be useful,
      10     but WITHOUT ANY WARRANTY; without even the implied warranty of
      11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      12     GNU General Public License for more details.
      13  
      14     You should have received a copy of the GNU General Public License
      15     along with this program; if not, see <https://www.gnu.org/licenses/>.  */
      16  
      17  /* Written by Bruno Haible <bruno@clisp.org>, 2005.
      18     Based on GCC's gthr-win32.h.  */
      19  
      20  #include <config.h>
      21  
      22  /* Specification.  */
      23  #include "windows-recmutex.h"
      24  
      25  #include <errno.h>
      26  
      27  void
      28  glwthread_recmutex_init (glwthread_recmutex_t *mutex)
      29  {
      30    mutex->owner = 0;
      31    mutex->depth = 0;
      32    InitializeCriticalSection (&mutex->lock);
      33    mutex->guard.done = 1;
      34  }
      35  
      36  int
      37  glwthread_recmutex_lock (glwthread_recmutex_t *mutex)
      38  {
      39    if (!mutex->guard.done)
      40      {
      41        if (InterlockedIncrement (&mutex->guard.started) == 0)
      42          /* This thread is the first one to need this mutex.  Initialize it.  */
      43          glwthread_recmutex_init (mutex);
      44        else
      45          {
      46            /* Don't let mutex->guard.started grow and wrap around.  */
      47            InterlockedDecrement (&mutex->guard.started);
      48            /* Yield the CPU while waiting for another thread to finish
      49               initializing this mutex.  */
      50            while (!mutex->guard.done)
      51              Sleep (0);
      52          }
      53      }
      54    {
      55      DWORD self = GetCurrentThreadId ();
      56      if (mutex->owner != self)
      57        {
      58          EnterCriticalSection (&mutex->lock);
      59          mutex->owner = self;
      60        }
      61      if (++(mutex->depth) == 0) /* wraparound? */
      62        {
      63          mutex->depth--;
      64          return EAGAIN;
      65        }
      66    }
      67    return 0;
      68  }
      69  
      70  int
      71  glwthread_recmutex_trylock (glwthread_recmutex_t *mutex)
      72  {
      73    if (!mutex->guard.done)
      74      {
      75        if (InterlockedIncrement (&mutex->guard.started) == 0)
      76          /* This thread is the first one to need this mutex.  Initialize it.  */
      77          glwthread_recmutex_init (mutex);
      78        else
      79          {
      80            /* Don't let mutex->guard.started grow and wrap around.  */
      81            InterlockedDecrement (&mutex->guard.started);
      82            /* Let another thread finish initializing this mutex, and let it also
      83               lock this mutex.  */
      84            return EBUSY;
      85          }
      86      }
      87    {
      88      DWORD self = GetCurrentThreadId ();
      89      if (mutex->owner != self)
      90        {
      91          if (!TryEnterCriticalSection (&mutex->lock))
      92            return EBUSY;
      93          mutex->owner = self;
      94        }
      95      if (++(mutex->depth) == 0) /* wraparound? */
      96        {
      97          mutex->depth--;
      98          return EAGAIN;
      99        }
     100    }
     101    return 0;
     102  }
     103  
     104  int
     105  glwthread_recmutex_unlock (glwthread_recmutex_t *mutex)
     106  {
     107    if (mutex->owner != GetCurrentThreadId ())
     108      return EPERM;
     109    if (mutex->depth == 0)
     110      return EINVAL;
     111    if (--(mutex->depth) == 0)
     112      {
     113        mutex->owner = 0;
     114        LeaveCriticalSection (&mutex->lock);
     115      }
     116    return 0;
     117  }
     118  
     119  int
     120  glwthread_recmutex_destroy (glwthread_recmutex_t *mutex)
     121  {
     122    if (mutex->owner != 0)
     123      return EBUSY;
     124    DeleteCriticalSection (&mutex->lock);
     125    mutex->guard.done = 0;
     126    return 0;
     127  }