LCOV - code coverage report
Current view: top level - port - cpl_multiproc.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 394 494 79.8 %
Date: 2026-11-03 15:23:57 Functions: 58 60 96.7 %

          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) && !defined(__COVERITY__) &&                                \
      49             :     (defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)))
      50             : #ifndef DEBUG_CONTENTION
      51             : #define DEBUG_CONTENTION
      52             : #endif
      53             : #endif
      54             : 
      55             : typedef struct _CPLSpinLock CPLSpinLock;
      56             : 
      57             : struct _CPLLock
      58             : {
      59             :     CPLLockType eType;
      60             : 
      61             :     union
      62             :     {
      63             :         CPLMutex *hMutex;
      64             :         CPLSpinLock *hSpinLock;
      65             :     } u;
      66             : 
      67             : #ifdef DEBUG_CONTENTION
      68             :     bool bDebugPerfAsked;
      69             :     bool bDebugPerf;
      70             :     volatile int nCurrentHolders;
      71             :     GUIntBig nStartTime;
      72             :     GIntBig nMaxDiff;
      73             :     double dfAvgDiff;
      74             :     GUIntBig nIters;
      75             : #endif
      76             : };
      77             : 
      78             : #ifdef DEBUG_CONTENTION
      79             : 
      80             : #if defined(__x86_64)
      81             : #define GCC_CPUID(level, a, b, c, d)                                           \
      82             :     __asm__ volatile("xchgq %%rbx, %q1\n"                                      \
      83             :                      "cpuid\n"                                                 \
      84             :                      "xchgq %%rbx, %q1"                                        \
      85             :                      : "=a"(a), "=r"(b), "=c"(c), "=d"(d)                      \
      86             :                      : "0"(level))
      87             : #else
      88             : #define GCC_CPUID(level, a, b, c, d)                                           \
      89             :     __asm__ volatile("xchgl %%ebx, %1\n"                                       \
      90             :                      "cpuid\n"                                                 \
      91             :                      "xchgl %%ebx, %1"                                         \
      92             :                      : "=a"(a), "=r"(b), "=c"(c), "=d"(d)                      \
      93             :                      : "0"(level))
      94             : #endif
      95             : 
      96     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     1952520 :     __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    82202600 : CPLMutexHolder::CPLMutexHolder(CPLMutex **phMutex, double dfWaitInSeconds,
     155    82202600 :                                const char *pszFileIn, int nLineIn, int nOptions)
     156    82202600 :     : hMutex(nullptr), pszFile(pszFileIn), nLine(nLineIn)
     157             : {
     158    82202600 :     if (phMutex == nullptr)
     159             :     {
     160           0 :         fprintf(stderr, "CPLMutexHolder: phMutex is 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    82202600 :     if (!CPLCreateOrAcquireMutexEx(phMutex, dfWaitInSeconds, nOptions))
     178             :     {
     179          77 :         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    82206100 :         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        5354 : static CPLMutex *GetMutexHolderMutexMember(CPLMutex *hMutexIn,
     207             :                                            double dfWaitInSeconds)
     208             : {
     209        5354 :     if (hMutexIn && !CPLAcquireMutex(hMutexIn, dfWaitInSeconds))
     210             :     {
     211           0 :         fprintf(stderr, "CPLMutexHolder: Failed to acquire mutex!\n");
     212           0 :         return nullptr;
     213             :     }
     214        5354 :     return hMutexIn;
     215             : }
     216             : 
     217        5354 : CPLMutexHolder::CPLMutexHolder(CPLMutex *hMutexIn, double dfWaitInSeconds,
     218        5354 :                                const char *pszFileIn, int nLineIn)
     219        5354 :     : hMutex(GetMutexHolderMutexMember(hMutexIn, dfWaitInSeconds)),
     220        5354 :       pszFile(pszFileIn), nLine(nLineIn)
     221             : {
     222        5354 : }
     223             : #endif  // ndef MUTEX_NONE
     224             : 
     225             : /************************************************************************/
     226             : /*                          ~CPLMutexHolder()                           */
     227             : /************************************************************************/
     228             : 
     229             : #ifdef MUTEX_NONE
     230             : CPLMutexHolder::~CPLMutexHolder()
     231             : {
     232             : }
     233             : #else
     234   164421000 : CPLMutexHolder::~CPLMutexHolder()
     235             : {
     236    82211600 :     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    82211500 :         CPLReleaseMutex(hMutex);
     243             :     }
     244    82209600 : }
     245             : #endif  // ndef MUTEX_NONE
     246             : 
     247     2109280 : int CPLCreateOrAcquireMutex(CPLMutex **phMutex, double dfWaitInSeconds)
     248             : {
     249     2109280 :     return CPLCreateOrAcquireMutexEx(phMutex, dfWaitInSeconds,
     250     2109860 :                                      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        1721 : 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        1721 : }
     425             : 
     426             : /************************************************************************/
     427             : /*                        CPLCleanupTLSList()                           */
     428             : /*                                                                      */
     429             : /*      Free resources associated with a TLS vector (implementation     */
     430             : /*      independent).                                                   */
     431             : /************************************************************************/
     432             : 
     433        8579 : static void CPLCleanupTLSList(void **papTLSList)
     434             : 
     435             : {
     436             : #ifdef DEBUG_VERBOSE
     437             :     printf("CPLCleanupTLSList(%p)\n", papTLSList); /*ok*/
     438             : #endif
     439             : 
     440        8579 :     if (papTLSList == nullptr)
     441           0 :         return;
     442             : 
     443      283080 :     for (int i = 0; i < CTLS_MAX; i++)
     444             :     {
     445      274502 :         if (papTLSList[i] != nullptr && papTLSList[i + CTLS_MAX] != nullptr)
     446             :         {
     447       15113 :             CPLTLSFreeFunc pfnFree =
     448       15113 :                 reinterpret_cast<CPLTLSFreeFunc>(papTLSList[i + CTLS_MAX]);
     449       15113 :             pfnFree(papTLSList[i]);
     450       15112 :             papTLSList[i] = nullptr;
     451             :         }
     452             :     }
     453             : 
     454        8578 :     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             :     bool bJoinable;
    1152             : } CPLStdCallThreadInfo;
    1153             : 
    1154             : static DWORD WINAPI CPLStdCallThreadJacket(void *pData)
    1155             : 
    1156             : {
    1157             :     CPLStdCallThreadInfo *psInfo = static_cast<CPLStdCallThreadInfo *>(pData);
    1158             : 
    1159             :     psInfo->pfnMain(psInfo->pAppData);
    1160             : 
    1161             :     // Only for detached threads
    1162             :     if (!psInfo->bJoinable)
    1163             :         CPLFree(psInfo);
    1164             : 
    1165             :     CPLCleanupTLS();
    1166             : 
    1167             :     return 0;
    1168             : }
    1169             : 
    1170             : /************************************************************************/
    1171             : /*                          CPLCreateThread()                           */
    1172             : /*                                                                      */
    1173             : /*      The WIN32 CreateThread() call requires an entry point that      */
    1174             : /*      has __stdcall conventions, so we provide a jacket function      */
    1175             : /*      to supply that.                                                 */
    1176             : /************************************************************************/
    1177             : 
    1178             : int CPLCreateThread(CPLThreadFunc pfnMain, void *pThreadArg)
    1179             : 
    1180             : {
    1181             :     CPLStdCallThreadInfo *psInfo = static_cast<CPLStdCallThreadInfo *>(
    1182             :         CPLCalloc(sizeof(CPLStdCallThreadInfo), 1));
    1183             :     psInfo->pAppData = pThreadArg;
    1184             :     psInfo->pfnMain = pfnMain;
    1185             :     psInfo->hThread = nullptr;
    1186             :     psInfo->bJoinable = false;
    1187             : 
    1188             :     DWORD nThreadId = 0;
    1189             :     HANDLE hThread =
    1190             :         CreateThread(nullptr, 0, CPLStdCallThreadJacket, psInfo, 0, &nThreadId);
    1191             : 
    1192             :     if (hThread == nullptr)
    1193             :         return -1;
    1194             : 
    1195             :     CloseHandle(hThread);
    1196             : 
    1197             :     return nThreadId;
    1198             : }
    1199             : 
    1200             : /************************************************************************/
    1201             : /*                      CPLCreateJoinableThread()                       */
    1202             : /************************************************************************/
    1203             : 
    1204             : CPLJoinableThread *CPLCreateJoinableThread(CPLThreadFunc pfnMain,
    1205             :                                            void *pThreadArg)
    1206             : 
    1207             : {
    1208             :     CPLStdCallThreadInfo *psInfo = static_cast<CPLStdCallThreadInfo *>(
    1209             :         CPLCalloc(sizeof(CPLStdCallThreadInfo), 1));
    1210             :     psInfo->pAppData = pThreadArg;
    1211             :     psInfo->pfnMain = pfnMain;
    1212             :     psInfo->bJoinable = true;
    1213             : 
    1214             :     DWORD nThreadId = 0;
    1215             :     HANDLE hThread =
    1216             :         CreateThread(nullptr, 0, CPLStdCallThreadJacket, psInfo, 0, &nThreadId);
    1217             : 
    1218             :     if (hThread == nullptr)
    1219             :         return nullptr;
    1220             : 
    1221             :     psInfo->hThread = hThread;
    1222             :     return reinterpret_cast<CPLJoinableThread *>(psInfo);
    1223             : }
    1224             : 
    1225             : /************************************************************************/
    1226             : /*                           CPLJoinThread()                            */
    1227             : /************************************************************************/
    1228             : 
    1229             : void CPLJoinThread(CPLJoinableThread *hJoinableThread)
    1230             : {
    1231             :     CPLStdCallThreadInfo *psInfo =
    1232             :         reinterpret_cast<CPLStdCallThreadInfo *>(hJoinableThread);
    1233             : 
    1234             :     WaitForSingleObject(psInfo->hThread, INFINITE);
    1235             :     CloseHandle(psInfo->hThread);
    1236             :     CPLFree(psInfo);
    1237             : }
    1238             : 
    1239             : /************************************************************************/
    1240             : /*                              CPLSleep()                              */
    1241             : /************************************************************************/
    1242             : 
    1243             : void CPLSleep(double dfWaitInSeconds)
    1244             : 
    1245             : {
    1246             :     Sleep(static_cast<DWORD>(dfWaitInSeconds * 1000.0));
    1247             : }
    1248             : 
    1249             : static bool bTLSKeySetup = false;
    1250             : static DWORD nTLSKey = 0;
    1251             : 
    1252             : /************************************************************************/
    1253             : /*                           CPLGetTLSList()                            */
    1254             : /************************************************************************/
    1255             : 
    1256             : static void **CPLGetTLSList(int *pbMemoryErrorOccurred)
    1257             : 
    1258             : {
    1259             :     void **papTLSList = nullptr;
    1260             : 
    1261             :     if (pbMemoryErrorOccurred)
    1262             :         *pbMemoryErrorOccurred = FALSE;
    1263             :     if (!bTLSKeySetup)
    1264             :     {
    1265             :         nTLSKey = TlsAlloc();
    1266             :         if (nTLSKey == TLS_OUT_OF_INDEXES)
    1267             :         {
    1268             :             if (pbMemoryErrorOccurred)
    1269             :             {
    1270             :                 *pbMemoryErrorOccurred = TRUE;
    1271             :                 fprintf(stderr, "CPLGetTLSList(): TlsAlloc() failed!\n");
    1272             :                 return nullptr;
    1273             :             }
    1274             :             CPLEmergencyError("CPLGetTLSList(): TlsAlloc() failed!");
    1275             :         }
    1276             :         bTLSKeySetup = true;
    1277             :     }
    1278             : 
    1279             :     papTLSList = static_cast<void **>(TlsGetValue(nTLSKey));
    1280             :     if (papTLSList == nullptr)
    1281             :     {
    1282             :         papTLSList =
    1283             :             static_cast<void **>(VSICalloc(sizeof(void *), CTLS_MAX * 2));
    1284             :         if (papTLSList == nullptr)
    1285             :         {
    1286             :             if (pbMemoryErrorOccurred)
    1287             :             {
    1288             :                 *pbMemoryErrorOccurred = TRUE;
    1289             :                 fprintf(stderr,
    1290             :                         "CPLGetTLSList() failed to allocate TLS list!\n");
    1291             :                 return nullptr;
    1292             :             }
    1293             :             CPLEmergencyError("CPLGetTLSList() failed to allocate TLS list!");
    1294             :         }
    1295             :         if (TlsSetValue(nTLSKey, papTLSList) == 0)
    1296             :         {
    1297             :             if (pbMemoryErrorOccurred)
    1298             :             {
    1299             :                 *pbMemoryErrorOccurred = TRUE;
    1300             :                 fprintf(stderr, "CPLGetTLSList(): TlsSetValue() failed!\n");
    1301             :                 return nullptr;
    1302             :             }
    1303             :             CPLEmergencyError("CPLGetTLSList(): TlsSetValue() failed!");
    1304             :         }
    1305             :     }
    1306             : 
    1307             :     return papTLSList;
    1308             : }
    1309             : 
    1310             : /************************************************************************/
    1311             : /*                           CPLFinalizeTLS()                           */
    1312             : /************************************************************************/
    1313             : 
    1314             : void CPLFinalizeTLS()
    1315             : {
    1316             :     CPLCleanupTLS();
    1317             : }
    1318             : 
    1319             : /************************************************************************/
    1320             : /*                           CPLCleanupTLS()                            */
    1321             : /************************************************************************/
    1322             : 
    1323             : void CPLCleanupTLS()
    1324             : 
    1325             : {
    1326             :     if (!bTLSKeySetup)
    1327             :         return;
    1328             : 
    1329             :     void **papTLSList = static_cast<void **>(TlsGetValue(nTLSKey));
    1330             :     if (papTLSList == nullptr)
    1331             :         return;
    1332             : 
    1333             :     TlsSetValue(nTLSKey, nullptr);
    1334             : 
    1335             :     CPLCleanupTLSList(papTLSList);
    1336             : }
    1337             : 
    1338             : // endif CPL_MULTIPROC_WIN32
    1339             : 
    1340             : #elif defined(CPL_MULTIPROC_PTHREAD)
    1341             : 
    1342             : #include <pthread.h>
    1343             : #include <time.h>
    1344             : #include <unistd.h>
    1345             : #include <sys/time.h>
    1346             : 
    1347             : #ifdef HAVE_SCHED_GETAFFINITY
    1348             : #include <sched.h>
    1349             : #endif
    1350             : 
    1351             : /************************************************************************/
    1352             : /* ==================================================================== */
    1353             : /*                        CPL_MULTIPROC_PTHREAD                         */
    1354             : /*                                                                      */
    1355             : /*    PTHREAD Implementation of multiprocessing functions.              */
    1356             : /* ==================================================================== */
    1357             : /************************************************************************/
    1358             : 
    1359             : /************************************************************************/
    1360             : /*                           CPLGetNumCPUs()                            */
    1361             : /************************************************************************/
    1362             : 
    1363        5192 : int CPLGetNumCPUs()
    1364             : {
    1365             :     int nCPUs;
    1366             : #ifdef _SC_NPROCESSORS_ONLN
    1367        5192 :     nCPUs = static_cast<int>(sysconf(_SC_NPROCESSORS_ONLN));
    1368             : #else
    1369             :     nCPUs = 1;
    1370             : #endif
    1371             : 
    1372             : #ifdef HAVE_SCHED_GETAFFINITY
    1373        5192 :     if (nCPUs > 1)
    1374             :     {
    1375        5192 :         cpu_set_t *set = CPU_ALLOC(nCPUs);
    1376        5192 :         if (set)
    1377             :         {
    1378        5192 :             size_t sizeof_set = CPU_ALLOC_SIZE(nCPUs);
    1379        5192 :             CPU_ZERO_S(sizeof_set, set);
    1380        5192 :             if (sched_getaffinity(getpid(), sizeof_set, set) == 0)
    1381        5192 :                 nCPUs = CPU_COUNT_S(sizeof_set, set);
    1382             :             else
    1383           0 :                 CPLDebug("CPL", "sched_getaffinity() failed");
    1384        5192 :             CPU_FREE(set);
    1385             :         }
    1386             :     }
    1387             : #endif
    1388             : 
    1389        5192 :     return nCPUs;
    1390             : }
    1391             : 
    1392             : /************************************************************************/
    1393             : /*                      CPLCreateOrAcquireMutex()                       */
    1394             : /************************************************************************/
    1395             : #ifdef HAVE_GCC_WARNING_ZERO_AS_NULL_POINTER_CONSTANT
    1396             : #pragma GCC diagnostic push
    1397             : #pragma GCC diagnostic ignored "-Wzero-as-null-pointer-constant"
    1398             : #endif
    1399             : static pthread_mutex_t global_mutex = PTHREAD_MUTEX_INITIALIZER;
    1400             : #ifdef HAVE_GCC_WARNING_ZERO_AS_NULL_POINTER_CONSTANT
    1401             : #pragma GCC diagnostic pop
    1402             : #endif
    1403             : 
    1404             : static CPLMutex *CPLCreateMutexInternal(bool bAlreadyInGlobalLock,
    1405             :                                         int nOptions);
    1406             : 
    1407    84312000 : int CPLCreateOrAcquireMutexEx(CPLMutex **phMutex, double dfWaitInSeconds,
    1408             :                               int nOptions)
    1409             : 
    1410             : {
    1411    84312000 :     pthread_mutex_lock(&global_mutex);
    1412    84317200 :     if (*phMutex == nullptr)
    1413             :     {
    1414       45896 :         *phMutex = CPLCreateMutexInternal(true, nOptions);
    1415       45896 :         const bool bSuccess = *phMutex != nullptr;
    1416       45896 :         pthread_mutex_unlock(&global_mutex);
    1417       45896 :         if (!bSuccess)
    1418           0 :             return false;
    1419             :     }
    1420             :     else
    1421             :     {
    1422    84271300 :         pthread_mutex_unlock(&global_mutex);
    1423             :     }
    1424             : 
    1425    84316600 :     return CPL_TO_BOOL(CPLAcquireMutex(*phMutex, dfWaitInSeconds));
    1426             : }
    1427             : 
    1428             : /************************************************************************/
    1429             : /*                  CPLCreateOrAcquireMutexInternal()                   */
    1430             : /************************************************************************/
    1431             : 
    1432        5058 : static bool CPLCreateOrAcquireMutexInternal(CPLLock **phLock,
    1433             :                                             double dfWaitInSeconds,
    1434             :                                             CPLLockType eType)
    1435             : {
    1436        5058 :     pthread_mutex_lock(&global_mutex);
    1437        5058 :     if (*phLock == nullptr)
    1438             :     {
    1439         522 :         *phLock = static_cast<CPLLock *>(calloc(1, sizeof(CPLLock)));
    1440         522 :         if (*phLock)
    1441             :         {
    1442         522 :             (*phLock)->eType = eType;
    1443        1044 :             (*phLock)->u.hMutex = CPLCreateMutexInternal(
    1444         522 :                 true, eType == LOCK_RECURSIVE_MUTEX ? CPL_MUTEX_RECURSIVE
    1445             :                                                     : CPL_MUTEX_ADAPTIVE);
    1446         522 :             if ((*phLock)->u.hMutex == nullptr)
    1447             :             {
    1448           0 :                 free(*phLock);
    1449           0 :                 *phLock = nullptr;
    1450             :             }
    1451             :         }
    1452         522 :         const bool bSuccess = *phLock != nullptr;
    1453         522 :         pthread_mutex_unlock(&global_mutex);
    1454         522 :         if (!bSuccess)
    1455           0 :             return false;
    1456             :     }
    1457             :     else
    1458             :     {
    1459        4536 :         pthread_mutex_unlock(&global_mutex);
    1460             :     }
    1461             : 
    1462        5058 :     return CPL_TO_BOOL(CPLAcquireMutex((*phLock)->u.hMutex, dfWaitInSeconds));
    1463             : }
    1464             : 
    1465             : /************************************************************************/
    1466             : /*                        CPLGetThreadingModel()                        */
    1467             : /************************************************************************/
    1468             : 
    1469          32 : const char *CPLGetThreadingModel()
    1470             : 
    1471             : {
    1472          32 :     return "pthread";
    1473             : }
    1474             : 
    1475             : /************************************************************************/
    1476             : /*                           CPLCreateMutex()                           */
    1477             : /************************************************************************/
    1478             : 
    1479             : typedef struct _MutexLinkedElt MutexLinkedElt;
    1480             : 
    1481             : struct _MutexLinkedElt
    1482             : {
    1483             :     pthread_mutex_t sMutex;
    1484             :     int nOptions;
    1485             :     _MutexLinkedElt *psPrev;
    1486             :     _MutexLinkedElt *psNext;
    1487             : };
    1488             : 
    1489             : static MutexLinkedElt *psMutexList = nullptr;
    1490             : 
    1491      545251 : static void CPLInitMutex(MutexLinkedElt *psItem)
    1492             : {
    1493      545251 :     if (psItem->nOptions == CPL_MUTEX_REGULAR)
    1494             :     {
    1495             : #ifdef HAVE_GCC_WARNING_ZERO_AS_NULL_POINTER_CONSTANT
    1496             : #pragma GCC diagnostic push
    1497             : #pragma GCC diagnostic ignored "-Wzero-as-null-pointer-constant"
    1498             : #endif
    1499           0 :         pthread_mutex_t tmp_mutex = PTHREAD_MUTEX_INITIALIZER;
    1500             : #ifdef HAVE_GCC_WARNING_ZERO_AS_NULL_POINTER_CONSTANT
    1501             : #pragma GCC diagnostic pop
    1502             : #endif
    1503           0 :         psItem->sMutex = tmp_mutex;
    1504           0 :         return;
    1505             :     }
    1506             : 
    1507             :     // When an adaptive mutex is required, we can safely fallback to regular
    1508             :     // mutex if we don't have HAVE_PTHREAD_MUTEX_ADAPTIVE_NP.
    1509      545251 :     if (psItem->nOptions == CPL_MUTEX_ADAPTIVE)
    1510             :     {
    1511             : #if defined(HAVE_PTHREAD_MUTEX_ADAPTIVE_NP)
    1512             :         pthread_mutexattr_t attr;
    1513         593 :         pthread_mutexattr_init(&attr);
    1514         593 :         pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ADAPTIVE_NP);
    1515         593 :         pthread_mutex_init(&(psItem->sMutex), &attr);
    1516             : #else
    1517             :         pthread_mutex_t tmp_mutex = PTHREAD_MUTEX_INITIALIZER;
    1518             :         psItem->sMutex = tmp_mutex;
    1519             : #endif
    1520         593 :         return;
    1521             :     }
    1522             : 
    1523             : #if defined(PTHREAD_MUTEX_RECURSIVE) || defined(HAVE_PTHREAD_MUTEX_RECURSIVE)
    1524             :     {
    1525             :         pthread_mutexattr_t attr;
    1526      544658 :         pthread_mutexattr_init(&attr);
    1527      544638 :         pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
    1528      544658 :         pthread_mutex_init(&(psItem->sMutex), &attr);
    1529             :     }
    1530             : // BSDs have PTHREAD_MUTEX_RECURSIVE as an enum, not a define.
    1531             : // But they have #define MUTEX_TYPE_COUNTING_FAST PTHREAD_MUTEX_RECURSIVE
    1532             : #elif defined(MUTEX_TYPE_COUNTING_FAST)
    1533             :     {
    1534             :         pthread_mutexattr_t attr;
    1535             :         pthread_mutexattr_init(&attr);
    1536             :         pthread_mutexattr_settype(&attr, MUTEX_TYPE_COUNTING_FAST);
    1537             :         pthread_mutex_init(&(psItem->sMutex), &attr);
    1538             :     }
    1539             : #elif defined(PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP)
    1540             :     pthread_mutex_t tmp_mutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
    1541             :     psItem->sMutex = tmp_mutex;
    1542             : #else
    1543             : #error "Recursive mutexes apparently unsupported, configure --without-threads"
    1544             : #endif
    1545             : }
    1546             : 
    1547      545250 : static CPLMutex *CPLCreateMutexInternal(bool bAlreadyInGlobalLock, int nOptions)
    1548             : {
    1549             :     MutexLinkedElt *psItem =
    1550      545250 :         static_cast<MutexLinkedElt *>(malloc(sizeof(MutexLinkedElt)));
    1551      545250 :     if (psItem == nullptr)
    1552             :     {
    1553           0 :         fprintf(stderr, "CPLCreateMutexInternal() failed.\n");
    1554           0 :         return nullptr;
    1555             :     }
    1556             : 
    1557      545250 :     if (!bAlreadyInGlobalLock)
    1558      498833 :         pthread_mutex_lock(&global_mutex);
    1559      545250 :     psItem->psPrev = nullptr;
    1560      545250 :     psItem->psNext = psMutexList;
    1561      545250 :     if (psMutexList)
    1562      543205 :         psMutexList->psPrev = psItem;
    1563      545250 :     psMutexList = psItem;
    1564      545250 :     if (!bAlreadyInGlobalLock)
    1565      498833 :         pthread_mutex_unlock(&global_mutex);
    1566             : 
    1567      545250 :     psItem->nOptions = nOptions;
    1568      545250 :     CPLInitMutex(psItem);
    1569             : 
    1570      545251 :     return reinterpret_cast<CPLMutex *>(psItem);
    1571             : }
    1572             : 
    1573      498761 : CPLMutex *CPLCreateMutex()
    1574             : {
    1575      498761 :     CPLMutex *mutex = CPLCreateMutexInternal(false, CPL_MUTEX_RECURSIVE);
    1576      498762 :     if (mutex)
    1577      498762 :         CPLAcquireMutex(mutex, 0);
    1578      498762 :     return mutex;
    1579             : }
    1580             : 
    1581          71 : CPLMutex *CPLCreateMutexEx(int nOptions)
    1582             : {
    1583          71 :     CPLMutex *mutex = CPLCreateMutexInternal(false, nOptions);
    1584          71 :     if (mutex)
    1585          71 :         CPLAcquireMutex(mutex, 0);
    1586          71 :     return mutex;
    1587             : }
    1588             : 
    1589             : /************************************************************************/
    1590             : /*                          CPLAcquireMutex()                           */
    1591             : /************************************************************************/
    1592             : 
    1593   114623000 : int CPLAcquireMutex(CPLMutex *hMutexIn, double /* dfWaitInSeconds */)
    1594             : {
    1595             :     // TODO: Need to add timeout support.
    1596   114623000 :     MutexLinkedElt *psItem = reinterpret_cast<MutexLinkedElt *>(hMutexIn);
    1597   114623000 :     const int err = pthread_mutex_lock(&(psItem->sMutex));
    1598             : 
    1599   114625000 :     if (err != 0)
    1600             :     {
    1601           0 :         if (err == EDEADLK)
    1602           0 :             fprintf(stderr, "CPLAcquireMutex: Error = %d/EDEADLK\n", err);
    1603             :         else
    1604           0 :             fprintf(stderr, "CPLAcquireMutex: Error = %d (%s)\n", err,
    1605             :                     strerror(err));
    1606             : 
    1607           0 :         return FALSE;
    1608             :     }
    1609             : 
    1610   114625000 :     return TRUE;
    1611             : }
    1612             : 
    1613             : /************************************************************************/
    1614             : /*                          CPLReleaseMutex()                           */
    1615             : /************************************************************************/
    1616             : 
    1617   114623000 : void CPLReleaseMutex(CPLMutex *hMutexIn)
    1618             : 
    1619             : {
    1620   114623000 :     MutexLinkedElt *psItem = reinterpret_cast<MutexLinkedElt *>(hMutexIn);
    1621   114623000 :     const int err = pthread_mutex_unlock(&(psItem->sMutex));
    1622   114623000 :     if (err != 0)
    1623             :     {
    1624           0 :         fprintf(stderr, "CPLReleaseMutex: Error = %d (%s)\n", err,
    1625             :                 strerror(err));
    1626             :     }
    1627   114623000 : }
    1628             : 
    1629             : /************************************************************************/
    1630             : /*                          CPLDestroyMutex()                           */
    1631             : /************************************************************************/
    1632             : 
    1633      536557 : void CPLDestroyMutex(CPLMutex *hMutexIn)
    1634             : 
    1635             : {
    1636      536557 :     MutexLinkedElt *psItem = reinterpret_cast<MutexLinkedElt *>(hMutexIn);
    1637      536557 :     const int err = pthread_mutex_destroy(&(psItem->sMutex));
    1638      536557 :     if (err != 0)
    1639             :     {
    1640           0 :         fprintf(stderr, "CPLDestroyMutex: Error = %d (%s)\n", err,
    1641             :                 strerror(err));
    1642             :     }
    1643      536557 :     pthread_mutex_lock(&global_mutex);
    1644      536557 :     if (psItem->psPrev)
    1645      485049 :         psItem->psPrev->psNext = psItem->psNext;
    1646      536557 :     if (psItem->psNext)
    1647      532181 :         psItem->psNext->psPrev = psItem->psPrev;
    1648      536557 :     if (psItem == psMutexList)
    1649       51508 :         psMutexList = psItem->psNext;
    1650      536557 :     pthread_mutex_unlock(&global_mutex);
    1651      536557 :     free(hMutexIn);
    1652      536557 : }
    1653             : 
    1654             : /************************************************************************/
    1655             : /*                         CPLReinitAllMutex()                          */
    1656             : /************************************************************************/
    1657             : 
    1658             : // Used by gdalclientserver.cpp just after forking, to avoid
    1659             : // deadlocks while mixing threads with fork.
    1660             : void CPLReinitAllMutex();  // TODO(schwehr): Put this in a header.
    1661             : 
    1662           0 : void CPLReinitAllMutex()
    1663             : {
    1664           0 :     MutexLinkedElt *psItem = psMutexList;
    1665           0 :     while (psItem != nullptr)
    1666             :     {
    1667           0 :         CPLInitMutex(psItem);
    1668           0 :         psItem = psItem->psNext;
    1669             :     }
    1670             : #ifdef HAVE_GCC_WARNING_ZERO_AS_NULL_POINTER_CONSTANT
    1671             : #pragma GCC diagnostic push
    1672             : #pragma GCC diagnostic ignored "-Wzero-as-null-pointer-constant"
    1673             : #endif
    1674           0 :     pthread_mutex_t tmp_global_mutex = PTHREAD_MUTEX_INITIALIZER;
    1675             : #ifdef HAVE_GCC_WARNING_ZERO_AS_NULL_POINTER_CONSTANT
    1676             : #pragma GCC diagnostic pop
    1677             : #endif
    1678           0 :     global_mutex = tmp_global_mutex;
    1679           0 : }
    1680             : 
    1681             : /************************************************************************/
    1682             : /*                           CPLCreateCond()                            */
    1683             : /************************************************************************/
    1684             : 
    1685      242849 : CPLCond *CPLCreateCond()
    1686             : {
    1687             :     pthread_cond_t *pCond =
    1688      242849 :         static_cast<pthread_cond_t *>(malloc(sizeof(pthread_cond_t)));
    1689      242849 :     if (pCond && pthread_cond_init(pCond, nullptr) == 0)
    1690      242841 :         return reinterpret_cast<CPLCond *>(pCond);
    1691           7 :     fprintf(stderr, "CPLCreateCond() failed.\n");
    1692           0 :     free(pCond);
    1693           0 :     return nullptr;
    1694             : }
    1695             : 
    1696             : /************************************************************************/
    1697             : /*                            CPLCondWait()                             */
    1698             : /************************************************************************/
    1699             : 
    1700       11117 : void CPLCondWait(CPLCond *hCond, CPLMutex *hMutex)
    1701             : {
    1702       11117 :     pthread_cond_t *pCond = reinterpret_cast<pthread_cond_t *>(hCond);
    1703       11117 :     MutexLinkedElt *psItem = reinterpret_cast<MutexLinkedElt *>(hMutex);
    1704       11117 :     pthread_mutex_t *pMutex = &(psItem->sMutex);
    1705       11117 :     pthread_cond_wait(pCond, pMutex);
    1706       11117 : }
    1707             : 
    1708             : /************************************************************************/
    1709             : /*                          CPLCondTimedWait()                          */
    1710             : /************************************************************************/
    1711             : 
    1712           0 : CPLCondTimedWaitReason CPLCondTimedWait(CPLCond *hCond, CPLMutex *hMutex,
    1713             :                                         double dfWaitInSeconds)
    1714             : {
    1715           0 :     pthread_cond_t *pCond = reinterpret_cast<pthread_cond_t *>(hCond);
    1716           0 :     MutexLinkedElt *psItem = reinterpret_cast<MutexLinkedElt *>(hMutex);
    1717           0 :     pthread_mutex_t *pMutex = &(psItem->sMutex);
    1718             :     struct timeval tv;
    1719             :     struct timespec ts;
    1720             : 
    1721           0 :     gettimeofday(&tv, nullptr);
    1722           0 :     ts.tv_sec = time(nullptr) + static_cast<int>(dfWaitInSeconds);
    1723           0 :     ts.tv_nsec =
    1724           0 :         static_cast<int>(tv.tv_usec) * 1000 +
    1725           0 :         static_cast<int>(1000 * 1000 * 1000 * fmod(dfWaitInSeconds, 1));
    1726           0 :     ts.tv_sec += ts.tv_nsec / (1000 * 1000 * 1000);
    1727           0 :     ts.tv_nsec %= (1000 * 1000 * 1000);
    1728           0 :     int ret = pthread_cond_timedwait(pCond, pMutex, &ts);
    1729           0 :     if (ret == 0)
    1730           0 :         return COND_TIMED_WAIT_COND;
    1731           0 :     else if (ret == ETIMEDOUT)
    1732           0 :         return COND_TIMED_WAIT_TIME_OUT;
    1733             :     else
    1734           0 :         return COND_TIMED_WAIT_OTHER;
    1735             : }
    1736             : 
    1737             : /************************************************************************/
    1738             : /*                           CPLCondSignal()                            */
    1739             : /************************************************************************/
    1740             : 
    1741       52433 : void CPLCondSignal(CPLCond *hCond)
    1742             : {
    1743       52433 :     pthread_cond_t *pCond = reinterpret_cast<pthread_cond_t *>(hCond);
    1744       52433 :     pthread_cond_signal(pCond);
    1745       52434 : }
    1746             : 
    1747             : /************************************************************************/
    1748             : /*                          CPLCondBroadcast()                          */
    1749             : /************************************************************************/
    1750             : 
    1751       38081 : void CPLCondBroadcast(CPLCond *hCond)
    1752             : {
    1753       38081 :     pthread_cond_t *pCond = reinterpret_cast<pthread_cond_t *>(hCond);
    1754       38081 :     pthread_cond_broadcast(pCond);
    1755       38081 : }
    1756             : 
    1757             : /************************************************************************/
    1758             : /*                           CPLDestroyCond()                           */
    1759             : /************************************************************************/
    1760             : 
    1761      242849 : void CPLDestroyCond(CPLCond *hCond)
    1762             : {
    1763      242849 :     pthread_cond_t *pCond = reinterpret_cast<pthread_cond_t *>(hCond);
    1764      242849 :     pthread_cond_destroy(pCond);
    1765      242849 :     free(hCond);
    1766      242849 : }
    1767             : 
    1768             : /************************************************************************/
    1769             : /*                            CPLLockFile()                             */
    1770             : /*                                                                      */
    1771             : /*      This is really a stub implementation, see first                 */
    1772             : /*      CPLLockFile() for caveats.                                      */
    1773             : /************************************************************************/
    1774             : 
    1775           3 : void *CPLLockFile(const char *pszPath, double dfWaitInSeconds)
    1776             : 
    1777             : {
    1778             :     /* -------------------------------------------------------------------- */
    1779             :     /*      We use a lock file with a name derived from the file we want    */
    1780             :     /*      to lock to represent the file being locked.  Note that for      */
    1781             :     /*      the stub implementation the target file does not even need      */
    1782             :     /*      to exist to be locked.                                          */
    1783             :     /* -------------------------------------------------------------------- */
    1784           3 :     const size_t nLen = strlen(pszPath) + 30;
    1785           3 :     char *pszLockFilename = static_cast<char *>(CPLMalloc(nLen));
    1786           3 :     snprintf(pszLockFilename, nLen, "%s.lock", pszPath);
    1787             : 
    1788           3 :     FILE *fpLock = fopen(pszLockFilename, "r");
    1789           3 :     while (fpLock != nullptr && dfWaitInSeconds > 0.0)
    1790             :     {
    1791           0 :         fclose(fpLock);
    1792           0 :         CPLSleep(std::min(dfWaitInSeconds, 0.5));
    1793           0 :         dfWaitInSeconds -= 0.5;
    1794             : 
    1795           0 :         fpLock = fopen(pszLockFilename, "r");
    1796             :     }
    1797             : 
    1798           3 :     if (fpLock != nullptr)
    1799             :     {
    1800           0 :         fclose(fpLock);
    1801           0 :         CPLFree(pszLockFilename);
    1802           0 :         return nullptr;
    1803             :     }
    1804             : 
    1805           3 :     fpLock = fopen(pszLockFilename, "w");
    1806             : 
    1807           3 :     if (fpLock == nullptr)
    1808             :     {
    1809           0 :         CPLFree(pszLockFilename);
    1810           0 :         return nullptr;
    1811             :     }
    1812             : 
    1813           3 :     fwrite("held\n", 1, 5, fpLock);
    1814           3 :     fclose(fpLock);
    1815             : 
    1816           3 :     return pszLockFilename;
    1817             : }
    1818             : 
    1819             : /************************************************************************/
    1820             : /*                           CPLUnlockFile()                            */
    1821             : /************************************************************************/
    1822             : 
    1823           3 : void CPLUnlockFile(void *hLock)
    1824             : 
    1825             : {
    1826           3 :     char *pszLockFilename = static_cast<char *>(hLock);
    1827             : 
    1828           3 :     if (hLock == nullptr)
    1829           0 :         return;
    1830             : 
    1831           3 :     VSIUnlink(pszLockFilename);
    1832             : 
    1833           3 :     CPLFree(pszLockFilename);
    1834             : }
    1835             : 
    1836             : /************************************************************************/
    1837             : /*                             CPLGetPID()                              */
    1838             : /************************************************************************/
    1839             : 
    1840    23194000 : GIntBig CPLGetPID()
    1841             : 
    1842             : {
    1843    23194000 :     return reinterpret_cast<GIntBig>(reinterpret_cast<void *>(pthread_self()));
    1844             : }
    1845             : 
    1846             : static pthread_key_t oTLSKey;
    1847             : static pthread_once_t oTLSKeySetup = PTHREAD_ONCE_INIT;
    1848             : 
    1849             : /************************************************************************/
    1850             : /*                            CPLMake_key()                             */
    1851             : /************************************************************************/
    1852             : 
    1853        6857 : static void CPLCleanupTLSListWrapper(void *papszList)
    1854             : {
    1855        6857 :     CPLCleanupTLSList(static_cast<void **>(papszList));
    1856        6857 : }
    1857             : 
    1858        1848 : static void CPLMake_key()
    1859             : 
    1860             : {
    1861        1848 :     if (pthread_key_create(&oTLSKey, CPLCleanupTLSListWrapper) != 0)
    1862             :     {
    1863           0 :         CPLError(CE_Fatal, CPLE_AppDefined, "pthread_key_create() failed!");
    1864             :     }
    1865        1848 : }
    1866             : 
    1867             : /************************************************************************/
    1868             : /*                           CPLGetTLSList()                            */
    1869             : /************************************************************************/
    1870             : 
    1871    90838100 : static void **CPLGetTLSList(int *pbMemoryErrorOccurred)
    1872             : 
    1873             : {
    1874    90838100 :     if (pbMemoryErrorOccurred)
    1875    86336100 :         *pbMemoryErrorOccurred = FALSE;
    1876             : 
    1877    90838100 :     if (pthread_once(&oTLSKeySetup, CPLMake_key) != 0)
    1878             :     {
    1879           0 :         if (pbMemoryErrorOccurred)
    1880             :         {
    1881           0 :             fprintf(stderr, "CPLGetTLSList(): pthread_once() failed!\n");
    1882           0 :             *pbMemoryErrorOccurred = TRUE;
    1883           0 :             return nullptr;
    1884             :         }
    1885           0 :         CPLEmergencyError("CPLGetTLSList(): pthread_once() failed!");
    1886             :     }
    1887             : 
    1888    90836600 :     void **papTLSList = static_cast<void **>(pthread_getspecific(oTLSKey));
    1889    90836300 :     if (papTLSList == nullptr)
    1890             :     {
    1891             :         papTLSList =
    1892       10353 :             static_cast<void **>(VSICalloc(sizeof(void *), CTLS_MAX * 2));
    1893        9974 :         if (papTLSList == nullptr)
    1894             :         {
    1895           0 :             if (pbMemoryErrorOccurred)
    1896             :             {
    1897           0 :                 fprintf(stderr,
    1898             :                         "CPLGetTLSList() failed to allocate TLS list!\n");
    1899           0 :                 *pbMemoryErrorOccurred = TRUE;
    1900           0 :                 return nullptr;
    1901             :             }
    1902           0 :             CPLEmergencyError("CPLGetTLSList() failed to allocate TLS list!");
    1903             :         }
    1904        9974 :         if (pthread_setspecific(oTLSKey, papTLSList) != 0)
    1905             :         {
    1906           0 :             if (pbMemoryErrorOccurred)
    1907             :             {
    1908           0 :                 fprintf(stderr,
    1909             :                         "CPLGetTLSList(): pthread_setspecific() failed!\n");
    1910           0 :                 *pbMemoryErrorOccurred = TRUE;
    1911           0 :                 return nullptr;
    1912             :             }
    1913           0 :             CPLEmergencyError("CPLGetTLSList(): pthread_setspecific() failed!");
    1914             :         }
    1915             :     }
    1916             : 
    1917    90835900 :     return papTLSList;
    1918             : }
    1919             : 
    1920             : /************************************************************************/
    1921             : /*                       CPLStdCallThreadJacket()                       */
    1922             : /************************************************************************/
    1923             : 
    1924             : typedef struct
    1925             : {
    1926             :     void *pAppData;
    1927             :     CPLThreadFunc pfnMain;
    1928             :     pthread_t hThread;
    1929             :     bool bJoinable;
    1930             : #ifdef CHECK_THREAD_CAN_ALLOCATE_TLS
    1931             :     bool bInitSucceeded;
    1932             :     bool bInitDone;
    1933             :     pthread_mutex_t sMutex;
    1934             :     pthread_cond_t sCond;
    1935             : #endif
    1936             : } CPLStdCallThreadInfo;
    1937             : 
    1938        4018 : static void *CPLStdCallThreadJacket(void *pData)
    1939             : 
    1940             : {
    1941        4018 :     CPLStdCallThreadInfo *psInfo = static_cast<CPLStdCallThreadInfo *>(pData);
    1942             : 
    1943             : #ifdef CHECK_THREAD_CAN_ALLOCATE_TLS
    1944             :     int bMemoryError = FALSE;
    1945             :     CPLGetTLSList(&bMemoryError);
    1946             :     if (bMemoryError)
    1947             :         goto error;
    1948             : 
    1949             :     assert(pthread_mutex_lock(&(psInfo->sMutex)) == 0);
    1950             :     psInfo->bInitDone = true;
    1951             :     assert(pthread_cond_signal(&(psInfo->sCond)) == 0);
    1952             :     assert(pthread_mutex_unlock(&(psInfo->sMutex)) == 0);
    1953             : #endif
    1954             : 
    1955        4018 :     psInfo->pfnMain(psInfo->pAppData);
    1956             : 
    1957        2983 :     if (!psInfo->bJoinable)
    1958           1 :         CPLFree(psInfo);
    1959             : 
    1960        2982 :     return nullptr;
    1961             : 
    1962             : #ifdef CHECK_THREAD_CAN_ALLOCATE_TLS
    1963             : error:
    1964             :     assert(pthread_mutex_lock(&(psInfo->sMutex)) == 0);
    1965             :     psInfo->bInitSucceeded = false;
    1966             :     psInfo->bInitDone = true;
    1967             :     assert(pthread_cond_signal(&(psInfo->sCond)) == 0);
    1968             :     assert(pthread_mutex_unlock(&(psInfo->sMutex)) == 0);
    1969             :     return nullptr;
    1970             : #endif
    1971             : }
    1972             : 
    1973             : /************************************************************************/
    1974             : /*                          CPLCreateThread()                           */
    1975             : /*                                                                      */
    1976             : /*      The WIN32 CreateThread() call requires an entry point that      */
    1977             : /*      has __stdcall conventions, so we provide a jacket function      */
    1978             : /*      to supply that.                                                 */
    1979             : /************************************************************************/
    1980             : 
    1981           1 : int CPLCreateThread(CPLThreadFunc pfnMain, void *pThreadArg)
    1982             : 
    1983             : {
    1984             :     CPLStdCallThreadInfo *psInfo = static_cast<CPLStdCallThreadInfo *>(
    1985           1 :         VSI_CALLOC_VERBOSE(sizeof(CPLStdCallThreadInfo), 1));
    1986           1 :     if (psInfo == nullptr)
    1987           0 :         return -1;
    1988           1 :     psInfo->pAppData = pThreadArg;
    1989           1 :     psInfo->pfnMain = pfnMain;
    1990           1 :     psInfo->bJoinable = false;
    1991             : #ifdef CHECK_THREAD_CAN_ALLOCATE_TLS
    1992             :     psInfo->bInitSucceeded = true;
    1993             :     psInfo->bInitDone = false;
    1994             :     pthread_mutex_t sMutex = PTHREAD_MUTEX_INITIALIZER;
    1995             :     psInfo->sMutex = sMutex;
    1996             :     if (pthread_cond_init(&(psInfo->sCond), nullptr) != 0)
    1997             :     {
    1998             :         CPLFree(psInfo);
    1999             :         fprintf(stderr, "CPLCreateThread() failed.\n");
    2000             :         return -1;
    2001             :     }
    2002             : #endif
    2003             : 
    2004             :     pthread_attr_t hThreadAttr;
    2005           1 :     pthread_attr_init(&hThreadAttr);
    2006           1 :     pthread_attr_setdetachstate(&hThreadAttr, PTHREAD_CREATE_DETACHED);
    2007           1 :     if (pthread_create(&(psInfo->hThread), &hThreadAttr, CPLStdCallThreadJacket,
    2008           1 :                        static_cast<void *>(psInfo)) != 0)
    2009             :     {
    2010             : #ifdef CHECK_THREAD_CAN_ALLOCATE_TLS
    2011             :         pthread_cond_destroy(&(psInfo->sCond));
    2012             : #endif
    2013           0 :         CPLFree(psInfo);
    2014           0 :         fprintf(stderr, "CPLCreateThread() failed.\n");
    2015           0 :         return -1;
    2016             :     }
    2017             : 
    2018             : #ifdef CHECK_THREAD_CAN_ALLOCATE_TLS
    2019             :     bool bInitSucceeded;
    2020             :     while (true)
    2021             :     {
    2022             :         assert(pthread_mutex_lock(&(psInfo->sMutex)) == 0);
    2023             :         bool bInitDone = psInfo->bInitDone;
    2024             :         if (!bInitDone)
    2025             :             assert(pthread_cond_wait(&(psInfo->sCond), &(psInfo->sMutex)) == 0);
    2026             :         bInitSucceeded = psInfo->bInitSucceeded;
    2027             :         assert(pthread_mutex_unlock(&(psInfo->sMutex)) == 0);
    2028             :         if (bInitDone)
    2029             :             break;
    2030             :     }
    2031             : 
    2032             :     pthread_cond_destroy(&(psInfo->sCond));
    2033             : 
    2034             :     if (!bInitSucceeded)
    2035             :     {
    2036             :         CPLFree(psInfo);
    2037             :         fprintf(stderr, "CPLCreateThread() failed.\n");
    2038             :         return -1;
    2039             :     }
    2040             : #endif
    2041             : 
    2042           1 :     return 1;  // Can we return the actual thread pid?
    2043             : }
    2044             : 
    2045             : /************************************************************************/
    2046             : /*                      CPLCreateJoinableThread()                       */
    2047             : /************************************************************************/
    2048             : 
    2049        4023 : CPLJoinableThread *CPLCreateJoinableThread(CPLThreadFunc pfnMain,
    2050             :                                            void *pThreadArg)
    2051             : 
    2052             : {
    2053             :     CPLStdCallThreadInfo *psInfo = static_cast<CPLStdCallThreadInfo *>(
    2054        4023 :         VSI_CALLOC_VERBOSE(sizeof(CPLStdCallThreadInfo), 1));
    2055        4023 :     if (psInfo == nullptr)
    2056           0 :         return nullptr;
    2057        4023 :     psInfo->pAppData = pThreadArg;
    2058        4023 :     psInfo->pfnMain = pfnMain;
    2059        4023 :     psInfo->bJoinable = true;
    2060             : #ifdef CHECK_THREAD_CAN_ALLOCATE_TLS
    2061             :     psInfo->bInitSucceeded = true;
    2062             :     psInfo->bInitDone = false;
    2063             :     pthread_mutex_t sMutex = PTHREAD_MUTEX_INITIALIZER;
    2064             :     psInfo->sMutex = sMutex;
    2065             :     {
    2066             :         int err = pthread_cond_init(&(psInfo->sCond), nullptr);
    2067             :         if (err != 0)
    2068             :         {
    2069             :             CPLFree(psInfo);
    2070             :             fprintf(stderr, "CPLCreateJoinableThread() failed: %s.\n",
    2071             :                     strerror(err));
    2072             :             return nullptr;
    2073             :         }
    2074             :     }
    2075             : #endif
    2076             : 
    2077             :     pthread_attr_t hThreadAttr;
    2078        4023 :     pthread_attr_init(&hThreadAttr);
    2079        4023 :     pthread_attr_setdetachstate(&hThreadAttr, PTHREAD_CREATE_JOINABLE);
    2080             :     int err =
    2081        4022 :         pthread_create(&(psInfo->hThread), &hThreadAttr, CPLStdCallThreadJacket,
    2082             :                        static_cast<void *>(psInfo));
    2083        4022 :     if (err != 0)
    2084             :     {
    2085             : #ifdef CHECK_THREAD_CAN_ALLOCATE_TLS
    2086             :         pthread_cond_destroy(&(psInfo->sCond));
    2087             : #endif
    2088           0 :         CPLFree(psInfo);
    2089           0 :         fprintf(stderr, "CPLCreateJoinableThread() failed: %s.\n",
    2090             :                 strerror(err));
    2091           0 :         return nullptr;
    2092             :     }
    2093             : 
    2094             : #ifdef CHECK_THREAD_CAN_ALLOCATE_TLS
    2095             :     bool bInitSucceeded;
    2096             :     while (true)
    2097             :     {
    2098             :         assert(pthread_mutex_lock(&(psInfo->sMutex)) == 0);
    2099             :         bool bInitDone = psInfo->bInitDone;
    2100             :         if (!bInitDone)
    2101             :             assert(pthread_cond_wait(&(psInfo->sCond), &(psInfo->sMutex)) == 0);
    2102             :         bInitSucceeded = psInfo->bInitSucceeded;
    2103             :         assert(pthread_mutex_unlock(&(psInfo->sMutex)) == 0);
    2104             :         if (bInitDone)
    2105             :             break;
    2106             :     }
    2107             : 
    2108             :     pthread_cond_destroy(&(psInfo->sCond));
    2109             : 
    2110             :     if (!bInitSucceeded)
    2111             :     {
    2112             :         void *status;
    2113             :         pthread_join(psInfo->hThread, &status);
    2114             :         CPLFree(psInfo);
    2115             :         fprintf(stderr, "CPLCreateJoinableThread() failed.\n");
    2116             :         return nullptr;
    2117             :     }
    2118             : #endif
    2119             : 
    2120        4022 :     return reinterpret_cast<CPLJoinableThread *>(psInfo);
    2121             : }
    2122             : 
    2123             : /************************************************************************/
    2124             : /*                           CPLJoinThread()                            */
    2125             : /************************************************************************/
    2126             : 
    2127        2982 : void CPLJoinThread(CPLJoinableThread *hJoinableThread)
    2128             : {
    2129        2982 :     CPLStdCallThreadInfo *psInfo =
    2130             :         reinterpret_cast<CPLStdCallThreadInfo *>(hJoinableThread);
    2131        2982 :     if (psInfo == nullptr)
    2132           0 :         return;
    2133             : 
    2134             :     void *status;
    2135        2982 :     pthread_join(psInfo->hThread, &status);
    2136             : 
    2137        2982 :     CPLFree(psInfo);
    2138             : }
    2139             : 
    2140             : /************************************************************************/
    2141             : /*                              CPLSleep()                              */
    2142             : /************************************************************************/
    2143             : 
    2144         108 : void CPLSleep(double dfWaitInSeconds)
    2145             : 
    2146             : {
    2147             :     struct timespec sRequest;
    2148             :     struct timespec sRemain;
    2149             : 
    2150         108 :     sRequest.tv_sec = static_cast<int>(floor(dfWaitInSeconds));
    2151         108 :     sRequest.tv_nsec =
    2152         108 :         static_cast<int>((dfWaitInSeconds - sRequest.tv_sec) * 1000000000);
    2153         108 :     nanosleep(&sRequest, &sRemain);
    2154         108 : }
    2155             : 
    2156             : /************************************************************************/
    2157             : /*                           CPLFinalizeTLS()                           */
    2158             : /************************************************************************/
    2159             : 
    2160         494 : void CPLFinalizeTLS()
    2161             : {
    2162         494 :     CPLCleanupTLS();
    2163             :     // See #5509 for the explanation why this may be needed.
    2164         494 :     pthread_key_delete(oTLSKey);
    2165         494 : }
    2166             : 
    2167             : /************************************************************************/
    2168             : /*                           CPLCleanupTLS()                            */
    2169             : /************************************************************************/
    2170             : 
    2171        1722 : void CPLCleanupTLS()
    2172             : 
    2173             : {
    2174        1722 :     void **papTLSList = static_cast<void **>(pthread_getspecific(oTLSKey));
    2175        1722 :     if (papTLSList == nullptr)
    2176           1 :         return;
    2177             : 
    2178        1721 :     pthread_setspecific(oTLSKey, nullptr);
    2179             : 
    2180        1721 :     CPLCleanupTLSList(papTLSList);
    2181             : }
    2182             : 
    2183             : /************************************************************************/
    2184             : /*                         CPLCreateSpinLock()                          */
    2185             : /************************************************************************/
    2186             : 
    2187             : #if defined(HAVE_PTHREAD_SPIN_LOCK)
    2188             : #define HAVE_SPINLOCK_IMPL
    2189             : 
    2190             : struct _CPLSpinLock
    2191             : {
    2192             :     pthread_spinlock_t spin;
    2193             : };
    2194             : 
    2195             : CPLSpinLock *CPLCreateSpinLock()
    2196             : {
    2197             :     CPLSpinLock *psSpin =
    2198             :         static_cast<CPLSpinLock *>(malloc(sizeof(CPLSpinLock)));
    2199             :     if (psSpin != nullptr &&
    2200             :         pthread_spin_init(&(psSpin->spin), PTHREAD_PROCESS_PRIVATE) == 0)
    2201             :     {
    2202             :         return psSpin;
    2203             :     }
    2204             :     else
    2205             :     {
    2206             :         fprintf(stderr, "CPLCreateSpinLock() failed.\n");
    2207             :         free(psSpin);
    2208             :         return nullptr;
    2209             :     }
    2210             : }
    2211             : 
    2212             : /************************************************************************/
    2213             : /*                         CPLAcquireSpinLock()                         */
    2214             : /************************************************************************/
    2215             : 
    2216             : int CPLAcquireSpinLock(CPLSpinLock *psSpin)
    2217             : {
    2218             :     return pthread_spin_lock(&(psSpin->spin)) == 0;
    2219             : }
    2220             : 
    2221             : /************************************************************************/
    2222             : /*                 CPLCreateOrAcquireSpinLockInternal()                 */
    2223             : /************************************************************************/
    2224             : 
    2225             : int CPLCreateOrAcquireSpinLockInternal(CPLLock **ppsLock)
    2226             : {
    2227             :     pthread_mutex_lock(&global_mutex);
    2228             :     if (*ppsLock == nullptr)
    2229             :     {
    2230             :         *ppsLock = static_cast<CPLLock *>(calloc(1, sizeof(CPLLock)));
    2231             :         if (*ppsLock != nullptr)
    2232             :         {
    2233             :             (*ppsLock)->eType = LOCK_SPIN;
    2234             :             (*ppsLock)->u.hSpinLock = CPLCreateSpinLock();
    2235             :             if ((*ppsLock)->u.hSpinLock == nullptr)
    2236             :             {
    2237             :                 free(*ppsLock);
    2238             :                 *ppsLock = nullptr;
    2239             :             }
    2240             :         }
    2241             :     }
    2242             :     pthread_mutex_unlock(&global_mutex);
    2243             :     // coverity[missing_unlock]
    2244             :     return (*ppsLock != nullptr && CPLAcquireSpinLock((*ppsLock)->u.hSpinLock));
    2245             : }
    2246             : 
    2247             : /************************************************************************/
    2248             : /*                         CPLReleaseSpinLock()                         */
    2249             : /************************************************************************/
    2250             : 
    2251             : void CPLReleaseSpinLock(CPLSpinLock *psSpin)
    2252             : {
    2253             :     pthread_spin_unlock(&(psSpin->spin));
    2254             : }
    2255             : 
    2256             : /************************************************************************/
    2257             : /*                         CPLDestroySpinLock()                         */
    2258             : /************************************************************************/
    2259             : 
    2260             : void CPLDestroySpinLock(CPLSpinLock *psSpin)
    2261             : {
    2262             :     pthread_spin_destroy(&(psSpin->spin));
    2263             :     free(psSpin);
    2264             : }
    2265             : #endif  // HAVE_PTHREAD_SPIN_LOCK
    2266             : 
    2267             : #endif  // def CPL_MULTIPROC_PTHREAD
    2268             : 
    2269             : /************************************************************************/
    2270             : /*                             CPLGetTLS()                              */
    2271             : /************************************************************************/
    2272             : 
    2273     2910180 : void *CPLGetTLS(int nIndex)
    2274             : 
    2275             : {
    2276     2910180 :     void **l_papTLSList = CPLGetTLSList(nullptr);
    2277             : 
    2278     2910190 :     CPLAssert(nIndex >= 0 && nIndex < CTLS_MAX);
    2279             : 
    2280     2910190 :     return l_papTLSList[nIndex];
    2281             : }
    2282             : 
    2283             : /************************************************************************/
    2284             : /*                            CPLGetTLSEx()                             */
    2285             : /************************************************************************/
    2286             : 
    2287    86333400 : void *CPLGetTLSEx(int nIndex, int *pbMemoryErrorOccurred)
    2288             : 
    2289             : {
    2290    86333400 :     void **l_papTLSList = CPLGetTLSList(pbMemoryErrorOccurred);
    2291    86331200 :     if (l_papTLSList == nullptr)
    2292           0 :         return nullptr;
    2293             : 
    2294    86331200 :     CPLAssert(nIndex >= 0 && nIndex < CTLS_MAX);
    2295             : 
    2296    86330700 :     return l_papTLSList[nIndex];
    2297             : }
    2298             : 
    2299             : /************************************************************************/
    2300             : /*                             CPLSetTLS()                              */
    2301             : /************************************************************************/
    2302             : 
    2303       28388 : void CPLSetTLS(int nIndex, void *pData, int bFreeOnExit)
    2304             : 
    2305             : {
    2306       28388 :     CPLSetTLSWithFreeFunc(nIndex, pData, (bFreeOnExit) ? CPLFree : nullptr);
    2307       28388 : }
    2308             : 
    2309             : /************************************************************************/
    2310             : /*                       CPLSetTLSWithFreeFunc()                        */
    2311             : /************************************************************************/
    2312             : 
    2313             : // Warning: The CPLTLSFreeFunc must not in any case directly or indirectly
    2314             : // use or fetch any TLS data, or a terminating thread will hang!
    2315     1595610 : void CPLSetTLSWithFreeFunc(int nIndex, void *pData, CPLTLSFreeFunc pfnFree)
    2316             : 
    2317             : {
    2318     1595610 :     void **l_papTLSList = CPLGetTLSList(nullptr);
    2319             : 
    2320     1595020 :     CPLAssert(nIndex >= 0 && nIndex < CTLS_MAX);
    2321             : 
    2322     1593840 :     l_papTLSList[nIndex] = pData;
    2323     1593840 :     l_papTLSList[CTLS_MAX + nIndex] = reinterpret_cast<void *>(pfnFree);
    2324     1593840 : }
    2325             : 
    2326             : /************************************************************************/
    2327             : /*                      CPLSetTLSWithFreeFuncEx()                       */
    2328             : /************************************************************************/
    2329             : 
    2330             : // Warning: the CPLTLSFreeFunc must not in any case directly or indirectly
    2331             : // use or fetch any TLS data, or a terminating thread will hang!
    2332        1677 : void CPLSetTLSWithFreeFuncEx(int nIndex, void *pData, CPLTLSFreeFunc pfnFree,
    2333             :                              int *pbMemoryErrorOccurred)
    2334             : 
    2335             : {
    2336        1677 :     void **l_papTLSList = CPLGetTLSList(pbMemoryErrorOccurred);
    2337             : 
    2338        1677 :     CPLAssert(nIndex >= 0 && nIndex < CTLS_MAX);
    2339             : 
    2340        1677 :     l_papTLSList[nIndex] = pData;
    2341        1677 :     l_papTLSList[CTLS_MAX + nIndex] = reinterpret_cast<void *>(pfnFree);
    2342        1677 : }
    2343             : #ifndef HAVE_SPINLOCK_IMPL
    2344             : 
    2345             : // No spinlock specific API? Fallback to mutex.
    2346             : 
    2347             : /************************************************************************/
    2348             : /*                         CPLCreateSpinLock()                          */
    2349             : /************************************************************************/
    2350             : 
    2351      242448 : CPLSpinLock *CPLCreateSpinLock(void)
    2352             : {
    2353      242448 :     CPLSpinLock *psSpin = reinterpret_cast<CPLSpinLock *>(CPLCreateMutex());
    2354      242453 :     if (psSpin)
    2355      242453 :         CPLReleaseSpinLock(psSpin);
    2356      242453 :     return psSpin;
    2357             : }
    2358             : 
    2359             : /************************************************************************/
    2360             : /*                     CPLCreateOrAcquireSpinLock()                     */
    2361             : /************************************************************************/
    2362             : 
    2363           4 : int CPLCreateOrAcquireSpinLockInternal(CPLLock **ppsLock)
    2364             : {
    2365           4 :     return CPLCreateOrAcquireMutexInternal(ppsLock, 1000, LOCK_ADAPTIVE_MUTEX);
    2366             : }
    2367             : 
    2368             : /************************************************************************/
    2369             : /*                         CPLAcquireSpinLock()                         */
    2370             : /************************************************************************/
    2371             : 
    2372     8132670 : int CPLAcquireSpinLock(CPLSpinLock *psSpin)
    2373             : {
    2374     8132670 :     return CPLAcquireMutex(reinterpret_cast<CPLMutex *>(psSpin), 1000);
    2375             : }
    2376             : 
    2377             : /************************************************************************/
    2378             : /*                         CPLReleaseSpinLock()                         */
    2379             : /************************************************************************/
    2380             : 
    2381     8375110 : void CPLReleaseSpinLock(CPLSpinLock *psSpin)
    2382             : {
    2383     8375110 :     CPLReleaseMutex(reinterpret_cast<CPLMutex *>(psSpin));
    2384     8375100 : }
    2385             : 
    2386             : /************************************************************************/
    2387             : /*                         CPLDestroySpinLock()                         */
    2388             : /************************************************************************/
    2389             : 
    2390      242453 : void CPLDestroySpinLock(CPLSpinLock *psSpin)
    2391             : {
    2392      242453 :     CPLDestroyMutex(reinterpret_cast<CPLMutex *>(psSpin));
    2393      242453 : }
    2394             : 
    2395             : #endif  // HAVE_SPINLOCK_IMPL
    2396             : 
    2397             : /************************************************************************/
    2398             : /*                           CPLCreateLock()                            */
    2399             : /************************************************************************/
    2400             : 
    2401      242524 : CPLLock *CPLCreateLock(CPLLockType eType)
    2402             : {
    2403      242524 :     switch (eType)
    2404             :     {
    2405          71 :         case LOCK_RECURSIVE_MUTEX:
    2406             :         case LOCK_ADAPTIVE_MUTEX:
    2407             :         {
    2408         142 :             CPLMutex *hMutex = CPLCreateMutexEx(eType == LOCK_RECURSIVE_MUTEX
    2409          71 :                                                     ? CPL_MUTEX_RECURSIVE
    2410             :                                                     : CPL_MUTEX_ADAPTIVE);
    2411          71 :             if (!hMutex)
    2412           0 :                 return nullptr;
    2413          71 :             CPLReleaseMutex(hMutex);
    2414          71 :             CPLLock *psLock = static_cast<CPLLock *>(malloc(sizeof(CPLLock)));
    2415          71 :             if (psLock == nullptr)
    2416             :             {
    2417           0 :                 fprintf(stderr, "CPLCreateLock() failed.\n");
    2418           0 :                 CPLDestroyMutex(hMutex);
    2419           0 :                 return nullptr;
    2420             :             }
    2421          71 :             psLock->eType = eType;
    2422          71 :             psLock->u.hMutex = hMutex;
    2423             : #ifdef DEBUG_CONTENTION
    2424          71 :             psLock->bDebugPerf = false;
    2425          71 :             psLock->bDebugPerfAsked = false;
    2426          71 :             psLock->nCurrentHolders = 0;
    2427          71 :             psLock->nStartTime = 0;
    2428             : #endif
    2429          71 :             return psLock;
    2430             :         }
    2431      242450 :         case LOCK_SPIN:
    2432             :         {
    2433      242450 :             CPLSpinLock *hSpinLock = CPLCreateSpinLock();
    2434      242453 :             if (!hSpinLock)
    2435           0 :                 return nullptr;
    2436      242453 :             CPLLock *psLock = static_cast<CPLLock *>(malloc(sizeof(CPLLock)));
    2437      242453 :             if (psLock == nullptr)
    2438             :             {
    2439           0 :                 fprintf(stderr, "CPLCreateLock() failed.\n");
    2440           0 :                 CPLDestroySpinLock(hSpinLock);
    2441           0 :                 return nullptr;
    2442             :             }
    2443      242453 :             psLock->eType = eType;
    2444      242453 :             psLock->u.hSpinLock = hSpinLock;
    2445             : #ifdef DEBUG_CONTENTION
    2446      242453 :             psLock->bDebugPerf = false;
    2447      242453 :             psLock->bDebugPerfAsked = false;
    2448      242453 :             psLock->nCurrentHolders = 0;
    2449      242453 :             psLock->nStartTime = 0;
    2450             : #endif
    2451      242453 :             return psLock;
    2452             :         }
    2453           3 :         default:
    2454           3 :             CPLAssert(false);
    2455             :             return nullptr;
    2456             :     }
    2457             : }
    2458             : 
    2459             : /************************************************************************/
    2460             : /*                       CPLCreateOrAcquireLock()                       */
    2461             : /************************************************************************/
    2462             : 
    2463        5058 : int CPLCreateOrAcquireLock(CPLLock **ppsLock, CPLLockType eType)
    2464             : {
    2465             : #ifdef DEBUG_CONTENTION
    2466        5058 :     GUIntBig nStartTime = 0;
    2467        5058 :     if ((*ppsLock) && (*ppsLock)->bDebugPerfAsked)
    2468           4 :         nStartTime = CPLrdtsc();
    2469             : #endif
    2470        5058 :     int ret = 0;
    2471             : 
    2472        5058 :     switch (eType)
    2473             :     {
    2474        5054 :         case LOCK_RECURSIVE_MUTEX:
    2475             :         case LOCK_ADAPTIVE_MUTEX:
    2476             :         {
    2477        5054 :             ret = CPLCreateOrAcquireMutexInternal(ppsLock, 1000, eType);
    2478        5054 :             break;
    2479             :         }
    2480           4 :         case LOCK_SPIN:
    2481             :         {
    2482           4 :             ret = CPLCreateOrAcquireSpinLockInternal(ppsLock);
    2483           4 :             break;
    2484             :         }
    2485           0 :         default:
    2486           0 :             CPLAssert(false);
    2487             :             return FALSE;
    2488             :     }
    2489             : #ifdef DEBUG_CONTENTION
    2490        5062 :     if (ret && (*ppsLock)->bDebugPerfAsked &&
    2491           4 :         CPLAtomicInc(&((*ppsLock)->nCurrentHolders)) == 1)
    2492             :     {
    2493           4 :         (*ppsLock)->bDebugPerf = true;
    2494           4 :         (*ppsLock)->nStartTime = nStartTime;
    2495             :     }
    2496             : #endif
    2497        5058 :     return ret;
    2498             : }
    2499             : 
    2500             : /************************************************************************/
    2501             : /*                           CPLAcquireLock()                           */
    2502             : /************************************************************************/
    2503             : 
    2504    26838500 : int CPLAcquireLock(CPLLock *psLock)
    2505             : {
    2506             : #ifdef DEBUG_CONTENTION
    2507    26838500 :     GUIntBig nStartTime = 0;
    2508    26838500 :     if (psLock->bDebugPerfAsked)
    2509     1952510 :         nStartTime = CPLrdtsc();
    2510             : #endif
    2511             :     int ret;
    2512    26838600 :     if (psLock->eType == LOCK_SPIN)
    2513     8132670 :         ret = CPLAcquireSpinLock(psLock->u.hSpinLock);
    2514             :     else
    2515    18705900 :         ret = CPLAcquireMutex(psLock->u.hMutex, 1000);
    2516             : #ifdef DEBUG_CONTENTION
    2517    28791500 :     if (ret && psLock->bDebugPerfAsked &&
    2518     1952510 :         CPLAtomicInc(&(psLock->nCurrentHolders)) == 1)
    2519             :     {
    2520     1952510 :         psLock->bDebugPerf = true;
    2521     1952510 :         psLock->nStartTime = nStartTime;
    2522             :     }
    2523             : #endif
    2524    26839000 :     return ret;
    2525             : }
    2526             : 
    2527             : /************************************************************************/
    2528             : /*                           CPLReleaseLock()                           */
    2529             : /************************************************************************/
    2530             : 
    2531    26844100 : void CPLReleaseLock(CPLLock *psLock)
    2532             : {
    2533             : #ifdef DEBUG_CONTENTION
    2534    26844100 :     bool bHitMaxDiff = false;
    2535    26844100 :     GIntBig nMaxDiff = 0;
    2536    26844100 :     double dfAvgDiff = 0;
    2537    26844100 :     if (psLock->bDebugPerf && CPLAtomicDec(&(psLock->nCurrentHolders)) == 0)
    2538             :     {
    2539     1952520 :         const GUIntBig nStopTime = CPLrdtscp();
    2540     1952520 :         const GIntBig nDiffTime =
    2541     1952520 :             static_cast<GIntBig>(nStopTime - psLock->nStartTime);
    2542     1952520 :         if (nDiffTime > psLock->nMaxDiff)
    2543             :         {
    2544          42 :             bHitMaxDiff = true;
    2545          42 :             psLock->nMaxDiff = nDiffTime;
    2546             :         }
    2547     1952520 :         nMaxDiff = psLock->nMaxDiff;
    2548     1952520 :         psLock->nIters++;
    2549     1952520 :         psLock->dfAvgDiff += (nDiffTime - psLock->dfAvgDiff) / psLock->nIters;
    2550     1952520 :         dfAvgDiff = psLock->dfAvgDiff;
    2551             :     }
    2552             : #endif
    2553    26844100 :     if (psLock->eType == LOCK_SPIN)
    2554     8132670 :         CPLReleaseSpinLock(psLock->u.hSpinLock);
    2555             :     else
    2556    18711400 :         CPLReleaseMutex(psLock->u.hMutex);
    2557             : #ifdef DEBUG_CONTENTION
    2558    26843400 :     if (psLock->bDebugPerf &&
    2559     1952450 :         (bHitMaxDiff || (psLock->nIters % 1000000) == (1000000 - 1)))
    2560             :     {
    2561          66 :         CPLDebug("LOCK", "Lock contention : max = " CPL_FRMT_GIB ", avg = %.0f",
    2562             :                  nMaxDiff, dfAvgDiff);
    2563             :     }
    2564             : #endif
    2565    26843400 : }
    2566             : 
    2567             : /************************************************************************/
    2568             : /*                           CPLDestroyLock()                           */
    2569             : /************************************************************************/
    2570             : 
    2571      242906 : void CPLDestroyLock(CPLLock *psLock)
    2572             : {
    2573      242906 :     if (psLock->eType == LOCK_SPIN)
    2574      242453 :         CPLDestroySpinLock(psLock->u.hSpinLock);
    2575             :     else
    2576         453 :         CPLDestroyMutex(psLock->u.hMutex);
    2577      242906 :     free(psLock);
    2578      242906 : }
    2579             : 
    2580             : /************************************************************************/
    2581             : /*                        CPLLockSetDebugPerf()                         */
    2582             : /************************************************************************/
    2583             : 
    2584             : #ifdef DEBUG_CONTENTION
    2585        5058 : void CPLLockSetDebugPerf(CPLLock *psLock, int bEnableIn)
    2586             : {
    2587        5058 :     psLock->bDebugPerfAsked = CPL_TO_BOOL(bEnableIn);
    2588        5058 : }
    2589             : #else
    2590             : void CPLLockSetDebugPerf(CPLLock * /* psLock */, int bEnableIn)
    2591             : {
    2592             :     if (!bEnableIn)
    2593             :         return;
    2594             : 
    2595             :     static bool bOnce = false;
    2596             :     if (!bOnce)
    2597             :     {
    2598             :         bOnce = true;
    2599             :         CPLDebug("LOCK", "DEBUG_CONTENTION not available");
    2600             :     }
    2601             : }
    2602             : #endif
    2603             : 
    2604             : /************************************************************************/
    2605             : /*                           CPLLockHolder()                            */
    2606             : /************************************************************************/
    2607             : 
    2608        5058 : CPLLockHolder::CPLLockHolder(CPLLock **phLock, CPLLockType eType,
    2609        5058 :                              const char *pszFileIn, int nLineIn)
    2610             : 
    2611             : {
    2612             : #ifndef MUTEX_NONE
    2613        5058 :     pszFile = pszFileIn;
    2614        5058 :     nLine = nLineIn;
    2615             : 
    2616             : #ifdef DEBUG_MUTEX
    2617             :     // XXX: There is no way to use CPLDebug() here because it works with
    2618             :     // mutexes itself so we will fall in infinite recursion. Good old
    2619             :     // fprintf() will do the job right.
    2620             :     fprintf(stderr, "CPLLockHolder: Request %p for pid %ld at %d/%s.\n",
    2621             :             *phLock, static_cast<long>(CPLGetPID()), nLine, pszFile);
    2622             : #endif
    2623             : 
    2624        5058 :     if (!CPLCreateOrAcquireLock(phLock, eType))
    2625             :     {
    2626           0 :         fprintf(stderr, "CPLLockHolder: Failed to acquire lock!\n");
    2627           0 :         hLock = nullptr;
    2628             :     }
    2629             :     else
    2630             :     {
    2631             : #ifdef DEBUG_MUTEX
    2632             :         fprintf(stderr, "CPLLockHolder: Acquired %p for pid %ld at %d/%s.\n",
    2633             :                 *phLock, static_cast<long>(CPLGetPID()), nLine, pszFile);
    2634             : #endif
    2635             : 
    2636        5058 :         hLock = *phLock;
    2637             :     }
    2638             : #endif  // ndef MUTEX_NONE
    2639        5058 : }
    2640             : 
    2641             : /************************************************************************/
    2642             : /*                           CPLLockHolder()                            */
    2643             : /************************************************************************/
    2644             : 
    2645    26833700 : CPLLockHolder::CPLLockHolder(CPLLock *hLockIn, const char *pszFileIn,
    2646    26833700 :                              int nLineIn)
    2647             : 
    2648             : {
    2649             : #ifndef MUTEX_NONE
    2650    26833700 :     pszFile = pszFileIn;
    2651    26833700 :     nLine = nLineIn;
    2652    26833700 :     hLock = hLockIn;
    2653             : 
    2654    26833700 :     if (hLock != nullptr)
    2655             :     {
    2656    26833700 :         if (!CPLAcquireLock(hLock))
    2657             :         {
    2658           0 :             fprintf(stderr, "CPLLockHolder: Failed to acquire lock!\n");
    2659           0 :             hLock = nullptr;
    2660             :         }
    2661             :     }
    2662             : #endif  // ndef MUTEX_NONE
    2663    26834200 : }
    2664             : 
    2665             : /************************************************************************/
    2666             : /*                           ~CPLLockHolder()                           */
    2667             : /************************************************************************/
    2668             : 
    2669    53677800 : CPLLockHolder::~CPLLockHolder()
    2670             : 
    2671             : {
    2672             : #ifndef MUTEX_NONE
    2673    26839300 :     if (hLock != nullptr)
    2674             :     {
    2675             : #ifdef DEBUG_MUTEX
    2676             :         fprintf(stderr, "~CPLLockHolder: Release %p for pid %ld at %d/%s.\n",
    2677             :                 hLock, static_cast<long>(CPLGetPID()), nLine, pszFile);
    2678             : #endif
    2679    26839300 :         CPLReleaseLock(hLock);
    2680             :     }
    2681             : #endif  // ndef MUTEX_NONE
    2682    26838500 : }
    2683             : 
    2684             : /************************************************************************/
    2685             : /*                       CPLGetCurrentProcessID()                       */
    2686             : /************************************************************************/
    2687             : 
    2688             : #ifdef CPL_MULTIPROC_WIN32
    2689             : 
    2690             : int CPLGetCurrentProcessID()
    2691             : {
    2692             :     return GetCurrentProcessId();
    2693             : }
    2694             : 
    2695             : #else
    2696             : 
    2697             : #include <sys/types.h>
    2698             : #include <unistd.h>
    2699             : 
    2700        3334 : int CPLGetCurrentProcessID()
    2701             : {
    2702        3334 :     return getpid();
    2703             : }
    2704             : 
    2705             : #endif

Generated by: LCOV version 1.14