LCOV - code coverage report
Current view: top level - port - cpl_multiproc.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 385 492 78.3 %
Date: 2024-11-21 22:18:42 Functions: 57 59 96.6 %

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

Generated by: LCOV version 1.14