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