1/*
2    Title:      Mutex and Condition Variable library.
3
4    Copyright (c) 2007, 2012, 2015, 2019 David C. J. Matthews
5
6    This library is free software; you can redistribute it and/or
7    modify it under the terms of the GNU Lesser General Public
8    License version 2.1 as published by the Free Software Foundation.
9
10    This library is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    Lesser General Public License for more details.
14
15    You should have received a copy of the GNU Lesser General Public
16    License along with this library; if not, write to the Free Software
17    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
18
19*/
20
21#ifdef HAVE_CONFIG_H
22#include "config.h"
23#elif defined(_WIN32)
24#include "winconfig.h"
25#else
26#error "No configuration file"
27#endif
28
29#if (!defined(_WIN32))
30// Configure requires pthread unless this is native Windows.
31#include <pthread.h>
32#else
33#include <windows.h>
34#endif
35
36#ifdef HAVE_ERRNO_H
37#include <errno.h>
38#endif
39
40#ifdef HAVE_SYS_TIME_H
41#include <sys/time.h>
42#endif
43
44#ifdef HAVE_TIME_H
45#include <time.h>
46#endif
47
48#if (defined(HAVE_SEMAPHORE_H) && !defined(_WIN32))
49// Don't include semaphore.h on Mingw.  It's provided but doesn't compile.
50#include <semaphore.h>
51#endif
52
53#ifdef HAVE_SYS_TYPES_H
54#include <sys/types.h>
55#endif
56
57#ifdef HAVE_SYS_STAT_H
58#include <sys/stat.h>
59#endif
60
61#ifdef HAVE_FCNTL_H
62#include <fcntl.h>
63#endif
64
65#ifdef HAVE_UNISTD_H
66#include <unistd.h>
67#endif
68
69#ifdef HAVE_STDIO_H
70#include <stdio.h>
71#endif
72
73#include "locking.h"
74#include "diagnostics.h"
75
76// Report contended locks after this many attempts
77#define LOCK_REPORT_COUNT   50
78
79PLock::PLock(const char *n): lockName(n), lockCount(0)
80{
81#if (!defined(_WIN32))
82    pthread_mutex_init(&lock, 0);
83#else
84    InitializeCriticalSection(&lock);
85#endif
86}
87
88PLock::~PLock()
89{
90#if (!defined(_WIN32))
91    pthread_mutex_destroy(&lock);
92#else
93    DeleteCriticalSection(&lock);
94#endif
95}
96
97void PLock::Lock(void)
98{
99    if (debugOptions & DEBUG_CONTENTION)
100    {
101        // Report a heavily contended lock.
102        if (Trylock())
103            return;
104        if (++lockCount > LOCK_REPORT_COUNT)
105        {
106            if (lockName != 0)
107                Log("Lock: contention on lock: %s\n", lockName);
108            else
109                Log("Lock: contention on lock at %p\n", &lock);
110            lockCount = 0;
111        }
112        // Drop through to a normal lock
113    }
114#if (!defined(_WIN32))
115    pthread_mutex_lock(&lock);
116#else
117    EnterCriticalSection(&lock);
118#endif
119}
120
121void PLock::Unlock(void)
122{
123#if (!defined(_WIN32))
124    pthread_mutex_unlock(&lock);
125#else
126    LeaveCriticalSection(&lock);
127#endif
128}
129
130bool PLock::Trylock(void)
131{
132#if (!defined(_WIN32))
133    // Since we use normal mutexes this returns EBUSY if the
134    // current thread owns the mutex.
135    return pthread_mutex_trylock(&lock) != EBUSY;
136#else
137    // This is not implemented properly in Windows.  There is
138    // TryEnterCriticalSection in Win NT and later but that
139    // returns TRUE if the current thread owns the mutex.
140   return TryEnterCriticalSection(&lock) == TRUE;
141#endif
142}
143
144PCondVar::PCondVar()
145{
146#if (!defined(_WIN32))
147    pthread_cond_init(&cond, NULL);
148#else
149    InitializeConditionVariable(&cond);
150#endif
151}
152
153PCondVar::~PCondVar()
154{
155#if (!defined(_WIN32))
156    pthread_cond_destroy(&cond);
157#endif
158}
159
160// Wait indefinitely.  Drops the lock and reaquires it.
161void PCondVar::Wait(PLock *pLock)
162{
163#if (!defined(_WIN32))
164    pthread_cond_wait(&cond, &pLock->lock);
165#else
166    SleepConditionVariableCS(&cond, &pLock->lock, INFINITE);
167#endif
168}
169
170// Wait until a specified absolute time.  Drops the lock and reaquires it.
171#if (defined(_WIN32))
172// Windows with Windows-style times
173void PCondVar::WaitUntil(PLock *pLock, const FILETIME *time)
174{
175    FILETIME now;
176    GetSystemTimeAsFileTime(&now);
177    LARGE_INTEGER liNow, liTime;
178    liNow.HighPart = now.dwHighDateTime;
179    liNow.LowPart = now.dwLowDateTime;
180    liTime.HighPart = time->dwHighDateTime;
181    liTime.LowPart = time->dwLowDateTime;
182    if (liNow.QuadPart >= liTime.QuadPart) // Already past the time
183        return;
184    DWORD toWait = (DWORD)((liTime.QuadPart - liNow.QuadPart) / (LONGLONG)10000);
185    (void)WaitFor(pLock, toWait);
186}
187#else
188// Unix-style times
189void PCondVar::WaitUntil(PLock *pLock, const timespec *time)
190{
191    pthread_cond_timedwait(&cond, &pLock->lock, time);
192}
193#endif
194
195// Wait for a number of milliseconds.  Used within the RTS.  Drops the lock and reaquires it.
196// Returns true if the return was because the condition variable had been signalled.
197// Returns false if the timeout expired or there was an error.
198bool PCondVar::WaitFor(PLock *pLock, unsigned milliseconds)
199{
200#if (!defined(_WIN32))
201    struct timespec waitTime;
202    struct timeval tv;
203    if (gettimeofday(&tv, NULL) != 0)
204        return false;
205    waitTime.tv_sec = tv.tv_sec + milliseconds / 1000;
206    waitTime.tv_nsec = (tv.tv_usec + (milliseconds % 1000) * 1000) * 1000;
207    if (waitTime.tv_nsec >= 1000*1000*1000)
208    {
209        waitTime.tv_nsec -= 1000*1000*1000;
210        waitTime.tv_sec += 1;
211    }
212    return pthread_cond_timedwait(&cond, &pLock->lock, &waitTime) == 0;
213#else
214    // SleepConditionVariableCS returns zero on error or timeout.
215    return SleepConditionVariableCS(&cond, &pLock->lock, milliseconds) != 0;
216#endif
217}
218
219// Wake up all the waiting threads.
220void PCondVar::Signal(void)
221{
222#if (!defined(_WIN32))
223    pthread_cond_broadcast(&cond);
224#else
225    WakeAllConditionVariable(&cond);
226#endif
227}
228
229
230// Initialise a semphore.  Tries to create an unnamed semaphore if
231// it can but tries a named semaphore if it can't.  Mac OS X only
232// supports named semaphores.
233// The semaphore is initialised with a count of zero.
234PSemaphore::PSemaphore()
235{
236#if (!defined(_WIN32))
237    sema = 0;
238    isLocal = true;
239#else
240    sema = NULL;
241#endif
242}
243
244PSemaphore::~PSemaphore()
245{
246#if (!defined(_WIN32))
247    if (sema && isLocal) sem_destroy(sema);
248    else if (sema && !isLocal) sem_close(sema);
249#else
250    if (sema != NULL) CloseHandle(sema);
251#endif
252}
253
254bool PSemaphore::Init(unsigned init, unsigned max)
255{
256#if (!defined(_WIN32))
257    isLocal = true;
258    if (sem_init(&localSema, 0, init) == 0) {
259        sema = &localSema;
260        return true;
261    }
262#if (defined(__CYGWIN__))
263    // Cygwin doesn't define sem_unlink but that doesn't matter
264    // since sem_init works.
265    sema = 0;
266    return false;
267#else
268    isLocal = false;
269    char semname[30];
270    static int count=0;
271    sprintf(semname, "poly%0d-%0d", (int)getpid(), count++);
272    sema = sem_open(semname, O_CREAT|O_EXCL, 00666, init);
273    if (sema == (sem_t*)SEM_FAILED) {
274        sema = 0;
275        return false;
276    }
277    sem_unlink(semname);
278    return true;
279#endif
280#else
281    sema = CreateSemaphore(NULL, init, max, NULL);
282    return sema != NULL;
283#endif
284}
285
286bool PSemaphore::Wait(void)
287{
288#if (!defined(_WIN32))
289    // Wait until the semaphore is signalled.  A Unix signal may interrupt
290    // it so we need to retry in that case.
291    while (sem_wait(sema) == -1)
292    {
293        if (errno != EINTR)
294            return false;
295    }
296    return true;
297#else
298    return WaitForSingleObject(sema, INFINITE) == WAIT_OBJECT_0;
299#endif
300}
301
302void PSemaphore::Signal(void)
303{
304#if (!defined(_WIN32))
305    sem_post(sema);
306#else
307    ReleaseSemaphore(sema, 1, NULL);
308#endif
309}
310
311
312
313