LCOV - code coverage report
Current view: top level - port - cpl_multiproc.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 389 492 79.1 %
Date: 2025-05-24 03:54:53 Functions: 57 59 96.6 %

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

Generated by: LCOV version 1.14