1 /* Timed mutexes (native Windows implementation).
2 Copyright (C) 2005-2020 Free Software Foundation, Inc.
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 2, or (at your option)
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.
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/>. */
17 /* Written by Bruno Haible <bruno@clisp.org>, 2005, 2019.
18 Based on GCC's gthr-win32.h. */
23 #include "windows-timedmutex.h"
29 /* Don't assume that UNICODE is not defined. */
31 #define CreateEvent CreateEventA
34 glwthread_timedmutex_init (glwthread_timedmutex_t
*mutex
)
36 /* Attempt to allocate an auto-reset event object. */
38 <https://docs.microsoft.com/en-us/windows/desktop/api/synchapi/nf-synchapi-createeventa> */
39 HANDLE event
= CreateEvent (NULL
, FALSE
, FALSE
, NULL
);
40 if (event
== INVALID_HANDLE_VALUE
)
43 InitializeCriticalSection (&mutex
->lock
);
44 mutex
->guard
.done
= 1;
49 glwthread_timedmutex_lock (glwthread_timedmutex_t
*mutex
)
51 if (!mutex
->guard
.done
)
53 if (InterlockedIncrement (&mutex
->guard
.started
) == 0)
55 /* This thread is the first one to need this mutex.
57 int err
= glwthread_timedmutex_init (mutex
);
61 InterlockedDecrement (&mutex
->guard
.started
);
67 /* Don't let mutex->guard.started grow and wrap around. */
68 InterlockedDecrement (&mutex
->guard
.started
);
69 /* Yield the CPU while waiting for another thread to finish
70 initializing this mutex. */
71 while (!mutex
->guard
.done
)
75 EnterCriticalSection (&mutex
->lock
);
80 glwthread_timedmutex_trylock (glwthread_timedmutex_t
*mutex
)
82 if (!mutex
->guard
.done
)
84 if (InterlockedIncrement (&mutex
->guard
.started
) == 0)
86 /* This thread is the first one to need this mutex.
88 int err
= glwthread_timedmutex_init (mutex
);
92 InterlockedDecrement (&mutex
->guard
.started
);
98 /* Don't let mutex->guard.started grow and wrap around. */
99 InterlockedDecrement (&mutex
->guard
.started
);
100 /* Let another thread finish initializing this mutex, and let it also
105 if (!TryEnterCriticalSection (&mutex
->lock
))
111 glwthread_timedmutex_timedlock (glwthread_timedmutex_t
*mutex
,
112 const struct timespec
*abstime
)
114 if (!mutex
->guard
.done
)
116 if (InterlockedIncrement (&mutex
->guard
.started
) == 0)
118 /* This thread is the first one to need this mutex.
120 int err
= glwthread_timedmutex_init (mutex
);
123 /* Undo increment. */
124 InterlockedDecrement (&mutex
->guard
.started
);
130 /* Don't let mutex->guard.started grow and wrap around. */
131 InterlockedDecrement (&mutex
->guard
.started
);
132 /* Yield the CPU while waiting for another thread to finish
133 initializing this mutex. */
134 while (!mutex
->guard
.done
)
140 "Under no circumstance shall the function fail with a timeout if
141 the mutex can be locked immediately. The validity of the abstime
142 parameter need not be checked if the mutex can be locked
144 Therefore start the loop with a TryEnterCriticalSection call. */
147 if (TryEnterCriticalSection (&mutex
->lock
))
151 struct timeval currtime
;
155 gettimeofday (&currtime
, NULL
);
157 /* Wait until another thread signals the event or until the
159 if (currtime
.tv_sec
> abstime
->tv_sec
)
163 unsigned long seconds
= abstime
->tv_sec
- currtime
.tv_sec
;
164 timeout
= seconds
* 1000;
165 if (timeout
/ 1000 != seconds
) /* overflow? */
170 abstime
->tv_nsec
/ 1000000 - currtime
.tv_usec
/ 1000;
171 if (milliseconds
>= 0)
173 timeout
+= milliseconds
;
174 if (timeout
< milliseconds
) /* overflow? */
179 if (timeout
>= - milliseconds
)
180 timeout
-= (- milliseconds
);
189 /* WaitForSingleObject
190 <https://docs.microsoft.com/en-us/windows/desktop/api/synchapi/nf-synchapi-waitforsingleobject> */
191 result
= WaitForSingleObject (mutex
->event
, timeout
);
192 if (result
== WAIT_FAILED
)
194 if (result
== WAIT_TIMEOUT
)
196 /* Another thread has just unlocked the mutex. We have good chances at
204 glwthread_timedmutex_unlock (glwthread_timedmutex_t
*mutex
)
206 if (!mutex
->guard
.done
)
208 LeaveCriticalSection (&mutex
->lock
);
209 /* Notify one of the threads that were waiting with a timeout. */
211 <https://docs.microsoft.com/en-us/windows/desktop/api/synchapi/nf-synchapi-setevent> */
212 SetEvent (mutex
->event
);
217 glwthread_timedmutex_destroy (glwthread_timedmutex_t
*mutex
)
219 if (!mutex
->guard
.done
)
221 DeleteCriticalSection (&mutex
->lock
);
223 <https://docs.microsoft.com/en-us/windows/desktop/api/handleapi/nf-handleapi-closehandle> */
224 CloseHandle (mutex
->event
);
225 mutex
->guard
.done
= 0;