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

OSGeo / gdal / 12706066811

10 Jan 2025 08:38AM UTC coverage: 70.084% (-2.5%) from 72.549%
12706066811

Pull #11629

github

web-flow
Merge 9418dc48f into 0df468c56
Pull Request #11629: add uv documentation for python package

563296 of 803749 relevant lines covered (70.08%)

223434.74 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) &&                                                          \
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,510✔
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,510✔
105
    __asm__ volatile("rdtsc" : "=a"(a), "=d"(d));
1,952,510✔
106
    return static_cast<GUIntBig>(a) | (static_cast<GUIntBig>(d) << 32);
1,952,520✔
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,
67,345,700✔
155
                               const char *pszFileIn, int nLineIn, int nOptions)
67,345,700✔
156
    : hMutex(nullptr), pszFile(pszFileIn), nLine(nLineIn)
67,345,700✔
157
{
158
    if (phMutex == nullptr)
67,345,700✔
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))
67,345,700✔
178
    {
179
        fprintf(stderr, "CPLMutexHolder: Failed to acquire mutex!\n");
10✔
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;
67,361,800✔
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,
15,091✔
207
                                           double dfWaitInSeconds)
208
{
209
    if (hMutexIn && !CPLAcquireMutex(hMutexIn, dfWaitInSeconds))
15,091✔
210
    {
211
        fprintf(stderr, "CPLMutexHolder: Failed to acquire mutex!\n");
×
212
        return nullptr;
×
213
    }
214
    return hMutexIn;
15,091✔
215
}
216

217
CPLMutexHolder::CPLMutexHolder(CPLMutex *hMutexIn, double dfWaitInSeconds,
15,091✔
218
                               const char *pszFileIn, int nLineIn)
15,091✔
219
    : hMutex(GetMutexHolderMutexMember(hMutexIn, dfWaitInSeconds)),
15,091✔
220
      pszFile(pszFileIn), nLine(nLineIn)
15,091✔
221
{
222
}
15,091✔
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()
134,754,000✔
235
{
236
    if (hMutex != nullptr)
67,377,000✔
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);
67,376,900✔
243
    }
244
}
67,376,900✔
245
#endif  // ndef MUTEX_NONE
246

247
int CPLCreateOrAcquireMutex(CPLMutex **phMutex, double dfWaitInSeconds)
1,373,460✔
248
{
249
    return CPLCreateOrAcquireMutexEx(phMutex, dfWaitInSeconds,
1,373,460✔
250
                                     CPL_MUTEX_RECURSIVE);
1,373,170✔
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,380✔
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,380✔
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,057✔
434

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

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

443
    for (int i = 0; i < CTLS_MAX; i++)
100,765✔
444
    {
445
        if (papTLSList[i] != nullptr && papTLSList[i + CTLS_MAX] != nullptr)
97,708✔
446
        {
447
            CPLTLSFreeFunc pfnFree =
6,983✔
448
                reinterpret_cast<CPLTLSFreeFunc>(papTLSList[i + CTLS_MAX]);
6,983✔
449
            pfnFree(papTLSList[i]);
6,983✔
450
            papTLSList[i] = nullptr;
6,983✔
451
        }
452
    }
453

454
    CPLFree(papTLSList);
3,057✔
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
/*      Lock a file.  This implementation has a terrible race           */
641
/*      condition.  If we don't succeed in opening the lock file, we    */
642
/*      assume we can create one and own the target file, but other     */
643
/*      processes might easily try creating the target file at the      */
644
/*      same time, overlapping us.  Death!  Mayhem!  The traditional    */
645
/*      solution is to use open() with _O_CREAT|_O_EXCL but this        */
646
/*      function and these arguments aren't trivially portable.         */
647
/*      Also, this still leaves a race condition on NFS drivers         */
648
/*      (apparently).                                                   */
649
/************************************************************************/
650

651
void *CPLLockFile(const char *pszPath, double dfWaitInSeconds)
652

653
{
654
    /* -------------------------------------------------------------------- */
655
    /*      We use a lock file with a name derived from the file we want    */
656
    /*      to lock to represent the file being locked.  Note that for      */
657
    /*      the stub implementation the target file does not even need      */
658
    /*      to exist to be locked.                                          */
659
    /* -------------------------------------------------------------------- */
660
    char *pszLockFilename =
661
        static_cast<char *>(CPLMalloc(strlen(pszPath) + 30));
662
    snprintf(pszLockFilename, strlen(pszPath) + 30, "%s.lock", pszPath);
663

664
    FILE *fpLock = fopen(pszLockFilename, "r");
665
    while (fpLock != nullptr && dfWaitInSeconds > 0.0)
666
    {
667
        fclose(fpLock);
668
        CPLSleep(std::min(dfWaitInSeconds, 0.5));
669
        dfWaitInSeconds -= 0.5;
670

671
        fpLock = fopen(pszLockFilename, "r");
672
    }
673

674
    if (fpLock != nullptr)
675
    {
676
        fclose(fpLock);
677
        CPLFree(pszLockFilename);
678
        return nullptr;
679
    }
680

681
    fpLock = fopen(pszLockFilename, "w");
682

683
    if (fpLock == nullptr)
684
    {
685
        CPLFree(pszLockFilename);
686
        return nullptr;
687
    }
688

689
    fwrite("held\n", 1, 5, fpLock);
690
    fclose(fpLock);
691

692
    return pszLockFilename;
693
}
694

695
/************************************************************************/
696
/*                           CPLUnlockFile()                            */
697
/************************************************************************/
698

699
void CPLUnlockFile(void *hLock)
700

701
{
702
    char *pszLockFilename = static_cast<char *>(hLock);
703

704
    if (hLock == nullptr)
705
        return;
706

707
    VSIUnlink(pszLockFilename);
708

709
    CPLFree(pszLockFilename);
710
}
711

712
/************************************************************************/
713
/*                             CPLGetPID()                              */
714
/************************************************************************/
715

716
GIntBig CPLGetPID()
717

718
{
719
    return 1;
720
}
721

722
/************************************************************************/
723
/*                          CPLCreateThread();                          */
724
/************************************************************************/
725

726
int CPLCreateThread(CPLThreadFunc /* pfnMain */, void * /* pArg */)
727
{
728
    CPLDebug("CPLCreateThread", "Fails to dummy implementation");
729

730
    return -1;
731
}
732

733
/************************************************************************/
734
/*                      CPLCreateJoinableThread()                       */
735
/************************************************************************/
736

737
CPLJoinableThread *CPLCreateJoinableThread(CPLThreadFunc /* pfnMain */,
738
                                           void * /* pThreadArg */)
739
{
740
    CPLDebug("CPLCreateJoinableThread", "Fails to dummy implementation");
741

742
    return nullptr;
743
}
744

745
/************************************************************************/
746
/*                          CPLJoinThread()                             */
747
/************************************************************************/
748

749
void CPLJoinThread(CPLJoinableThread * /* hJoinableThread */)
750
{
751
}
752

753
/************************************************************************/
754
/*                              CPLSleep()                              */
755
/************************************************************************/
756

757
void CPLSleep(double dfWaitInSeconds)
758
{
759
    time_t ltime;
760

761
    time(&ltime);
762
    const time_t ttime = ltime + static_cast<int>(dfWaitInSeconds + 0.5);
763

764
    for (; ltime < ttime; time(&ltime))
765
    {
766
        // Currently we just busy wait.  Perhaps we could at least block on io?
767
    }
768
}
769

770
/************************************************************************/
771
/*                           CPLGetTLSList()                            */
772
/************************************************************************/
773

774
static void **papTLSList = nullptr;
775

776
static void **CPLGetTLSList(int *pbMemoryErrorOccurred)
777

778
{
779
    if (pbMemoryErrorOccurred)
780
        *pbMemoryErrorOccurred = FALSE;
781
    if (papTLSList == nullptr)
782
    {
783
        papTLSList =
784
            static_cast<void **>(VSICalloc(sizeof(void *), CTLS_MAX * 2));
785
        if (papTLSList == nullptr)
786
        {
787
            if (pbMemoryErrorOccurred)
788
            {
789
                *pbMemoryErrorOccurred = TRUE;
790
                fprintf(stderr,
791
                        "CPLGetTLSList() failed to allocate TLS list!\n");
792
                return nullptr;
793
            }
794
            CPLEmergencyError("CPLGetTLSList() failed to allocate TLS list!");
795
        }
796
    }
797

798
    return papTLSList;
799
}
800

801
/************************************************************************/
802
/*                             CPLFinalizeTLS()                         */
803
/************************************************************************/
804

805
void CPLFinalizeTLS()
806
{
807
    CPLCleanupTLS();
808
}
809

810
/************************************************************************/
811
/*                           CPLCleanupTLS()                            */
812
/************************************************************************/
813

814
void CPLCleanupTLS()
815

816
{
817
    CPLCleanupTLSList(papTLSList);
818
    papTLSList = nullptr;
819
}
820

821
// endif CPL_MULTIPROC_STUB
822

823
#elif defined(CPL_MULTIPROC_WIN32)
824

825
/************************************************************************/
826
/* ==================================================================== */
827
/*                        CPL_MULTIPROC_WIN32                           */
828
/*                                                                      */
829
/*    WIN32 Implementation of multiprocessing functions.                */
830
/* ==================================================================== */
831
/************************************************************************/
832

833
/* InitializeCriticalSectionAndSpinCount requires _WIN32_WINNT >= 0x403 */
834
#undef _WIN32_WINNT
835
#define _WIN32_WINNT 0x0500
836

837
#include <windows.h>
838

839
/************************************************************************/
840
/*                             CPLGetNumCPUs()                          */
841
/************************************************************************/
842

843
int CPLGetNumCPUs()
844
{
845
    SYSTEM_INFO info;
846
    GetSystemInfo(&info);
847
    const DWORD dwNum = info.dwNumberOfProcessors;
848
    if (dwNum < 1)
849
        return 1;
850
    return static_cast<int>(dwNum);
851
}
852

853
/************************************************************************/
854
/*                        CPLGetThreadingModel()                        */
855
/************************************************************************/
856

857
const char *CPLGetThreadingModel()
858

859
{
860
    return "win32";
861
}
862

863
/************************************************************************/
864
/*                           CPLCreateMutex()                           */
865
/************************************************************************/
866

867
CPLMutex *CPLCreateMutex()
868

869
{
870
#ifdef USE_WIN32_MUTEX
871
    HANDLE hMutex = CreateMutex(nullptr, TRUE, nullptr);
872

873
    return (CPLMutex *)hMutex;
874
#else
875

876
    // Do not use CPLMalloc() since its debugging infrastructure
877
    // can call the CPL*Mutex functions.
878
    CRITICAL_SECTION *pcs =
879
        static_cast<CRITICAL_SECTION *>(malloc(sizeof(*pcs)));
880
    if (pcs)
881
    {
882
        InitializeCriticalSectionAndSpinCount(pcs, 4000);
883
        EnterCriticalSection(pcs);
884
    }
885

886
    return reinterpret_cast<CPLMutex *>(pcs);
887
#endif
888
}
889

890
CPLMutex *CPLCreateMutexEx(int /* nOptions */)
891

892
{
893
    return CPLCreateMutex();
894
}
895

896
/************************************************************************/
897
/*                          CPLAcquireMutex()                           */
898
/************************************************************************/
899

900
int CPLAcquireMutex(CPLMutex *hMutexIn, double dfWaitInSeconds)
901

902
{
903
#ifdef USE_WIN32_MUTEX
904
    HANDLE hMutex = (HANDLE)hMutexIn;
905
    const DWORD hr =
906
        WaitForSingleObject(hMutex, static_cast<int>(dfWaitInSeconds * 1000));
907

908
    return hr != WAIT_TIMEOUT;
909
#else
910
    CRITICAL_SECTION *pcs = reinterpret_cast<CRITICAL_SECTION *>(hMutexIn);
911
    BOOL ret;
912

913
    if (dfWaitInSeconds >= 1000.0)
914
    {
915
        // We assume this is the synonymous for infinite, so it is more
916
        // efficient to use EnterCriticalSection() directly
917
        EnterCriticalSection(pcs);
918
        ret = TRUE;
919
    }
920
    else
921
    {
922
        while ((ret = TryEnterCriticalSection(pcs)) == 0 &&
923
               dfWaitInSeconds > 0.0)
924
        {
925
            CPLSleep(std::min(dfWaitInSeconds, 0.01));
926
            dfWaitInSeconds -= 0.01;
927
        }
928
    }
929

930
    return ret;
931
#endif
932
}
933

934
/************************************************************************/
935
/*                          CPLReleaseMutex()                           */
936
/************************************************************************/
937

938
void CPLReleaseMutex(CPLMutex *hMutexIn)
939

940
{
941
#ifdef USE_WIN32_MUTEX
942
    HANDLE hMutex = (HANDLE)hMutexIn;
943

944
    ReleaseMutex(hMutex);
945
#else
946
    CRITICAL_SECTION *pcs = reinterpret_cast<CRITICAL_SECTION *>(hMutexIn);
947

948
    LeaveCriticalSection(pcs);
949
#endif
950
}
951

952
/************************************************************************/
953
/*                          CPLDestroyMutex()                           */
954
/************************************************************************/
955

956
void CPLDestroyMutex(CPLMutex *hMutexIn)
957

958
{
959
#ifdef USE_WIN32_MUTEX
960
    HANDLE hMutex = (HANDLE)hMutexIn;
961

962
    CloseHandle(hMutex);
963
#else
964
    CRITICAL_SECTION *pcs = reinterpret_cast<CRITICAL_SECTION *>(hMutexIn);
965

966
    DeleteCriticalSection(pcs);
967
    free(pcs);
968
#endif
969
}
970

971
/************************************************************************/
972
/*                            CPLCreateCond()                           */
973
/************************************************************************/
974

975
struct _WaiterItem
976
{
977
    HANDLE hEvent;
978
    struct _WaiterItem *psNext;
979
};
980
typedef struct _WaiterItem WaiterItem;
981

982
typedef struct
983
{
984
    CPLMutex *hInternalMutex;
985
    WaiterItem *psWaiterList;
986
} Win32Cond;
987

988
CPLCond *CPLCreateCond()
989
{
990
    Win32Cond *psCond = static_cast<Win32Cond *>(malloc(sizeof(Win32Cond)));
991
    if (psCond == nullptr)
992
        return nullptr;
993
    psCond->hInternalMutex = CPLCreateMutex();
994
    if (psCond->hInternalMutex == nullptr)
995
    {
996
        free(psCond);
997
        return nullptr;
998
    }
999
    CPLReleaseMutex(psCond->hInternalMutex);
1000
    psCond->psWaiterList = nullptr;
1001
    return reinterpret_cast<CPLCond *>(psCond);
1002
}
1003

1004
/************************************************************************/
1005
/*                            CPLCondWait()                             */
1006
/************************************************************************/
1007

1008
static void CPLTLSFreeEvent(void *pData)
1009
{
1010
    CloseHandle(static_cast<HANDLE>(pData));
1011
}
1012

1013
void CPLCondWait(CPLCond *hCond, CPLMutex *hClientMutex)
1014
{
1015
    CPLCondTimedWait(hCond, hClientMutex, -1);
1016
}
1017

1018
/************************************************************************/
1019
/*                         CPLCondTimedWait()                           */
1020
/************************************************************************/
1021

1022
CPLCondTimedWaitReason CPLCondTimedWait(CPLCond *hCond, CPLMutex *hClientMutex,
1023
                                        double dfWaitInSeconds)
1024
{
1025
    Win32Cond *psCond = reinterpret_cast<Win32Cond *>(hCond);
1026

1027
    HANDLE hEvent = static_cast<HANDLE>(CPLGetTLS(CTLS_WIN32_COND));
1028
    if (hEvent == nullptr)
1029
    {
1030
        hEvent = CreateEvent(nullptr, /* security attributes */
1031
                             0,       /* manual reset = no */
1032
                             0,       /* initial state = unsignaled */
1033
                             nullptr /* no name */);
1034
        CPLAssert(hEvent != nullptr);
1035

1036
        CPLSetTLSWithFreeFunc(CTLS_WIN32_COND, hEvent, CPLTLSFreeEvent);
1037
    }
1038

1039
    /* Insert the waiter into the waiter list of the condition */
1040
    CPLAcquireMutex(psCond->hInternalMutex, 1000.0);
1041

1042
    WaiterItem *psItem = static_cast<WaiterItem *>(malloc(sizeof(WaiterItem)));
1043
    CPLAssert(psItem != nullptr);
1044

1045
    psItem->hEvent = hEvent;
1046
    psItem->psNext = psCond->psWaiterList;
1047

1048
    psCond->psWaiterList = psItem;
1049

1050
    CPLReleaseMutex(psCond->hInternalMutex);
1051

1052
    // Release the client mutex before waiting for the event being signaled.
1053
    CPLReleaseMutex(hClientMutex);
1054

1055
    // Ideally we would check that we do not get WAIT_FAILED but it is hard
1056
    // to report a failure.
1057
    auto ret = WaitForSingleObject(
1058
        hEvent, dfWaitInSeconds < 0 ? INFINITE
1059
                                    : static_cast<int>(dfWaitInSeconds * 1000));
1060

1061
    // Reacquire the client mutex.
1062
    CPLAcquireMutex(hClientMutex, 1000.0);
1063

1064
    if (ret == WAIT_OBJECT_0)
1065
        return COND_TIMED_WAIT_COND;
1066
    if (ret == WAIT_TIMEOUT)
1067
        return COND_TIMED_WAIT_TIME_OUT;
1068
    return COND_TIMED_WAIT_OTHER;
1069
}
1070

1071
/************************************************************************/
1072
/*                            CPLCondSignal()                           */
1073
/************************************************************************/
1074

1075
void CPLCondSignal(CPLCond *hCond)
1076
{
1077
    Win32Cond *psCond = reinterpret_cast<Win32Cond *>(hCond);
1078

1079
    // Signal the first registered event, and remove it from the list.
1080
    CPLAcquireMutex(psCond->hInternalMutex, 1000.0);
1081

1082
    WaiterItem *psIter = psCond->psWaiterList;
1083
    if (psIter != nullptr)
1084
    {
1085
        SetEvent(psIter->hEvent);
1086
        psCond->psWaiterList = psIter->psNext;
1087
        free(psIter);
1088
    }
1089

1090
    CPLReleaseMutex(psCond->hInternalMutex);
1091
}
1092

1093
/************************************************************************/
1094
/*                           CPLCondBroadcast()                         */
1095
/************************************************************************/
1096

1097
void CPLCondBroadcast(CPLCond *hCond)
1098
{
1099
    Win32Cond *psCond = reinterpret_cast<Win32Cond *>(hCond);
1100

1101
    // Signal all the registered events, and remove them from the list.
1102
    CPLAcquireMutex(psCond->hInternalMutex, 1000.0);
1103

1104
    WaiterItem *psIter = psCond->psWaiterList;
1105
    while (psIter != nullptr)
1106
    {
1107
        WaiterItem *psNext = psIter->psNext;
1108
        SetEvent(psIter->hEvent);
1109
        free(psIter);
1110
        psIter = psNext;
1111
    }
1112
    psCond->psWaiterList = nullptr;
1113

1114
    CPLReleaseMutex(psCond->hInternalMutex);
1115
}
1116

1117
/************************************************************************/
1118
/*                            CPLDestroyCond()                          */
1119
/************************************************************************/
1120

1121
void CPLDestroyCond(CPLCond *hCond)
1122
{
1123
    Win32Cond *psCond = reinterpret_cast<Win32Cond *>(hCond);
1124
    CPLDestroyMutex(psCond->hInternalMutex);
1125
    psCond->hInternalMutex = nullptr;
1126
    CPLAssert(psCond->psWaiterList == nullptr);
1127
    free(psCond);
1128
}
1129

1130
/************************************************************************/
1131
/*                            CPLLockFile()                             */
1132
/************************************************************************/
1133

1134
void *CPLLockFile(const char *pszPath, double dfWaitInSeconds)
1135

1136
{
1137
    char *pszLockFilename =
1138
        static_cast<char *>(CPLMalloc(strlen(pszPath) + 30));
1139
    snprintf(pszLockFilename, strlen(pszPath) + 30, "%s.lock", pszPath);
1140

1141
    // FIXME: use CreateFileW()
1142
    HANDLE hLockFile =
1143
        CreateFileA(pszLockFilename, GENERIC_WRITE, 0, nullptr, CREATE_NEW,
1144
                    FILE_ATTRIBUTE_NORMAL | FILE_FLAG_DELETE_ON_CLOSE, nullptr);
1145

1146
    while (GetLastError() == ERROR_ALREADY_EXISTS && dfWaitInSeconds > 0.0)
1147
    {
1148
        CloseHandle(hLockFile);
1149
        CPLSleep(std::min(dfWaitInSeconds, 0.125));
1150
        dfWaitInSeconds -= 0.125;
1151

1152
        hLockFile = CreateFileA(
1153
            pszLockFilename, GENERIC_WRITE, 0, nullptr, CREATE_NEW,
1154
            FILE_ATTRIBUTE_NORMAL | FILE_FLAG_DELETE_ON_CLOSE, nullptr);
1155
    }
1156

1157
    CPLFree(pszLockFilename);
1158

1159
    if (hLockFile == INVALID_HANDLE_VALUE)
1160
        return nullptr;
1161

1162
    if (GetLastError() == ERROR_ALREADY_EXISTS)
1163
    {
1164
        CloseHandle(hLockFile);
1165
        return nullptr;
1166
    }
1167

1168
    return static_cast<void *>(hLockFile);
1169
}
1170

1171
/************************************************************************/
1172
/*                           CPLUnlockFile()                            */
1173
/************************************************************************/
1174

1175
void CPLUnlockFile(void *hLock)
1176

1177
{
1178
    HANDLE hLockFile = static_cast<HANDLE>(hLock);
1179

1180
    CloseHandle(hLockFile);
1181
}
1182

1183
/************************************************************************/
1184
/*                             CPLGetPID()                              */
1185
/************************************************************************/
1186

1187
GIntBig CPLGetPID()
1188

1189
{
1190
    return static_cast<GIntBig>(GetCurrentThreadId());
1191
}
1192

1193
/************************************************************************/
1194
/*                       CPLStdCallThreadJacket()                       */
1195
/************************************************************************/
1196

1197
typedef struct
1198
{
1199
    void *pAppData;
1200
    CPLThreadFunc pfnMain;
1201
    HANDLE hThread;
1202
} CPLStdCallThreadInfo;
1203

1204
static DWORD WINAPI CPLStdCallThreadJacket(void *pData)
1205

1206
{
1207
    CPLStdCallThreadInfo *psInfo = static_cast<CPLStdCallThreadInfo *>(pData);
1208

1209
    psInfo->pfnMain(psInfo->pAppData);
1210

1211
    if (psInfo->hThread == nullptr)
1212
        CPLFree(psInfo);  // Only for detached threads.
1213

1214
    CPLCleanupTLS();
1215

1216
    return 0;
1217
}
1218

1219
/************************************************************************/
1220
/*                          CPLCreateThread()                           */
1221
/*                                                                      */
1222
/*      The WIN32 CreateThread() call requires an entry point that      */
1223
/*      has __stdcall conventions, so we provide a jacket function      */
1224
/*      to supply that.                                                 */
1225
/************************************************************************/
1226

1227
int CPLCreateThread(CPLThreadFunc pfnMain, void *pThreadArg)
1228

1229
{
1230
    CPLStdCallThreadInfo *psInfo = static_cast<CPLStdCallThreadInfo *>(
1231
        CPLCalloc(sizeof(CPLStdCallThreadInfo), 1));
1232
    psInfo->pAppData = pThreadArg;
1233
    psInfo->pfnMain = pfnMain;
1234
    psInfo->hThread = nullptr;
1235

1236
    DWORD nThreadId = 0;
1237
    HANDLE hThread =
1238
        CreateThread(nullptr, 0, CPLStdCallThreadJacket, psInfo, 0, &nThreadId);
1239

1240
    if (hThread == nullptr)
1241
        return -1;
1242

1243
    CloseHandle(hThread);
1244

1245
    return nThreadId;
1246
}
1247

1248
/************************************************************************/
1249
/*                      CPLCreateJoinableThread()                       */
1250
/************************************************************************/
1251

1252
CPLJoinableThread *CPLCreateJoinableThread(CPLThreadFunc pfnMain,
1253
                                           void *pThreadArg)
1254

1255
{
1256
    CPLStdCallThreadInfo *psInfo = static_cast<CPLStdCallThreadInfo *>(
1257
        CPLCalloc(sizeof(CPLStdCallThreadInfo), 1));
1258
    psInfo->pAppData = pThreadArg;
1259
    psInfo->pfnMain = pfnMain;
1260

1261
    DWORD nThreadId = 0;
1262
    HANDLE hThread =
1263
        CreateThread(nullptr, 0, CPLStdCallThreadJacket, psInfo, 0, &nThreadId);
1264

1265
    if (hThread == nullptr)
1266
        return nullptr;
1267

1268
    psInfo->hThread = hThread;
1269
    return reinterpret_cast<CPLJoinableThread *>(psInfo);
1270
}
1271

1272
/************************************************************************/
1273
/*                          CPLJoinThread()                             */
1274
/************************************************************************/
1275

1276
void CPLJoinThread(CPLJoinableThread *hJoinableThread)
1277
{
1278
    CPLStdCallThreadInfo *psInfo =
1279
        reinterpret_cast<CPLStdCallThreadInfo *>(hJoinableThread);
1280

1281
    WaitForSingleObject(psInfo->hThread, INFINITE);
1282
    CloseHandle(psInfo->hThread);
1283
    CPLFree(psInfo);
1284
}
1285

1286
/************************************************************************/
1287
/*                              CPLSleep()                              */
1288
/************************************************************************/
1289

1290
void CPLSleep(double dfWaitInSeconds)
1291

1292
{
1293
    Sleep(static_cast<DWORD>(dfWaitInSeconds * 1000.0));
1294
}
1295

1296
static bool bTLSKeySetup = false;
1297
static DWORD nTLSKey = 0;
1298

1299
/************************************************************************/
1300
/*                           CPLGetTLSList()                            */
1301
/************************************************************************/
1302

1303
static void **CPLGetTLSList(int *pbMemoryErrorOccurred)
1304

1305
{
1306
    void **papTLSList = nullptr;
1307

1308
    if (pbMemoryErrorOccurred)
1309
        *pbMemoryErrorOccurred = FALSE;
1310
    if (!bTLSKeySetup)
1311
    {
1312
        nTLSKey = TlsAlloc();
1313
        if (nTLSKey == TLS_OUT_OF_INDEXES)
1314
        {
1315
            if (pbMemoryErrorOccurred)
1316
            {
1317
                *pbMemoryErrorOccurred = TRUE;
1318
                fprintf(stderr, "CPLGetTLSList(): TlsAlloc() failed!\n");
1319
                return nullptr;
1320
            }
1321
            CPLEmergencyError("CPLGetTLSList(): TlsAlloc() failed!");
1322
        }
1323
        bTLSKeySetup = true;
1324
    }
1325

1326
    papTLSList = static_cast<void **>(TlsGetValue(nTLSKey));
1327
    if (papTLSList == nullptr)
1328
    {
1329
        papTLSList =
1330
            static_cast<void **>(VSICalloc(sizeof(void *), CTLS_MAX * 2));
1331
        if (papTLSList == nullptr)
1332
        {
1333
            if (pbMemoryErrorOccurred)
1334
            {
1335
                *pbMemoryErrorOccurred = TRUE;
1336
                fprintf(stderr,
1337
                        "CPLGetTLSList() failed to allocate TLS list!\n");
1338
                return nullptr;
1339
            }
1340
            CPLEmergencyError("CPLGetTLSList() failed to allocate TLS list!");
1341
        }
1342
        if (TlsSetValue(nTLSKey, papTLSList) == 0)
1343
        {
1344
            if (pbMemoryErrorOccurred)
1345
            {
1346
                *pbMemoryErrorOccurred = TRUE;
1347
                fprintf(stderr, "CPLGetTLSList(): TlsSetValue() failed!\n");
1348
                return nullptr;
1349
            }
1350
            CPLEmergencyError("CPLGetTLSList(): TlsSetValue() failed!");
1351
        }
1352
    }
1353

1354
    return papTLSList;
1355
}
1356

1357
/************************************************************************/
1358
/*                             CPLFinalizeTLS()                         */
1359
/************************************************************************/
1360

1361
void CPLFinalizeTLS()
1362
{
1363
    CPLCleanupTLS();
1364
}
1365

1366
/************************************************************************/
1367
/*                           CPLCleanupTLS()                            */
1368
/************************************************************************/
1369

1370
void CPLCleanupTLS()
1371

1372
{
1373
    if (!bTLSKeySetup)
1374
        return;
1375

1376
    void **papTLSList = static_cast<void **>(TlsGetValue(nTLSKey));
1377
    if (papTLSList == nullptr)
1378
        return;
1379

1380
    TlsSetValue(nTLSKey, nullptr);
1381

1382
    CPLCleanupTLSList(papTLSList);
1383
}
1384

1385
// endif CPL_MULTIPROC_WIN32
1386

1387
#elif defined(CPL_MULTIPROC_PTHREAD)
1388

1389
#include <pthread.h>
1390
#include <time.h>
1391
#include <unistd.h>
1392
#include <sys/time.h>
1393

1394
#ifdef HAVE_SCHED_GETAFFINITY
1395
#include <sched.h>
1396
#endif
1397

1398
/************************************************************************/
1399
/* ==================================================================== */
1400
/*                        CPL_MULTIPROC_PTHREAD                         */
1401
/*                                                                      */
1402
/*    PTHREAD Implementation of multiprocessing functions.              */
1403
/* ==================================================================== */
1404
/************************************************************************/
1405

1406
/************************************************************************/
1407
/*                             CPLGetNumCPUs()                          */
1408
/************************************************************************/
1409

1410
int CPLGetNumCPUs()
4,404✔
1411
{
1412
    int nCPUs;
1413
#ifdef _SC_NPROCESSORS_ONLN
1414
    nCPUs = static_cast<int>(sysconf(_SC_NPROCESSORS_ONLN));
4,404✔
1415
#else
1416
    nCPUs = 1;
1417
#endif
1418

1419
#ifdef HAVE_SCHED_GETAFFINITY
1420
    if (nCPUs > 1)
4,404✔
1421
    {
1422
        cpu_set_t *set = CPU_ALLOC(nCPUs);
4,404✔
1423
        if (set)
4,404✔
1424
        {
1425
            size_t sizeof_set = CPU_ALLOC_SIZE(nCPUs);
4,404✔
1426
            CPU_ZERO_S(sizeof_set, set);
4,404✔
1427
            if (sched_getaffinity(getpid(), sizeof_set, set) == 0)
4,404✔
1428
                nCPUs = CPU_COUNT_S(sizeof_set, set);
4,404✔
1429
            else
1430
                CPLDebug("CPL", "sched_getaffinity() failed");
×
1431
            CPU_FREE(set);
4,404✔
1432
        }
1433
    }
1434
#endif
1435

1436
    return nCPUs;
4,404✔
1437
}
1438

1439
/************************************************************************/
1440
/*                      CPLCreateOrAcquireMutex()                       */
1441
/************************************************************************/
1442
#ifdef HAVE_GCC_WARNING_ZERO_AS_NULL_POINTER_CONSTANT
1443
#pragma GCC diagnostic push
1444
#pragma GCC diagnostic ignored "-Wzero-as-null-pointer-constant"
1445
#endif
1446
static pthread_mutex_t global_mutex = PTHREAD_MUTEX_INITIALIZER;
1447
#ifdef HAVE_GCC_WARNING_ZERO_AS_NULL_POINTER_CONSTANT
1448
#pragma GCC diagnostic pop
1449
#endif
1450

1451
static CPLMutex *CPLCreateMutexInternal(bool bAlreadyInGlobalLock,
1452
                                        int nOptions);
1453

1454
int CPLCreateOrAcquireMutexEx(CPLMutex **phMutex, double dfWaitInSeconds,
68,720,400✔
1455
                              int nOptions)
1456

1457
{
1458
    pthread_mutex_lock(&global_mutex);
68,720,400✔
1459
    if (*phMutex == nullptr)
68,736,200✔
1460
    {
1461
        *phMutex = CPLCreateMutexInternal(true, nOptions);
32,486✔
1462
        const bool bSuccess = *phMutex != nullptr;
32,486✔
1463
        pthread_mutex_unlock(&global_mutex);
32,486✔
1464
        if (!bSuccess)
32,486✔
1465
            return false;
×
1466
    }
1467
    else
1468
    {
1469
        pthread_mutex_unlock(&global_mutex);
68,703,700✔
1470
    }
1471

1472
    return CPL_TO_BOOL(CPLAcquireMutex(*phMutex, dfWaitInSeconds));
68,735,100✔
1473
}
1474

1475
/************************************************************************/
1476
/*                   CPLCreateOrAcquireMutexInternal()                  */
1477
/************************************************************************/
1478

1479
static bool CPLCreateOrAcquireMutexInternal(CPLLock **phLock,
5,047✔
1480
                                            double dfWaitInSeconds,
1481
                                            CPLLockType eType)
1482
{
1483
    pthread_mutex_lock(&global_mutex);
5,047✔
1484
    if (*phLock == nullptr)
5,047✔
1485
    {
1486
        *phLock = static_cast<CPLLock *>(calloc(1, sizeof(CPLLock)));
548✔
1487
        if (*phLock)
548✔
1488
        {
1489
            (*phLock)->eType = eType;
548✔
1490
            (*phLock)->u.hMutex = CPLCreateMutexInternal(
1,096✔
1491
                true, eType == LOCK_RECURSIVE_MUTEX ? CPL_MUTEX_RECURSIVE
548✔
1492
                                                    : CPL_MUTEX_ADAPTIVE);
1493
            if ((*phLock)->u.hMutex == nullptr)
548✔
1494
            {
1495
                free(*phLock);
×
1496
                *phLock = nullptr;
×
1497
            }
1498
        }
1499
        const bool bSuccess = *phLock != nullptr;
548✔
1500
        pthread_mutex_unlock(&global_mutex);
548✔
1501
        if (!bSuccess)
548✔
1502
            return false;
×
1503
    }
1504
    else
1505
    {
1506
        pthread_mutex_unlock(&global_mutex);
4,499✔
1507
    }
1508

1509
    return CPL_TO_BOOL(CPLAcquireMutex((*phLock)->u.hMutex, dfWaitInSeconds));
5,047✔
1510
}
1511

1512
/************************************************************************/
1513
/*                        CPLGetThreadingModel()                        */
1514
/************************************************************************/
1515

1516
const char *CPLGetThreadingModel()
29✔
1517

1518
{
1519
    return "pthread";
29✔
1520
}
1521

1522
/************************************************************************/
1523
/*                           CPLCreateMutex()                           */
1524
/************************************************************************/
1525

1526
typedef struct _MutexLinkedElt MutexLinkedElt;
1527

1528
struct _MutexLinkedElt
1529
{
1530
    pthread_mutex_t sMutex;
1531
    int nOptions;
1532
    _MutexLinkedElt *psPrev;
1533
    _MutexLinkedElt *psNext;
1534
};
1535

1536
static MutexLinkedElt *psMutexList = nullptr;
1537

1538
static void CPLInitMutex(MutexLinkedElt *psItem)
110,226✔
1539
{
1540
    if (psItem->nOptions == CPL_MUTEX_REGULAR)
110,226✔
1541
    {
1542
#ifdef HAVE_GCC_WARNING_ZERO_AS_NULL_POINTER_CONSTANT
1543
#pragma GCC diagnostic push
1544
#pragma GCC diagnostic ignored "-Wzero-as-null-pointer-constant"
1545
#endif
1546
        pthread_mutex_t tmp_mutex = PTHREAD_MUTEX_INITIALIZER;
×
1547
#ifdef HAVE_GCC_WARNING_ZERO_AS_NULL_POINTER_CONSTANT
1548
#pragma GCC diagnostic pop
1549
#endif
1550
        psItem->sMutex = tmp_mutex;
×
1551
        return;
×
1552
    }
1553

1554
    // When an adaptive mutex is required, we can safely fallback to regular
1555
    // mutex if we don't have HAVE_PTHREAD_MUTEX_ADAPTIVE_NP.
1556
    if (psItem->nOptions == CPL_MUTEX_ADAPTIVE)
110,226✔
1557
    {
1558
#if defined(HAVE_PTHREAD_MUTEX_ADAPTIVE_NP)
1559
        pthread_mutexattr_t attr;
1560
        pthread_mutexattr_init(&attr);
618✔
1561
        pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ADAPTIVE_NP);
618✔
1562
        pthread_mutex_init(&(psItem->sMutex), &attr);
618✔
1563
#else
1564
        pthread_mutex_t tmp_mutex = PTHREAD_MUTEX_INITIALIZER;
1565
        psItem->sMutex = tmp_mutex;
1566
#endif
1567
        return;
618✔
1568
    }
1569

1570
#if defined(PTHREAD_MUTEX_RECURSIVE) || defined(HAVE_PTHREAD_MUTEX_RECURSIVE)
1571
    {
1572
        pthread_mutexattr_t attr;
1573
        pthread_mutexattr_init(&attr);
109,608✔
1574
        pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
109,609✔
1575
        pthread_mutex_init(&(psItem->sMutex), &attr);
109,607✔
1576
    }
1577
// BSDs have PTHREAD_MUTEX_RECURSIVE as an enum, not a define.
1578
// But they have #define MUTEX_TYPE_COUNTING_FAST PTHREAD_MUTEX_RECURSIVE
1579
#elif defined(MUTEX_TYPE_COUNTING_FAST)
1580
    {
1581
        pthread_mutexattr_t attr;
1582
        pthread_mutexattr_init(&attr);
1583
        pthread_mutexattr_settype(&attr, MUTEX_TYPE_COUNTING_FAST);
1584
        pthread_mutex_init(&(psItem->sMutex), &attr);
1585
    }
1586
#elif defined(PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP)
1587
    pthread_mutex_t tmp_mutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
1588
    psItem->sMutex = tmp_mutex;
1589
#else
1590
#error "Recursive mutexes apparently unsupported, configure --without-threads"
1591
#endif
1592
}
1593

1594
static CPLMutex *CPLCreateMutexInternal(bool bAlreadyInGlobalLock, int nOptions)
110,223✔
1595
{
1596
    MutexLinkedElt *psItem =
1597
        static_cast<MutexLinkedElt *>(malloc(sizeof(MutexLinkedElt)));
110,223✔
1598
    if (psItem == nullptr)
110,223✔
1599
    {
1600
        fprintf(stderr, "CPLCreateMutexInternal() failed.\n");
×
1601
        return nullptr;
×
1602
    }
1603

1604
    if (!bAlreadyInGlobalLock)
110,223✔
1605
        pthread_mutex_lock(&global_mutex);
77,190✔
1606
    psItem->psPrev = nullptr;
110,226✔
1607
    psItem->psNext = psMutexList;
110,226✔
1608
    if (psMutexList)
110,226✔
1609
        psMutexList->psPrev = psItem;
108,811✔
1610
    psMutexList = psItem;
110,226✔
1611
    if (!bAlreadyInGlobalLock)
110,226✔
1612
        pthread_mutex_unlock(&global_mutex);
77,193✔
1613

1614
    psItem->nOptions = nOptions;
110,226✔
1615
    CPLInitMutex(psItem);
110,226✔
1616

1617
    return reinterpret_cast<CPLMutex *>(psItem);
110,225✔
1618
}
1619

1620
CPLMutex *CPLCreateMutex()
77,121✔
1621
{
1622
    CPLMutex *mutex = CPLCreateMutexInternal(false, CPL_MUTEX_RECURSIVE);
77,121✔
1623
    if (mutex)
77,121✔
1624
        CPLAcquireMutex(mutex, 0);
77,121✔
1625
    return mutex;
77,122✔
1626
}
1627

1628
CPLMutex *CPLCreateMutexEx(int nOptions)
70✔
1629
{
1630
    CPLMutex *mutex = CPLCreateMutexInternal(false, nOptions);
70✔
1631
    if (mutex)
70✔
1632
        CPLAcquireMutex(mutex, 0);
70✔
1633
    return mutex;
70✔
1634
}
1635

1636
/************************************************************************/
1637
/*                          CPLAcquireMutex()                           */
1638
/************************************************************************/
1639

1640
int CPLAcquireMutex(CPLMutex *hMutexIn, double /* dfWaitInSeconds */)
94,411,200✔
1641
{
1642
    // TODO: Need to add timeout support.
1643
    MutexLinkedElt *psItem = reinterpret_cast<MutexLinkedElt *>(hMutexIn);
94,411,200✔
1644
    const int err = pthread_mutex_lock(&(psItem->sMutex));
94,411,200✔
1645

1646
    if (err != 0)
94,416,800✔
1647
    {
1648
        if (err == EDEADLK)
×
1649
            fprintf(stderr, "CPLAcquireMutex: Error = %d/EDEADLK\n", err);
×
1650
        else
1651
            fprintf(stderr, "CPLAcquireMutex: Error = %d (%s)\n", err,
×
1652
                    strerror(err));
1653

1654
        return FALSE;
×
1655
    }
1656

1657
    return TRUE;
94,416,800✔
1658
}
1659

1660
/************************************************************************/
1661
/*                          CPLReleaseMutex()                           */
1662
/************************************************************************/
1663

1664
void CPLReleaseMutex(CPLMutex *hMutexIn)
94,415,800✔
1665

1666
{
1667
    MutexLinkedElt *psItem = reinterpret_cast<MutexLinkedElt *>(hMutexIn);
94,415,800✔
1668
    const int err = pthread_mutex_unlock(&(psItem->sMutex));
94,415,800✔
1669
    if (err != 0)
94,416,700✔
1670
    {
1671
        fprintf(stderr, "CPLReleaseMutex: Error = %d (%s)\n", err,
×
1672
                strerror(err));
1673
    }
1674
}
94,416,700✔
1675

1676
/************************************************************************/
1677
/*                          CPLDestroyMutex()                           */
1678
/************************************************************************/
1679

1680
void CPLDestroyMutex(CPLMutex *hMutexIn)
104,503✔
1681

1682
{
1683
    MutexLinkedElt *psItem = reinterpret_cast<MutexLinkedElt *>(hMutexIn);
104,503✔
1684
    const int err = pthread_mutex_destroy(&(psItem->sMutex));
104,503✔
1685
    if (err != 0)
104,503✔
1686
    {
1687
        fprintf(stderr, "CPLDestroyMutex: Error = %d (%s)\n", err,
×
1688
                strerror(err));
1689
    }
1690
    pthread_mutex_lock(&global_mutex);
104,503✔
1691
    if (psItem->psPrev)
104,503✔
1692
        psItem->psPrev->psNext = psItem->psNext;
68,523✔
1693
    if (psItem->psNext)
104,503✔
1694
        psItem->psNext->psPrev = psItem->psPrev;
100,724✔
1695
    if (psItem == psMutexList)
104,503✔
1696
        psMutexList = psItem->psNext;
35,980✔
1697
    pthread_mutex_unlock(&global_mutex);
104,503✔
1698
    free(hMutexIn);
104,503✔
1699
}
104,503✔
1700

1701
/************************************************************************/
1702
/*                          CPLReinitAllMutex()                         */
1703
/************************************************************************/
1704

1705
// Used by gdalclientserver.cpp just after forking, to avoid
1706
// deadlocks while mixing threads with fork.
1707
void CPLReinitAllMutex();  // TODO(schwehr): Put this in a header.
1708

1709
void CPLReinitAllMutex()
×
1710
{
1711
    MutexLinkedElt *psItem = psMutexList;
×
1712
    while (psItem != nullptr)
×
1713
    {
1714
        CPLInitMutex(psItem);
×
1715
        psItem = psItem->psNext;
×
1716
    }
1717
#ifdef HAVE_GCC_WARNING_ZERO_AS_NULL_POINTER_CONSTANT
1718
#pragma GCC diagnostic push
1719
#pragma GCC diagnostic ignored "-Wzero-as-null-pointer-constant"
1720
#endif
1721
    pthread_mutex_t tmp_global_mutex = PTHREAD_MUTEX_INITIALIZER;
×
1722
#ifdef HAVE_GCC_WARNING_ZERO_AS_NULL_POINTER_CONSTANT
1723
#pragma GCC diagnostic pop
1724
#endif
1725
    global_mutex = tmp_global_mutex;
×
1726
}
×
1727

1728
/************************************************************************/
1729
/*                            CPLCreateCond()                           */
1730
/************************************************************************/
1731

1732
CPLCond *CPLCreateCond()
33,766✔
1733
{
1734
    pthread_cond_t *pCond =
1735
        static_cast<pthread_cond_t *>(malloc(sizeof(pthread_cond_t)));
33,766✔
1736
    if (pCond && pthread_cond_init(pCond, nullptr) == 0)
33,766✔
1737
        return reinterpret_cast<CPLCond *>(pCond);
33,765✔
1738
    fprintf(stderr, "CPLCreateCond() failed.\n");
×
1739
    free(pCond);
×
1740
    return nullptr;
×
1741
}
1742

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

1747
void CPLCondWait(CPLCond *hCond, CPLMutex *hMutex)
1,133✔
1748
{
1749
    pthread_cond_t *pCond = reinterpret_cast<pthread_cond_t *>(hCond);
1,133✔
1750
    MutexLinkedElt *psItem = reinterpret_cast<MutexLinkedElt *>(hMutex);
1,133✔
1751
    pthread_mutex_t *pMutex = &(psItem->sMutex);
1,133✔
1752
    pthread_cond_wait(pCond, pMutex);
1,133✔
1753
}
1,133✔
1754

1755
/************************************************************************/
1756
/*                         CPLCondTimedWait()                           */
1757
/************************************************************************/
1758

1759
CPLCondTimedWaitReason CPLCondTimedWait(CPLCond *hCond, CPLMutex *hMutex,
×
1760
                                        double dfWaitInSeconds)
1761
{
1762
    pthread_cond_t *pCond = reinterpret_cast<pthread_cond_t *>(hCond);
×
1763
    MutexLinkedElt *psItem = reinterpret_cast<MutexLinkedElt *>(hMutex);
×
1764
    pthread_mutex_t *pMutex = &(psItem->sMutex);
×
1765
    struct timeval tv;
1766
    struct timespec ts;
1767

1768
    gettimeofday(&tv, nullptr);
×
1769
    ts.tv_sec = time(nullptr) + static_cast<int>(dfWaitInSeconds);
×
1770
    ts.tv_nsec =
×
1771
        static_cast<int>(tv.tv_usec) * 1000 +
×
1772
        static_cast<int>(1000 * 1000 * 1000 * fmod(dfWaitInSeconds, 1));
×
1773
    ts.tv_sec += ts.tv_nsec / (1000 * 1000 * 1000);
×
1774
    ts.tv_nsec %= (1000 * 1000 * 1000);
×
1775
    int ret = pthread_cond_timedwait(pCond, pMutex, &ts);
×
1776
    if (ret == 0)
×
1777
        return COND_TIMED_WAIT_COND;
×
1778
    else if (ret == ETIMEDOUT)
×
1779
        return COND_TIMED_WAIT_TIME_OUT;
×
1780
    else
1781
        return COND_TIMED_WAIT_OTHER;
×
1782
}
1783

1784
/************************************************************************/
1785
/*                            CPLCondSignal()                           */
1786
/************************************************************************/
1787

1788
void CPLCondSignal(CPLCond *hCond)
32,741✔
1789
{
1790
    pthread_cond_t *pCond = reinterpret_cast<pthread_cond_t *>(hCond);
32,741✔
1791
    pthread_cond_signal(pCond);
32,741✔
1792
}
32,740✔
1793

1794
/************************************************************************/
1795
/*                           CPLCondBroadcast()                         */
1796
/************************************************************************/
1797

1798
void CPLCondBroadcast(CPLCond *hCond)
102✔
1799
{
1800
    pthread_cond_t *pCond = reinterpret_cast<pthread_cond_t *>(hCond);
102✔
1801
    pthread_cond_broadcast(pCond);
102✔
1802
}
102✔
1803

1804
/************************************************************************/
1805
/*                            CPLDestroyCond()                          */
1806
/************************************************************************/
1807

1808
void CPLDestroyCond(CPLCond *hCond)
33,767✔
1809
{
1810
    pthread_cond_t *pCond = reinterpret_cast<pthread_cond_t *>(hCond);
33,767✔
1811
    pthread_cond_destroy(pCond);
33,767✔
1812
    free(hCond);
33,767✔
1813
}
33,767✔
1814

1815
/************************************************************************/
1816
/*                            CPLLockFile()                             */
1817
/*                                                                      */
1818
/*      This is really a stub implementation, see first                 */
1819
/*      CPLLockFile() for caveats.                                      */
1820
/************************************************************************/
1821

1822
void *CPLLockFile(const char *pszPath, double dfWaitInSeconds)
3✔
1823

1824
{
1825
    /* -------------------------------------------------------------------- */
1826
    /*      We use a lock file with a name derived from the file we want    */
1827
    /*      to lock to represent the file being locked.  Note that for      */
1828
    /*      the stub implementation the target file does not even need      */
1829
    /*      to exist to be locked.                                          */
1830
    /* -------------------------------------------------------------------- */
1831
    const size_t nLen = strlen(pszPath) + 30;
3✔
1832
    char *pszLockFilename = static_cast<char *>(CPLMalloc(nLen));
3✔
1833
    snprintf(pszLockFilename, nLen, "%s.lock", pszPath);
3✔
1834

1835
    FILE *fpLock = fopen(pszLockFilename, "r");
3✔
1836
    while (fpLock != nullptr && dfWaitInSeconds > 0.0)
3✔
1837
    {
1838
        fclose(fpLock);
×
1839
        CPLSleep(std::min(dfWaitInSeconds, 0.5));
×
1840
        dfWaitInSeconds -= 0.5;
×
1841

1842
        fpLock = fopen(pszLockFilename, "r");
×
1843
    }
1844

1845
    if (fpLock != nullptr)
3✔
1846
    {
1847
        fclose(fpLock);
×
1848
        CPLFree(pszLockFilename);
×
1849
        return nullptr;
×
1850
    }
1851

1852
    fpLock = fopen(pszLockFilename, "w");
3✔
1853

1854
    if (fpLock == nullptr)
3✔
1855
    {
1856
        CPLFree(pszLockFilename);
×
1857
        return nullptr;
×
1858
    }
1859

1860
    fwrite("held\n", 1, 5, fpLock);
3✔
1861
    fclose(fpLock);
3✔
1862

1863
    return pszLockFilename;
3✔
1864
}
1865

1866
/************************************************************************/
1867
/*                           CPLUnlockFile()                            */
1868
/************************************************************************/
1869

1870
void CPLUnlockFile(void *hLock)
3✔
1871

1872
{
1873
    char *pszLockFilename = static_cast<char *>(hLock);
3✔
1874

1875
    if (hLock == nullptr)
3✔
1876
        return;
×
1877

1878
    VSIUnlink(pszLockFilename);
3✔
1879

1880
    CPLFree(pszLockFilename);
3✔
1881
}
1882

1883
/************************************************************************/
1884
/*                             CPLGetPID()                              */
1885
/************************************************************************/
1886

1887
GIntBig CPLGetPID()
20,199,400✔
1888

1889
{
1890
    return reinterpret_cast<GIntBig>(reinterpret_cast<void *>(pthread_self()));
20,199,400✔
1891
}
1892

1893
static pthread_key_t oTLSKey;
1894
static pthread_once_t oTLSKeySetup = PTHREAD_ONCE_INIT;
1895

1896
/************************************************************************/
1897
/*                             CPLMake_key()                            */
1898
/************************************************************************/
1899

1900
static void CPLMake_key()
1,416✔
1901

1902
{
1903
    if (pthread_key_create(&oTLSKey, reinterpret_cast<void (*)(void *)>(
1,416✔
1904
                                         CPLCleanupTLSList)) != 0)
1,416✔
1905
    {
1906
        CPLError(CE_Fatal, CPLE_AppDefined, "pthread_key_create() failed!");
×
1907
    }
1908
}
1,416✔
1909

1910
/************************************************************************/
1911
/*                           CPLGetTLSList()                            */
1912
/************************************************************************/
1913

1914
static void **CPLGetTLSList(int *pbMemoryErrorOccurred)
63,185,300✔
1915

1916
{
1917
    if (pbMemoryErrorOccurred)
63,185,300✔
1918
        *pbMemoryErrorOccurred = FALSE;
60,156,600✔
1919

1920
    if (pthread_once(&oTLSKeySetup, CPLMake_key) != 0)
63,185,300✔
1921
    {
1922
        if (pbMemoryErrorOccurred)
×
1923
        {
1924
            fprintf(stderr, "CPLGetTLSList(): pthread_once() failed!\n");
×
1925
            *pbMemoryErrorOccurred = TRUE;
×
1926
            return nullptr;
×
1927
        }
1928
        CPLEmergencyError("CPLGetTLSList(): pthread_once() failed!");
×
1929
    }
1930

1931
    void **papTLSList = static_cast<void **>(pthread_getspecific(oTLSKey));
63,168,000✔
1932
    if (papTLSList == nullptr)
63,176,500✔
1933
    {
1934
        papTLSList =
1935
            static_cast<void **>(VSICalloc(sizeof(void *), CTLS_MAX * 2));
4,587✔
1936
        if (papTLSList == nullptr)
3,594✔
1937
        {
1938
            if (pbMemoryErrorOccurred)
×
1939
            {
1940
                fprintf(stderr,
×
1941
                        "CPLGetTLSList() failed to allocate TLS list!\n");
1942
                *pbMemoryErrorOccurred = TRUE;
×
1943
                return nullptr;
×
1944
            }
1945
            CPLEmergencyError("CPLGetTLSList() failed to allocate TLS list!");
×
1946
        }
1947
        if (pthread_setspecific(oTLSKey, papTLSList) != 0)
3,594✔
1948
        {
1949
            if (pbMemoryErrorOccurred)
×
1950
            {
1951
                fprintf(stderr,
×
1952
                        "CPLGetTLSList(): pthread_setspecific() failed!\n");
1953
                *pbMemoryErrorOccurred = TRUE;
×
1954
                return nullptr;
×
1955
            }
1956
            CPLEmergencyError("CPLGetTLSList(): pthread_setspecific() failed!");
×
1957
        }
1958
    }
1959

1960
    return papTLSList;
63,175,500✔
1961
}
1962

1963
/************************************************************************/
1964
/*                       CPLStdCallThreadJacket()                       */
1965
/************************************************************************/
1966

1967
typedef struct
1968
{
1969
    void *pAppData;
1970
    CPLThreadFunc pfnMain;
1971
    pthread_t hThread;
1972
    bool bJoinable;
1973
#ifdef CHECK_THREAD_CAN_ALLOCATE_TLS
1974
    bool bInitSucceeded;
1975
    bool bInitDone;
1976
    pthread_mutex_t sMutex;
1977
    pthread_cond_t sCond;
1978
#endif
1979
} CPLStdCallThreadInfo;
1980

1981
static void *CPLStdCallThreadJacket(void *pData)
4,829✔
1982

1983
{
1984
    CPLStdCallThreadInfo *psInfo = static_cast<CPLStdCallThreadInfo *>(pData);
4,829✔
1985

1986
#ifdef CHECK_THREAD_CAN_ALLOCATE_TLS
1987
    int bMemoryError = FALSE;
1988
    CPLGetTLSList(&bMemoryError);
1989
    if (bMemoryError)
1990
        goto error;
1991

1992
    assert(pthread_mutex_lock(&(psInfo->sMutex)) == 0);
1993
    psInfo->bInitDone = true;
1994
    assert(pthread_cond_signal(&(psInfo->sCond)) == 0);
1995
    assert(pthread_mutex_unlock(&(psInfo->sMutex)) == 0);
1996
#endif
1997

1998
    psInfo->pfnMain(psInfo->pAppData);
4,829✔
1999

2000
    if (!psInfo->bJoinable)
3,790✔
2001
        CPLFree(psInfo);
1✔
2002

2003
    return nullptr;
3,790✔
2004

2005
#ifdef CHECK_THREAD_CAN_ALLOCATE_TLS
2006
error:
2007
    assert(pthread_mutex_lock(&(psInfo->sMutex)) == 0);
2008
    psInfo->bInitSucceeded = false;
2009
    psInfo->bInitDone = true;
2010
    assert(pthread_cond_signal(&(psInfo->sCond)) == 0);
2011
    assert(pthread_mutex_unlock(&(psInfo->sMutex)) == 0);
2012
    return nullptr;
2013
#endif
2014
}
2015

2016
/************************************************************************/
2017
/*                          CPLCreateThread()                           */
2018
/*                                                                      */
2019
/*      The WIN32 CreateThread() call requires an entry point that      */
2020
/*      has __stdcall conventions, so we provide a jacket function      */
2021
/*      to supply that.                                                 */
2022
/************************************************************************/
2023

2024
int CPLCreateThread(CPLThreadFunc pfnMain, void *pThreadArg)
1✔
2025

2026
{
2027
    CPLStdCallThreadInfo *psInfo = static_cast<CPLStdCallThreadInfo *>(
2028
        VSI_CALLOC_VERBOSE(sizeof(CPLStdCallThreadInfo), 1));
1✔
2029
    if (psInfo == nullptr)
1✔
2030
        return -1;
×
2031
    psInfo->pAppData = pThreadArg;
1✔
2032
    psInfo->pfnMain = pfnMain;
1✔
2033
    psInfo->bJoinable = false;
1✔
2034
#ifdef CHECK_THREAD_CAN_ALLOCATE_TLS
2035
    psInfo->bInitSucceeded = true;
2036
    psInfo->bInitDone = false;
2037
    pthread_mutex_t sMutex = PTHREAD_MUTEX_INITIALIZER;
2038
    psInfo->sMutex = sMutex;
2039
    if (pthread_cond_init(&(psInfo->sCond), nullptr) != 0)
2040
    {
2041
        CPLFree(psInfo);
2042
        fprintf(stderr, "CPLCreateThread() failed.\n");
2043
        return -1;
2044
    }
2045
#endif
2046

2047
    pthread_attr_t hThreadAttr;
2048
    pthread_attr_init(&hThreadAttr);
1✔
2049
    pthread_attr_setdetachstate(&hThreadAttr, PTHREAD_CREATE_DETACHED);
1✔
2050
    if (pthread_create(&(psInfo->hThread), &hThreadAttr, CPLStdCallThreadJacket,
1✔
2051
                       static_cast<void *>(psInfo)) != 0)
1✔
2052
    {
2053
#ifdef CHECK_THREAD_CAN_ALLOCATE_TLS
2054
        pthread_cond_destroy(&(psInfo->sCond));
2055
#endif
2056
        CPLFree(psInfo);
×
2057
        fprintf(stderr, "CPLCreateThread() failed.\n");
×
2058
        return -1;
×
2059
    }
2060

2061
#ifdef CHECK_THREAD_CAN_ALLOCATE_TLS
2062
    bool bInitSucceeded;
2063
    while (true)
2064
    {
2065
        assert(pthread_mutex_lock(&(psInfo->sMutex)) == 0);
2066
        bool bInitDone = psInfo->bInitDone;
2067
        if (!bInitDone)
2068
            assert(pthread_cond_wait(&(psInfo->sCond), &(psInfo->sMutex)) == 0);
2069
        bInitSucceeded = psInfo->bInitSucceeded;
2070
        assert(pthread_mutex_unlock(&(psInfo->sMutex)) == 0);
2071
        if (bInitDone)
2072
            break;
2073
    }
2074

2075
    pthread_cond_destroy(&(psInfo->sCond));
2076

2077
    if (!bInitSucceeded)
2078
    {
2079
        CPLFree(psInfo);
2080
        fprintf(stderr, "CPLCreateThread() failed.\n");
2081
        return -1;
2082
    }
2083
#endif
2084

2085
    return 1;  // Can we return the actual thread pid?
1✔
2086
}
2087

2088
/************************************************************************/
2089
/*                      CPLCreateJoinableThread()                       */
2090
/************************************************************************/
2091

2092
CPLJoinableThread *CPLCreateJoinableThread(CPLThreadFunc pfnMain,
4,828✔
2093
                                           void *pThreadArg)
2094

2095
{
2096
    CPLStdCallThreadInfo *psInfo = static_cast<CPLStdCallThreadInfo *>(
2097
        VSI_CALLOC_VERBOSE(sizeof(CPLStdCallThreadInfo), 1));
4,828✔
2098
    if (psInfo == nullptr)
4,828✔
2099
        return nullptr;
×
2100
    psInfo->pAppData = pThreadArg;
4,828✔
2101
    psInfo->pfnMain = pfnMain;
4,828✔
2102
    psInfo->bJoinable = true;
4,828✔
2103
#ifdef CHECK_THREAD_CAN_ALLOCATE_TLS
2104
    psInfo->bInitSucceeded = true;
2105
    psInfo->bInitDone = false;
2106
    pthread_mutex_t sMutex = PTHREAD_MUTEX_INITIALIZER;
2107
    psInfo->sMutex = sMutex;
2108
    {
2109
        int err = pthread_cond_init(&(psInfo->sCond), nullptr);
2110
        if (err != 0)
2111
        {
2112
            CPLFree(psInfo);
2113
            fprintf(stderr, "CPLCreateJoinableThread() failed: %s.\n",
2114
                    strerror(err));
2115
            return nullptr;
2116
        }
2117
    }
2118
#endif
2119

2120
    pthread_attr_t hThreadAttr;
2121
    pthread_attr_init(&hThreadAttr);
4,828✔
2122
    pthread_attr_setdetachstate(&hThreadAttr, PTHREAD_CREATE_JOINABLE);
4,828✔
2123
    int err =
2124
        pthread_create(&(psInfo->hThread), &hThreadAttr, CPLStdCallThreadJacket,
4,828✔
2125
                       static_cast<void *>(psInfo));
2126
    if (err != 0)
4,828✔
2127
    {
2128
#ifdef CHECK_THREAD_CAN_ALLOCATE_TLS
2129
        pthread_cond_destroy(&(psInfo->sCond));
2130
#endif
2131
        CPLFree(psInfo);
×
2132
        fprintf(stderr, "CPLCreateJoinableThread() failed: %s.\n",
×
2133
                strerror(err));
2134
        return nullptr;
×
2135
    }
2136

2137
#ifdef CHECK_THREAD_CAN_ALLOCATE_TLS
2138
    bool bInitSucceeded;
2139
    while (true)
2140
    {
2141
        assert(pthread_mutex_lock(&(psInfo->sMutex)) == 0);
2142
        bool bInitDone = psInfo->bInitDone;
2143
        if (!bInitDone)
2144
            assert(pthread_cond_wait(&(psInfo->sCond), &(psInfo->sMutex)) == 0);
2145
        bInitSucceeded = psInfo->bInitSucceeded;
2146
        assert(pthread_mutex_unlock(&(psInfo->sMutex)) == 0);
2147
        if (bInitDone)
2148
            break;
2149
    }
2150

2151
    pthread_cond_destroy(&(psInfo->sCond));
2152

2153
    if (!bInitSucceeded)
2154
    {
2155
        void *status;
2156
        pthread_join(psInfo->hThread, &status);
2157
        CPLFree(psInfo);
2158
        fprintf(stderr, "CPLCreateJoinableThread() failed.\n");
2159
        return nullptr;
2160
    }
2161
#endif
2162

2163
    return reinterpret_cast<CPLJoinableThread *>(psInfo);
4,828✔
2164
}
2165

2166
/************************************************************************/
2167
/*                          CPLJoinThread()                             */
2168
/************************************************************************/
2169

2170
void CPLJoinThread(CPLJoinableThread *hJoinableThread)
3,789✔
2171
{
2172
    CPLStdCallThreadInfo *psInfo =
3,789✔
2173
        reinterpret_cast<CPLStdCallThreadInfo *>(hJoinableThread);
2174
    if (psInfo == nullptr)
3,789✔
2175
        return;
×
2176

2177
    void *status;
2178
    pthread_join(psInfo->hThread, &status);
3,789✔
2179

2180
    CPLFree(psInfo);
3,789✔
2181
}
2182

2183
/************************************************************************/
2184
/*                              CPLSleep()                              */
2185
/************************************************************************/
2186

2187
void CPLSleep(double dfWaitInSeconds)
69✔
2188

2189
{
2190
    struct timespec sRequest;
2191
    struct timespec sRemain;
2192

2193
    sRequest.tv_sec = static_cast<int>(floor(dfWaitInSeconds));
69✔
2194
    sRequest.tv_nsec =
69✔
2195
        static_cast<int>((dfWaitInSeconds - sRequest.tv_sec) * 1000000000);
69✔
2196
    nanosleep(&sRequest, &sRemain);
69✔
2197
}
69✔
2198

2199
/************************************************************************/
2200
/*                             CPLFinalizeTLS()                         */
2201
/************************************************************************/
2202

2203
void CPLFinalizeTLS()
440✔
2204
{
2205
    CPLCleanupTLS();
440✔
2206
    // See #5509 for the explanation why this may be needed.
2207
    pthread_key_delete(oTLSKey);
440✔
2208
}
440✔
2209

2210
/************************************************************************/
2211
/*                             CPLCleanupTLS()                          */
2212
/************************************************************************/
2213

2214
void CPLCleanupTLS()
1,381✔
2215

2216
{
2217
    void **papTLSList = static_cast<void **>(pthread_getspecific(oTLSKey));
1,381✔
2218
    if (papTLSList == nullptr)
1,381✔
2219
        return;
1✔
2220

2221
    pthread_setspecific(oTLSKey, nullptr);
1,380✔
2222

2223
    CPLCleanupTLSList(papTLSList);
1,380✔
2224
}
2225

2226
/************************************************************************/
2227
/*                          CPLCreateSpinLock()                         */
2228
/************************************************************************/
2229

2230
#if defined(HAVE_PTHREAD_SPIN_LOCK)
2231
#define HAVE_SPINLOCK_IMPL
2232

2233
struct _CPLSpinLock
2234
{
2235
    pthread_spinlock_t spin;
2236
};
2237

2238
CPLSpinLock *CPLCreateSpinLock()
2239
{
2240
    CPLSpinLock *psSpin =
2241
        static_cast<CPLSpinLock *>(malloc(sizeof(CPLSpinLock)));
2242
    if (psSpin != nullptr &&
2243
        pthread_spin_init(&(psSpin->spin), PTHREAD_PROCESS_PRIVATE) == 0)
2244
    {
2245
        return psSpin;
2246
    }
2247
    else
2248
    {
2249
        fprintf(stderr, "CPLCreateSpinLock() failed.\n");
2250
        free(psSpin);
2251
        return nullptr;
2252
    }
2253
}
2254

2255
/************************************************************************/
2256
/*                        CPLAcquireSpinLock()                          */
2257
/************************************************************************/
2258

2259
int CPLAcquireSpinLock(CPLSpinLock *psSpin)
2260
{
2261
    return pthread_spin_lock(&(psSpin->spin)) == 0;
2262
}
2263

2264
/************************************************************************/
2265
/*                   CPLCreateOrAcquireSpinLockInternal()               */
2266
/************************************************************************/
2267

2268
int CPLCreateOrAcquireSpinLockInternal(CPLLock **ppsLock)
2269
{
2270
    pthread_mutex_lock(&global_mutex);
2271
    if (*ppsLock == nullptr)
2272
    {
2273
        *ppsLock = static_cast<CPLLock *>(calloc(1, sizeof(CPLLock)));
2274
        if (*ppsLock != nullptr)
2275
        {
2276
            (*ppsLock)->eType = LOCK_SPIN;
2277
            (*ppsLock)->u.hSpinLock = CPLCreateSpinLock();
2278
            if ((*ppsLock)->u.hSpinLock == nullptr)
2279
            {
2280
                free(*ppsLock);
2281
                *ppsLock = nullptr;
2282
            }
2283
        }
2284
    }
2285
    pthread_mutex_unlock(&global_mutex);
2286
    // coverity[missing_unlock]
2287
    return (*ppsLock != nullptr && CPLAcquireSpinLock((*ppsLock)->u.hSpinLock));
2288
}
2289

2290
/************************************************************************/
2291
/*                       CPLReleaseSpinLock()                           */
2292
/************************************************************************/
2293

2294
void CPLReleaseSpinLock(CPLSpinLock *psSpin)
2295
{
2296
    pthread_spin_unlock(&(psSpin->spin));
2297
}
2298

2299
/************************************************************************/
2300
/*                        CPLDestroySpinLock()                          */
2301
/************************************************************************/
2302

2303
void CPLDestroySpinLock(CPLSpinLock *psSpin)
2304
{
2305
    pthread_spin_destroy(&(psSpin->spin));
2306
    free(psSpin);
2307
}
2308
#endif  // HAVE_PTHREAD_SPIN_LOCK
2309

2310
#endif  // def CPL_MULTIPROC_PTHREAD
2311

2312
/************************************************************************/
2313
/*                             CPLGetTLS()                              */
2314
/************************************************************************/
2315

2316
void *CPLGetTLS(int nIndex)
1,467,270✔
2317

2318
{
2319
    void **l_papTLSList = CPLGetTLSList(nullptr);
1,467,270✔
2320

2321
    CPLAssert(nIndex >= 0 && nIndex < CTLS_MAX);
1,467,270✔
2322

2323
    return l_papTLSList[nIndex];
1,467,240✔
2324
}
2325

2326
/************************************************************************/
2327
/*                            CPLGetTLSEx()                             */
2328
/************************************************************************/
2329

2330
void *CPLGetTLSEx(int nIndex, int *pbMemoryErrorOccurred)
60,167,200✔
2331

2332
{
2333
    void **l_papTLSList = CPLGetTLSList(pbMemoryErrorOccurred);
60,167,200✔
2334
    if (l_papTLSList == nullptr)
60,155,600✔
2335
        return nullptr;
×
2336

2337
    CPLAssert(nIndex >= 0 && nIndex < CTLS_MAX);
60,155,600✔
2338

2339
    return l_papTLSList[nIndex];
60,140,500✔
2340
}
2341

2342
/************************************************************************/
2343
/*                             CPLSetTLS()                              */
2344
/************************************************************************/
2345

2346
void CPLSetTLS(int nIndex, void *pData, int bFreeOnExit)
18,982✔
2347

2348
{
2349
    CPLSetTLSWithFreeFunc(nIndex, pData, (bFreeOnExit) ? CPLFree : nullptr);
18,982✔
2350
}
18,981✔
2351

2352
/************************************************************************/
2353
/*                      CPLSetTLSWithFreeFunc()                         */
2354
/************************************************************************/
2355

2356
// Warning: The CPLTLSFreeFunc must not in any case directly or indirectly
2357
// use or fetch any TLS data, or a terminating thread will hang!
2358
void CPLSetTLSWithFreeFunc(int nIndex, void *pData, CPLTLSFreeFunc pfnFree)
1,558,600✔
2359

2360
{
2361
    void **l_papTLSList = CPLGetTLSList(nullptr);
1,558,600✔
2362

2363
    CPLAssert(nIndex >= 0 && nIndex < CTLS_MAX);
1,552,950✔
2364

2365
    l_papTLSList[nIndex] = pData;
1,548,440✔
2366
    l_papTLSList[CTLS_MAX + nIndex] = reinterpret_cast<void *>(pfnFree);
1,548,440✔
2367
}
1,548,440✔
2368

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

2373
// Warning: the CPLTLSFreeFunc must not in any case directly or indirectly
2374
// use or fetch any TLS data, or a terminating thread will hang!
2375
void CPLSetTLSWithFreeFuncEx(int nIndex, void *pData, CPLTLSFreeFunc pfnFree,
1,371✔
2376
                             int *pbMemoryErrorOccurred)
2377

2378
{
2379
    void **l_papTLSList = CPLGetTLSList(pbMemoryErrorOccurred);
1,371✔
2380

2381
    CPLAssert(nIndex >= 0 && nIndex < CTLS_MAX);
1,371✔
2382

2383
    l_papTLSList[nIndex] = pData;
1,371✔
2384
    l_papTLSList[CTLS_MAX + nIndex] = reinterpret_cast<void *>(pfnFree);
1,371✔
2385
}
1,371✔
2386
#ifndef HAVE_SPINLOCK_IMPL
2387

2388
// No spinlock specific API? Fallback to mutex.
2389

2390
/************************************************************************/
2391
/*                          CPLCreateSpinLock()                         */
2392
/************************************************************************/
2393

2394
CPLSpinLock *CPLCreateSpinLock(void)
33,526✔
2395
{
2396
    CPLSpinLock *psSpin = reinterpret_cast<CPLSpinLock *>(CPLCreateMutex());
33,526✔
2397
    if (psSpin)
33,526✔
2398
        CPLReleaseSpinLock(psSpin);
33,527✔
2399
    return psSpin;
33,526✔
2400
}
2401

2402
/************************************************************************/
2403
/*                     CPLCreateOrAcquireSpinLock()                     */
2404
/************************************************************************/
2405

2406
int CPLCreateOrAcquireSpinLockInternal(CPLLock **ppsLock)
4✔
2407
{
2408
    return CPLCreateOrAcquireMutexInternal(ppsLock, 1000, LOCK_ADAPTIVE_MUTEX);
4✔
2409
}
2410

2411
/************************************************************************/
2412
/*                        CPLAcquireSpinLock()                          */
2413
/************************************************************************/
2414

2415
int CPLAcquireSpinLock(CPLSpinLock *psSpin)
6,545,070✔
2416
{
2417
    return CPLAcquireMutex(reinterpret_cast<CPLMutex *>(psSpin), 1000);
6,545,070✔
2418
}
2419

2420
/************************************************************************/
2421
/*                       CPLReleaseSpinLock()                           */
2422
/************************************************************************/
2423

2424
void CPLReleaseSpinLock(CPLSpinLock *psSpin)
6,578,590✔
2425
{
2426
    CPLReleaseMutex(reinterpret_cast<CPLMutex *>(psSpin));
6,578,590✔
2427
}
6,578,650✔
2428

2429
/************************************************************************/
2430
/*                        CPLDestroySpinLock()                          */
2431
/************************************************************************/
2432

2433
void CPLDestroySpinLock(CPLSpinLock *psSpin)
33,527✔
2434
{
2435
    CPLDestroyMutex(reinterpret_cast<CPLMutex *>(psSpin));
33,527✔
2436
}
33,527✔
2437

2438
#endif  // HAVE_SPINLOCK_IMPL
2439

2440
/************************************************************************/
2441
/*                            CPLCreateLock()                           */
2442
/************************************************************************/
2443

2444
CPLLock *CPLCreateLock(CPLLockType eType)
33,597✔
2445
{
2446
    switch (eType)
33,597✔
2447
    {
2448
        case LOCK_RECURSIVE_MUTEX:
70✔
2449
        case LOCK_ADAPTIVE_MUTEX:
2450
        {
2451
            CPLMutex *hMutex = CPLCreateMutexEx(eType == LOCK_RECURSIVE_MUTEX
140✔
2452
                                                    ? CPL_MUTEX_RECURSIVE
70✔
2453
                                                    : CPL_MUTEX_ADAPTIVE);
2454
            if (!hMutex)
70✔
2455
                return nullptr;
×
2456
            CPLReleaseMutex(hMutex);
70✔
2457
            CPLLock *psLock = static_cast<CPLLock *>(malloc(sizeof(CPLLock)));
70✔
2458
            if (psLock == nullptr)
70✔
2459
            {
2460
                fprintf(stderr, "CPLCreateLock() failed.\n");
×
2461
                CPLDestroyMutex(hMutex);
×
2462
                return nullptr;
×
2463
            }
2464
            psLock->eType = eType;
70✔
2465
            psLock->u.hMutex = hMutex;
70✔
2466
#ifdef DEBUG_CONTENTION
2467
            psLock->bDebugPerf = false;
70✔
2468
            psLock->bDebugPerfAsked = false;
70✔
2469
            psLock->nCurrentHolders = 0;
70✔
2470
            psLock->nStartTime = 0;
70✔
2471
#endif
2472
            return psLock;
70✔
2473
        }
2474
        case LOCK_SPIN:
33,527✔
2475
        {
2476
            CPLSpinLock *hSpinLock = CPLCreateSpinLock();
33,527✔
2477
            if (!hSpinLock)
33,527✔
2478
                return nullptr;
×
2479
            CPLLock *psLock = static_cast<CPLLock *>(malloc(sizeof(CPLLock)));
33,527✔
2480
            if (psLock == nullptr)
33,527✔
2481
            {
2482
                fprintf(stderr, "CPLCreateLock() failed.\n");
×
2483
                CPLDestroySpinLock(hSpinLock);
×
2484
                return nullptr;
×
2485
            }
2486
            psLock->eType = eType;
33,527✔
2487
            psLock->u.hSpinLock = hSpinLock;
33,527✔
2488
#ifdef DEBUG_CONTENTION
2489
            psLock->bDebugPerf = false;
33,527✔
2490
            psLock->bDebugPerfAsked = false;
33,527✔
2491
            psLock->nCurrentHolders = 0;
33,527✔
2492
            psLock->nStartTime = 0;
33,527✔
2493
#endif
2494
            return psLock;
33,527✔
2495
        }
2496
        default:
×
2497
            CPLAssert(false);
×
2498
            return nullptr;
2499
    }
2500
}
2501

2502
/************************************************************************/
2503
/*                       CPLCreateOrAcquireLock()                       */
2504
/************************************************************************/
2505

2506
int CPLCreateOrAcquireLock(CPLLock **ppsLock, CPLLockType eType)
5,047✔
2507
{
2508
#ifdef DEBUG_CONTENTION
2509
    GUIntBig nStartTime = 0;
5,047✔
2510
    if ((*ppsLock) && (*ppsLock)->bDebugPerfAsked)
5,047✔
2511
        nStartTime = CPLrdtsc();
4✔
2512
#endif
2513
    int ret = 0;
5,047✔
2514

2515
    switch (eType)
5,047✔
2516
    {
2517
        case LOCK_RECURSIVE_MUTEX:
5,043✔
2518
        case LOCK_ADAPTIVE_MUTEX:
2519
        {
2520
            ret = CPLCreateOrAcquireMutexInternal(ppsLock, 1000, eType);
5,043✔
2521
            break;
5,043✔
2522
        }
2523
        case LOCK_SPIN:
4✔
2524
        {
2525
            ret = CPLCreateOrAcquireSpinLockInternal(ppsLock);
4✔
2526
            break;
4✔
2527
        }
2528
        default:
×
2529
            CPLAssert(false);
×
2530
            return FALSE;
2531
    }
2532
#ifdef DEBUG_CONTENTION
2533
    if (ret && (*ppsLock)->bDebugPerfAsked &&
5,051✔
2534
        CPLAtomicInc(&((*ppsLock)->nCurrentHolders)) == 1)
4✔
2535
    {
2536
        (*ppsLock)->bDebugPerf = true;
4✔
2537
        (*ppsLock)->nStartTime = nStartTime;
4✔
2538
    }
2539
#endif
2540
    return ret;
5,047✔
2541
}
2542

2543
/************************************************************************/
2544
/*                          CPLAcquireLock()                            */
2545
/************************************************************************/
2546

2547
int CPLAcquireLock(CPLLock *psLock)
24,121,200✔
2548
{
2549
#ifdef DEBUG_CONTENTION
2550
    GUIntBig nStartTime = 0;
24,121,200✔
2551
    if (psLock->bDebugPerfAsked)
24,121,200✔
2552
        nStartTime = CPLrdtsc();
1,952,510✔
2553
#endif
2554
    int ret;
2555
    if (psLock->eType == LOCK_SPIN)
24,125,900✔
2556
        ret = CPLAcquireSpinLock(psLock->u.hSpinLock);
6,545,100✔
2557
    else
2558
        ret = CPLAcquireMutex(psLock->u.hMutex, 1000);
17,580,800✔
2559
#ifdef DEBUG_CONTENTION
2560
    if (ret && psLock->bDebugPerfAsked &&
26,080,200✔
2561
        CPLAtomicInc(&(psLock->nCurrentHolders)) == 1)
1,952,510✔
2562
    {
2563
        psLock->bDebugPerf = true;
1,952,510✔
2564
        psLock->nStartTime = nStartTime;
1,952,510✔
2565
    }
2566
#endif
2567
    return ret;
24,127,700✔
2568
}
2569

2570
/************************************************************************/
2571
/*                         CPLReleaseLock()                             */
2572
/************************************************************************/
2573

2574
void CPLReleaseLock(CPLLock *psLock)
24,132,700✔
2575
{
2576
#ifdef DEBUG_CONTENTION
2577
    bool bHitMaxDiff = false;
24,132,700✔
2578
    GIntBig nMaxDiff = 0;
24,132,700✔
2579
    double dfAvgDiff = 0;
24,132,700✔
2580
    if (psLock->bDebugPerf && CPLAtomicDec(&(psLock->nCurrentHolders)) == 0)
24,132,700✔
2581
    {
2582
        const GUIntBig nStopTime = CPLrdtscp();
1,952,520✔
2583
        // coverity[missing_lock:FALSE]
2584
        const GIntBig nDiffTime =
1,952,520✔
2585
            static_cast<GIntBig>(nStopTime - psLock->nStartTime);
1,952,520✔
2586
        if (nDiffTime > psLock->nMaxDiff)
1,952,520✔
2587
        {
2588
            bHitMaxDiff = true;
29✔
2589
            psLock->nMaxDiff = nDiffTime;
29✔
2590
        }
2591
        nMaxDiff = psLock->nMaxDiff;
1,952,520✔
2592
        psLock->nIters++;
1,952,520✔
2593
        psLock->dfAvgDiff += (nDiffTime - psLock->dfAvgDiff) / psLock->nIters;
1,952,520✔
2594
        dfAvgDiff = psLock->dfAvgDiff;
1,952,520✔
2595
    }
2596
#endif
2597
    if (psLock->eType == LOCK_SPIN)
24,132,700✔
2598
        CPLReleaseSpinLock(psLock->u.hSpinLock);
6,545,080✔
2599
    else
2600
        CPLReleaseMutex(psLock->u.hMutex);
17,587,600✔
2601
#ifdef DEBUG_CONTENTION
2602
    if (psLock->bDebugPerf &&
24,132,800✔
2603
        (bHitMaxDiff || (psLock->nIters % 1000000) == (1000000 - 1)))
1,952,490✔
2604
    {
2605
        CPLDebug("LOCK", "Lock contention : max = " CPL_FRMT_GIB ", avg = %.0f",
29✔
2606
                 nMaxDiff, dfAvgDiff);
2607
    }
2608
#endif
2609
}
24,132,800✔
2610

2611
/************************************************************************/
2612
/*                          CPLDestroyLock()                            */
2613
/************************************************************************/
2614

2615
void CPLDestroyLock(CPLLock *psLock)
34,006✔
2616
{
2617
    if (psLock->eType == LOCK_SPIN)
34,006✔
2618
        CPLDestroySpinLock(psLock->u.hSpinLock);
33,527✔
2619
    else
2620
        CPLDestroyMutex(psLock->u.hMutex);
479✔
2621
    free(psLock);
34,006✔
2622
}
34,006✔
2623

2624
/************************************************************************/
2625
/*                       CPLLockSetDebugPerf()                          */
2626
/************************************************************************/
2627

2628
#ifdef DEBUG_CONTENTION
2629
void CPLLockSetDebugPerf(CPLLock *psLock, int bEnableIn)
5,047✔
2630
{
2631
    psLock->bDebugPerfAsked = CPL_TO_BOOL(bEnableIn);
5,047✔
2632
}
5,047✔
2633
#else
2634
void CPLLockSetDebugPerf(CPLLock * /* psLock */, int bEnableIn)
2635
{
2636
    if (!bEnableIn)
2637
        return;
2638

2639
    static bool bOnce = false;
2640
    if (!bOnce)
2641
    {
2642
        bOnce = true;
2643
        CPLDebug("LOCK", "DEBUG_CONTENTION not available");
2644
    }
2645
}
2646
#endif
2647

2648
/************************************************************************/
2649
/*                           CPLLockHolder()                            */
2650
/************************************************************************/
2651

2652
CPLLockHolder::CPLLockHolder(CPLLock **phLock, CPLLockType eType,
5,047✔
2653
                             const char *pszFileIn, int nLineIn)
5,047✔
2654

2655
{
2656
#ifndef MUTEX_NONE
2657
    pszFile = pszFileIn;
5,047✔
2658
    nLine = nLineIn;
5,047✔
2659

2660
#ifdef DEBUG_MUTEX
2661
    // XXX: There is no way to use CPLDebug() here because it works with
2662
    // mutexes itself so we will fall in infinite recursion. Good old
2663
    // fprintf() will do the job right.
2664
    fprintf(stderr, "CPLLockHolder: Request %p for pid %ld at %d/%s.\n",
2665
            *phLock, static_cast<long>(CPLGetPID()), nLine, pszFile);
2666
#endif
2667

2668
    if (!CPLCreateOrAcquireLock(phLock, eType))
5,047✔
2669
    {
2670
        fprintf(stderr, "CPLLockHolder: Failed to acquire lock!\n");
×
2671
        hLock = nullptr;
×
2672
    }
2673
    else
2674
    {
2675
#ifdef DEBUG_MUTEX
2676
        fprintf(stderr, "CPLLockHolder: Acquired %p for pid %ld at %d/%s.\n",
2677
                *phLock, static_cast<long>(CPLGetPID()), nLine, pszFile);
2678
#endif
2679

2680
        hLock = *phLock;
5,047✔
2681
    }
2682
#endif  // ndef MUTEX_NONE
2683
}
5,047✔
2684

2685
/************************************************************************/
2686
/*                           CPLLockHolder()                            */
2687
/************************************************************************/
2688

2689
CPLLockHolder::CPLLockHolder(CPLLock *hLockIn, const char *pszFileIn,
24,121,500✔
2690
                             int nLineIn)
24,121,500✔
2691

2692
{
2693
#ifndef MUTEX_NONE
2694
    pszFile = pszFileIn;
24,121,500✔
2695
    nLine = nLineIn;
24,121,500✔
2696
    hLock = hLockIn;
24,121,500✔
2697

2698
    if (hLock != nullptr)
24,121,500✔
2699
    {
2700
        if (!CPLAcquireLock(hLock))
24,119,700✔
2701
        {
2702
            fprintf(stderr, "CPLLockHolder: Failed to acquire lock!\n");
×
2703
            hLock = nullptr;
×
2704
        }
2705
    }
2706
#endif  // ndef MUTEX_NONE
2707
}
24,124,600✔
2708

2709
/************************************************************************/
2710
/*                          ~CPLLockHolder()                            */
2711
/************************************************************************/
2712

2713
CPLLockHolder::~CPLLockHolder()
48,255,900✔
2714

2715
{
2716
#ifndef MUTEX_NONE
2717
    if (hLock != nullptr)
24,127,900✔
2718
    {
2719
#ifdef DEBUG_MUTEX
2720
        fprintf(stderr, "~CPLLockHolder: Release %p for pid %ld at %d/%s.\n",
2721
                hLock, static_cast<long>(CPLGetPID()), nLine, pszFile);
2722
#endif
2723
        CPLReleaseLock(hLock);
24,127,900✔
2724
    }
2725
#endif  // ndef MUTEX_NONE
2726
}
24,128,000✔
2727

2728
/************************************************************************/
2729
/*                       CPLGetCurrentProcessID()                       */
2730
/************************************************************************/
2731

2732
#ifdef CPL_MULTIPROC_WIN32
2733

2734
int CPLGetCurrentProcessID()
2735
{
2736
    return GetCurrentProcessId();
2737
}
2738

2739
#else
2740

2741
#include <sys/types.h>
2742
#include <unistd.h>
2743

2744
int CPLGetCurrentProcessID()
2,336✔
2745
{
2746
    return getpid();
2,336✔
2747
}
2748

2749
#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