Coverage Report

Created: 2025-06-13 06:29

/src/gdal/port/cpl_multiproc.cpp
Line
Count
Source (jump to first uncovered line)
1
/**********************************************************************
2
 *
3
 * Project:  CPL - Common Portability Library
4
 * Purpose:  CPL Multi-Threading, and process handling portability functions.
5
 * Author:   Frank Warmerdam, warmerdam@pobox.com
6
 *
7
 **********************************************************************
8
 * Copyright (c) 2002, Frank Warmerdam
9
 * Copyright (c) 2009-2013, Even Rouault <even dot rouault at spatialys.com>
10
 *
11
 * SPDX-License-Identifier: MIT
12
 ****************************************************************************/
13
14
#ifndef _GNU_SOURCE
15
#define _GNU_SOURCE
16
#endif
17
18
// Include cpl_config.h BEFORE cpl_multiproc.h, as the later may undefine
19
// CPL_MULTIPROC_PTHREAD for mingw case.
20
21
#include "cpl_config.h"
22
#include "cpl_multiproc.h"
23
24
#ifdef CHECK_THREAD_CAN_ALLOCATE_TLS
25
#include <cassert>
26
#endif
27
#include <cerrno>
28
#include <cmath>
29
#include <cstddef>
30
#include <cstdio>
31
#include <cstdlib>
32
#include <cstring>
33
#include <ctime>
34
#include <algorithm>
35
36
#include "cpl_atomic_ops.h"
37
#include "cpl_conv.h"
38
#include "cpl_error.h"
39
#include "cpl_string.h"
40
#include "cpl_vsi.h"
41
42
#if defined(CPL_MULTIPROC_STUB) && !defined(DEBUG)
43
#define MUTEX_NONE
44
#endif
45
46
// #define DEBUG_MUTEX
47
48
#if defined(DEBUG) &&                                                          \
49
    (defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)))
50
#ifndef DEBUG_CONTENTION
51
#define DEBUG_CONTENTION
52
#endif
53
#endif
54
55
typedef struct _CPLSpinLock CPLSpinLock;
56
57
struct _CPLLock
58
{
59
    CPLLockType eType;
60
61
    union
62
    {
63
        CPLMutex *hMutex;
64
        CPLSpinLock *hSpinLock;
65
    } u;
66
67
#ifdef DEBUG_CONTENTION
68
    bool bDebugPerfAsked;
69
    bool bDebugPerf;
70
    volatile int nCurrentHolders;
71
    GUIntBig nStartTime;
72
    GIntBig nMaxDiff;
73
    double dfAvgDiff;
74
    GUIntBig nIters;
75
#endif
76
};
77
78
#ifdef DEBUG_CONTENTION
79
80
#if defined(__x86_64)
81
#define GCC_CPUID(level, a, b, c, d)                                           \
82
0
    __asm__ volatile("xchgq %%rbx, %q1\n"                                      \
83
0
                     "cpuid\n"                                                 \
84
0
                     "xchgq %%rbx, %q1"                                        \
85
0
                     : "=a"(a), "=r"(b), "=c"(c), "=d"(d)                      \
86
0
                     : "0"(level))
87
#else
88
#define GCC_CPUID(level, a, b, c, d)                                           \
89
    __asm__ volatile("xchgl %%ebx, %1\n"                                       \
90
                     "cpuid\n"                                                 \
91
                     "xchgl %%ebx, %1"                                         \
92
                     : "=a"(a), "=r"(b), "=c"(c), "=d"(d)                      \
93
                     : "0"(level))
94
#endif
95
96
static GUIntBig CPLrdtsc()
97
0
{
98
0
    unsigned int a;
99
0
    unsigned int d;
100
0
    unsigned int unused1;
101
0
    unsigned int unused2;
102
0
    unsigned int unused3;
103
0
    unsigned int unused4;
104
0
    GCC_CPUID(0, unused1, unused2, unused3, unused4);
105
0
    __asm__ volatile("rdtsc" : "=a"(a), "=d"(d));
106
0
    return static_cast<GUIntBig>(a) | (static_cast<GUIntBig>(d) << 32);
107
0
}
108
109
static GUIntBig CPLrdtscp()
110
0
{
111
0
    unsigned int a;
112
0
    unsigned int d;
113
0
    unsigned int unused1;
114
0
    unsigned int unused2;
115
0
    unsigned int unused3;
116
0
    unsigned int unused4;
117
0
    __asm__ volatile("rdtscp" : "=a"(a), "=d"(d));
118
0
    GCC_CPUID(0, unused1, unused2, unused3, unused4);
119
0
    return static_cast<GUIntBig>(a) | (static_cast<GUIntBig>(d) << 32);
120
0
}
121
#endif
122
123
static CPLSpinLock *CPLCreateSpinLock();  // Returned NON acquired.
124
static int CPLCreateOrAcquireSpinLockInternal(CPLLock **);
125
static int CPLAcquireSpinLock(CPLSpinLock *);
126
static void CPLReleaseSpinLock(CPLSpinLock *);
127
static void CPLDestroySpinLock(CPLSpinLock *);
128
129
#ifndef CPL_MULTIPROC_PTHREAD
130
#ifndef MUTEX_NONE
131
static CPLMutex *CPLCreateOrAcquireMasterMutex(double);
132
static CPLMutex *&CPLCreateOrAcquireMasterMutexInternal(double);
133
static CPLMutex *CPLCreateUnacquiredMutex();
134
#endif
135
#endif
136
137
// We don't want it to be publicly used since it solves rather tricky issues
138
// that are better to remain hidden.
139
void CPLFinalizeTLS();
140
141
/************************************************************************/
142
/*                           CPLMutexHolder()                           */
143
/************************************************************************/
144
145
#ifdef MUTEX_NONE
146
CPLMutexHolder::CPLMutexHolder(CPLMutex ** /* phMutex */,
147
                               double /* dfWaitInSeconds */,
148
                               const char * /* pszFileIn */, int /* nLineIn */,
149
                               int /* nOptions */)
150
{
151
}
152
153
#else
154
CPLMutexHolder::CPLMutexHolder(CPLMutex **phMutex, double dfWaitInSeconds,
155
                               const char *pszFileIn, int nLineIn, int nOptions)
156
400k
    : hMutex(nullptr), pszFile(pszFileIn), nLine(nLineIn)
157
400k
{
158
400k
    if (phMutex == nullptr)
159
0
    {
160
0
        fprintf(stderr, "CPLMutexHolder: phMutex )) NULL !\n");
161
0
        hMutex = nullptr;
162
0
        return;
163
0
    }
164
165
#ifdef DEBUG_MUTEX
166
    // There is no way to use CPLDebug() here because it works with
167
    // mutexes itself so we will fall in infinite recursion.
168
    // fprintf() will do the job right.
169
    fprintf(stderr, "CPLMutexHolder: Request %p for pid %ld at %d/%s.\n",
170
            *phMutex, static_cast<long>(CPLGetPID()), nLine, pszFile);
171
#else
172
    // TODO(schwehr): Find a better way to do handle this.
173
400k
    (void)pszFile;
174
400k
    (void)nLine;
175
400k
#endif
176
177
400k
    if (!CPLCreateOrAcquireMutexEx(phMutex, dfWaitInSeconds, nOptions))
178
0
    {
179
0
        fprintf(stderr, "CPLMutexHolder: Failed to acquire mutex!\n");
180
0
        hMutex = nullptr;
181
0
    }
182
400k
    else
183
400k
    {
184
#ifdef DEBUG_MUTEX
185
        fprintf(stderr, "CPLMutexHolder: Acquired %p for pid %ld at %d/%s.\n",
186
                *phMutex, static_cast<long>(CPLGetPID()), nLine, pszFile);
187
#endif
188
189
400k
        hMutex = *phMutex;
190
400k
    }
191
400k
}
192
#endif  // ndef MUTEX_NONE
193
194
/************************************************************************/
195
/*                           CPLMutexHolder()                           */
196
/************************************************************************/
197
198
#ifdef MUTEX_NONE
199
CPLMutexHolder::CPLMutexHolder(CPLMutex * /* hMutexIn */,
200
                               double /* dfWaitInSeconds */,
201
                               const char * /* pszFileIn */, int /* nLineIn */)
202
{
203
}
204
#else
205
206
static CPLMutex *GetMutexHolderMutexMember(CPLMutex *hMutexIn,
207
                                           double dfWaitInSeconds)
208
0
{
209
0
    if (hMutexIn && !CPLAcquireMutex(hMutexIn, dfWaitInSeconds))
210
0
    {
211
0
        fprintf(stderr, "CPLMutexHolder: Failed to acquire mutex!\n");
212
0
        return nullptr;
213
0
    }
214
0
    return hMutexIn;
215
0
}
216
217
CPLMutexHolder::CPLMutexHolder(CPLMutex *hMutexIn, double dfWaitInSeconds,
218
                               const char *pszFileIn, int nLineIn)
219
0
    : hMutex(GetMutexHolderMutexMember(hMutexIn, dfWaitInSeconds)),
220
0
      pszFile(pszFileIn), nLine(nLineIn)
221
0
{
222
0
}
223
#endif  // ndef MUTEX_NONE
224
225
/************************************************************************/
226
/*                          ~CPLMutexHolder()                           */
227
/************************************************************************/
228
229
#ifdef MUTEX_NONE
230
CPLMutexHolder::~CPLMutexHolder()
231
{
232
}
233
#else
234
CPLMutexHolder::~CPLMutexHolder()
235
400k
{
236
400k
    if (hMutex != nullptr)
237
400k
    {
238
#ifdef DEBUG_MUTEX
239
        fprintf(stderr, "~CPLMutexHolder: Release %p for pid %ld at %d/%s.\n",
240
                hMutex, static_cast<long>(CPLGetPID()), nLine, pszFile);
241
#endif
242
400k
        CPLReleaseMutex(hMutex);
243
400k
    }
244
400k
}
245
#endif  // ndef MUTEX_NONE
246
247
int CPLCreateOrAcquireMutex(CPLMutex **phMutex, double dfWaitInSeconds)
248
0
{
249
0
    return CPLCreateOrAcquireMutexEx(phMutex, dfWaitInSeconds,
250
0
                                     CPL_MUTEX_RECURSIVE);
251
0
}
252
253
/************************************************************************/
254
/*                      CPLCreateOrAcquireMutex()                       */
255
/************************************************************************/
256
257
#ifndef CPL_MULTIPROC_PTHREAD
258
259
#ifndef MUTEX_NONE
260
CPLMutex *CPLCreateUnacquiredMutex()
261
{
262
    CPLMutex *hMutex = CPLCreateMutex();
263
    if (hMutex)
264
    {
265
        CPLReleaseMutex(hMutex);
266
    }
267
    return hMutex;
268
}
269
270
CPLMutex *&
271
CPLCreateOrAcquireMasterMutexInternal(double dfWaitInSeconds = 1000.0)
272
{
273
    // The dynamic initialization of the block scope hCOAMutex
274
    // with static storage duration is thread-safe in C++11
275
    static CPLMutex *hCOAMutex = CPLCreateUnacquiredMutex();
276
277
    // WARNING: although adding an CPLAssert(hCOAMutex); might seem logical
278
    // here, do not enable it (see comment below). It calls CPLError that
279
    // uses the hCOAMutex itself leading to recursive mutex acquisition
280
    // and likely a stack overflow.
281
282
    if (!hCOAMutex)
283
    {
284
        // Fall back to this, ironically, NOT thread-safe re-initialisation of
285
        // hCOAMutex in case of a memory error or call to CPLCleanupMasterMutex
286
        // sequenced in an unusual, unexpected or erroneous way.
287
        // For example, an unusual sequence could be:
288
        //   GDALDriverManager has been instantiated,
289
        //   then OGRCleanupAll is called which calls CPLCleanupMasterMutex,
290
        //   then CPLFreeConfig is called which acquires the hCOAMutex
291
        //   that has already been released and destroyed.
292
293
        hCOAMutex = CPLCreateUnacquiredMutex();
294
    }
295
296
    if (hCOAMutex)
297
    {
298
        CPLAcquireMutex(hCOAMutex, dfWaitInSeconds);
299
    }
300
301
    return hCOAMutex;
302
}
303
304
CPLMutex *CPLCreateOrAcquireMasterMutex(double dfWaitInSeconds = 1000.0)
305
{
306
    CPLMutex *hCOAMutex =
307
        CPLCreateOrAcquireMasterMutexInternal(dfWaitInSeconds);
308
    return hCOAMutex;
309
}
310
#endif
311
312
#ifdef MUTEX_NONE
313
314
int CPLCreateOrAcquireMutexEx(CPLMutex **phMutex, double dfWaitInSeconds,
315
                              int nOptions)
316
{
317
    return false;
318
}
319
#else
320
int CPLCreateOrAcquireMutexEx(CPLMutex **phMutex, double dfWaitInSeconds,
321
                              int nOptions)
322
{
323
    bool bSuccess = false;
324
325
    CPLMutex *hCOAMutex = CPLCreateOrAcquireMasterMutex(dfWaitInSeconds);
326
    if (hCOAMutex == nullptr)
327
    {
328
        *phMutex = nullptr;
329
        return FALSE;
330
    }
331
332
    if (*phMutex == nullptr)
333
    {
334
        *phMutex = CPLCreateMutexEx(nOptions);
335
        bSuccess = *phMutex != nullptr;
336
        CPLReleaseMutex(hCOAMutex);
337
    }
338
    else
339
    {
340
        CPLReleaseMutex(hCOAMutex);
341
342
        bSuccess = CPL_TO_BOOL(CPLAcquireMutex(*phMutex, dfWaitInSeconds));
343
    }
344
345
    return bSuccess;
346
}
347
#endif  // ndef MUTEX_NONE
348
349
/************************************************************************/
350
/*                   CPLCreateOrAcquireMutexInternal()                  */
351
/************************************************************************/
352
353
#ifdef MUTEX_NONE
354
static bool CPLCreateOrAcquireMutexInternal(CPLLock **phLock,
355
                                            double dfWaitInSeconds,
356
                                            CPLLockType eType)
357
{
358
    return false;
359
}
360
#else
361
static bool CPLCreateOrAcquireMutexInternal(CPLLock **phLock,
362
                                            double dfWaitInSeconds,
363
                                            CPLLockType eType)
364
365
{
366
    bool bSuccess = false;
367
368
    CPLMutex *hCOAMutex = CPLCreateOrAcquireMasterMutex(dfWaitInSeconds);
369
    if (hCOAMutex == nullptr)
370
    {
371
        *phLock = nullptr;
372
        return FALSE;
373
    }
374
375
    if (*phLock == nullptr)
376
    {
377
        *phLock = static_cast<CPLLock *>(calloc(1, sizeof(CPLLock)));
378
        if (*phLock)
379
        {
380
            (*phLock)->eType = eType;
381
            (*phLock)->u.hMutex = CPLCreateMutexEx(
382
                (eType == LOCK_RECURSIVE_MUTEX) ? CPL_MUTEX_RECURSIVE
383
                                                : CPL_MUTEX_ADAPTIVE);
384
            if ((*phLock)->u.hMutex == nullptr)
385
            {
386
                free(*phLock);
387
                *phLock = nullptr;
388
            }
389
        }
390
        bSuccess = *phLock != nullptr;
391
        CPLReleaseMutex(hCOAMutex);
392
    }
393
    else
394
    {
395
        CPLReleaseMutex(hCOAMutex);
396
397
        bSuccess =
398
            CPL_TO_BOOL(CPLAcquireMutex((*phLock)->u.hMutex, dfWaitInSeconds));
399
    }
400
401
    return bSuccess;
402
}
403
#endif  // ndef MUTEX_NONE
404
405
#endif  // CPL_MULTIPROC_PTHREAD
406
407
/************************************************************************/
408
/*                      CPLCleanupMasterMutex()                         */
409
/************************************************************************/
410
411
void CPLCleanupMasterMutex()
412
0
{
413
#ifndef CPL_MULTIPROC_PTHREAD
414
#ifndef MUTEX_NONE
415
    CPLMutex *&hCOAMutex = CPLCreateOrAcquireMasterMutexInternal();
416
    if (hCOAMutex != nullptr)
417
    {
418
        CPLReleaseMutex(hCOAMutex);
419
        CPLDestroyMutex(hCOAMutex);
420
        hCOAMutex = nullptr;
421
    }
422
#endif
423
#endif
424
0
}
425
426
/************************************************************************/
427
/*                        CPLCleanupTLSList()                           */
428
/*                                                                      */
429
/*      Free resources associated with a TLS vector (implementation     */
430
/*      independent).                                                   */
431
/************************************************************************/
432
433
static void CPLCleanupTLSList(void **papTLSList)
434
435
0
{
436
#ifdef DEBUG_VERBOSE
437
    printf("CPLCleanupTLSList(%p)\n", papTLSList); /*ok*/
438
#endif
439
440
0
    if (papTLSList == nullptr)
441
0
        return;
442
443
0
    for (int i = 0; i < CTLS_MAX; i++)
444
0
    {
445
0
        if (papTLSList[i] != nullptr && papTLSList[i + CTLS_MAX] != nullptr)
446
0
        {
447
0
            CPLTLSFreeFunc pfnFree =
448
0
                reinterpret_cast<CPLTLSFreeFunc>(papTLSList[i + CTLS_MAX]);
449
0
            pfnFree(papTLSList[i]);
450
0
            papTLSList[i] = nullptr;
451
0
        }
452
0
    }
453
454
0
    CPLFree(papTLSList);
455
0
}
456
457
#if defined(CPL_MULTIPROC_STUB)
458
/************************************************************************/
459
/* ==================================================================== */
460
/*                        CPL_MULTIPROC_STUB                            */
461
/*                                                                      */
462
/*      Stub implementation.  Mutexes don't provide exclusion, file     */
463
/*      locking is achieved with extra "lock files", and thread         */
464
/*      creation doesn't work.  The PID is always just one.             */
465
/* ==================================================================== */
466
/************************************************************************/
467
468
/************************************************************************/
469
/*                             CPLGetNumCPUs()                          */
470
/************************************************************************/
471
472
int CPLGetNumCPUs()
473
{
474
    return 1;
475
}
476
477
/************************************************************************/
478
/*                        CPLGetThreadingModel()                        */
479
/************************************************************************/
480
481
const char *CPLGetThreadingModel()
482
483
{
484
    return "stub";
485
}
486
487
/************************************************************************/
488
/*                           CPLCreateMutex()                           */
489
/************************************************************************/
490
491
#ifdef MUTEX_NONE
492
CPLMutex *CPLCreateMutex()
493
{
494
    return (CPLMutex *)0xdeadbeef;
495
}
496
#else
497
CPLMutex *CPLCreateMutex()
498
{
499
    unsigned char *pabyMutex = static_cast<unsigned char *>(malloc(4));
500
    if (pabyMutex == nullptr)
501
        return nullptr;
502
503
    pabyMutex[0] = 1;
504
    pabyMutex[1] = 'r';
505
    pabyMutex[2] = 'e';
506
    pabyMutex[3] = 'd';
507
508
    return (CPLMutex *)pabyMutex;
509
}
510
#endif
511
512
CPLMutex *CPLCreateMutexEx(int /*nOptions*/)
513
514
{
515
    return CPLCreateMutex();
516
}
517
518
/************************************************************************/
519
/*                          CPLAcquireMutex()                           */
520
/************************************************************************/
521
522
#ifdef MUTEX_NONE
523
int CPLAcquireMutex(CPLMutex *hMutex, double /* dfWaitInSeconds */)
524
{
525
    return TRUE;
526
}
527
#else
528
int CPLAcquireMutex(CPLMutex *hMutex, double /*dfWaitInSeconds*/)
529
{
530
    unsigned char *pabyMutex = reinterpret_cast<unsigned char *>(hMutex);
531
532
    CPLAssert(pabyMutex[1] == 'r' && pabyMutex[2] == 'e' &&
533
              pabyMutex[3] == 'd');
534
535
    pabyMutex[0] += 1;
536
537
    return TRUE;
538
}
539
#endif  // ! MUTEX_NONE
540
541
/************************************************************************/
542
/*                          CPLReleaseMutex()                           */
543
/************************************************************************/
544
545
#ifdef MUTEX_NONE
546
void CPLReleaseMutex(CPLMutex * /* hMutex */)
547
{
548
}
549
#else
550
void CPLReleaseMutex(CPLMutex *hMutex)
551
{
552
    unsigned char *pabyMutex = reinterpret_cast<unsigned char *>(hMutex);
553
554
    CPLAssert(pabyMutex[1] == 'r' && pabyMutex[2] == 'e' &&
555
              pabyMutex[3] == 'd');
556
557
    if (pabyMutex[0] < 1)
558
        CPLDebug("CPLMultiProc",
559
                 "CPLReleaseMutex() called on mutex with %d as ref count!",
560
                 pabyMutex[0]);
561
562
    pabyMutex[0] -= 1;
563
}
564
#endif
565
566
/************************************************************************/
567
/*                          CPLDestroyMutex()                           */
568
/************************************************************************/
569
570
#ifdef MUTEX_NONE
571
void CPLDestroyMutex(CPLMutex * /* hMutex */)
572
{
573
}
574
#else
575
void CPLDestroyMutex(CPLMutex *hMutex)
576
{
577
    unsigned char *pabyMutex = reinterpret_cast<unsigned char *>(hMutex);
578
579
    CPLAssert(pabyMutex[1] == 'r' && pabyMutex[2] == 'e' &&
580
              pabyMutex[3] == 'd');
581
582
    free(pabyMutex);
583
}
584
#endif
585
586
/************************************************************************/
587
/*                            CPLCreateCond()                           */
588
/************************************************************************/
589
590
CPLCond *CPLCreateCond()
591
{
592
    return nullptr;
593
}
594
595
/************************************************************************/
596
/*                            CPLCondWait()                             */
597
/************************************************************************/
598
599
void CPLCondWait(CPLCond * /* hCond */, CPLMutex * /* hMutex */)
600
{
601
}
602
603
/************************************************************************/
604
/*                         CPLCondTimedWait()                           */
605
/************************************************************************/
606
607
CPLCondTimedWaitReason CPLCondTimedWait(CPLCond * /* hCond */,
608
                                        CPLMutex * /* hMutex */, double)
609
{
610
    return COND_TIMED_WAIT_OTHER;
611
}
612
613
/************************************************************************/
614
/*                            CPLCondSignal()                           */
615
/************************************************************************/
616
617
void CPLCondSignal(CPLCond * /* hCond */)
618
{
619
}
620
621
/************************************************************************/
622
/*                           CPLCondBroadcast()                         */
623
/************************************************************************/
624
625
void CPLCondBroadcast(CPLCond * /* hCond */)
626
{
627
}
628
629
/************************************************************************/
630
/*                            CPLDestroyCond()                          */
631
/************************************************************************/
632
633
void CPLDestroyCond(CPLCond * /* hCond */)
634
{
635
}
636
637
/************************************************************************/
638
/*                            CPLLockFile()                             */
639
/************************************************************************/
640
641
void *CPLLockFile(const char *pszPath, double dfWaitInSeconds)
642
643
{
644
    CPLLockFileHandle hHandle = nullptr;
645
    CPLStringList aosOptions;
646
    aosOptions.SetNameValue("WAIT_TIME", CPLSPrintf("%f", dfWaitInSeconds));
647
    CPLLockFileEx(pszPath, &hHandle, aosOptions);
648
    return hHandle;
649
}
650
651
/************************************************************************/
652
/*                           CPLUnlockFile()                            */
653
/************************************************************************/
654
655
void CPLUnlockFile(void *hLock)
656
657
{
658
    CPLUnlockFileEx(static_cast<CPLLockFileHandle>(hLock));
659
}
660
661
/************************************************************************/
662
/*                             CPLGetPID()                              */
663
/************************************************************************/
664
665
GIntBig CPLGetPID()
666
667
{
668
    return 1;
669
}
670
671
/************************************************************************/
672
/*                          CPLCreateThread();                          */
673
/************************************************************************/
674
675
int CPLCreateThread(CPLThreadFunc /* pfnMain */, void * /* pArg */)
676
{
677
    CPLDebug("CPLCreateThread", "Fails to dummy implementation");
678
679
    return -1;
680
}
681
682
/************************************************************************/
683
/*                      CPLCreateJoinableThread()                       */
684
/************************************************************************/
685
686
CPLJoinableThread *CPLCreateJoinableThread(CPLThreadFunc /* pfnMain */,
687
                                           void * /* pThreadArg */)
688
{
689
    CPLDebug("CPLCreateJoinableThread", "Fails to dummy implementation");
690
691
    return nullptr;
692
}
693
694
/************************************************************************/
695
/*                          CPLJoinThread()                             */
696
/************************************************************************/
697
698
void CPLJoinThread(CPLJoinableThread * /* hJoinableThread */)
699
{
700
}
701
702
/************************************************************************/
703
/*                              CPLSleep()                              */
704
/************************************************************************/
705
706
void CPLSleep(double dfWaitInSeconds)
707
{
708
    time_t ltime;
709
710
    time(&ltime);
711
    const time_t ttime = ltime + static_cast<int>(dfWaitInSeconds + 0.5);
712
713
    for (; ltime < ttime; time(&ltime))
714
    {
715
        // Currently we just busy wait.  Perhaps we could at least block on io?
716
    }
717
}
718
719
/************************************************************************/
720
/*                           CPLGetTLSList()                            */
721
/************************************************************************/
722
723
static void **papTLSList = nullptr;
724
725
static void **CPLGetTLSList(int *pbMemoryErrorOccurred)
726
727
{
728
    if (pbMemoryErrorOccurred)
729
        *pbMemoryErrorOccurred = FALSE;
730
    if (papTLSList == nullptr)
731
    {
732
        papTLSList =
733
            static_cast<void **>(VSICalloc(sizeof(void *), CTLS_MAX * 2));
734
        if (papTLSList == nullptr)
735
        {
736
            if (pbMemoryErrorOccurred)
737
            {
738
                *pbMemoryErrorOccurred = TRUE;
739
                fprintf(stderr,
740
                        "CPLGetTLSList() failed to allocate TLS list!\n");
741
                return nullptr;
742
            }
743
            CPLEmergencyError("CPLGetTLSList() failed to allocate TLS list!");
744
        }
745
    }
746
747
    return papTLSList;
748
}
749
750
/************************************************************************/
751
/*                             CPLFinalizeTLS()                         */
752
/************************************************************************/
753
754
void CPLFinalizeTLS()
755
{
756
    CPLCleanupTLS();
757
}
758
759
/************************************************************************/
760
/*                           CPLCleanupTLS()                            */
761
/************************************************************************/
762
763
void CPLCleanupTLS()
764
765
{
766
    CPLCleanupTLSList(papTLSList);
767
    papTLSList = nullptr;
768
}
769
770
// endif CPL_MULTIPROC_STUB
771
772
#elif defined(CPL_MULTIPROC_WIN32)
773
774
/************************************************************************/
775
/* ==================================================================== */
776
/*                        CPL_MULTIPROC_WIN32                           */
777
/*                                                                      */
778
/*    WIN32 Implementation of multiprocessing functions.                */
779
/* ==================================================================== */
780
/************************************************************************/
781
782
/* InitializeCriticalSectionAndSpinCount requires _WIN32_WINNT >= 0x403 */
783
#undef _WIN32_WINNT
784
#define _WIN32_WINNT 0x0500
785
786
#include <windows.h>
787
788
/************************************************************************/
789
/*                             CPLGetNumCPUs()                          */
790
/************************************************************************/
791
792
int CPLGetNumCPUs()
793
{
794
    SYSTEM_INFO info;
795
    GetSystemInfo(&info);
796
    const DWORD dwNum = info.dwNumberOfProcessors;
797
    if (dwNum < 1)
798
        return 1;
799
    return static_cast<int>(dwNum);
800
}
801
802
/************************************************************************/
803
/*                        CPLGetThreadingModel()                        */
804
/************************************************************************/
805
806
const char *CPLGetThreadingModel()
807
808
{
809
    return "win32";
810
}
811
812
/************************************************************************/
813
/*                           CPLCreateMutex()                           */
814
/************************************************************************/
815
816
CPLMutex *CPLCreateMutex()
817
818
{
819
#ifdef USE_WIN32_MUTEX
820
    HANDLE hMutex = CreateMutex(nullptr, TRUE, nullptr);
821
822
    return (CPLMutex *)hMutex;
823
#else
824
825
    // Do not use CPLMalloc() since its debugging infrastructure
826
    // can call the CPL*Mutex functions.
827
    CRITICAL_SECTION *pcs =
828
        static_cast<CRITICAL_SECTION *>(malloc(sizeof(*pcs)));
829
    if (pcs)
830
    {
831
        InitializeCriticalSectionAndSpinCount(pcs, 4000);
832
        EnterCriticalSection(pcs);
833
    }
834
835
    return reinterpret_cast<CPLMutex *>(pcs);
836
#endif
837
}
838
839
CPLMutex *CPLCreateMutexEx(int /* nOptions */)
840
841
{
842
    return CPLCreateMutex();
843
}
844
845
/************************************************************************/
846
/*                          CPLAcquireMutex()                           */
847
/************************************************************************/
848
849
int CPLAcquireMutex(CPLMutex *hMutexIn, double dfWaitInSeconds)
850
851
{
852
#ifdef USE_WIN32_MUTEX
853
    HANDLE hMutex = (HANDLE)hMutexIn;
854
    const DWORD hr =
855
        WaitForSingleObject(hMutex, static_cast<int>(dfWaitInSeconds * 1000));
856
857
    return hr != WAIT_TIMEOUT;
858
#else
859
    CRITICAL_SECTION *pcs = reinterpret_cast<CRITICAL_SECTION *>(hMutexIn);
860
    BOOL ret;
861
862
    if (dfWaitInSeconds >= 1000.0)
863
    {
864
        // We assume this is the synonymous for infinite, so it is more
865
        // efficient to use EnterCriticalSection() directly
866
        EnterCriticalSection(pcs);
867
        ret = TRUE;
868
    }
869
    else
870
    {
871
        while ((ret = TryEnterCriticalSection(pcs)) == 0 &&
872
               dfWaitInSeconds > 0.0)
873
        {
874
            CPLSleep(std::min(dfWaitInSeconds, 0.01));
875
            dfWaitInSeconds -= 0.01;
876
        }
877
    }
878
879
    return ret;
880
#endif
881
}
882
883
/************************************************************************/
884
/*                          CPLReleaseMutex()                           */
885
/************************************************************************/
886
887
void CPLReleaseMutex(CPLMutex *hMutexIn)
888
889
{
890
#ifdef USE_WIN32_MUTEX
891
    HANDLE hMutex = (HANDLE)hMutexIn;
892
893
    ReleaseMutex(hMutex);
894
#else
895
    CRITICAL_SECTION *pcs = reinterpret_cast<CRITICAL_SECTION *>(hMutexIn);
896
897
    LeaveCriticalSection(pcs);
898
#endif
899
}
900
901
/************************************************************************/
902
/*                          CPLDestroyMutex()                           */
903
/************************************************************************/
904
905
void CPLDestroyMutex(CPLMutex *hMutexIn)
906
907
{
908
#ifdef USE_WIN32_MUTEX
909
    HANDLE hMutex = (HANDLE)hMutexIn;
910
911
    CloseHandle(hMutex);
912
#else
913
    CRITICAL_SECTION *pcs = reinterpret_cast<CRITICAL_SECTION *>(hMutexIn);
914
915
    DeleteCriticalSection(pcs);
916
    free(pcs);
917
#endif
918
}
919
920
/************************************************************************/
921
/*                            CPLCreateCond()                           */
922
/************************************************************************/
923
924
struct _WaiterItem
925
{
926
    HANDLE hEvent;
927
    struct _WaiterItem *psNext;
928
};
929
typedef struct _WaiterItem WaiterItem;
930
931
typedef struct
932
{
933
    CPLMutex *hInternalMutex;
934
    WaiterItem *psWaiterList;
935
} Win32Cond;
936
937
CPLCond *CPLCreateCond()
938
{
939
    Win32Cond *psCond = static_cast<Win32Cond *>(malloc(sizeof(Win32Cond)));
940
    if (psCond == nullptr)
941
        return nullptr;
942
    psCond->hInternalMutex = CPLCreateMutex();
943
    if (psCond->hInternalMutex == nullptr)
944
    {
945
        free(psCond);
946
        return nullptr;
947
    }
948
    CPLReleaseMutex(psCond->hInternalMutex);
949
    psCond->psWaiterList = nullptr;
950
    return reinterpret_cast<CPLCond *>(psCond);
951
}
952
953
/************************************************************************/
954
/*                            CPLCondWait()                             */
955
/************************************************************************/
956
957
static void CPLTLSFreeEvent(void *pData)
958
{
959
    CloseHandle(static_cast<HANDLE>(pData));
960
}
961
962
void CPLCondWait(CPLCond *hCond, CPLMutex *hClientMutex)
963
{
964
    CPLCondTimedWait(hCond, hClientMutex, -1);
965
}
966
967
/************************************************************************/
968
/*                         CPLCondTimedWait()                           */
969
/************************************************************************/
970
971
CPLCondTimedWaitReason CPLCondTimedWait(CPLCond *hCond, CPLMutex *hClientMutex,
972
                                        double dfWaitInSeconds)
973
{
974
    Win32Cond *psCond = reinterpret_cast<Win32Cond *>(hCond);
975
976
    HANDLE hEvent = static_cast<HANDLE>(CPLGetTLS(CTLS_WIN32_COND));
977
    if (hEvent == nullptr)
978
    {
979
        hEvent = CreateEvent(nullptr, /* security attributes */
980
                             0,       /* manual reset = no */
981
                             0,       /* initial state = unsignaled */
982
                             nullptr /* no name */);
983
        CPLAssert(hEvent != nullptr);
984
985
        CPLSetTLSWithFreeFunc(CTLS_WIN32_COND, hEvent, CPLTLSFreeEvent);
986
    }
987
988
    /* Insert the waiter into the waiter list of the condition */
989
    CPLAcquireMutex(psCond->hInternalMutex, 1000.0);
990
991
    WaiterItem *psItem = static_cast<WaiterItem *>(malloc(sizeof(WaiterItem)));
992
    CPLAssert(psItem != nullptr);
993
994
    psItem->hEvent = hEvent;
995
    psItem->psNext = psCond->psWaiterList;
996
997
    psCond->psWaiterList = psItem;
998
999
    CPLReleaseMutex(psCond->hInternalMutex);
1000
1001
    // Release the client mutex before waiting for the event being signaled.
1002
    CPLReleaseMutex(hClientMutex);
1003
1004
    // Ideally we would check that we do not get WAIT_FAILED but it is hard
1005
    // to report a failure.
1006
    auto ret = WaitForSingleObject(
1007
        hEvent, dfWaitInSeconds < 0 ? INFINITE
1008
                                    : static_cast<int>(dfWaitInSeconds * 1000));
1009
1010
    // Reacquire the client mutex.
1011
    CPLAcquireMutex(hClientMutex, 1000.0);
1012
1013
    if (ret == WAIT_OBJECT_0)
1014
        return COND_TIMED_WAIT_COND;
1015
    if (ret == WAIT_TIMEOUT)
1016
        return COND_TIMED_WAIT_TIME_OUT;
1017
    return COND_TIMED_WAIT_OTHER;
1018
}
1019
1020
/************************************************************************/
1021
/*                            CPLCondSignal()                           */
1022
/************************************************************************/
1023
1024
void CPLCondSignal(CPLCond *hCond)
1025
{
1026
    Win32Cond *psCond = reinterpret_cast<Win32Cond *>(hCond);
1027
1028
    // Signal the first registered event, and remove it from the list.
1029
    CPLAcquireMutex(psCond->hInternalMutex, 1000.0);
1030
1031
    WaiterItem *psIter = psCond->psWaiterList;
1032
    if (psIter != nullptr)
1033
    {
1034
        SetEvent(psIter->hEvent);
1035
        psCond->psWaiterList = psIter->psNext;
1036
        free(psIter);
1037
    }
1038
1039
    CPLReleaseMutex(psCond->hInternalMutex);
1040
}
1041
1042
/************************************************************************/
1043
/*                           CPLCondBroadcast()                         */
1044
/************************************************************************/
1045
1046
void CPLCondBroadcast(CPLCond *hCond)
1047
{
1048
    Win32Cond *psCond = reinterpret_cast<Win32Cond *>(hCond);
1049
1050
    // Signal all the registered events, and remove them from the list.
1051
    CPLAcquireMutex(psCond->hInternalMutex, 1000.0);
1052
1053
    WaiterItem *psIter = psCond->psWaiterList;
1054
    while (psIter != nullptr)
1055
    {
1056
        WaiterItem *psNext = psIter->psNext;
1057
        SetEvent(psIter->hEvent);
1058
        free(psIter);
1059
        psIter = psNext;
1060
    }
1061
    psCond->psWaiterList = nullptr;
1062
1063
    CPLReleaseMutex(psCond->hInternalMutex);
1064
}
1065
1066
/************************************************************************/
1067
/*                            CPLDestroyCond()                          */
1068
/************************************************************************/
1069
1070
void CPLDestroyCond(CPLCond *hCond)
1071
{
1072
    Win32Cond *psCond = reinterpret_cast<Win32Cond *>(hCond);
1073
    CPLDestroyMutex(psCond->hInternalMutex);
1074
    psCond->hInternalMutex = nullptr;
1075
    CPLAssert(psCond->psWaiterList == nullptr);
1076
    free(psCond);
1077
}
1078
1079
/************************************************************************/
1080
/*                            CPLLockFile()                             */
1081
/************************************************************************/
1082
1083
void *CPLLockFile(const char *pszPath, double dfWaitInSeconds)
1084
1085
{
1086
    char *pszLockFilename =
1087
        static_cast<char *>(CPLMalloc(strlen(pszPath) + 30));
1088
    snprintf(pszLockFilename, strlen(pszPath) + 30, "%s.lock", pszPath);
1089
1090
    // FIXME: use CreateFileW()
1091
    HANDLE hLockFile =
1092
        CreateFileA(pszLockFilename, GENERIC_WRITE, 0, nullptr, CREATE_NEW,
1093
                    FILE_ATTRIBUTE_NORMAL | FILE_FLAG_DELETE_ON_CLOSE, nullptr);
1094
1095
    while (GetLastError() == ERROR_ALREADY_EXISTS && dfWaitInSeconds > 0.0)
1096
    {
1097
        CloseHandle(hLockFile);
1098
        CPLSleep(std::min(dfWaitInSeconds, 0.125));
1099
        dfWaitInSeconds -= 0.125;
1100
1101
        hLockFile = CreateFileA(
1102
            pszLockFilename, GENERIC_WRITE, 0, nullptr, CREATE_NEW,
1103
            FILE_ATTRIBUTE_NORMAL | FILE_FLAG_DELETE_ON_CLOSE, nullptr);
1104
    }
1105
1106
    CPLFree(pszLockFilename);
1107
1108
    if (hLockFile == INVALID_HANDLE_VALUE)
1109
        return nullptr;
1110
1111
    if (GetLastError() == ERROR_ALREADY_EXISTS)
1112
    {
1113
        CloseHandle(hLockFile);
1114
        return nullptr;
1115
    }
1116
1117
    return static_cast<void *>(hLockFile);
1118
}
1119
1120
/************************************************************************/
1121
/*                           CPLUnlockFile()                            */
1122
/************************************************************************/
1123
1124
void CPLUnlockFile(void *hLock)
1125
1126
{
1127
    HANDLE hLockFile = static_cast<HANDLE>(hLock);
1128
1129
    CloseHandle(hLockFile);
1130
}
1131
1132
/************************************************************************/
1133
/*                             CPLGetPID()                              */
1134
/************************************************************************/
1135
1136
GIntBig CPLGetPID()
1137
1138
{
1139
    return static_cast<GIntBig>(GetCurrentThreadId());
1140
}
1141
1142
/************************************************************************/
1143
/*                       CPLStdCallThreadJacket()                       */
1144
/************************************************************************/
1145
1146
typedef struct
1147
{
1148
    void *pAppData;
1149
    CPLThreadFunc pfnMain;
1150
    HANDLE hThread;
1151
} CPLStdCallThreadInfo;
1152
1153
static DWORD WINAPI CPLStdCallThreadJacket(void *pData)
1154
1155
{
1156
    CPLStdCallThreadInfo *psInfo = static_cast<CPLStdCallThreadInfo *>(pData);
1157
1158
    psInfo->pfnMain(psInfo->pAppData);
1159
1160
    if (psInfo->hThread == nullptr)
1161
        CPLFree(psInfo);  // Only for detached threads.
1162
1163
    CPLCleanupTLS();
1164
1165
    return 0;
1166
}
1167
1168
/************************************************************************/
1169
/*                          CPLCreateThread()                           */
1170
/*                                                                      */
1171
/*      The WIN32 CreateThread() call requires an entry point that      */
1172
/*      has __stdcall conventions, so we provide a jacket function      */
1173
/*      to supply that.                                                 */
1174
/************************************************************************/
1175
1176
int CPLCreateThread(CPLThreadFunc pfnMain, void *pThreadArg)
1177
1178
{
1179
    CPLStdCallThreadInfo *psInfo = static_cast<CPLStdCallThreadInfo *>(
1180
        CPLCalloc(sizeof(CPLStdCallThreadInfo), 1));
1181
    psInfo->pAppData = pThreadArg;
1182
    psInfo->pfnMain = pfnMain;
1183
    psInfo->hThread = nullptr;
1184
1185
    DWORD nThreadId = 0;
1186
    HANDLE hThread =
1187
        CreateThread(nullptr, 0, CPLStdCallThreadJacket, psInfo, 0, &nThreadId);
1188
1189
    if (hThread == nullptr)
1190
        return -1;
1191
1192
    CloseHandle(hThread);
1193
1194
    return nThreadId;
1195
}
1196
1197
/************************************************************************/
1198
/*                      CPLCreateJoinableThread()                       */
1199
/************************************************************************/
1200
1201
CPLJoinableThread *CPLCreateJoinableThread(CPLThreadFunc pfnMain,
1202
                                           void *pThreadArg)
1203
1204
{
1205
    CPLStdCallThreadInfo *psInfo = static_cast<CPLStdCallThreadInfo *>(
1206
        CPLCalloc(sizeof(CPLStdCallThreadInfo), 1));
1207
    psInfo->pAppData = pThreadArg;
1208
    psInfo->pfnMain = pfnMain;
1209
1210
    DWORD nThreadId = 0;
1211
    HANDLE hThread =
1212
        CreateThread(nullptr, 0, CPLStdCallThreadJacket, psInfo, 0, &nThreadId);
1213
1214
    if (hThread == nullptr)
1215
        return nullptr;
1216
1217
    psInfo->hThread = hThread;
1218
    return reinterpret_cast<CPLJoinableThread *>(psInfo);
1219
}
1220
1221
/************************************************************************/
1222
/*                          CPLJoinThread()                             */
1223
/************************************************************************/
1224
1225
void CPLJoinThread(CPLJoinableThread *hJoinableThread)
1226
{
1227
    CPLStdCallThreadInfo *psInfo =
1228
        reinterpret_cast<CPLStdCallThreadInfo *>(hJoinableThread);
1229
1230
    WaitForSingleObject(psInfo->hThread, INFINITE);
1231
    CloseHandle(psInfo->hThread);
1232
    CPLFree(psInfo);
1233
}
1234
1235
/************************************************************************/
1236
/*                              CPLSleep()                              */
1237
/************************************************************************/
1238
1239
void CPLSleep(double dfWaitInSeconds)
1240
1241
{
1242
    Sleep(static_cast<DWORD>(dfWaitInSeconds * 1000.0));
1243
}
1244
1245
static bool bTLSKeySetup = false;
1246
static DWORD nTLSKey = 0;
1247
1248
/************************************************************************/
1249
/*                           CPLGetTLSList()                            */
1250
/************************************************************************/
1251
1252
static void **CPLGetTLSList(int *pbMemoryErrorOccurred)
1253
1254
{
1255
    void **papTLSList = nullptr;
1256
1257
    if (pbMemoryErrorOccurred)
1258
        *pbMemoryErrorOccurred = FALSE;
1259
    if (!bTLSKeySetup)
1260
    {
1261
        nTLSKey = TlsAlloc();
1262
        if (nTLSKey == TLS_OUT_OF_INDEXES)
1263
        {
1264
            if (pbMemoryErrorOccurred)
1265
            {
1266
                *pbMemoryErrorOccurred = TRUE;
1267
                fprintf(stderr, "CPLGetTLSList(): TlsAlloc() failed!\n");
1268
                return nullptr;
1269
            }
1270
            CPLEmergencyError("CPLGetTLSList(): TlsAlloc() failed!");
1271
        }
1272
        bTLSKeySetup = true;
1273
    }
1274
1275
    papTLSList = static_cast<void **>(TlsGetValue(nTLSKey));
1276
    if (papTLSList == nullptr)
1277
    {
1278
        papTLSList =
1279
            static_cast<void **>(VSICalloc(sizeof(void *), CTLS_MAX * 2));
1280
        if (papTLSList == nullptr)
1281
        {
1282
            if (pbMemoryErrorOccurred)
1283
            {
1284
                *pbMemoryErrorOccurred = TRUE;
1285
                fprintf(stderr,
1286
                        "CPLGetTLSList() failed to allocate TLS list!\n");
1287
                return nullptr;
1288
            }
1289
            CPLEmergencyError("CPLGetTLSList() failed to allocate TLS list!");
1290
        }
1291
        if (TlsSetValue(nTLSKey, papTLSList) == 0)
1292
        {
1293
            if (pbMemoryErrorOccurred)
1294
            {
1295
                *pbMemoryErrorOccurred = TRUE;
1296
                fprintf(stderr, "CPLGetTLSList(): TlsSetValue() failed!\n");
1297
                return nullptr;
1298
            }
1299
            CPLEmergencyError("CPLGetTLSList(): TlsSetValue() failed!");
1300
        }
1301
    }
1302
1303
    return papTLSList;
1304
}
1305
1306
/************************************************************************/
1307
/*                             CPLFinalizeTLS()                         */
1308
/************************************************************************/
1309
1310
void CPLFinalizeTLS()
1311
{
1312
    CPLCleanupTLS();
1313
}
1314
1315
/************************************************************************/
1316
/*                           CPLCleanupTLS()                            */
1317
/************************************************************************/
1318
1319
void CPLCleanupTLS()
1320
1321
{
1322
    if (!bTLSKeySetup)
1323
        return;
1324
1325
    void **papTLSList = static_cast<void **>(TlsGetValue(nTLSKey));
1326
    if (papTLSList == nullptr)
1327
        return;
1328
1329
    TlsSetValue(nTLSKey, nullptr);
1330
1331
    CPLCleanupTLSList(papTLSList);
1332
}
1333
1334
// endif CPL_MULTIPROC_WIN32
1335
1336
#elif defined(CPL_MULTIPROC_PTHREAD)
1337
1338
#include <pthread.h>
1339
#include <time.h>
1340
#include <unistd.h>
1341
#include <sys/time.h>
1342
1343
#ifdef HAVE_SCHED_GETAFFINITY
1344
#include <sched.h>
1345
#endif
1346
1347
/************************************************************************/
1348
/* ==================================================================== */
1349
/*                        CPL_MULTIPROC_PTHREAD                         */
1350
/*                                                                      */
1351
/*    PTHREAD Implementation of multiprocessing functions.              */
1352
/* ==================================================================== */
1353
/************************************************************************/
1354
1355
/************************************************************************/
1356
/*                             CPLGetNumCPUs()                          */
1357
/************************************************************************/
1358
1359
int CPLGetNumCPUs()
1360
0
{
1361
0
    int nCPUs;
1362
0
#ifdef _SC_NPROCESSORS_ONLN
1363
0
    nCPUs = static_cast<int>(sysconf(_SC_NPROCESSORS_ONLN));
1364
#else
1365
    nCPUs = 1;
1366
#endif
1367
1368
0
#ifdef HAVE_SCHED_GETAFFINITY
1369
0
    if (nCPUs > 1)
1370
0
    {
1371
0
        cpu_set_t *set = CPU_ALLOC(nCPUs);
1372
0
        if (set)
1373
0
        {
1374
0
            size_t sizeof_set = CPU_ALLOC_SIZE(nCPUs);
1375
0
            CPU_ZERO_S(sizeof_set, set);
1376
0
            if (sched_getaffinity(getpid(), sizeof_set, set) == 0)
1377
0
                nCPUs = CPU_COUNT_S(sizeof_set, set);
1378
0
            else
1379
0
                CPLDebug("CPL", "sched_getaffinity() failed");
1380
0
            CPU_FREE(set);
1381
0
        }
1382
0
    }
1383
0
#endif
1384
1385
0
    return nCPUs;
1386
0
}
1387
1388
/************************************************************************/
1389
/*                      CPLCreateOrAcquireMutex()                       */
1390
/************************************************************************/
1391
#ifdef HAVE_GCC_WARNING_ZERO_AS_NULL_POINTER_CONSTANT
1392
#pragma GCC diagnostic push
1393
#pragma GCC diagnostic ignored "-Wzero-as-null-pointer-constant"
1394
#endif
1395
static pthread_mutex_t global_mutex = PTHREAD_MUTEX_INITIALIZER;
1396
#ifdef HAVE_GCC_WARNING_ZERO_AS_NULL_POINTER_CONSTANT
1397
#pragma GCC diagnostic pop
1398
#endif
1399
1400
static CPLMutex *CPLCreateMutexInternal(bool bAlreadyInGlobalLock,
1401
                                        int nOptions);
1402
1403
int CPLCreateOrAcquireMutexEx(CPLMutex **phMutex, double dfWaitInSeconds,
1404
                              int nOptions)
1405
1406
400k
{
1407
400k
    pthread_mutex_lock(&global_mutex);
1408
400k
    if (*phMutex == nullptr)
1409
18
    {
1410
18
        *phMutex = CPLCreateMutexInternal(true, nOptions);
1411
18
        const bool bSuccess = *phMutex != nullptr;
1412
18
        pthread_mutex_unlock(&global_mutex);
1413
18
        if (!bSuccess)
1414
0
            return false;
1415
18
    }
1416
400k
    else
1417
400k
    {
1418
400k
        pthread_mutex_unlock(&global_mutex);
1419
400k
    }
1420
1421
400k
    return CPL_TO_BOOL(CPLAcquireMutex(*phMutex, dfWaitInSeconds));
1422
400k
}
1423
1424
/************************************************************************/
1425
/*                   CPLCreateOrAcquireMutexInternal()                  */
1426
/************************************************************************/
1427
1428
static bool CPLCreateOrAcquireMutexInternal(CPLLock **phLock,
1429
                                            double dfWaitInSeconds,
1430
                                            CPLLockType eType)
1431
0
{
1432
0
    pthread_mutex_lock(&global_mutex);
1433
0
    if (*phLock == nullptr)
1434
0
    {
1435
0
        *phLock = static_cast<CPLLock *>(calloc(1, sizeof(CPLLock)));
1436
0
        if (*phLock)
1437
0
        {
1438
0
            (*phLock)->eType = eType;
1439
0
            (*phLock)->u.hMutex = CPLCreateMutexInternal(
1440
0
                true, eType == LOCK_RECURSIVE_MUTEX ? CPL_MUTEX_RECURSIVE
1441
0
                                                    : CPL_MUTEX_ADAPTIVE);
1442
0
            if ((*phLock)->u.hMutex == nullptr)
1443
0
            {
1444
0
                free(*phLock);
1445
0
                *phLock = nullptr;
1446
0
            }
1447
0
        }
1448
0
        const bool bSuccess = *phLock != nullptr;
1449
0
        pthread_mutex_unlock(&global_mutex);
1450
0
        if (!bSuccess)
1451
0
            return false;
1452
0
    }
1453
0
    else
1454
0
    {
1455
0
        pthread_mutex_unlock(&global_mutex);
1456
0
    }
1457
1458
0
    return CPL_TO_BOOL(CPLAcquireMutex((*phLock)->u.hMutex, dfWaitInSeconds));
1459
0
}
1460
1461
/************************************************************************/
1462
/*                        CPLGetThreadingModel()                        */
1463
/************************************************************************/
1464
1465
const char *CPLGetThreadingModel()
1466
1467
0
{
1468
0
    return "pthread";
1469
0
}
1470
1471
/************************************************************************/
1472
/*                           CPLCreateMutex()                           */
1473
/************************************************************************/
1474
1475
typedef struct _MutexLinkedElt MutexLinkedElt;
1476
1477
struct _MutexLinkedElt
1478
{
1479
    pthread_mutex_t sMutex;
1480
    int nOptions;
1481
    _MutexLinkedElt *psPrev;
1482
    _MutexLinkedElt *psNext;
1483
};
1484
1485
static MutexLinkedElt *psMutexList = nullptr;
1486
1487
static void CPLInitMutex(MutexLinkedElt *psItem)
1488
18
{
1489
18
    if (psItem->nOptions == CPL_MUTEX_REGULAR)
1490
0
    {
1491
0
#ifdef HAVE_GCC_WARNING_ZERO_AS_NULL_POINTER_CONSTANT
1492
0
#pragma GCC diagnostic push
1493
0
#pragma GCC diagnostic ignored "-Wzero-as-null-pointer-constant"
1494
0
#endif
1495
0
        pthread_mutex_t tmp_mutex = PTHREAD_MUTEX_INITIALIZER;
1496
0
#ifdef HAVE_GCC_WARNING_ZERO_AS_NULL_POINTER_CONSTANT
1497
0
#pragma GCC diagnostic pop
1498
0
#endif
1499
0
        psItem->sMutex = tmp_mutex;
1500
0
        return;
1501
0
    }
1502
1503
    // When an adaptive mutex is required, we can safely fallback to regular
1504
    // mutex if we don't have HAVE_PTHREAD_MUTEX_ADAPTIVE_NP.
1505
18
    if (psItem->nOptions == CPL_MUTEX_ADAPTIVE)
1506
0
    {
1507
0
#if defined(HAVE_PTHREAD_MUTEX_ADAPTIVE_NP)
1508
0
        pthread_mutexattr_t attr;
1509
0
        pthread_mutexattr_init(&attr);
1510
0
        pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ADAPTIVE_NP);
1511
0
        pthread_mutex_init(&(psItem->sMutex), &attr);
1512
#else
1513
        pthread_mutex_t tmp_mutex = PTHREAD_MUTEX_INITIALIZER;
1514
        psItem->sMutex = tmp_mutex;
1515
#endif
1516
0
        return;
1517
0
    }
1518
1519
18
#if defined(PTHREAD_MUTEX_RECURSIVE) || defined(HAVE_PTHREAD_MUTEX_RECURSIVE)
1520
18
    {
1521
18
        pthread_mutexattr_t attr;
1522
18
        pthread_mutexattr_init(&attr);
1523
18
        pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
1524
18
        pthread_mutex_init(&(psItem->sMutex), &attr);
1525
18
    }
1526
// BSDs have PTHREAD_MUTEX_RECURSIVE as an enum, not a define.
1527
// But they have #define MUTEX_TYPE_COUNTING_FAST PTHREAD_MUTEX_RECURSIVE
1528
#elif defined(MUTEX_TYPE_COUNTING_FAST)
1529
    {
1530
        pthread_mutexattr_t attr;
1531
        pthread_mutexattr_init(&attr);
1532
        pthread_mutexattr_settype(&attr, MUTEX_TYPE_COUNTING_FAST);
1533
        pthread_mutex_init(&(psItem->sMutex), &attr);
1534
    }
1535
#elif defined(PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP)
1536
    pthread_mutex_t tmp_mutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
1537
    psItem->sMutex = tmp_mutex;
1538
#else
1539
#error "Recursive mutexes apparently unsupported, configure --without-threads"
1540
#endif
1541
18
}
1542
1543
static CPLMutex *CPLCreateMutexInternal(bool bAlreadyInGlobalLock, int nOptions)
1544
18
{
1545
18
    MutexLinkedElt *psItem =
1546
18
        static_cast<MutexLinkedElt *>(malloc(sizeof(MutexLinkedElt)));
1547
18
    if (psItem == nullptr)
1548
0
    {
1549
0
        fprintf(stderr, "CPLCreateMutexInternal() failed.\n");
1550
0
        return nullptr;
1551
0
    }
1552
1553
18
    if (!bAlreadyInGlobalLock)
1554
0
        pthread_mutex_lock(&global_mutex);
1555
18
    psItem->psPrev = nullptr;
1556
18
    psItem->psNext = psMutexList;
1557
18
    if (psMutexList)
1558
12
        psMutexList->psPrev = psItem;
1559
18
    psMutexList = psItem;
1560
18
    if (!bAlreadyInGlobalLock)
1561
0
        pthread_mutex_unlock(&global_mutex);
1562
1563
18
    psItem->nOptions = nOptions;
1564
18
    CPLInitMutex(psItem);
1565
1566
18
    return reinterpret_cast<CPLMutex *>(psItem);
1567
18
}
1568
1569
CPLMutex *CPLCreateMutex()
1570
0
{
1571
0
    CPLMutex *mutex = CPLCreateMutexInternal(false, CPL_MUTEX_RECURSIVE);
1572
0
    if (mutex)
1573
0
        CPLAcquireMutex(mutex, 0);
1574
0
    return mutex;
1575
0
}
1576
1577
CPLMutex *CPLCreateMutexEx(int nOptions)
1578
0
{
1579
0
    CPLMutex *mutex = CPLCreateMutexInternal(false, nOptions);
1580
0
    if (mutex)
1581
0
        CPLAcquireMutex(mutex, 0);
1582
0
    return mutex;
1583
0
}
1584
1585
/************************************************************************/
1586
/*                          CPLAcquireMutex()                           */
1587
/************************************************************************/
1588
1589
int CPLAcquireMutex(CPLMutex *hMutexIn, double /* dfWaitInSeconds */)
1590
400k
{
1591
    // TODO: Need to add timeout support.
1592
400k
    MutexLinkedElt *psItem = reinterpret_cast<MutexLinkedElt *>(hMutexIn);
1593
400k
    const int err = pthread_mutex_lock(&(psItem->sMutex));
1594
1595
400k
    if (err != 0)
1596
0
    {
1597
0
        if (err == EDEADLK)
1598
0
            fprintf(stderr, "CPLAcquireMutex: Error = %d/EDEADLK\n", err);
1599
0
        else
1600
0
            fprintf(stderr, "CPLAcquireMutex: Error = %d (%s)\n", err,
1601
0
                    strerror(err));
1602
1603
0
        return FALSE;
1604
0
    }
1605
1606
400k
    return TRUE;
1607
400k
}
1608
1609
/************************************************************************/
1610
/*                          CPLReleaseMutex()                           */
1611
/************************************************************************/
1612
1613
void CPLReleaseMutex(CPLMutex *hMutexIn)
1614
1615
400k
{
1616
400k
    MutexLinkedElt *psItem = reinterpret_cast<MutexLinkedElt *>(hMutexIn);
1617
400k
    const int err = pthread_mutex_unlock(&(psItem->sMutex));
1618
400k
    if (err != 0)
1619
0
    {
1620
0
        fprintf(stderr, "CPLReleaseMutex: Error = %d (%s)\n", err,
1621
0
                strerror(err));
1622
0
    }
1623
400k
}
1624
1625
/************************************************************************/
1626
/*                          CPLDestroyMutex()                           */
1627
/************************************************************************/
1628
1629
void CPLDestroyMutex(CPLMutex *hMutexIn)
1630
1631
0
{
1632
0
    MutexLinkedElt *psItem = reinterpret_cast<MutexLinkedElt *>(hMutexIn);
1633
0
    const int err = pthread_mutex_destroy(&(psItem->sMutex));
1634
0
    if (err != 0)
1635
0
    {
1636
0
        fprintf(stderr, "CPLDestroyMutex: Error = %d (%s)\n", err,
1637
0
                strerror(err));
1638
0
    }
1639
0
    pthread_mutex_lock(&global_mutex);
1640
0
    if (psItem->psPrev)
1641
0
        psItem->psPrev->psNext = psItem->psNext;
1642
0
    if (psItem->psNext)
1643
0
        psItem->psNext->psPrev = psItem->psPrev;
1644
0
    if (psItem == psMutexList)
1645
0
        psMutexList = psItem->psNext;
1646
0
    pthread_mutex_unlock(&global_mutex);
1647
0
    free(hMutexIn);
1648
0
}
1649
1650
/************************************************************************/
1651
/*                          CPLReinitAllMutex()                         */
1652
/************************************************************************/
1653
1654
// Used by gdalclientserver.cpp just after forking, to avoid
1655
// deadlocks while mixing threads with fork.
1656
void CPLReinitAllMutex();  // TODO(schwehr): Put this in a header.
1657
1658
void CPLReinitAllMutex()
1659
0
{
1660
0
    MutexLinkedElt *psItem = psMutexList;
1661
0
    while (psItem != nullptr)
1662
0
    {
1663
0
        CPLInitMutex(psItem);
1664
0
        psItem = psItem->psNext;
1665
0
    }
1666
0
#ifdef HAVE_GCC_WARNING_ZERO_AS_NULL_POINTER_CONSTANT
1667
0
#pragma GCC diagnostic push
1668
0
#pragma GCC diagnostic ignored "-Wzero-as-null-pointer-constant"
1669
0
#endif
1670
0
    pthread_mutex_t tmp_global_mutex = PTHREAD_MUTEX_INITIALIZER;
1671
0
#ifdef HAVE_GCC_WARNING_ZERO_AS_NULL_POINTER_CONSTANT
1672
0
#pragma GCC diagnostic pop
1673
0
#endif
1674
0
    global_mutex = tmp_global_mutex;
1675
0
}
1676
1677
/************************************************************************/
1678
/*                            CPLCreateCond()                           */
1679
/************************************************************************/
1680
1681
CPLCond *CPLCreateCond()
1682
0
{
1683
0
    pthread_cond_t *pCond =
1684
0
        static_cast<pthread_cond_t *>(malloc(sizeof(pthread_cond_t)));
1685
0
    if (pCond && pthread_cond_init(pCond, nullptr) == 0)
1686
0
        return reinterpret_cast<CPLCond *>(pCond);
1687
0
    fprintf(stderr, "CPLCreateCond() failed.\n");
1688
0
    free(pCond);
1689
0
    return nullptr;
1690
0
}
1691
1692
/************************************************************************/
1693
/*                            CPLCondWait()                             */
1694
/************************************************************************/
1695
1696
void CPLCondWait(CPLCond *hCond, CPLMutex *hMutex)
1697
0
{
1698
0
    pthread_cond_t *pCond = reinterpret_cast<pthread_cond_t *>(hCond);
1699
0
    MutexLinkedElt *psItem = reinterpret_cast<MutexLinkedElt *>(hMutex);
1700
0
    pthread_mutex_t *pMutex = &(psItem->sMutex);
1701
0
    pthread_cond_wait(pCond, pMutex);
1702
0
}
1703
1704
/************************************************************************/
1705
/*                         CPLCondTimedWait()                           */
1706
/************************************************************************/
1707
1708
CPLCondTimedWaitReason CPLCondTimedWait(CPLCond *hCond, CPLMutex *hMutex,
1709
                                        double dfWaitInSeconds)
1710
0
{
1711
0
    pthread_cond_t *pCond = reinterpret_cast<pthread_cond_t *>(hCond);
1712
0
    MutexLinkedElt *psItem = reinterpret_cast<MutexLinkedElt *>(hMutex);
1713
0
    pthread_mutex_t *pMutex = &(psItem->sMutex);
1714
0
    struct timeval tv;
1715
0
    struct timespec ts;
1716
1717
0
    gettimeofday(&tv, nullptr);
1718
0
    ts.tv_sec = time(nullptr) + static_cast<int>(dfWaitInSeconds);
1719
0
    ts.tv_nsec =
1720
0
        static_cast<int>(tv.tv_usec) * 1000 +
1721
0
        static_cast<int>(1000 * 1000 * 1000 * fmod(dfWaitInSeconds, 1));
1722
0
    ts.tv_sec += ts.tv_nsec / (1000 * 1000 * 1000);
1723
0
    ts.tv_nsec %= (1000 * 1000 * 1000);
1724
0
    int ret = pthread_cond_timedwait(pCond, pMutex, &ts);
1725
0
    if (ret == 0)
1726
0
        return COND_TIMED_WAIT_COND;
1727
0
    else if (ret == ETIMEDOUT)
1728
0
        return COND_TIMED_WAIT_TIME_OUT;
1729
0
    else
1730
0
        return COND_TIMED_WAIT_OTHER;
1731
0
}
1732
1733
/************************************************************************/
1734
/*                            CPLCondSignal()                           */
1735
/************************************************************************/
1736
1737
void CPLCondSignal(CPLCond *hCond)
1738
0
{
1739
0
    pthread_cond_t *pCond = reinterpret_cast<pthread_cond_t *>(hCond);
1740
0
    pthread_cond_signal(pCond);
1741
0
}
1742
1743
/************************************************************************/
1744
/*                           CPLCondBroadcast()                         */
1745
/************************************************************************/
1746
1747
void CPLCondBroadcast(CPLCond *hCond)
1748
0
{
1749
0
    pthread_cond_t *pCond = reinterpret_cast<pthread_cond_t *>(hCond);
1750
0
    pthread_cond_broadcast(pCond);
1751
0
}
1752
1753
/************************************************************************/
1754
/*                            CPLDestroyCond()                          */
1755
/************************************************************************/
1756
1757
void CPLDestroyCond(CPLCond *hCond)
1758
0
{
1759
0
    pthread_cond_t *pCond = reinterpret_cast<pthread_cond_t *>(hCond);
1760
0
    pthread_cond_destroy(pCond);
1761
0
    free(hCond);
1762
0
}
1763
1764
/************************************************************************/
1765
/*                            CPLLockFile()                             */
1766
/*                                                                      */
1767
/*      This is really a stub implementation, see first                 */
1768
/*      CPLLockFile() for caveats.                                      */
1769
/************************************************************************/
1770
1771
void *CPLLockFile(const char *pszPath, double dfWaitInSeconds)
1772
1773
0
{
1774
    /* -------------------------------------------------------------------- */
1775
    /*      We use a lock file with a name derived from the file we want    */
1776
    /*      to lock to represent the file being locked.  Note that for      */
1777
    /*      the stub implementation the target file does not even need      */
1778
    /*      to exist to be locked.                                          */
1779
    /* -------------------------------------------------------------------- */
1780
0
    const size_t nLen = strlen(pszPath) + 30;
1781
0
    char *pszLockFilename = static_cast<char *>(CPLMalloc(nLen));
1782
0
    snprintf(pszLockFilename, nLen, "%s.lock", pszPath);
1783
1784
0
    FILE *fpLock = fopen(pszLockFilename, "r");
1785
0
    while (fpLock != nullptr && dfWaitInSeconds > 0.0)
1786
0
    {
1787
0
        fclose(fpLock);
1788
0
        CPLSleep(std::min(dfWaitInSeconds, 0.5));
1789
0
        dfWaitInSeconds -= 0.5;
1790
1791
0
        fpLock = fopen(pszLockFilename, "r");
1792
0
    }
1793
1794
0
    if (fpLock != nullptr)
1795
0
    {
1796
0
        fclose(fpLock);
1797
0
        CPLFree(pszLockFilename);
1798
0
        return nullptr;
1799
0
    }
1800
1801
0
    fpLock = fopen(pszLockFilename, "w");
1802
1803
0
    if (fpLock == nullptr)
1804
0
    {
1805
0
        CPLFree(pszLockFilename);
1806
0
        return nullptr;
1807
0
    }
1808
1809
0
    fwrite("held\n", 1, 5, fpLock);
1810
0
    fclose(fpLock);
1811
1812
0
    return pszLockFilename;
1813
0
}
1814
1815
/************************************************************************/
1816
/*                           CPLUnlockFile()                            */
1817
/************************************************************************/
1818
1819
void CPLUnlockFile(void *hLock)
1820
1821
0
{
1822
0
    char *pszLockFilename = static_cast<char *>(hLock);
1823
1824
0
    if (hLock == nullptr)
1825
0
        return;
1826
1827
0
    VSIUnlink(pszLockFilename);
1828
1829
0
    CPLFree(pszLockFilename);
1830
0
}
1831
1832
/************************************************************************/
1833
/*                             CPLGetPID()                              */
1834
/************************************************************************/
1835
1836
GIntBig CPLGetPID()
1837
1838
5.10k
{
1839
5.10k
    return reinterpret_cast<GIntBig>(reinterpret_cast<void *>(pthread_self()));
1840
5.10k
}
1841
1842
static pthread_key_t oTLSKey;
1843
static pthread_once_t oTLSKeySetup = PTHREAD_ONCE_INIT;
1844
1845
/************************************************************************/
1846
/*                             CPLMake_key()                            */
1847
/************************************************************************/
1848
1849
static void CPLMake_key()
1850
1851
6
{
1852
6
    if (pthread_key_create(&oTLSKey, reinterpret_cast<void (*)(void *)>(
1853
6
                                         CPLCleanupTLSList)) != 0)
1854
0
    {
1855
0
        CPLError(CE_Fatal, CPLE_AppDefined, "pthread_key_create() failed!");
1856
0
    }
1857
6
}
1858
1859
/************************************************************************/
1860
/*                           CPLGetTLSList()                            */
1861
/************************************************************************/
1862
1863
static void **CPLGetTLSList(int *pbMemoryErrorOccurred)
1864
1865
304k
{
1866
304k
    if (pbMemoryErrorOccurred)
1867
277k
        *pbMemoryErrorOccurred = FALSE;
1868
1869
304k
    if (pthread_once(&oTLSKeySetup, CPLMake_key) != 0)
1870
0
    {
1871
0
        if (pbMemoryErrorOccurred)
1872
0
        {
1873
0
            fprintf(stderr, "CPLGetTLSList(): pthread_once() failed!\n");
1874
0
            *pbMemoryErrorOccurred = TRUE;
1875
0
            return nullptr;
1876
0
        }
1877
0
        CPLEmergencyError("CPLGetTLSList(): pthread_once() failed!");
1878
0
    }
1879
1880
304k
    void **papTLSList = static_cast<void **>(pthread_getspecific(oTLSKey));
1881
304k
    if (papTLSList == nullptr)
1882
6
    {
1883
6
        papTLSList =
1884
6
            static_cast<void **>(VSICalloc(sizeof(void *), CTLS_MAX * 2));
1885
6
        if (papTLSList == nullptr)
1886
0
        {
1887
0
            if (pbMemoryErrorOccurred)
1888
0
            {
1889
0
                fprintf(stderr,
1890
0
                        "CPLGetTLSList() failed to allocate TLS list!\n");
1891
0
                *pbMemoryErrorOccurred = TRUE;
1892
0
                return nullptr;
1893
0
            }
1894
0
            CPLEmergencyError("CPLGetTLSList() failed to allocate TLS list!");
1895
0
        }
1896
6
        if (pthread_setspecific(oTLSKey, papTLSList) != 0)
1897
0
        {
1898
0
            if (pbMemoryErrorOccurred)
1899
0
            {
1900
0
                fprintf(stderr,
1901
0
                        "CPLGetTLSList(): pthread_setspecific() failed!\n");
1902
0
                *pbMemoryErrorOccurred = TRUE;
1903
0
                return nullptr;
1904
0
            }
1905
0
            CPLEmergencyError("CPLGetTLSList(): pthread_setspecific() failed!");
1906
0
        }
1907
6
    }
1908
1909
304k
    return papTLSList;
1910
304k
}
1911
1912
/************************************************************************/
1913
/*                       CPLStdCallThreadJacket()                       */
1914
/************************************************************************/
1915
1916
typedef struct
1917
{
1918
    void *pAppData;
1919
    CPLThreadFunc pfnMain;
1920
    pthread_t hThread;
1921
    bool bJoinable;
1922
#ifdef CHECK_THREAD_CAN_ALLOCATE_TLS
1923
    bool bInitSucceeded;
1924
    bool bInitDone;
1925
    pthread_mutex_t sMutex;
1926
    pthread_cond_t sCond;
1927
#endif
1928
} CPLStdCallThreadInfo;
1929
1930
static void *CPLStdCallThreadJacket(void *pData)
1931
1932
0
{
1933
0
    CPLStdCallThreadInfo *psInfo = static_cast<CPLStdCallThreadInfo *>(pData);
1934
1935
#ifdef CHECK_THREAD_CAN_ALLOCATE_TLS
1936
    int bMemoryError = FALSE;
1937
    CPLGetTLSList(&bMemoryError);
1938
    if (bMemoryError)
1939
        goto error;
1940
1941
    assert(pthread_mutex_lock(&(psInfo->sMutex)) == 0);
1942
    psInfo->bInitDone = true;
1943
    assert(pthread_cond_signal(&(psInfo->sCond)) == 0);
1944
    assert(pthread_mutex_unlock(&(psInfo->sMutex)) == 0);
1945
#endif
1946
1947
0
    psInfo->pfnMain(psInfo->pAppData);
1948
1949
0
    if (!psInfo->bJoinable)
1950
0
        CPLFree(psInfo);
1951
1952
0
    return nullptr;
1953
1954
#ifdef CHECK_THREAD_CAN_ALLOCATE_TLS
1955
error:
1956
    assert(pthread_mutex_lock(&(psInfo->sMutex)) == 0);
1957
    psInfo->bInitSucceeded = false;
1958
    psInfo->bInitDone = true;
1959
    assert(pthread_cond_signal(&(psInfo->sCond)) == 0);
1960
    assert(pthread_mutex_unlock(&(psInfo->sMutex)) == 0);
1961
    return nullptr;
1962
#endif
1963
0
}
1964
1965
/************************************************************************/
1966
/*                          CPLCreateThread()                           */
1967
/*                                                                      */
1968
/*      The WIN32 CreateThread() call requires an entry point that      */
1969
/*      has __stdcall conventions, so we provide a jacket function      */
1970
/*      to supply that.                                                 */
1971
/************************************************************************/
1972
1973
int CPLCreateThread(CPLThreadFunc pfnMain, void *pThreadArg)
1974
1975
0
{
1976
0
    CPLStdCallThreadInfo *psInfo = static_cast<CPLStdCallThreadInfo *>(
1977
0
        VSI_CALLOC_VERBOSE(sizeof(CPLStdCallThreadInfo), 1));
1978
0
    if (psInfo == nullptr)
1979
0
        return -1;
1980
0
    psInfo->pAppData = pThreadArg;
1981
0
    psInfo->pfnMain = pfnMain;
1982
0
    psInfo->bJoinable = false;
1983
#ifdef CHECK_THREAD_CAN_ALLOCATE_TLS
1984
    psInfo->bInitSucceeded = true;
1985
    psInfo->bInitDone = false;
1986
    pthread_mutex_t sMutex = PTHREAD_MUTEX_INITIALIZER;
1987
    psInfo->sMutex = sMutex;
1988
    if (pthread_cond_init(&(psInfo->sCond), nullptr) != 0)
1989
    {
1990
        CPLFree(psInfo);
1991
        fprintf(stderr, "CPLCreateThread() failed.\n");
1992
        return -1;
1993
    }
1994
#endif
1995
1996
0
    pthread_attr_t hThreadAttr;
1997
0
    pthread_attr_init(&hThreadAttr);
1998
0
    pthread_attr_setdetachstate(&hThreadAttr, PTHREAD_CREATE_DETACHED);
1999
0
    if (pthread_create(&(psInfo->hThread), &hThreadAttr, CPLStdCallThreadJacket,
2000
0
                       static_cast<void *>(psInfo)) != 0)
2001
0
    {
2002
#ifdef CHECK_THREAD_CAN_ALLOCATE_TLS
2003
        pthread_cond_destroy(&(psInfo->sCond));
2004
#endif
2005
0
        CPLFree(psInfo);
2006
0
        fprintf(stderr, "CPLCreateThread() failed.\n");
2007
0
        return -1;
2008
0
    }
2009
2010
#ifdef CHECK_THREAD_CAN_ALLOCATE_TLS
2011
    bool bInitSucceeded;
2012
    while (true)
2013
    {
2014
        assert(pthread_mutex_lock(&(psInfo->sMutex)) == 0);
2015
        bool bInitDone = psInfo->bInitDone;
2016
        if (!bInitDone)
2017
            assert(pthread_cond_wait(&(psInfo->sCond), &(psInfo->sMutex)) == 0);
2018
        bInitSucceeded = psInfo->bInitSucceeded;
2019
        assert(pthread_mutex_unlock(&(psInfo->sMutex)) == 0);
2020
        if (bInitDone)
2021
            break;
2022
    }
2023
2024
    pthread_cond_destroy(&(psInfo->sCond));
2025
2026
    if (!bInitSucceeded)
2027
    {
2028
        CPLFree(psInfo);
2029
        fprintf(stderr, "CPLCreateThread() failed.\n");
2030
        return -1;
2031
    }
2032
#endif
2033
2034
0
    return 1;  // Can we return the actual thread pid?
2035
0
}
2036
2037
/************************************************************************/
2038
/*                      CPLCreateJoinableThread()                       */
2039
/************************************************************************/
2040
2041
CPLJoinableThread *CPLCreateJoinableThread(CPLThreadFunc pfnMain,
2042
                                           void *pThreadArg)
2043
2044
0
{
2045
0
    CPLStdCallThreadInfo *psInfo = static_cast<CPLStdCallThreadInfo *>(
2046
0
        VSI_CALLOC_VERBOSE(sizeof(CPLStdCallThreadInfo), 1));
2047
0
    if (psInfo == nullptr)
2048
0
        return nullptr;
2049
0
    psInfo->pAppData = pThreadArg;
2050
0
    psInfo->pfnMain = pfnMain;
2051
0
    psInfo->bJoinable = true;
2052
#ifdef CHECK_THREAD_CAN_ALLOCATE_TLS
2053
    psInfo->bInitSucceeded = true;
2054
    psInfo->bInitDone = false;
2055
    pthread_mutex_t sMutex = PTHREAD_MUTEX_INITIALIZER;
2056
    psInfo->sMutex = sMutex;
2057
    {
2058
        int err = pthread_cond_init(&(psInfo->sCond), nullptr);
2059
        if (err != 0)
2060
        {
2061
            CPLFree(psInfo);
2062
            fprintf(stderr, "CPLCreateJoinableThread() failed: %s.\n",
2063
                    strerror(err));
2064
            return nullptr;
2065
        }
2066
    }
2067
#endif
2068
2069
0
    pthread_attr_t hThreadAttr;
2070
0
    pthread_attr_init(&hThreadAttr);
2071
0
    pthread_attr_setdetachstate(&hThreadAttr, PTHREAD_CREATE_JOINABLE);
2072
0
    int err =
2073
0
        pthread_create(&(psInfo->hThread), &hThreadAttr, CPLStdCallThreadJacket,
2074
0
                       static_cast<void *>(psInfo));
2075
0
    if (err != 0)
2076
0
    {
2077
#ifdef CHECK_THREAD_CAN_ALLOCATE_TLS
2078
        pthread_cond_destroy(&(psInfo->sCond));
2079
#endif
2080
0
        CPLFree(psInfo);
2081
0
        fprintf(stderr, "CPLCreateJoinableThread() failed: %s.\n",
2082
0
                strerror(err));
2083
0
        return nullptr;
2084
0
    }
2085
2086
#ifdef CHECK_THREAD_CAN_ALLOCATE_TLS
2087
    bool bInitSucceeded;
2088
    while (true)
2089
    {
2090
        assert(pthread_mutex_lock(&(psInfo->sMutex)) == 0);
2091
        bool bInitDone = psInfo->bInitDone;
2092
        if (!bInitDone)
2093
            assert(pthread_cond_wait(&(psInfo->sCond), &(psInfo->sMutex)) == 0);
2094
        bInitSucceeded = psInfo->bInitSucceeded;
2095
        assert(pthread_mutex_unlock(&(psInfo->sMutex)) == 0);
2096
        if (bInitDone)
2097
            break;
2098
    }
2099
2100
    pthread_cond_destroy(&(psInfo->sCond));
2101
2102
    if (!bInitSucceeded)
2103
    {
2104
        void *status;
2105
        pthread_join(psInfo->hThread, &status);
2106
        CPLFree(psInfo);
2107
        fprintf(stderr, "CPLCreateJoinableThread() failed.\n");
2108
        return nullptr;
2109
    }
2110
#endif
2111
2112
0
    return reinterpret_cast<CPLJoinableThread *>(psInfo);
2113
0
}
2114
2115
/************************************************************************/
2116
/*                          CPLJoinThread()                             */
2117
/************************************************************************/
2118
2119
void CPLJoinThread(CPLJoinableThread *hJoinableThread)
2120
0
{
2121
0
    CPLStdCallThreadInfo *psInfo =
2122
0
        reinterpret_cast<CPLStdCallThreadInfo *>(hJoinableThread);
2123
0
    if (psInfo == nullptr)
2124
0
        return;
2125
2126
0
    void *status;
2127
0
    pthread_join(psInfo->hThread, &status);
2128
2129
0
    CPLFree(psInfo);
2130
0
}
2131
2132
/************************************************************************/
2133
/*                              CPLSleep()                              */
2134
/************************************************************************/
2135
2136
void CPLSleep(double dfWaitInSeconds)
2137
2138
0
{
2139
0
    struct timespec sRequest;
2140
0
    struct timespec sRemain;
2141
2142
0
    sRequest.tv_sec = static_cast<int>(floor(dfWaitInSeconds));
2143
0
    sRequest.tv_nsec =
2144
0
        static_cast<int>((dfWaitInSeconds - sRequest.tv_sec) * 1000000000);
2145
0
    nanosleep(&sRequest, &sRemain);
2146
0
}
2147
2148
/************************************************************************/
2149
/*                             CPLFinalizeTLS()                         */
2150
/************************************************************************/
2151
2152
void CPLFinalizeTLS()
2153
0
{
2154
0
    CPLCleanupTLS();
2155
    // See #5509 for the explanation why this may be needed.
2156
0
    pthread_key_delete(oTLSKey);
2157
0
}
2158
2159
/************************************************************************/
2160
/*                             CPLCleanupTLS()                          */
2161
/************************************************************************/
2162
2163
void CPLCleanupTLS()
2164
2165
0
{
2166
0
    void **papTLSList = static_cast<void **>(pthread_getspecific(oTLSKey));
2167
0
    if (papTLSList == nullptr)
2168
0
        return;
2169
2170
0
    pthread_setspecific(oTLSKey, nullptr);
2171
2172
0
    CPLCleanupTLSList(papTLSList);
2173
0
}
2174
2175
/************************************************************************/
2176
/*                          CPLCreateSpinLock()                         */
2177
/************************************************************************/
2178
2179
#if defined(HAVE_PTHREAD_SPIN_LOCK)
2180
#define HAVE_SPINLOCK_IMPL
2181
2182
struct _CPLSpinLock
2183
{
2184
    pthread_spinlock_t spin;
2185
};
2186
2187
CPLSpinLock *CPLCreateSpinLock()
2188
0
{
2189
0
    CPLSpinLock *psSpin =
2190
0
        static_cast<CPLSpinLock *>(malloc(sizeof(CPLSpinLock)));
2191
0
    if (psSpin != nullptr &&
2192
0
        pthread_spin_init(&(psSpin->spin), PTHREAD_PROCESS_PRIVATE) == 0)
2193
0
    {
2194
0
        return psSpin;
2195
0
    }
2196
0
    else
2197
0
    {
2198
0
        fprintf(stderr, "CPLCreateSpinLock() failed.\n");
2199
0
        free(psSpin);
2200
0
        return nullptr;
2201
0
    }
2202
0
}
2203
2204
/************************************************************************/
2205
/*                        CPLAcquireSpinLock()                          */
2206
/************************************************************************/
2207
2208
int CPLAcquireSpinLock(CPLSpinLock *psSpin)
2209
0
{
2210
0
    return pthread_spin_lock(&(psSpin->spin)) == 0;
2211
0
}
2212
2213
/************************************************************************/
2214
/*                   CPLCreateOrAcquireSpinLockInternal()               */
2215
/************************************************************************/
2216
2217
int CPLCreateOrAcquireSpinLockInternal(CPLLock **ppsLock)
2218
0
{
2219
0
    pthread_mutex_lock(&global_mutex);
2220
0
    if (*ppsLock == nullptr)
2221
0
    {
2222
0
        *ppsLock = static_cast<CPLLock *>(calloc(1, sizeof(CPLLock)));
2223
0
        if (*ppsLock != nullptr)
2224
0
        {
2225
0
            (*ppsLock)->eType = LOCK_SPIN;
2226
0
            (*ppsLock)->u.hSpinLock = CPLCreateSpinLock();
2227
0
            if ((*ppsLock)->u.hSpinLock == nullptr)
2228
0
            {
2229
0
                free(*ppsLock);
2230
0
                *ppsLock = nullptr;
2231
0
            }
2232
0
        }
2233
0
    }
2234
0
    pthread_mutex_unlock(&global_mutex);
2235
    // coverity[missing_unlock]
2236
0
    return (*ppsLock != nullptr && CPLAcquireSpinLock((*ppsLock)->u.hSpinLock));
2237
0
}
2238
2239
/************************************************************************/
2240
/*                       CPLReleaseSpinLock()                           */
2241
/************************************************************************/
2242
2243
void CPLReleaseSpinLock(CPLSpinLock *psSpin)
2244
0
{
2245
0
    pthread_spin_unlock(&(psSpin->spin));
2246
0
}
2247
2248
/************************************************************************/
2249
/*                        CPLDestroySpinLock()                          */
2250
/************************************************************************/
2251
2252
void CPLDestroySpinLock(CPLSpinLock *psSpin)
2253
0
{
2254
0
    pthread_spin_destroy(&(psSpin->spin));
2255
0
    free(psSpin);
2256
0
}
2257
#endif  // HAVE_PTHREAD_SPIN_LOCK
2258
2259
#endif  // def CPL_MULTIPROC_PTHREAD
2260
2261
/************************************************************************/
2262
/*                             CPLGetTLS()                              */
2263
/************************************************************************/
2264
2265
void *CPLGetTLS(int nIndex)
2266
2267
27.7k
{
2268
27.7k
    void **l_papTLSList = CPLGetTLSList(nullptr);
2269
2270
27.7k
    CPLAssert(nIndex >= 0 && nIndex < CTLS_MAX);
2271
2272
27.7k
    return l_papTLSList[nIndex];
2273
27.7k
}
2274
2275
/************************************************************************/
2276
/*                            CPLGetTLSEx()                             */
2277
/************************************************************************/
2278
2279
void *CPLGetTLSEx(int nIndex, int *pbMemoryErrorOccurred)
2280
2281
277k
{
2282
277k
    void **l_papTLSList = CPLGetTLSList(pbMemoryErrorOccurred);
2283
277k
    if (l_papTLSList == nullptr)
2284
0
        return nullptr;
2285
2286
277k
    CPLAssert(nIndex >= 0 && nIndex < CTLS_MAX);
2287
2288
277k
    return l_papTLSList[nIndex];
2289
277k
}
2290
2291
/************************************************************************/
2292
/*                             CPLSetTLS()                              */
2293
/************************************************************************/
2294
2295
void CPLSetTLS(int nIndex, void *pData, int bFreeOnExit)
2296
2297
13
{
2298
13
    CPLSetTLSWithFreeFunc(nIndex, pData, (bFreeOnExit) ? CPLFree : nullptr);
2299
13
}
2300
2301
/************************************************************************/
2302
/*                      CPLSetTLSWithFreeFunc()                         */
2303
/************************************************************************/
2304
2305
// Warning: The CPLTLSFreeFunc must not in any case directly or indirectly
2306
// use or fetch any TLS data, or a terminating thread will hang!
2307
void CPLSetTLSWithFreeFunc(int nIndex, void *pData, CPLTLSFreeFunc pfnFree)
2308
2309
13
{
2310
13
    void **l_papTLSList = CPLGetTLSList(nullptr);
2311
2312
13
    CPLAssert(nIndex >= 0 && nIndex < CTLS_MAX);
2313
2314
13
    l_papTLSList[nIndex] = pData;
2315
13
    l_papTLSList[CTLS_MAX + nIndex] = reinterpret_cast<void *>(pfnFree);
2316
13
}
2317
2318
/************************************************************************/
2319
/*                      CPLSetTLSWithFreeFuncEx()                       */
2320
/************************************************************************/
2321
2322
// Warning: the CPLTLSFreeFunc must not in any case directly or indirectly
2323
// use or fetch any TLS data, or a terminating thread will hang!
2324
void CPLSetTLSWithFreeFuncEx(int nIndex, void *pData, CPLTLSFreeFunc pfnFree,
2325
                             int *pbMemoryErrorOccurred)
2326
2327
0
{
2328
0
    void **l_papTLSList = CPLGetTLSList(pbMemoryErrorOccurred);
2329
2330
0
    CPLAssert(nIndex >= 0 && nIndex < CTLS_MAX);
2331
2332
0
    l_papTLSList[nIndex] = pData;
2333
0
    l_papTLSList[CTLS_MAX + nIndex] = reinterpret_cast<void *>(pfnFree);
2334
0
}
2335
#ifndef HAVE_SPINLOCK_IMPL
2336
2337
// No spinlock specific API? Fallback to mutex.
2338
2339
/************************************************************************/
2340
/*                          CPLCreateSpinLock()                         */
2341
/************************************************************************/
2342
2343
CPLSpinLock *CPLCreateSpinLock(void)
2344
{
2345
    CPLSpinLock *psSpin = reinterpret_cast<CPLSpinLock *>(CPLCreateMutex());
2346
    if (psSpin)
2347
        CPLReleaseSpinLock(psSpin);
2348
    return psSpin;
2349
}
2350
2351
/************************************************************************/
2352
/*                     CPLCreateOrAcquireSpinLock()                     */
2353
/************************************************************************/
2354
2355
int CPLCreateOrAcquireSpinLockInternal(CPLLock **ppsLock)
2356
{
2357
    return CPLCreateOrAcquireMutexInternal(ppsLock, 1000, LOCK_ADAPTIVE_MUTEX);
2358
}
2359
2360
/************************************************************************/
2361
/*                        CPLAcquireSpinLock()                          */
2362
/************************************************************************/
2363
2364
int CPLAcquireSpinLock(CPLSpinLock *psSpin)
2365
{
2366
    return CPLAcquireMutex(reinterpret_cast<CPLMutex *>(psSpin), 1000);
2367
}
2368
2369
/************************************************************************/
2370
/*                       CPLReleaseSpinLock()                           */
2371
/************************************************************************/
2372
2373
void CPLReleaseSpinLock(CPLSpinLock *psSpin)
2374
{
2375
    CPLReleaseMutex(reinterpret_cast<CPLMutex *>(psSpin));
2376
}
2377
2378
/************************************************************************/
2379
/*                        CPLDestroySpinLock()                          */
2380
/************************************************************************/
2381
2382
void CPLDestroySpinLock(CPLSpinLock *psSpin)
2383
{
2384
    CPLDestroyMutex(reinterpret_cast<CPLMutex *>(psSpin));
2385
}
2386
2387
#endif  // HAVE_SPINLOCK_IMPL
2388
2389
/************************************************************************/
2390
/*                            CPLCreateLock()                           */
2391
/************************************************************************/
2392
2393
CPLLock *CPLCreateLock(CPLLockType eType)
2394
0
{
2395
0
    switch (eType)
2396
0
    {
2397
0
        case LOCK_RECURSIVE_MUTEX:
2398
0
        case LOCK_ADAPTIVE_MUTEX:
2399
0
        {
2400
0
            CPLMutex *hMutex = CPLCreateMutexEx(eType == LOCK_RECURSIVE_MUTEX
2401
0
                                                    ? CPL_MUTEX_RECURSIVE
2402
0
                                                    : CPL_MUTEX_ADAPTIVE);
2403
0
            if (!hMutex)
2404
0
                return nullptr;
2405
0
            CPLReleaseMutex(hMutex);
2406
0
            CPLLock *psLock = static_cast<CPLLock *>(malloc(sizeof(CPLLock)));
2407
0
            if (psLock == nullptr)
2408
0
            {
2409
0
                fprintf(stderr, "CPLCreateLock() failed.\n");
2410
0
                CPLDestroyMutex(hMutex);
2411
0
                return nullptr;
2412
0
            }
2413
0
            psLock->eType = eType;
2414
0
            psLock->u.hMutex = hMutex;
2415
0
#ifdef DEBUG_CONTENTION
2416
0
            psLock->bDebugPerf = false;
2417
0
            psLock->bDebugPerfAsked = false;
2418
0
            psLock->nCurrentHolders = 0;
2419
0
            psLock->nStartTime = 0;
2420
0
#endif
2421
0
            return psLock;
2422
0
        }
2423
0
        case LOCK_SPIN:
2424
0
        {
2425
0
            CPLSpinLock *hSpinLock = CPLCreateSpinLock();
2426
0
            if (!hSpinLock)
2427
0
                return nullptr;
2428
0
            CPLLock *psLock = static_cast<CPLLock *>(malloc(sizeof(CPLLock)));
2429
0
            if (psLock == nullptr)
2430
0
            {
2431
0
                fprintf(stderr, "CPLCreateLock() failed.\n");
2432
0
                CPLDestroySpinLock(hSpinLock);
2433
0
                return nullptr;
2434
0
            }
2435
0
            psLock->eType = eType;
2436
0
            psLock->u.hSpinLock = hSpinLock;
2437
0
#ifdef DEBUG_CONTENTION
2438
0
            psLock->bDebugPerf = false;
2439
0
            psLock->bDebugPerfAsked = false;
2440
0
            psLock->nCurrentHolders = 0;
2441
0
            psLock->nStartTime = 0;
2442
0
#endif
2443
0
            return psLock;
2444
0
        }
2445
0
        default:
2446
0
            CPLAssert(false);
2447
0
            return nullptr;
2448
0
    }
2449
0
}
2450
2451
/************************************************************************/
2452
/*                       CPLCreateOrAcquireLock()                       */
2453
/************************************************************************/
2454
2455
int CPLCreateOrAcquireLock(CPLLock **ppsLock, CPLLockType eType)
2456
0
{
2457
0
#ifdef DEBUG_CONTENTION
2458
0
    GUIntBig nStartTime = 0;
2459
0
    if ((*ppsLock) && (*ppsLock)->bDebugPerfAsked)
2460
0
        nStartTime = CPLrdtsc();
2461
0
#endif
2462
0
    int ret = 0;
2463
2464
0
    switch (eType)
2465
0
    {
2466
0
        case LOCK_RECURSIVE_MUTEX:
2467
0
        case LOCK_ADAPTIVE_MUTEX:
2468
0
        {
2469
0
            ret = CPLCreateOrAcquireMutexInternal(ppsLock, 1000, eType);
2470
0
            break;
2471
0
        }
2472
0
        case LOCK_SPIN:
2473
0
        {
2474
0
            ret = CPLCreateOrAcquireSpinLockInternal(ppsLock);
2475
0
            break;
2476
0
        }
2477
0
        default:
2478
0
            CPLAssert(false);
2479
0
            return FALSE;
2480
0
    }
2481
0
#ifdef DEBUG_CONTENTION
2482
0
    if (ret && (*ppsLock)->bDebugPerfAsked &&
2483
0
        CPLAtomicInc(&((*ppsLock)->nCurrentHolders)) == 1)
2484
0
    {
2485
0
        (*ppsLock)->bDebugPerf = true;
2486
0
        (*ppsLock)->nStartTime = nStartTime;
2487
0
    }
2488
0
#endif
2489
0
    return ret;
2490
0
}
2491
2492
/************************************************************************/
2493
/*                          CPLAcquireLock()                            */
2494
/************************************************************************/
2495
2496
int CPLAcquireLock(CPLLock *psLock)
2497
0
{
2498
0
#ifdef DEBUG_CONTENTION
2499
0
    GUIntBig nStartTime = 0;
2500
0
    if (psLock->bDebugPerfAsked)
2501
0
        nStartTime = CPLrdtsc();
2502
0
#endif
2503
0
    int ret;
2504
0
    if (psLock->eType == LOCK_SPIN)
2505
0
        ret = CPLAcquireSpinLock(psLock->u.hSpinLock);
2506
0
    else
2507
0
        ret = CPLAcquireMutex(psLock->u.hMutex, 1000);
2508
0
#ifdef DEBUG_CONTENTION
2509
0
    if (ret && psLock->bDebugPerfAsked &&
2510
0
        CPLAtomicInc(&(psLock->nCurrentHolders)) == 1)
2511
0
    {
2512
0
        psLock->bDebugPerf = true;
2513
0
        psLock->nStartTime = nStartTime;
2514
0
    }
2515
0
#endif
2516
0
    return ret;
2517
0
}
2518
2519
/************************************************************************/
2520
/*                         CPLReleaseLock()                             */
2521
/************************************************************************/
2522
2523
void CPLReleaseLock(CPLLock *psLock)
2524
0
{
2525
0
#ifdef DEBUG_CONTENTION
2526
0
    bool bHitMaxDiff = false;
2527
0
    GIntBig nMaxDiff = 0;
2528
0
    double dfAvgDiff = 0;
2529
0
    if (psLock->bDebugPerf && CPLAtomicDec(&(psLock->nCurrentHolders)) == 0)
2530
0
    {
2531
0
        const GUIntBig nStopTime = CPLrdtscp();
2532
        // coverity[missing_lock:FALSE]
2533
0
        const GIntBig nDiffTime =
2534
0
            static_cast<GIntBig>(nStopTime - psLock->nStartTime);
2535
0
        if (nDiffTime > psLock->nMaxDiff)
2536
0
        {
2537
0
            bHitMaxDiff = true;
2538
0
            psLock->nMaxDiff = nDiffTime;
2539
0
        }
2540
0
        nMaxDiff = psLock->nMaxDiff;
2541
0
        psLock->nIters++;
2542
0
        psLock->dfAvgDiff += (nDiffTime - psLock->dfAvgDiff) / psLock->nIters;
2543
0
        dfAvgDiff = psLock->dfAvgDiff;
2544
0
    }
2545
0
#endif
2546
0
    if (psLock->eType == LOCK_SPIN)
2547
0
        CPLReleaseSpinLock(psLock->u.hSpinLock);
2548
0
    else
2549
0
        CPLReleaseMutex(psLock->u.hMutex);
2550
0
#ifdef DEBUG_CONTENTION
2551
0
    if (psLock->bDebugPerf &&
2552
0
        (bHitMaxDiff || (psLock->nIters % 1000000) == (1000000 - 1)))
2553
0
    {
2554
0
        CPLDebug("LOCK", "Lock contention : max = " CPL_FRMT_GIB ", avg = %.0f",
2555
0
                 nMaxDiff, dfAvgDiff);
2556
0
    }
2557
0
#endif
2558
0
}
2559
2560
/************************************************************************/
2561
/*                          CPLDestroyLock()                            */
2562
/************************************************************************/
2563
2564
void CPLDestroyLock(CPLLock *psLock)
2565
0
{
2566
0
    if (psLock->eType == LOCK_SPIN)
2567
0
        CPLDestroySpinLock(psLock->u.hSpinLock);
2568
0
    else
2569
0
        CPLDestroyMutex(psLock->u.hMutex);
2570
0
    free(psLock);
2571
0
}
2572
2573
/************************************************************************/
2574
/*                       CPLLockSetDebugPerf()                          */
2575
/************************************************************************/
2576
2577
#ifdef DEBUG_CONTENTION
2578
void CPLLockSetDebugPerf(CPLLock *psLock, int bEnableIn)
2579
0
{
2580
0
    psLock->bDebugPerfAsked = CPL_TO_BOOL(bEnableIn);
2581
0
}
2582
#else
2583
void CPLLockSetDebugPerf(CPLLock * /* psLock */, int bEnableIn)
2584
{
2585
    if (!bEnableIn)
2586
        return;
2587
2588
    static bool bOnce = false;
2589
    if (!bOnce)
2590
    {
2591
        bOnce = true;
2592
        CPLDebug("LOCK", "DEBUG_CONTENTION not available");
2593
    }
2594
}
2595
#endif
2596
2597
/************************************************************************/
2598
/*                           CPLLockHolder()                            */
2599
/************************************************************************/
2600
2601
CPLLockHolder::CPLLockHolder(CPLLock **phLock, CPLLockType eType,
2602
                             const char *pszFileIn, int nLineIn)
2603
2604
0
{
2605
0
#ifndef MUTEX_NONE
2606
0
    pszFile = pszFileIn;
2607
0
    nLine = nLineIn;
2608
2609
#ifdef DEBUG_MUTEX
2610
    // XXX: There is no way to use CPLDebug() here because it works with
2611
    // mutexes itself so we will fall in infinite recursion. Good old
2612
    // fprintf() will do the job right.
2613
    fprintf(stderr, "CPLLockHolder: Request %p for pid %ld at %d/%s.\n",
2614
            *phLock, static_cast<long>(CPLGetPID()), nLine, pszFile);
2615
#endif
2616
2617
0
    if (!CPLCreateOrAcquireLock(phLock, eType))
2618
0
    {
2619
0
        fprintf(stderr, "CPLLockHolder: Failed to acquire lock!\n");
2620
0
        hLock = nullptr;
2621
0
    }
2622
0
    else
2623
0
    {
2624
#ifdef DEBUG_MUTEX
2625
        fprintf(stderr, "CPLLockHolder: Acquired %p for pid %ld at %d/%s.\n",
2626
                *phLock, static_cast<long>(CPLGetPID()), nLine, pszFile);
2627
#endif
2628
2629
0
        hLock = *phLock;
2630
0
    }
2631
0
#endif  // ndef MUTEX_NONE
2632
0
}
2633
2634
/************************************************************************/
2635
/*                           CPLLockHolder()                            */
2636
/************************************************************************/
2637
2638
CPLLockHolder::CPLLockHolder(CPLLock *hLockIn, const char *pszFileIn,
2639
                             int nLineIn)
2640
2641
0
{
2642
0
#ifndef MUTEX_NONE
2643
0
    pszFile = pszFileIn;
2644
0
    nLine = nLineIn;
2645
0
    hLock = hLockIn;
2646
2647
0
    if (hLock != nullptr)
2648
0
    {
2649
0
        if (!CPLAcquireLock(hLock))
2650
0
        {
2651
0
            fprintf(stderr, "CPLLockHolder: Failed to acquire lock!\n");
2652
0
            hLock = nullptr;
2653
0
        }
2654
0
    }
2655
0
#endif  // ndef MUTEX_NONE
2656
0
}
2657
2658
/************************************************************************/
2659
/*                          ~CPLLockHolder()                            */
2660
/************************************************************************/
2661
2662
CPLLockHolder::~CPLLockHolder()
2663
2664
0
{
2665
0
#ifndef MUTEX_NONE
2666
0
    if (hLock != nullptr)
2667
0
    {
2668
#ifdef DEBUG_MUTEX
2669
        fprintf(stderr, "~CPLLockHolder: Release %p for pid %ld at %d/%s.\n",
2670
                hLock, static_cast<long>(CPLGetPID()), nLine, pszFile);
2671
#endif
2672
0
        CPLReleaseLock(hLock);
2673
0
    }
2674
0
#endif  // ndef MUTEX_NONE
2675
0
}
2676
2677
/************************************************************************/
2678
/*                       CPLGetCurrentProcessID()                       */
2679
/************************************************************************/
2680
2681
#ifdef CPL_MULTIPROC_WIN32
2682
2683
int CPLGetCurrentProcessID()
2684
{
2685
    return GetCurrentProcessId();
2686
}
2687
2688
#else
2689
2690
#include <sys/types.h>
2691
#include <unistd.h>
2692
2693
int CPLGetCurrentProcessID()
2694
19.4k
{
2695
19.4k
    return getpid();
2696
19.4k
}
2697
2698
#endif