• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

OSGeo / gdal / 15899162844

26 Jun 2025 10:14AM UTC coverage: 71.088% (+0.004%) from 71.084%
15899162844

Pull #12623

github

web-flow
Merge c704a8392 into f5cb024d4
Pull Request #12623: gdal raster overview add: add a --overview-src option

209 of 244 new or added lines in 5 files covered. (85.66%)

96 existing lines in 44 files now uncovered.

574014 of 807474 relevant lines covered (71.09%)

250815.03 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

79.07
/port/cpl_multiproc.cpp
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) && !defined(__COVERITY__) &&                                \
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
    __asm__ volatile("xchgq %%rbx, %q1\n"                                      \
83
                     "cpuid\n"                                                 \
84
                     "xchgq %%rbx, %q1"                                        \
85
                     : "=a"(a), "=r"(b), "=c"(c), "=d"(d)                      \
86
                     : "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()
1,952,520✔
97
{
98
    unsigned int a;
99
    unsigned int d;
100
    unsigned int unused1;
101
    unsigned int unused2;
102
    unsigned int unused3;
103
    unsigned int unused4;
104
    GCC_CPUID(0, unused1, unused2, unused3, unused4);
1,952,520✔
105
    __asm__ volatile("rdtsc" : "=a"(a), "=d"(d));
1,952,520✔
106
    return static_cast<GUIntBig>(a) | (static_cast<GUIntBig>(d) << 32);
1,952,510✔
107
}
108

109
static GUIntBig CPLrdtscp()
1,952,520✔
110
{
111
    unsigned int a;
112
    unsigned int d;
113
    unsigned int unused1;
114
    unsigned int unused2;
115
    unsigned int unused3;
116
    unsigned int unused4;
117
    __asm__ volatile("rdtscp" : "=a"(a), "=d"(d));
1,952,520✔
118
    GCC_CPUID(0, unused1, unused2, unused3, unused4);
1,952,520✔
119
    return static_cast<GUIntBig>(a) | (static_cast<GUIntBig>(d) << 32);
1,952,520✔
120
}
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,
70,489,900✔
155
                               const char *pszFileIn, int nLineIn, int nOptions)
70,489,900✔
156
    : hMutex(nullptr), pszFile(pszFileIn), nLine(nLineIn)
70,489,900✔
157
{
158
    if (phMutex == nullptr)
70,489,900✔
159
    {
160
        fprintf(stderr, "CPLMutexHolder: phMutex )) NULL !\n");
×
161
        hMutex = nullptr;
×
162
        return;
×
163
    }
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
    (void)pszFile;
174
    (void)nLine;
175
#endif
176

177
    if (!CPLCreateOrAcquireMutexEx(phMutex, dfWaitInSeconds, nOptions))
70,489,900✔
178
    {
179
        fprintf(stderr, "CPLMutexHolder: Failed to acquire mutex!\n");
15✔
180
        hMutex = nullptr;
×
181
    }
182
    else
183
    {
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
        hMutex = *phMutex;
70,496,000✔
190
    }
191
}
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,
5,267✔
207
                                           double dfWaitInSeconds)
208
{
209
    if (hMutexIn && !CPLAcquireMutex(hMutexIn, dfWaitInSeconds))
5,267✔
210
    {
211
        fprintf(stderr, "CPLMutexHolder: Failed to acquire mutex!\n");
×
212
        return nullptr;
×
213
    }
214
    return hMutexIn;
5,267✔
215
}
216

217
CPLMutexHolder::CPLMutexHolder(CPLMutex *hMutexIn, double dfWaitInSeconds,
5,267✔
218
                               const char *pszFileIn, int nLineIn)
5,267✔
219
    : hMutex(GetMutexHolderMutexMember(hMutexIn, dfWaitInSeconds)),
5,267✔
220
      pszFile(pszFileIn), nLine(nLineIn)
5,267✔
221
{
222
}
5,267✔
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()
141,000,000✔
235
{
236
    if (hMutex != nullptr)
70,501,100✔
237
    {
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
        CPLReleaseMutex(hMutex);
70,501,100✔
243
    }
244
}
70,498,400✔
245
#endif  // ndef MUTEX_NONE
246

247
int CPLCreateOrAcquireMutex(CPLMutex **phMutex, double dfWaitInSeconds)
2,055,310✔
248
{
249
    return CPLCreateOrAcquireMutexEx(phMutex, dfWaitInSeconds,
2,055,310✔
250
                                     CPL_MUTEX_RECURSIVE);
2,055,360✔
251
}
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()
1,540✔
412
{
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
}
1,540✔
425

426
/************************************************************************/
427
/*                        CPLCleanupTLSList()                           */
428
/*                                                                      */
429
/*      Free resources associated with a TLS vector (implementation     */
430
/*      independent).                                                   */
431
/************************************************************************/
432

433
static void CPLCleanupTLSList(void **papTLSList)
3,240✔
434

435
{
436
#ifdef DEBUG_VERBOSE
437
    printf("CPLCleanupTLSList(%p)\n", papTLSList); /*ok*/
438
#endif
439

440
    if (papTLSList == nullptr)
3,240✔
441
        return;
×
442

443
    for (int i = 0; i < CTLS_MAX; i++)
106,920✔
444
    {
445
        if (papTLSList[i] != nullptr && papTLSList[i + CTLS_MAX] != nullptr)
103,680✔
446
        {
447
            CPLTLSFreeFunc pfnFree =
6,976✔
448
                reinterpret_cast<CPLTLSFreeFunc>(papTLSList[i + CTLS_MAX]);
6,976✔
449
            pfnFree(papTLSList[i]);
6,976✔
450
            papTLSList[i] = nullptr;
6,976✔
451
        }
452
    }
453

454
    CPLFree(papTLSList);
3,240✔
455
}
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()
4,832✔
1360
{
1361
    int nCPUs;
1362
#ifdef _SC_NPROCESSORS_ONLN
1363
    nCPUs = static_cast<int>(sysconf(_SC_NPROCESSORS_ONLN));
4,832✔
1364
#else
1365
    nCPUs = 1;
1366
#endif
1367

1368
#ifdef HAVE_SCHED_GETAFFINITY
1369
    if (nCPUs > 1)
4,832✔
1370
    {
1371
        cpu_set_t *set = CPU_ALLOC(nCPUs);
4,832✔
1372
        if (set)
4,832✔
1373
        {
1374
            size_t sizeof_set = CPU_ALLOC_SIZE(nCPUs);
4,832✔
1375
            CPU_ZERO_S(sizeof_set, set);
4,832✔
1376
            if (sched_getaffinity(getpid(), sizeof_set, set) == 0)
4,832✔
1377
                nCPUs = CPU_COUNT_S(sizeof_set, set);
4,832✔
1378
            else
1379
                CPLDebug("CPL", "sched_getaffinity() failed");
×
1380
            CPU_FREE(set);
4,832✔
1381
        }
1382
    }
1383
#endif
1384

1385
    return nCPUs;
4,832✔
1386
}
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,
72,544,600✔
1404
                              int nOptions)
1405

1406
{
1407
    pthread_mutex_lock(&global_mutex);
72,544,600✔
1408
    if (*phMutex == nullptr)
72,551,700✔
1409
    {
1410
        *phMutex = CPLCreateMutexInternal(true, nOptions);
39,047✔
1411
        const bool bSuccess = *phMutex != nullptr;
39,047✔
1412
        pthread_mutex_unlock(&global_mutex);
39,047✔
1413
        if (!bSuccess)
39,047✔
1414
            return false;
×
1415
    }
1416
    else
1417
    {
1418
        pthread_mutex_unlock(&global_mutex);
72,512,700✔
1419
    }
1420

1421
    return CPL_TO_BOOL(CPLAcquireMutex(*phMutex, dfWaitInSeconds));
72,548,000✔
1422
}
1423

1424
/************************************************************************/
1425
/*                   CPLCreateOrAcquireMutexInternal()                  */
1426
/************************************************************************/
1427

1428
static bool CPLCreateOrAcquireMutexInternal(CPLLock **phLock,
4,994✔
1429
                                            double dfWaitInSeconds,
1430
                                            CPLLockType eType)
1431
{
1432
    pthread_mutex_lock(&global_mutex);
4,994✔
1433
    if (*phLock == nullptr)
4,994✔
1434
    {
1435
        *phLock = static_cast<CPLLock *>(calloc(1, sizeof(CPLLock)));
513✔
1436
        if (*phLock)
513✔
1437
        {
1438
            (*phLock)->eType = eType;
513✔
1439
            (*phLock)->u.hMutex = CPLCreateMutexInternal(
1,026✔
1440
                true, eType == LOCK_RECURSIVE_MUTEX ? CPL_MUTEX_RECURSIVE
513✔
1441
                                                    : CPL_MUTEX_ADAPTIVE);
1442
            if ((*phLock)->u.hMutex == nullptr)
513✔
1443
            {
1444
                free(*phLock);
×
1445
                *phLock = nullptr;
×
1446
            }
1447
        }
1448
        const bool bSuccess = *phLock != nullptr;
513✔
1449
        pthread_mutex_unlock(&global_mutex);
513✔
1450
        if (!bSuccess)
513✔
1451
            return false;
×
1452
    }
1453
    else
1454
    {
1455
        pthread_mutex_unlock(&global_mutex);
4,481✔
1456
    }
1457

1458
    return CPL_TO_BOOL(CPLAcquireMutex((*phLock)->u.hMutex, dfWaitInSeconds));
4,994✔
1459
}
1460

1461
/************************************************************************/
1462
/*                        CPLGetThreadingModel()                        */
1463
/************************************************************************/
1464

1465
const char *CPLGetThreadingModel()
29✔
1466

1467
{
1468
    return "pthread";
29✔
1469
}
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)
523,611✔
1488
{
1489
    if (psItem->nOptions == CPL_MUTEX_REGULAR)
523,611✔
1490
    {
1491
#ifdef HAVE_GCC_WARNING_ZERO_AS_NULL_POINTER_CONSTANT
1492
#pragma GCC diagnostic push
1493
#pragma GCC diagnostic ignored "-Wzero-as-null-pointer-constant"
1494
#endif
1495
        pthread_mutex_t tmp_mutex = PTHREAD_MUTEX_INITIALIZER;
×
1496
#ifdef HAVE_GCC_WARNING_ZERO_AS_NULL_POINTER_CONSTANT
1497
#pragma GCC diagnostic pop
1498
#endif
1499
        psItem->sMutex = tmp_mutex;
×
1500
        return;
×
1501
    }
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
    if (psItem->nOptions == CPL_MUTEX_ADAPTIVE)
523,611✔
1506
    {
1507
#if defined(HAVE_PTHREAD_MUTEX_ADAPTIVE_NP)
1508
        pthread_mutexattr_t attr;
1509
        pthread_mutexattr_init(&attr);
584✔
1510
        pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ADAPTIVE_NP);
584✔
1511
        pthread_mutex_init(&(psItem->sMutex), &attr);
584✔
1512
#else
1513
        pthread_mutex_t tmp_mutex = PTHREAD_MUTEX_INITIALIZER;
1514
        psItem->sMutex = tmp_mutex;
1515
#endif
1516
        return;
584✔
1517
    }
1518

1519
#if defined(PTHREAD_MUTEX_RECURSIVE) || defined(HAVE_PTHREAD_MUTEX_RECURSIVE)
1520
    {
1521
        pthread_mutexattr_t attr;
1522
        pthread_mutexattr_init(&attr);
523,027✔
1523
        pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
523,027✔
1524
        pthread_mutex_init(&(psItem->sMutex), &attr);
523,027✔
1525
    }
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
}
1542

1543
static CPLMutex *CPLCreateMutexInternal(bool bAlreadyInGlobalLock, int nOptions)
523,609✔
1544
{
1545
    MutexLinkedElt *psItem =
1546
        static_cast<MutexLinkedElt *>(malloc(sizeof(MutexLinkedElt)));
523,609✔
1547
    if (psItem == nullptr)
523,609✔
1548
    {
1549
        fprintf(stderr, "CPLCreateMutexInternal() failed.\n");
×
1550
        return nullptr;
×
1551
    }
1552

1553
    if (!bAlreadyInGlobalLock)
523,609✔
1554
        pthread_mutex_lock(&global_mutex);
484,048✔
1555
    psItem->psPrev = nullptr;
523,612✔
1556
    psItem->psNext = psMutexList;
523,612✔
1557
    if (psMutexList)
523,612✔
1558
        psMutexList->psPrev = psItem;
521,948✔
1559
    psMutexList = psItem;
523,612✔
1560
    if (!bAlreadyInGlobalLock)
523,612✔
1561
        pthread_mutex_unlock(&global_mutex);
484,051✔
1562

1563
    psItem->nOptions = nOptions;
523,612✔
1564
    CPLInitMutex(psItem);
523,612✔
1565

1566
    return reinterpret_cast<CPLMutex *>(psItem);
523,609✔
1567
}
1568

1569
CPLMutex *CPLCreateMutex()
483,959✔
1570
{
1571
    CPLMutex *mutex = CPLCreateMutexInternal(false, CPL_MUTEX_RECURSIVE);
483,959✔
1572
    if (mutex)
483,978✔
1573
        CPLAcquireMutex(mutex, 0);
483,978✔
1574
    return mutex;
483,978✔
1575
}
1576

1577
CPLMutex *CPLCreateMutexEx(int nOptions)
71✔
1578
{
1579
    CPLMutex *mutex = CPLCreateMutexInternal(false, nOptions);
71✔
1580
    if (mutex)
71✔
1581
        CPLAcquireMutex(mutex, 0);
71✔
1582
    return mutex;
71✔
1583
}
1584

1585
/************************************************************************/
1586
/*                          CPLAcquireMutex()                           */
1587
/************************************************************************/
1588

1589
int CPLAcquireMutex(CPLMutex *hMutexIn, double /* dfWaitInSeconds */)
102,363,000✔
1590
{
1591
    // TODO: Need to add timeout support.
1592
    MutexLinkedElt *psItem = reinterpret_cast<MutexLinkedElt *>(hMutexIn);
102,363,000✔
1593
    const int err = pthread_mutex_lock(&(psItem->sMutex));
102,363,000✔
1594

1595
    if (err != 0)
102,370,000✔
1596
    {
1597
        if (err == EDEADLK)
×
1598
            fprintf(stderr, "CPLAcquireMutex: Error = %d/EDEADLK\n", err);
×
1599
        else
1600
            fprintf(stderr, "CPLAcquireMutex: Error = %d (%s)\n", err,
×
1601
                    strerror(err));
1602

1603
        return FALSE;
×
1604
    }
1605

1606
    return TRUE;
102,370,000✔
1607
}
1608

1609
/************************************************************************/
1610
/*                          CPLReleaseMutex()                           */
1611
/************************************************************************/
1612

1613
void CPLReleaseMutex(CPLMutex *hMutexIn)
102,370,000✔
1614

1615
{
1616
    MutexLinkedElt *psItem = reinterpret_cast<MutexLinkedElt *>(hMutexIn);
102,370,000✔
1617
    const int err = pthread_mutex_unlock(&(psItem->sMutex));
102,370,000✔
1618
    if (err != 0)
102,370,000✔
1619
    {
1620
        fprintf(stderr, "CPLReleaseMutex: Error = %d (%s)\n", err,
×
1621
                strerror(err));
1622
    }
1623
}
102,370,000✔
1624

1625
/************************************************************************/
1626
/*                          CPLDestroyMutex()                           */
1627
/************************************************************************/
1628

1629
void CPLDestroyMutex(CPLMutex *hMutexIn)
517,126✔
1630

1631
{
1632
    MutexLinkedElt *psItem = reinterpret_cast<MutexLinkedElt *>(hMutexIn);
517,126✔
1633
    const int err = pthread_mutex_destroy(&(psItem->sMutex));
517,126✔
1634
    if (err != 0)
517,126✔
1635
    {
1636
        fprintf(stderr, "CPLDestroyMutex: Error = %d (%s)\n", err,
×
1637
                strerror(err));
1638
    }
1639
    pthread_mutex_lock(&global_mutex);
517,126✔
1640
    if (psItem->psPrev)
517,126✔
1641
        psItem->psPrev->psNext = psItem->psNext;
472,775✔
1642
    if (psItem->psNext)
517,126✔
1643
        psItem->psNext->psPrev = psItem->psPrev;
513,098✔
1644
    if (psItem == psMutexList)
517,126✔
1645
        psMutexList = psItem->psNext;
44,351✔
1646
    pthread_mutex_unlock(&global_mutex);
517,126✔
1647
    free(hMutexIn);
517,125✔
1648
}
517,125✔
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
{
1660
    MutexLinkedElt *psItem = psMutexList;
×
1661
    while (psItem != nullptr)
×
1662
    {
1663
        CPLInitMutex(psItem);
×
1664
        psItem = psItem->psNext;
×
1665
    }
1666
#ifdef HAVE_GCC_WARNING_ZERO_AS_NULL_POINTER_CONSTANT
1667
#pragma GCC diagnostic push
1668
#pragma GCC diagnostic ignored "-Wzero-as-null-pointer-constant"
1669
#endif
1670
    pthread_mutex_t tmp_global_mutex = PTHREAD_MUTEX_INITIALIZER;
×
1671
#ifdef HAVE_GCC_WARNING_ZERO_AS_NULL_POINTER_CONSTANT
1672
#pragma GCC diagnostic pop
1673
#endif
1674
    global_mutex = tmp_global_mutex;
×
1675
}
×
1676

1677
/************************************************************************/
1678
/*                            CPLCreateCond()                           */
1679
/************************************************************************/
1680

1681
CPLCond *CPLCreateCond()
236,408✔
1682
{
1683
    pthread_cond_t *pCond =
1684
        static_cast<pthread_cond_t *>(malloc(sizeof(pthread_cond_t)));
236,408✔
1685
    if (pCond && pthread_cond_init(pCond, nullptr) == 0)
236,408✔
1686
        return reinterpret_cast<CPLCond *>(pCond);
236,406✔
1687
    fprintf(stderr, "CPLCreateCond() failed.\n");
×
1688
    free(pCond);
×
1689
    return nullptr;
×
1690
}
1691

1692
/************************************************************************/
1693
/*                            CPLCondWait()                             */
1694
/************************************************************************/
1695

1696
void CPLCondWait(CPLCond *hCond, CPLMutex *hMutex)
9,083✔
1697
{
1698
    pthread_cond_t *pCond = reinterpret_cast<pthread_cond_t *>(hCond);
9,083✔
1699
    MutexLinkedElt *psItem = reinterpret_cast<MutexLinkedElt *>(hMutex);
9,083✔
1700
    pthread_mutex_t *pMutex = &(psItem->sMutex);
9,083✔
1701
    pthread_cond_wait(pCond, pMutex);
9,083✔
1702
}
9,083✔
1703

1704
/************************************************************************/
1705
/*                         CPLCondTimedWait()                           */
1706
/************************************************************************/
1707

1708
CPLCondTimedWaitReason CPLCondTimedWait(CPLCond *hCond, CPLMutex *hMutex,
×
1709
                                        double dfWaitInSeconds)
1710
{
1711
    pthread_cond_t *pCond = reinterpret_cast<pthread_cond_t *>(hCond);
×
1712
    MutexLinkedElt *psItem = reinterpret_cast<MutexLinkedElt *>(hMutex);
×
1713
    pthread_mutex_t *pMutex = &(psItem->sMutex);
×
1714
    struct timeval tv;
1715
    struct timespec ts;
1716

1717
    gettimeofday(&tv, nullptr);
×
1718
    ts.tv_sec = time(nullptr) + static_cast<int>(dfWaitInSeconds);
×
1719
    ts.tv_nsec =
×
1720
        static_cast<int>(tv.tv_usec) * 1000 +
×
1721
        static_cast<int>(1000 * 1000 * 1000 * fmod(dfWaitInSeconds, 1));
×
1722
    ts.tv_sec += ts.tv_nsec / (1000 * 1000 * 1000);
×
1723
    ts.tv_nsec %= (1000 * 1000 * 1000);
×
1724
    int ret = pthread_cond_timedwait(pCond, pMutex, &ts);
×
1725
    if (ret == 0)
×
1726
        return COND_TIMED_WAIT_COND;
×
1727
    else if (ret == ETIMEDOUT)
×
1728
        return COND_TIMED_WAIT_TIME_OUT;
×
1729
    else
1730
        return COND_TIMED_WAIT_OTHER;
×
1731
}
1732

1733
/************************************************************************/
1734
/*                            CPLCondSignal()                           */
1735
/************************************************************************/
1736

1737
void CPLCondSignal(CPLCond *hCond)
51,989✔
1738
{
1739
    pthread_cond_t *pCond = reinterpret_cast<pthread_cond_t *>(hCond);
51,989✔
1740
    pthread_cond_signal(pCond);
51,989✔
1741
}
51,989✔
1742

1743
/************************************************************************/
1744
/*                           CPLCondBroadcast()                         */
1745
/************************************************************************/
1746

1747
void CPLCondBroadcast(CPLCond *hCond)
103✔
1748
{
1749
    pthread_cond_t *pCond = reinterpret_cast<pthread_cond_t *>(hCond);
103✔
1750
    pthread_cond_broadcast(pCond);
103✔
1751
}
103✔
1752

1753
/************************************************************************/
1754
/*                            CPLDestroyCond()                          */
1755
/************************************************************************/
1756

1757
void CPLDestroyCond(CPLCond *hCond)
236,410✔
1758
{
1759
    pthread_cond_t *pCond = reinterpret_cast<pthread_cond_t *>(hCond);
236,410✔
1760
    pthread_cond_destroy(pCond);
236,410✔
1761
    free(hCond);
236,410✔
1762
}
236,410✔
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)
3✔
1772

1773
{
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
    const size_t nLen = strlen(pszPath) + 30;
3✔
1781
    char *pszLockFilename = static_cast<char *>(CPLMalloc(nLen));
3✔
1782
    snprintf(pszLockFilename, nLen, "%s.lock", pszPath);
3✔
1783

1784
    FILE *fpLock = fopen(pszLockFilename, "r");
3✔
1785
    while (fpLock != nullptr && dfWaitInSeconds > 0.0)
3✔
1786
    {
1787
        fclose(fpLock);
×
1788
        CPLSleep(std::min(dfWaitInSeconds, 0.5));
×
1789
        dfWaitInSeconds -= 0.5;
×
1790

1791
        fpLock = fopen(pszLockFilename, "r");
×
1792
    }
1793

1794
    if (fpLock != nullptr)
3✔
1795
    {
1796
        fclose(fpLock);
×
1797
        CPLFree(pszLockFilename);
×
1798
        return nullptr;
×
1799
    }
1800

1801
    fpLock = fopen(pszLockFilename, "w");
3✔
1802

1803
    if (fpLock == nullptr)
3✔
1804
    {
1805
        CPLFree(pszLockFilename);
×
1806
        return nullptr;
×
1807
    }
1808

1809
    fwrite("held\n", 1, 5, fpLock);
3✔
1810
    fclose(fpLock);
3✔
1811

1812
    return pszLockFilename;
3✔
1813
}
1814

1815
/************************************************************************/
1816
/*                           CPLUnlockFile()                            */
1817
/************************************************************************/
1818

1819
void CPLUnlockFile(void *hLock)
3✔
1820

1821
{
1822
    char *pszLockFilename = static_cast<char *>(hLock);
3✔
1823

1824
    if (hLock == nullptr)
3✔
1825
        return;
×
1826

1827
    VSIUnlink(pszLockFilename);
3✔
1828

1829
    CPLFree(pszLockFilename);
3✔
1830
}
1831

1832
/************************************************************************/
1833
/*                             CPLGetPID()                              */
1834
/************************************************************************/
1835

1836
GIntBig CPLGetPID()
21,978,200✔
1837

1838
{
1839
    return reinterpret_cast<GIntBig>(reinterpret_cast<void *>(pthread_self()));
21,978,200✔
1840
}
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()
1,465✔
1850

1851
{
1852
    if (pthread_key_create(&oTLSKey, reinterpret_cast<void (*)(void *)>(
1,465✔
1853
                                         CPLCleanupTLSList)) != 0)
1,465✔
1854
    {
1855
        CPLError(CE_Fatal, CPLE_AppDefined, "pthread_key_create() failed!");
×
1856
    }
1857
}
1,465✔
1858

1859
/************************************************************************/
1860
/*                           CPLGetTLSList()                            */
1861
/************************************************************************/
1862

1863
static void **CPLGetTLSList(int *pbMemoryErrorOccurred)
64,214,100✔
1864

1865
{
1866
    if (pbMemoryErrorOccurred)
64,214,100✔
1867
        *pbMemoryErrorOccurred = FALSE;
60,120,700✔
1868

1869
    if (pthread_once(&oTLSKeySetup, CPLMake_key) != 0)
64,214,100✔
1870
    {
1871
        if (pbMemoryErrorOccurred)
×
1872
        {
1873
            fprintf(stderr, "CPLGetTLSList(): pthread_once() failed!\n");
×
1874
            *pbMemoryErrorOccurred = TRUE;
×
1875
            return nullptr;
×
1876
        }
1877
        CPLEmergencyError("CPLGetTLSList(): pthread_once() failed!");
×
1878
    }
1879

1880
    void **papTLSList = static_cast<void **>(pthread_getspecific(oTLSKey));
64,147,900✔
1881
    if (papTLSList == nullptr)
64,160,300✔
1882
    {
1883
        papTLSList =
1884
            static_cast<void **>(VSICalloc(sizeof(void *), CTLS_MAX * 2));
10,492✔
1885
        if (papTLSList == nullptr)
4,342✔
1886
        {
1887
            if (pbMemoryErrorOccurred)
×
1888
            {
1889
                fprintf(stderr,
×
1890
                        "CPLGetTLSList() failed to allocate TLS list!\n");
1891
                *pbMemoryErrorOccurred = TRUE;
×
1892
                return nullptr;
×
1893
            }
1894
            CPLEmergencyError("CPLGetTLSList() failed to allocate TLS list!");
×
1895
        }
1896
        if (pthread_setspecific(oTLSKey, papTLSList) != 0)
4,342✔
1897
        {
1898
            if (pbMemoryErrorOccurred)
×
1899
            {
1900
                fprintf(stderr,
×
1901
                        "CPLGetTLSList(): pthread_setspecific() failed!\n");
1902
                *pbMemoryErrorOccurred = TRUE;
×
1903
                return nullptr;
×
1904
            }
1905
            CPLEmergencyError("CPLGetTLSList(): pthread_setspecific() failed!");
×
1906
        }
1907
    }
1908

1909
    return papTLSList;
64,154,100✔
1910
}
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)
3,801✔
1931

1932
{
1933
    CPLStdCallThreadInfo *psInfo = static_cast<CPLStdCallThreadInfo *>(pData);
3,801✔
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
    psInfo->pfnMain(psInfo->pAppData);
3,801✔
1948

1949
    if (!psInfo->bJoinable)
2,765✔
1950
        CPLFree(psInfo);
1✔
1951

1952
    return nullptr;
2,765✔
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
}
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)
1✔
1974

1975
{
1976
    CPLStdCallThreadInfo *psInfo = static_cast<CPLStdCallThreadInfo *>(
1977
        VSI_CALLOC_VERBOSE(sizeof(CPLStdCallThreadInfo), 1));
1✔
1978
    if (psInfo == nullptr)
1✔
1979
        return -1;
×
1980
    psInfo->pAppData = pThreadArg;
1✔
1981
    psInfo->pfnMain = pfnMain;
1✔
1982
    psInfo->bJoinable = false;
1✔
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
    pthread_attr_t hThreadAttr;
1997
    pthread_attr_init(&hThreadAttr);
1✔
1998
    pthread_attr_setdetachstate(&hThreadAttr, PTHREAD_CREATE_DETACHED);
1✔
1999
    if (pthread_create(&(psInfo->hThread), &hThreadAttr, CPLStdCallThreadJacket,
1✔
2000
                       static_cast<void *>(psInfo)) != 0)
1✔
2001
    {
2002
#ifdef CHECK_THREAD_CAN_ALLOCATE_TLS
2003
        pthread_cond_destroy(&(psInfo->sCond));
2004
#endif
2005
        CPLFree(psInfo);
×
2006
        fprintf(stderr, "CPLCreateThread() failed.\n");
×
2007
        return -1;
×
2008
    }
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
    return 1;  // Can we return the actual thread pid?
1✔
2035
}
2036

2037
/************************************************************************/
2038
/*                      CPLCreateJoinableThread()                       */
2039
/************************************************************************/
2040

2041
CPLJoinableThread *CPLCreateJoinableThread(CPLThreadFunc pfnMain,
3,805✔
2042
                                           void *pThreadArg)
2043

2044
{
2045
    CPLStdCallThreadInfo *psInfo = static_cast<CPLStdCallThreadInfo *>(
2046
        VSI_CALLOC_VERBOSE(sizeof(CPLStdCallThreadInfo), 1));
3,805✔
2047
    if (psInfo == nullptr)
3,805✔
2048
        return nullptr;
×
2049
    psInfo->pAppData = pThreadArg;
3,805✔
2050
    psInfo->pfnMain = pfnMain;
3,805✔
2051
    psInfo->bJoinable = true;
3,805✔
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
    pthread_attr_t hThreadAttr;
2070
    pthread_attr_init(&hThreadAttr);
3,805✔
2071
    pthread_attr_setdetachstate(&hThreadAttr, PTHREAD_CREATE_JOINABLE);
3,805✔
2072
    int err =
2073
        pthread_create(&(psInfo->hThread), &hThreadAttr, CPLStdCallThreadJacket,
3,805✔
2074
                       static_cast<void *>(psInfo));
2075
    if (err != 0)
3,805✔
2076
    {
2077
#ifdef CHECK_THREAD_CAN_ALLOCATE_TLS
2078
        pthread_cond_destroy(&(psInfo->sCond));
2079
#endif
2080
        CPLFree(psInfo);
×
2081
        fprintf(stderr, "CPLCreateJoinableThread() failed: %s.\n",
×
2082
                strerror(err));
2083
        return nullptr;
×
2084
    }
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
    return reinterpret_cast<CPLJoinableThread *>(psInfo);
3,805✔
2113
}
2114

2115
/************************************************************************/
2116
/*                          CPLJoinThread()                             */
2117
/************************************************************************/
2118

2119
void CPLJoinThread(CPLJoinableThread *hJoinableThread)
2,764✔
2120
{
2121
    CPLStdCallThreadInfo *psInfo =
2,764✔
2122
        reinterpret_cast<CPLStdCallThreadInfo *>(hJoinableThread);
2123
    if (psInfo == nullptr)
2,764✔
2124
        return;
×
2125

2126
    void *status;
2127
    pthread_join(psInfo->hThread, &status);
2,764✔
2128

2129
    CPLFree(psInfo);
2,764✔
2130
}
2131

2132
/************************************************************************/
2133
/*                              CPLSleep()                              */
2134
/************************************************************************/
2135

2136
void CPLSleep(double dfWaitInSeconds)
134✔
2137

2138
{
2139
    struct timespec sRequest;
2140
    struct timespec sRemain;
2141

2142
    sRequest.tv_sec = static_cast<int>(floor(dfWaitInSeconds));
134✔
2143
    sRequest.tv_nsec =
134✔
2144
        static_cast<int>((dfWaitInSeconds - sRequest.tv_sec) * 1000000000);
134✔
2145
    nanosleep(&sRequest, &sRemain);
134✔
2146
}
134✔
2147

2148
/************************************************************************/
2149
/*                             CPLFinalizeTLS()                         */
2150
/************************************************************************/
2151

2152
void CPLFinalizeTLS()
427✔
2153
{
2154
    CPLCleanupTLS();
427✔
2155
    // See #5509 for the explanation why this may be needed.
2156
    pthread_key_delete(oTLSKey);
427✔
2157
}
427✔
2158

2159
/************************************************************************/
2160
/*                             CPLCleanupTLS()                          */
2161
/************************************************************************/
2162

2163
void CPLCleanupTLS()
1,541✔
2164

2165
{
2166
    void **papTLSList = static_cast<void **>(pthread_getspecific(oTLSKey));
1,541✔
2167
    if (papTLSList == nullptr)
1,541✔
2168
        return;
1✔
2169

2170
    pthread_setspecific(oTLSKey, nullptr);
1,540✔
2171

2172
    CPLCleanupTLSList(papTLSList);
1,540✔
2173
}
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
{
2189
    CPLSpinLock *psSpin =
2190
        static_cast<CPLSpinLock *>(malloc(sizeof(CPLSpinLock)));
2191
    if (psSpin != nullptr &&
2192
        pthread_spin_init(&(psSpin->spin), PTHREAD_PROCESS_PRIVATE) == 0)
2193
    {
2194
        return psSpin;
2195
    }
2196
    else
2197
    {
2198
        fprintf(stderr, "CPLCreateSpinLock() failed.\n");
2199
        free(psSpin);
2200
        return nullptr;
2201
    }
2202
}
2203

2204
/************************************************************************/
2205
/*                        CPLAcquireSpinLock()                          */
2206
/************************************************************************/
2207

2208
int CPLAcquireSpinLock(CPLSpinLock *psSpin)
2209
{
2210
    return pthread_spin_lock(&(psSpin->spin)) == 0;
2211
}
2212

2213
/************************************************************************/
2214
/*                   CPLCreateOrAcquireSpinLockInternal()               */
2215
/************************************************************************/
2216

2217
int CPLCreateOrAcquireSpinLockInternal(CPLLock **ppsLock)
2218
{
2219
    pthread_mutex_lock(&global_mutex);
2220
    if (*ppsLock == nullptr)
2221
    {
2222
        *ppsLock = static_cast<CPLLock *>(calloc(1, sizeof(CPLLock)));
2223
        if (*ppsLock != nullptr)
2224
        {
2225
            (*ppsLock)->eType = LOCK_SPIN;
2226
            (*ppsLock)->u.hSpinLock = CPLCreateSpinLock();
2227
            if ((*ppsLock)->u.hSpinLock == nullptr)
2228
            {
2229
                free(*ppsLock);
2230
                *ppsLock = nullptr;
2231
            }
2232
        }
2233
    }
2234
    pthread_mutex_unlock(&global_mutex);
2235
    // coverity[missing_unlock]
2236
    return (*ppsLock != nullptr && CPLAcquireSpinLock((*ppsLock)->u.hSpinLock));
2237
}
2238

2239
/************************************************************************/
2240
/*                       CPLReleaseSpinLock()                           */
2241
/************************************************************************/
2242

2243
void CPLReleaseSpinLock(CPLSpinLock *psSpin)
2244
{
2245
    pthread_spin_unlock(&(psSpin->spin));
2246
}
2247

2248
/************************************************************************/
2249
/*                        CPLDestroySpinLock()                          */
2250
/************************************************************************/
2251

2252
void CPLDestroySpinLock(CPLSpinLock *psSpin)
2253
{
2254
    pthread_spin_destroy(&(psSpin->spin));
2255
    free(psSpin);
2256
}
2257
#endif  // HAVE_PTHREAD_SPIN_LOCK
2258

2259
#endif  // def CPL_MULTIPROC_PTHREAD
2260

2261
/************************************************************************/
2262
/*                             CPLGetTLS()                              */
2263
/************************************************************************/
2264

2265
void *CPLGetTLS(int nIndex)
2,611,020✔
2266

2267
{
2268
    void **l_papTLSList = CPLGetTLSList(nullptr);
2,611,020✔
2269

2270
    CPLAssert(nIndex >= 0 && nIndex < CTLS_MAX);
2,611,000✔
2271

2272
    return l_papTLSList[nIndex];
2,610,990✔
2273
}
2274

2275
/************************************************************************/
2276
/*                            CPLGetTLSEx()                             */
2277
/************************************************************************/
2278

2279
void *CPLGetTLSEx(int nIndex, int *pbMemoryErrorOccurred)
60,170,400✔
2280

2281
{
2282
    void **l_papTLSList = CPLGetTLSList(pbMemoryErrorOccurred);
60,170,400✔
2283
    if (l_papTLSList == nullptr)
60,133,200✔
2284
        return nullptr;
×
2285

2286
    CPLAssert(nIndex >= 0 && nIndex < CTLS_MAX);
60,133,200✔
2287

2288
    return l_papTLSList[nIndex];
60,107,400✔
2289
}
2290

2291
/************************************************************************/
2292
/*                             CPLSetTLS()                              */
2293
/************************************************************************/
2294

2295
void CPLSetTLS(int nIndex, void *pData, int bFreeOnExit)
21,276✔
2296

2297
{
2298
    CPLSetTLSWithFreeFunc(nIndex, pData, (bFreeOnExit) ? CPLFree : nullptr);
21,276✔
2299
}
21,274✔
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)
1,464,040✔
2308

2309
{
2310
    void **l_papTLSList = CPLGetTLSList(nullptr);
1,464,040✔
2311

2312
    CPLAssert(nIndex >= 0 && nIndex < CTLS_MAX);
1,420,810✔
2313

2314
    l_papTLSList[nIndex] = pData;
1,404,910✔
2315
    l_papTLSList[CTLS_MAX + nIndex] = reinterpret_cast<void *>(pfnFree);
1,404,910✔
2316
}
1,404,910✔
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,
1,538✔
2325
                             int *pbMemoryErrorOccurred)
2326

2327
{
2328
    void **l_papTLSList = CPLGetTLSList(pbMemoryErrorOccurred);
1,538✔
2329

2330
    CPLAssert(nIndex >= 0 && nIndex < CTLS_MAX);
1,538✔
2331

2332
    l_papTLSList[nIndex] = pData;
1,538✔
2333
    l_papTLSList[CTLS_MAX + nIndex] = reinterpret_cast<void *>(pfnFree);
1,538✔
2334
}
1,538✔
2335
#ifndef HAVE_SPINLOCK_IMPL
2336

2337
// No spinlock specific API? Fallback to mutex.
2338

2339
/************************************************************************/
2340
/*                          CPLCreateSpinLock()                         */
2341
/************************************************************************/
2342

2343
CPLSpinLock *CPLCreateSpinLock(void)
236,092✔
2344
{
2345
    CPLSpinLock *psSpin = reinterpret_cast<CPLSpinLock *>(CPLCreateMutex());
236,092✔
2346
    if (psSpin)
236,091✔
2347
        CPLReleaseSpinLock(psSpin);
236,091✔
2348
    return psSpin;
236,091✔
2349
}
2350

2351
/************************************************************************/
2352
/*                     CPLCreateOrAcquireSpinLock()                     */
2353
/************************************************************************/
2354

2355
int CPLCreateOrAcquireSpinLockInternal(CPLLock **ppsLock)
4✔
2356
{
2357
    return CPLCreateOrAcquireMutexInternal(ppsLock, 1000, LOCK_ADAPTIVE_MUTEX);
4✔
2358
}
2359

2360
/************************************************************************/
2361
/*                        CPLAcquireSpinLock()                          */
2362
/************************************************************************/
2363

2364
int CPLAcquireSpinLock(CPLSpinLock *psSpin)
7,985,670✔
2365
{
2366
    return CPLAcquireMutex(reinterpret_cast<CPLMutex *>(psSpin), 1000);
7,985,670✔
2367
}
2368

2369
/************************************************************************/
2370
/*                       CPLReleaseSpinLock()                           */
2371
/************************************************************************/
2372

2373
void CPLReleaseSpinLock(CPLSpinLock *psSpin)
8,221,770✔
2374
{
2375
    CPLReleaseMutex(reinterpret_cast<CPLMutex *>(psSpin));
8,221,770✔
2376
}
8,221,780✔
2377

2378
/************************************************************************/
2379
/*                        CPLDestroySpinLock()                          */
2380
/************************************************************************/
2381

2382
void CPLDestroySpinLock(CPLSpinLock *psSpin)
236,092✔
2383
{
2384
    CPLDestroyMutex(reinterpret_cast<CPLMutex *>(psSpin));
236,092✔
2385
}
236,092✔
2386

2387
#endif  // HAVE_SPINLOCK_IMPL
2388

2389
/************************************************************************/
2390
/*                            CPLCreateLock()                           */
2391
/************************************************************************/
2392

2393
CPLLock *CPLCreateLock(CPLLockType eType)
236,161✔
2394
{
2395
    switch (eType)
236,161✔
2396
    {
2397
        case LOCK_RECURSIVE_MUTEX:
71✔
2398
        case LOCK_ADAPTIVE_MUTEX:
2399
        {
2400
            CPLMutex *hMutex = CPLCreateMutexEx(eType == LOCK_RECURSIVE_MUTEX
142✔
2401
                                                    ? CPL_MUTEX_RECURSIVE
71✔
2402
                                                    : CPL_MUTEX_ADAPTIVE);
2403
            if (!hMutex)
71✔
2404
                return nullptr;
×
2405
            CPLReleaseMutex(hMutex);
71✔
2406
            CPLLock *psLock = static_cast<CPLLock *>(malloc(sizeof(CPLLock)));
71✔
2407
            if (psLock == nullptr)
71✔
2408
            {
2409
                fprintf(stderr, "CPLCreateLock() failed.\n");
×
2410
                CPLDestroyMutex(hMutex);
×
2411
                return nullptr;
×
2412
            }
2413
            psLock->eType = eType;
71✔
2414
            psLock->u.hMutex = hMutex;
71✔
2415
#ifdef DEBUG_CONTENTION
2416
            psLock->bDebugPerf = false;
71✔
2417
            psLock->bDebugPerfAsked = false;
71✔
2418
            psLock->nCurrentHolders = 0;
71✔
2419
            psLock->nStartTime = 0;
71✔
2420
#endif
2421
            return psLock;
71✔
2422
        }
2423
        case LOCK_SPIN:
236,091✔
2424
        {
2425
            CPLSpinLock *hSpinLock = CPLCreateSpinLock();
236,091✔
2426
            if (!hSpinLock)
236,091✔
2427
                return nullptr;
×
2428
            CPLLock *psLock = static_cast<CPLLock *>(malloc(sizeof(CPLLock)));
236,091✔
2429
            if (psLock == nullptr)
236,091✔
2430
            {
2431
                fprintf(stderr, "CPLCreateLock() failed.\n");
×
2432
                CPLDestroySpinLock(hSpinLock);
×
2433
                return nullptr;
×
2434
            }
2435
            psLock->eType = eType;
236,091✔
2436
            psLock->u.hSpinLock = hSpinLock;
236,091✔
2437
#ifdef DEBUG_CONTENTION
2438
            psLock->bDebugPerf = false;
236,091✔
2439
            psLock->bDebugPerfAsked = false;
236,091✔
2440
            psLock->nCurrentHolders = 0;
236,091✔
2441
            psLock->nStartTime = 0;
236,091✔
2442
#endif
2443
            return psLock;
236,091✔
2444
        }
UNCOV
2445
        default:
×
UNCOV
2446
            CPLAssert(false);
×
2447
            return nullptr;
2448
    }
2449
}
2450

2451
/************************************************************************/
2452
/*                       CPLCreateOrAcquireLock()                       */
2453
/************************************************************************/
2454

2455
int CPLCreateOrAcquireLock(CPLLock **ppsLock, CPLLockType eType)
4,994✔
2456
{
2457
#ifdef DEBUG_CONTENTION
2458
    GUIntBig nStartTime = 0;
4,994✔
2459
    if ((*ppsLock) && (*ppsLock)->bDebugPerfAsked)
4,994✔
2460
        nStartTime = CPLrdtsc();
4✔
2461
#endif
2462
    int ret = 0;
4,994✔
2463

2464
    switch (eType)
4,994✔
2465
    {
2466
        case LOCK_RECURSIVE_MUTEX:
4,990✔
2467
        case LOCK_ADAPTIVE_MUTEX:
2468
        {
2469
            ret = CPLCreateOrAcquireMutexInternal(ppsLock, 1000, eType);
4,990✔
2470
            break;
4,990✔
2471
        }
2472
        case LOCK_SPIN:
4✔
2473
        {
2474
            ret = CPLCreateOrAcquireSpinLockInternal(ppsLock);
4✔
2475
            break;
4✔
2476
        }
2477
        default:
×
2478
            CPLAssert(false);
×
2479
            return FALSE;
2480
    }
2481
#ifdef DEBUG_CONTENTION
2482
    if (ret && (*ppsLock)->bDebugPerfAsked &&
4,998✔
2483
        CPLAtomicInc(&((*ppsLock)->nCurrentHolders)) == 1)
4✔
2484
    {
2485
        (*ppsLock)->bDebugPerf = true;
4✔
2486
        (*ppsLock)->nStartTime = nStartTime;
4✔
2487
    }
2488
#endif
2489
    return ret;
4,994✔
2490
}
2491

2492
/************************************************************************/
2493
/*                          CPLAcquireLock()                            */
2494
/************************************************************************/
2495

2496
int CPLAcquireLock(CPLLock *psLock)
26,469,200✔
2497
{
2498
#ifdef DEBUG_CONTENTION
2499
    GUIntBig nStartTime = 0;
26,469,200✔
2500
    if (psLock->bDebugPerfAsked)
26,469,200✔
2501
        nStartTime = CPLrdtsc();
1,952,510✔
2502
#endif
2503
    int ret;
2504
    if (psLock->eType == LOCK_SPIN)
26,467,700✔
2505
        ret = CPLAcquireSpinLock(psLock->u.hSpinLock);
7,985,670✔
2506
    else
2507
        ret = CPLAcquireMutex(psLock->u.hMutex, 1000);
18,482,000✔
2508
#ifdef DEBUG_CONTENTION
2509
    if (ret && psLock->bDebugPerfAsked &&
28,422,800✔
2510
        CPLAtomicInc(&(psLock->nCurrentHolders)) == 1)
1,952,510✔
2511
    {
2512
        psLock->bDebugPerf = true;
1,952,510✔
2513
        psLock->nStartTime = nStartTime;
1,952,510✔
2514
    }
2515
#endif
2516
    return ret;
26,470,300✔
2517
}
2518

2519
/************************************************************************/
2520
/*                         CPLReleaseLock()                             */
2521
/************************************************************************/
2522

2523
void CPLReleaseLock(CPLLock *psLock)
26,475,300✔
2524
{
2525
#ifdef DEBUG_CONTENTION
2526
    bool bHitMaxDiff = false;
26,475,300✔
2527
    GIntBig nMaxDiff = 0;
26,475,300✔
2528
    double dfAvgDiff = 0;
26,475,300✔
2529
    if (psLock->bDebugPerf && CPLAtomicDec(&(psLock->nCurrentHolders)) == 0)
26,475,300✔
2530
    {
2531
        const GUIntBig nStopTime = CPLrdtscp();
1,952,520✔
2532
        const GIntBig nDiffTime =
1,952,520✔
2533
            static_cast<GIntBig>(nStopTime - psLock->nStartTime);
1,952,520✔
2534
        if (nDiffTime > psLock->nMaxDiff)
1,952,520✔
2535
        {
2536
            bHitMaxDiff = true;
43✔
2537
            psLock->nMaxDiff = nDiffTime;
43✔
2538
        }
2539
        nMaxDiff = psLock->nMaxDiff;
1,952,520✔
2540
        psLock->nIters++;
1,952,520✔
2541
        psLock->dfAvgDiff += (nDiffTime - psLock->dfAvgDiff) / psLock->nIters;
1,952,520✔
2542
        dfAvgDiff = psLock->dfAvgDiff;
1,952,520✔
2543
    }
2544
#endif
2545
    if (psLock->eType == LOCK_SPIN)
26,475,300✔
2546
        CPLReleaseSpinLock(psLock->u.hSpinLock);
7,985,680✔
2547
    else
2548
        CPLReleaseMutex(psLock->u.hMutex);
18,489,600✔
2549
#ifdef DEBUG_CONTENTION
2550
    if (psLock->bDebugPerf &&
26,475,300✔
2551
        (bHitMaxDiff || (psLock->nIters % 1000000) == (1000000 - 1)))
1,952,470✔
2552
    {
2553
        CPLDebug("LOCK", "Lock contention : max = " CPL_FRMT_GIB ", avg = %.0f",
43✔
2554
                 nMaxDiff, dfAvgDiff);
2555
    }
2556
#endif
2557
}
26,475,300✔
2558

2559
/************************************************************************/
2560
/*                          CPLDestroyLock()                            */
2561
/************************************************************************/
2562

2563
void CPLDestroyLock(CPLLock *psLock)
236,533✔
2564
{
2565
    if (psLock->eType == LOCK_SPIN)
236,533✔
2566
        CPLDestroySpinLock(psLock->u.hSpinLock);
236,092✔
2567
    else
2568
        CPLDestroyMutex(psLock->u.hMutex);
441✔
2569
    free(psLock);
236,533✔
2570
}
236,533✔
2571

2572
/************************************************************************/
2573
/*                       CPLLockSetDebugPerf()                          */
2574
/************************************************************************/
2575

2576
#ifdef DEBUG_CONTENTION
2577
void CPLLockSetDebugPerf(CPLLock *psLock, int bEnableIn)
4,994✔
2578
{
2579
    psLock->bDebugPerfAsked = CPL_TO_BOOL(bEnableIn);
4,994✔
2580
}
4,994✔
2581
#else
2582
void CPLLockSetDebugPerf(CPLLock * /* psLock */, int bEnableIn)
2583
{
2584
    if (!bEnableIn)
2585
        return;
2586

2587
    static bool bOnce = false;
2588
    if (!bOnce)
2589
    {
2590
        bOnce = true;
2591
        CPLDebug("LOCK", "DEBUG_CONTENTION not available");
2592
    }
2593
}
2594
#endif
2595

2596
/************************************************************************/
2597
/*                           CPLLockHolder()                            */
2598
/************************************************************************/
2599

2600
CPLLockHolder::CPLLockHolder(CPLLock **phLock, CPLLockType eType,
4,994✔
2601
                             const char *pszFileIn, int nLineIn)
4,994✔
2602

2603
{
2604
#ifndef MUTEX_NONE
2605
    pszFile = pszFileIn;
4,994✔
2606
    nLine = nLineIn;
4,994✔
2607

2608
#ifdef DEBUG_MUTEX
2609
    // XXX: There is no way to use CPLDebug() here because it works with
2610
    // mutexes itself so we will fall in infinite recursion. Good old
2611
    // fprintf() will do the job right.
2612
    fprintf(stderr, "CPLLockHolder: Request %p for pid %ld at %d/%s.\n",
2613
            *phLock, static_cast<long>(CPLGetPID()), nLine, pszFile);
2614
#endif
2615

2616
    if (!CPLCreateOrAcquireLock(phLock, eType))
4,994✔
2617
    {
2618
        fprintf(stderr, "CPLLockHolder: Failed to acquire lock!\n");
×
2619
        hLock = nullptr;
×
2620
    }
2621
    else
2622
    {
2623
#ifdef DEBUG_MUTEX
2624
        fprintf(stderr, "CPLLockHolder: Acquired %p for pid %ld at %d/%s.\n",
2625
                *phLock, static_cast<long>(CPLGetPID()), nLine, pszFile);
2626
#endif
2627

2628
        hLock = *phLock;
4,994✔
2629
    }
2630
#endif  // ndef MUTEX_NONE
2631
}
4,994✔
2632

2633
/************************************************************************/
2634
/*                           CPLLockHolder()                            */
2635
/************************************************************************/
2636

2637
CPLLockHolder::CPLLockHolder(CPLLock *hLockIn, const char *pszFileIn,
26,463,600✔
2638
                             int nLineIn)
26,463,600✔
2639

2640
{
2641
#ifndef MUTEX_NONE
2642
    pszFile = pszFileIn;
26,463,600✔
2643
    nLine = nLineIn;
26,463,600✔
2644
    hLock = hLockIn;
26,463,600✔
2645

2646
    if (hLock != nullptr)
26,463,600✔
2647
    {
2648
        if (!CPLAcquireLock(hLock))
26,462,800✔
2649
        {
2650
            fprintf(stderr, "CPLLockHolder: Failed to acquire lock!\n");
×
2651
            hLock = nullptr;
×
2652
        }
2653
    }
2654
#endif  // ndef MUTEX_NONE
2655
}
26,466,300✔
2656

2657
/************************************************************************/
2658
/*                          ~CPLLockHolder()                            */
2659
/************************************************************************/
2660

2661
CPLLockHolder::~CPLLockHolder()
52,941,000✔
2662

2663
{
2664
#ifndef MUTEX_NONE
2665
    if (hLock != nullptr)
26,470,500✔
2666
    {
2667
#ifdef DEBUG_MUTEX
2668
        fprintf(stderr, "~CPLLockHolder: Release %p for pid %ld at %d/%s.\n",
2669
                hLock, static_cast<long>(CPLGetPID()), nLine, pszFile);
2670
#endif
2671
        CPLReleaseLock(hLock);
26,470,500✔
2672
    }
2673
#endif  // ndef MUTEX_NONE
2674
}
26,470,500✔
2675

2676
/************************************************************************/
2677
/*                       CPLGetCurrentProcessID()                       */
2678
/************************************************************************/
2679

2680
#ifdef CPL_MULTIPROC_WIN32
2681

2682
int CPLGetCurrentProcessID()
2683
{
2684
    return GetCurrentProcessId();
2685
}
2686

2687
#else
2688

2689
#include <sys/types.h>
2690
#include <unistd.h>
2691

2692
int CPLGetCurrentProcessID()
2,472✔
2693
{
2694
    return getpid();
2,472✔
2695
}
2696

2697
#endif
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc