Home | History | Annotate | Line # | Download | only in import
windows-recmutex.c revision 1.1
      1 /* Plain recursive mutexes (native Windows implementation).
      2    Copyright (C) 2005-2020 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 (at) 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 }
    128