Remove .cvsignore files.
[gnulib.git] / lib / windows-mutex.c
blob2ac73a0728a906ee9b24d98cb8a7a597dce0e48a
1 /* Plain mutexes (native Windows implementation).
2 Copyright (C) 2005-2024 Free Software Foundation, Inc.
4 This file is free software: you can redistribute it and/or modify
5 it under the terms of the GNU Lesser General Public License as
6 published by the Free Software Foundation; either version 2.1 of the
7 License, or (at your option) any later version.
9 This file 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 Lesser General Public License for more details.
14 You should have received a copy of the GNU Lesser General Public License
15 along with this program. If not, see <https://www.gnu.org/licenses/>. */
17 /* Written by Bruno Haible <bruno@clisp.org>, 2005.
18 Based on GCC's gthr-win32.h. */
20 #include <config.h>
22 /* Specification. */
23 #include "windows-mutex.h"
25 #include <errno.h>
26 #include <stdlib.h>
28 void
29 glwthread_mutex_init (glwthread_mutex_t *mutex)
31 mutex->owner = 0;
32 InitializeCriticalSection (&mutex->lock);
33 mutex->guard.done = 1;
36 int
37 glwthread_mutex_lock (glwthread_mutex_t *mutex)
39 if (!mutex->guard.done)
41 if (InterlockedIncrement (&mutex->guard.started) == 0)
42 /* This thread is the first one to need this mutex. Initialize it. */
43 glwthread_mutex_init (mutex);
44 else
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);
54 /* If this thread already owns the mutex, POSIX pthread_mutex_lock() is
55 required to deadlock here. But let's not do that on purpose. */
56 EnterCriticalSection (&mutex->lock);
58 DWORD self = GetCurrentThreadId ();
59 mutex->owner = self;
61 return 0;
64 int
65 glwthread_mutex_trylock (glwthread_mutex_t *mutex)
67 if (!mutex->guard.done)
69 if (InterlockedIncrement (&mutex->guard.started) == 0)
70 /* This thread is the first one to need this mutex. Initialize it. */
71 glwthread_mutex_init (mutex);
72 else
74 /* Don't let mutex->guard.started grow and wrap around. */
75 InterlockedDecrement (&mutex->guard.started);
76 /* Let another thread finish initializing this mutex, and let it also
77 lock this mutex. */
78 return EBUSY;
81 if (!TryEnterCriticalSection (&mutex->lock))
82 return EBUSY;
84 DWORD self = GetCurrentThreadId ();
85 /* TryEnterCriticalSection succeeded. This means that the mutex was either
86 previously unlocked (and thus mutex->owner == 0) or previously locked by
87 this thread (and thus mutex->owner == self). Since the mutex is meant to
88 be plain, we need to fail in the latter case. */
89 if (mutex->owner == self)
91 LeaveCriticalSection (&mutex->lock);
92 return EBUSY;
94 if (mutex->owner != 0)
95 abort ();
96 mutex->owner = self;
98 return 0;
102 glwthread_mutex_unlock (glwthread_mutex_t *mutex)
104 if (!mutex->guard.done)
105 return EINVAL;
106 mutex->owner = 0;
107 LeaveCriticalSection (&mutex->lock);
108 return 0;
112 glwthread_mutex_destroy (glwthread_mutex_t *mutex)
114 if (!mutex->guard.done)
115 return EINVAL;
116 DeleteCriticalSection (&mutex->lock);
117 mutex->guard.done = 0;
118 return 0;