LCOV - code coverage report
Current view: top level - port - cpl_multiproc.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 387 491 78.8 %
Date: 2024-04-28 23:18:46 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             :  * Permission is hereby granted, free of charge, to any person obtaining a
      12             :  * copy of this software and associated documentation files (the "Software"),
      13             :  * to deal in the Software without restriction, including without limitation
      14             :  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      15             :  * and/or sell copies of the Software, and to permit persons to whom the
      16             :  * Software is furnished to do so, subject to the following conditions:
      17             :  *
      18             :  * The above copyright notice and this permission notice shall be included
      19             :  * in all copies or substantial portions of the Software.
      20             :  *
      21             :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
      22             :  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      23             :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
      24             :  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      25             :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
      26             :  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
      27             :  * DEALINGS IN THE SOFTWARE.
      28             :  ****************************************************************************/
      29             : 
      30             : #ifndef _GNU_SOURCE
      31             : #define _GNU_SOURCE
      32             : #endif
      33             : 
      34             : // Include cpl_config.h BEFORE cpl_multiproc.h, as the later may undefine
      35             : // CPL_MULTIPROC_PTHREAD for mingw case.
      36             : 
      37             : #include "cpl_config.h"
      38             : #include "cpl_multiproc.h"
      39             : 
      40             : #ifdef CHECK_THREAD_CAN_ALLOCATE_TLS
      41             : #include <cassert>
      42             : #endif
      43             : #include <cerrno>
      44             : #include <cmath>
      45             : #include <cstddef>
      46             : #include <cstdio>
      47             : #include <cstdlib>
      48             : #include <cstring>
      49             : #include <ctime>
      50             : #include <algorithm>
      51             : 
      52             : #include "cpl_atomic_ops.h"
      53             : #include "cpl_conv.h"
      54             : #include "cpl_error.h"
      55             : #include "cpl_string.h"
      56             : #include "cpl_vsi.h"
      57             : 
      58             : #if defined(CPL_MULTIPROC_STUB) && !defined(DEBUG)
      59             : #define MUTEX_NONE
      60             : #endif
      61             : 
      62             : // #define DEBUG_MUTEX
      63             : 
      64             : #if defined(DEBUG) &&                                                          \
      65             :     (defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)))
      66             : #ifndef DEBUG_CONTENTION
      67             : #define DEBUG_CONTENTION
      68             : #endif
      69             : #endif
      70             : 
      71             : typedef struct _CPLSpinLock CPLSpinLock;
      72             : 
      73             : struct _CPLLock
      74             : {
      75             :     CPLLockType eType;
      76             : 
      77             :     union
      78             :     {
      79             :         CPLMutex *hMutex;
      80             :         CPLSpinLock *hSpinLock;
      81             :     } u;
      82             : 
      83             : #ifdef DEBUG_CONTENTION
      84             :     bool bDebugPerfAsked;
      85             :     bool bDebugPerf;
      86             :     volatile int nCurrentHolders;
      87             :     GUIntBig nStartTime;
      88             :     GIntBig nMaxDiff;
      89             :     double dfAvgDiff;
      90             :     GUIntBig nIters;
      91             : #endif
      92             : };
      93             : 
      94             : #ifdef DEBUG_CONTENTION
      95             : 
      96             : #if defined(__x86_64)
      97             : #define GCC_CPUID(level, a, b, c, d)                                           \
      98             :     __asm__ volatile("xchgq %%rbx, %q1\n"                                      \
      99             :                      "cpuid\n"                                                 \
     100             :                      "xchgq %%rbx, %q1"                                        \
     101             :                      : "=a"(a), "=r"(b), "=c"(c), "=d"(d)                      \
     102             :                      : "0"(level))
     103             : #else
     104             : #define GCC_CPUID(level, a, b, c, d)                                           \
     105             :     __asm__ volatile("xchgl %%ebx, %1\n"                                       \
     106             :                      "cpuid\n"                                                 \
     107             :                      "xchgl %%ebx, %1"                                         \
     108             :                      : "=a"(a), "=r"(b), "=c"(c), "=d"(d)                      \
     109             :                      : "0"(level))
     110             : #endif
     111             : 
     112     1952510 : static GUIntBig CPLrdtsc()
     113             : {
     114             :     unsigned int a;
     115             :     unsigned int d;
     116             :     unsigned int unused1;
     117             :     unsigned int unused2;
     118             :     unsigned int unused3;
     119             :     unsigned int unused4;
     120     1952510 :     GCC_CPUID(0, unused1, unused2, unused3, unused4);
     121     1952510 :     __asm__ volatile("rdtsc" : "=a"(a), "=d"(d));
     122     1952510 :     return static_cast<GUIntBig>(a) | (static_cast<GUIntBig>(d) << 32);
     123             : }
     124             : 
     125     1952510 : static GUIntBig CPLrdtscp()
     126             : {
     127             :     unsigned int a;
     128             :     unsigned int d;
     129             :     unsigned int unused1;
     130             :     unsigned int unused2;
     131             :     unsigned int unused3;
     132             :     unsigned int unused4;
     133     1952510 :     __asm__ volatile("rdtscp" : "=a"(a), "=d"(d));
     134     1952510 :     GCC_CPUID(0, unused1, unused2, unused3, unused4);
     135     1952510 :     return static_cast<GUIntBig>(a) | (static_cast<GUIntBig>(d) << 32);
     136             : }
     137             : #endif
     138             : 
     139             : static CPLSpinLock *CPLCreateSpinLock();  // Returned NON acquired.
     140             : static int CPLCreateOrAcquireSpinLockInternal(CPLLock **);
     141             : static int CPLAcquireSpinLock(CPLSpinLock *);
     142             : static void CPLReleaseSpinLock(CPLSpinLock *);
     143             : static void CPLDestroySpinLock(CPLSpinLock *);
     144             : 
     145             : #ifndef CPL_MULTIPROC_PTHREAD
     146             : #ifndef MUTEX_NONE
     147             : static CPLMutex *CPLCreateOrAcquireMasterMutex(double);
     148             : static CPLMutex *&CPLCreateOrAcquireMasterMutexInternal(double);
     149             : static CPLMutex *CPLCreateUnacquiredMutex();
     150             : #endif
     151             : #endif
     152             : 
     153             : // We don't want it to be publicly used since it solves rather tricky issues
     154             : // that are better to remain hidden.
     155             : void CPLFinalizeTLS();
     156             : 
     157             : /************************************************************************/
     158             : /*                           CPLMutexHolder()                           */
     159             : /************************************************************************/
     160             : 
     161             : #ifdef MUTEX_NONE
     162             : CPLMutexHolder::CPLMutexHolder(CPLMutex ** /* phMutex */,
     163             :                                double /* dfWaitInSeconds */,
     164             :                                const char * /* pszFileIn */, int /* nLineIn */,
     165             :                                int /* nOptions */)
     166             : {
     167             : }
     168             : 
     169             : #else
     170    63454600 : CPLMutexHolder::CPLMutexHolder(CPLMutex **phMutex, double dfWaitInSeconds,
     171    63454600 :                                const char *pszFileIn, int nLineIn, int nOptions)
     172    63454600 :     : hMutex(nullptr), pszFile(pszFileIn), nLine(nLineIn)
     173             : {
     174    63454600 :     if (phMutex == nullptr)
     175             :     {
     176           0 :         fprintf(stderr, "CPLMutexHolder: phMutex )) NULL !\n");
     177           0 :         hMutex = nullptr;
     178           0 :         return;
     179             :     }
     180             : 
     181             : #ifdef DEBUG_MUTEX
     182             :     // There is no way to use CPLDebug() here because it works with
     183             :     // mutexes itself so we will fall in infinite recursion.
     184             :     // fprintf() will do the job right.
     185             :     fprintf(stderr, "CPLMutexHolder: Request %p for pid %ld at %d/%s.\n",
     186             :             *phMutex, static_cast<long>(CPLGetPID()), nLine, pszFile);
     187             : #else
     188             :     // TODO(schwehr): Find a better way to do handle this.
     189             :     (void)pszFile;
     190             :     (void)nLine;
     191             : #endif
     192             : 
     193    63454600 :     if (!CPLCreateOrAcquireMutexEx(phMutex, dfWaitInSeconds, nOptions))
     194             :     {
     195           5 :         fprintf(stderr, "CPLMutexHolder: Failed to acquire mutex!\n");
     196           0 :         hMutex = nullptr;
     197             :     }
     198             :     else
     199             :     {
     200             : #ifdef DEBUG_MUTEX
     201             :         fprintf(stderr, "CPLMutexHolder: Acquired %p for pid %ld at %d/%s.\n",
     202             :                 *phMutex, static_cast<long>(CPLGetPID()), nLine, pszFile);
     203             : #endif
     204             : 
     205    63464500 :         hMutex = *phMutex;
     206             :     }
     207             : }
     208             : #endif  // ndef MUTEX_NONE
     209             : 
     210             : /************************************************************************/
     211             : /*                           CPLMutexHolder()                           */
     212             : /************************************************************************/
     213             : 
     214             : #ifdef MUTEX_NONE
     215             : CPLMutexHolder::CPLMutexHolder(CPLMutex * /* hMutexIn */,
     216             :                                double /* dfWaitInSeconds */,
     217             :                                const char * /* pszFileIn */, int /* nLineIn */)
     218             : {
     219             : }
     220             : #else
     221             : 
     222       15045 : static CPLMutex *GetMutexHolderMutexMember(CPLMutex *hMutexIn,
     223             :                                            double dfWaitInSeconds)
     224             : {
     225       15045 :     if (hMutexIn && !CPLAcquireMutex(hMutexIn, dfWaitInSeconds))
     226             :     {
     227           0 :         fprintf(stderr, "CPLMutexHolder: Failed to acquire mutex!\n");
     228           0 :         return nullptr;
     229             :     }
     230       15045 :     return hMutexIn;
     231             : }
     232             : 
     233       15045 : CPLMutexHolder::CPLMutexHolder(CPLMutex *hMutexIn, double dfWaitInSeconds,
     234       15045 :                                const char *pszFileIn, int nLineIn)
     235       15045 :     : hMutex(GetMutexHolderMutexMember(hMutexIn, dfWaitInSeconds)),
     236       15045 :       pszFile(pszFileIn), nLine(nLineIn)
     237             : {
     238       15045 : }
     239             : #endif  // ndef MUTEX_NONE
     240             : 
     241             : /************************************************************************/
     242             : /*                          ~CPLMutexHolder()                           */
     243             : /************************************************************************/
     244             : 
     245             : #ifdef MUTEX_NONE
     246             : CPLMutexHolder::~CPLMutexHolder()
     247             : {
     248             : }
     249             : #else
     250   126957000 : CPLMutexHolder::~CPLMutexHolder()
     251             : {
     252    63479500 :     if (hMutex != nullptr)
     253             :     {
     254             : #ifdef DEBUG_MUTEX
     255             :         fprintf(stderr, "~CPLMutexHolder: Release %p for pid %ld at %d/%s.\n",
     256             :                 hMutex, static_cast<long>(CPLGetPID()), nLine, pszFile);
     257             : #endif
     258    63479400 :         CPLReleaseMutex(hMutex);
     259             :     }
     260    63477400 : }
     261             : #endif  // ndef MUTEX_NONE
     262             : 
     263     1304900 : int CPLCreateOrAcquireMutex(CPLMutex **phMutex, double dfWaitInSeconds)
     264             : {
     265     1304900 :     return CPLCreateOrAcquireMutexEx(phMutex, dfWaitInSeconds,
     266     1305730 :                                      CPL_MUTEX_RECURSIVE);
     267             : }
     268             : 
     269             : /************************************************************************/
     270             : /*                      CPLCreateOrAcquireMutex()                       */
     271             : /************************************************************************/
     272             : 
     273             : #ifndef CPL_MULTIPROC_PTHREAD
     274             : 
     275             : #ifndef MUTEX_NONE
     276             : CPLMutex *CPLCreateUnacquiredMutex()
     277             : {
     278             :     CPLMutex *hMutex = CPLCreateMutex();
     279             :     if (hMutex)
     280             :     {
     281             :         CPLReleaseMutex(hMutex);
     282             :     }
     283             :     return hMutex;
     284             : }
     285             : 
     286             : CPLMutex *&
     287             : CPLCreateOrAcquireMasterMutexInternal(double dfWaitInSeconds = 1000.0)
     288             : {
     289             :     // The dynamic initialization of the block scope hCOAMutex
     290             :     // with static storage duration is thread-safe in C++11
     291             :     static CPLMutex *hCOAMutex = CPLCreateUnacquiredMutex();
     292             : 
     293             :     // WARNING: although adding an CPLAssert(hCOAMutex); might seem logical
     294             :     // here, do not enable it (see comment below). It calls CPLError that
     295             :     // uses the hCOAMutex itself leading to recursive mutex acquisition
     296             :     // and likely a stack overflow.
     297             : 
     298             :     if (!hCOAMutex)
     299             :     {
     300             :         // Fall back to this, ironically, NOT thread-safe re-initialisation of
     301             :         // hCOAMutex in case of a memory error or call to CPLCleanupMasterMutex
     302             :         // sequenced in an unusual, unexpected or erroneous way.
     303             :         // For example, an unusual sequence could be:
     304             :         //   GDALDriverManager has been instantiated,
     305             :         //   then OGRCleanupAll is called which calls CPLCleanupMasterMutex,
     306             :         //   then CPLFreeConfig is called which acquires the hCOAMutex
     307             :         //   that has already been released and destroyed.
     308             : 
     309             :         hCOAMutex = CPLCreateUnacquiredMutex();
     310             :     }
     311             : 
     312             :     if (hCOAMutex)
     313             :     {
     314             :         CPLAcquireMutex(hCOAMutex, dfWaitInSeconds);
     315             :     }
     316             : 
     317             :     return hCOAMutex;
     318             : }
     319             : 
     320             : CPLMutex *CPLCreateOrAcquireMasterMutex(double dfWaitInSeconds = 1000.0)
     321             : {
     322             :     CPLMutex *hCOAMutex =
     323             :         CPLCreateOrAcquireMasterMutexInternal(dfWaitInSeconds);
     324             :     return hCOAMutex;
     325             : }
     326             : #endif
     327             : 
     328             : #ifdef MUTEX_NONE
     329             : 
     330             : int CPLCreateOrAcquireMutexEx(CPLMutex **phMutex, double dfWaitInSeconds,
     331             :                               int nOptions)
     332             : {
     333             :     return false;
     334             : }
     335             : #else
     336             : int CPLCreateOrAcquireMutexEx(CPLMutex **phMutex, double dfWaitInSeconds,
     337             :                               int nOptions)
     338             : {
     339             :     bool bSuccess = false;
     340             : 
     341             :     CPLMutex *hCOAMutex = CPLCreateOrAcquireMasterMutex(dfWaitInSeconds);
     342             :     if (hCOAMutex == nullptr)
     343             :     {
     344             :         *phMutex = nullptr;
     345             :         return FALSE;
     346             :     }
     347             : 
     348             :     if (*phMutex == nullptr)
     349             :     {
     350             :         *phMutex = CPLCreateMutexEx(nOptions);
     351             :         bSuccess = *phMutex != nullptr;
     352             :         CPLReleaseMutex(hCOAMutex);
     353             :     }
     354             :     else
     355             :     {
     356             :         CPLReleaseMutex(hCOAMutex);
     357             : 
     358             :         bSuccess = CPL_TO_BOOL(CPLAcquireMutex(*phMutex, dfWaitInSeconds));
     359             :     }
     360             : 
     361             :     return bSuccess;
     362             : }
     363             : #endif  // ndef MUTEX_NONE
     364             : 
     365             : /************************************************************************/
     366             : /*                   CPLCreateOrAcquireMutexInternal()                  */
     367             : /************************************************************************/
     368             : 
     369             : #ifdef MUTEX_NONE
     370             : static bool CPLCreateOrAcquireMutexInternal(CPLLock **phLock,
     371             :                                             double dfWaitInSeconds,
     372             :                                             CPLLockType eType)
     373             : {
     374             :     return false;
     375             : }
     376             : #else
     377             : static bool CPLCreateOrAcquireMutexInternal(CPLLock **phLock,
     378             :                                             double dfWaitInSeconds,
     379             :                                             CPLLockType eType)
     380             : 
     381             : {
     382             :     bool bSuccess = false;
     383             : 
     384             :     CPLMutex *hCOAMutex = CPLCreateOrAcquireMasterMutex(dfWaitInSeconds);
     385             :     if (hCOAMutex == nullptr)
     386             :     {
     387             :         *phLock = nullptr;
     388             :         return FALSE;
     389             :     }
     390             : 
     391             :     if (*phLock == nullptr)
     392             :     {
     393             :         *phLock = static_cast<CPLLock *>(calloc(1, sizeof(CPLLock)));
     394             :         if (*phLock)
     395             :         {
     396             :             (*phLock)->eType = eType;
     397             :             (*phLock)->u.hMutex = CPLCreateMutexEx(
     398             :                 (eType == LOCK_RECURSIVE_MUTEX) ? CPL_MUTEX_RECURSIVE
     399             :                                                 : CPL_MUTEX_ADAPTIVE);
     400             :             if ((*phLock)->u.hMutex == nullptr)
     401             :             {
     402             :                 free(*phLock);
     403             :                 *phLock = nullptr;
     404             :             }
     405             :         }
     406             :         bSuccess = *phLock != nullptr;
     407             :         CPLReleaseMutex(hCOAMutex);
     408             :     }
     409             :     else
     410             :     {
     411             :         CPLReleaseMutex(hCOAMutex);
     412             : 
     413             :         bSuccess =
     414             :             CPL_TO_BOOL(CPLAcquireMutex((*phLock)->u.hMutex, dfWaitInSeconds));
     415             :     }
     416             : 
     417             :     return bSuccess;
     418             : }
     419             : #endif  // ndef MUTEX_NONE
     420             : 
     421             : #endif  // CPL_MULTIPROC_PTHREAD
     422             : 
     423             : /************************************************************************/
     424             : /*                      CPLCleanupMasterMutex()                         */
     425             : /************************************************************************/
     426             : 
     427        1231 : void CPLCleanupMasterMutex()
     428             : {
     429             : #ifndef CPL_MULTIPROC_PTHREAD
     430             : #ifndef MUTEX_NONE
     431             :     CPLMutex *&hCOAMutex = CPLCreateOrAcquireMasterMutexInternal();
     432             :     if (hCOAMutex != nullptr)
     433             :     {
     434             :         CPLReleaseMutex(hCOAMutex);
     435             :         CPLDestroyMutex(hCOAMutex);
     436             :         hCOAMutex = nullptr;
     437             :     }
     438             : #endif
     439             : #endif
     440        1231 : }
     441             : 
     442             : /************************************************************************/
     443             : /*                        CPLCleanupTLSList()                           */
     444             : /*                                                                      */
     445             : /*      Free resources associated with a TLS vector (implementation     */
     446             : /*      independent).                                                   */
     447             : /************************************************************************/
     448             : 
     449        1729 : static void CPLCleanupTLSList(void **papTLSList)
     450             : 
     451             : {
     452             : #ifdef DEBUG_VERBOSE
     453             :     printf("CPLCleanupTLSList(%p)\n", papTLSList); /*ok*/
     454             : #endif
     455             : 
     456        1729 :     if (papTLSList == nullptr)
     457           0 :         return;
     458             : 
     459       57048 :     for (int i = 0; i < CTLS_MAX; i++)
     460             :     {
     461       55319 :         if (papTLSList[i] != nullptr && papTLSList[i + CTLS_MAX] != nullptr)
     462             :         {
     463        5279 :             CPLTLSFreeFunc pfnFree =
     464        5279 :                 reinterpret_cast<CPLTLSFreeFunc>(papTLSList[i + CTLS_MAX]);
     465        5279 :             pfnFree(papTLSList[i]);
     466        5279 :             papTLSList[i] = nullptr;
     467             :         }
     468             :     }
     469             : 
     470        1729 :     CPLFree(papTLSList);
     471             : }
     472             : 
     473             : #if defined(CPL_MULTIPROC_STUB)
     474             : /************************************************************************/
     475             : /* ==================================================================== */
     476             : /*                        CPL_MULTIPROC_STUB                            */
     477             : /*                                                                      */
     478             : /*      Stub implementation.  Mutexes don't provide exclusion, file     */
     479             : /*      locking is achieved with extra "lock files", and thread         */
     480             : /*      creation doesn't work.  The PID is always just one.             */
     481             : /* ==================================================================== */
     482             : /************************************************************************/
     483             : 
     484             : /************************************************************************/
     485             : /*                             CPLGetNumCPUs()                          */
     486             : /************************************************************************/
     487             : 
     488             : int CPLGetNumCPUs()
     489             : {
     490             :     return 1;
     491             : }
     492             : 
     493             : /************************************************************************/
     494             : /*                        CPLGetThreadingModel()                        */
     495             : /************************************************************************/
     496             : 
     497             : const char *CPLGetThreadingModel()
     498             : 
     499             : {
     500             :     return "stub";
     501             : }
     502             : 
     503             : /************************************************************************/
     504             : /*                           CPLCreateMutex()                           */
     505             : /************************************************************************/
     506             : 
     507             : #ifdef MUTEX_NONE
     508             : CPLMutex *CPLCreateMutex()
     509             : {
     510             :     return (CPLMutex *)0xdeadbeef;
     511             : }
     512             : #else
     513             : CPLMutex *CPLCreateMutex()
     514             : {
     515             :     unsigned char *pabyMutex = static_cast<unsigned char *>(malloc(4));
     516             :     if (pabyMutex == nullptr)
     517             :         return nullptr;
     518             : 
     519             :     pabyMutex[0] = 1;
     520             :     pabyMutex[1] = 'r';
     521             :     pabyMutex[2] = 'e';
     522             :     pabyMutex[3] = 'd';
     523             : 
     524             :     return (CPLMutex *)pabyMutex;
     525             : }
     526             : #endif
     527             : 
     528             : CPLMutex *CPLCreateMutexEx(int /*nOptions*/)
     529             : 
     530             : {
     531             :     return CPLCreateMutex();
     532             : }
     533             : 
     534             : /************************************************************************/
     535             : /*                          CPLAcquireMutex()                           */
     536             : /************************************************************************/
     537             : 
     538             : #ifdef MUTEX_NONE
     539             : int CPLAcquireMutex(CPLMutex *hMutex, double /* dfWaitInSeconds */)
     540             : {
     541             :     return TRUE;
     542             : }
     543             : #else
     544             : int CPLAcquireMutex(CPLMutex *hMutex, double /*dfWaitInSeconds*/)
     545             : {
     546             :     unsigned char *pabyMutex = reinterpret_cast<unsigned char *>(hMutex);
     547             : 
     548             :     CPLAssert(pabyMutex[1] == 'r' && pabyMutex[2] == 'e' &&
     549             :               pabyMutex[3] == 'd');
     550             : 
     551             :     pabyMutex[0] += 1;
     552             : 
     553             :     return TRUE;
     554             : }
     555             : #endif  // ! MUTEX_NONE
     556             : 
     557             : /************************************************************************/
     558             : /*                          CPLReleaseMutex()                           */
     559             : /************************************************************************/
     560             : 
     561             : #ifdef MUTEX_NONE
     562             : void CPLReleaseMutex(CPLMutex * /* hMutex */)
     563             : {
     564             : }
     565             : #else
     566             : void CPLReleaseMutex(CPLMutex *hMutex)
     567             : {
     568             :     unsigned char *pabyMutex = reinterpret_cast<unsigned char *>(hMutex);
     569             : 
     570             :     CPLAssert(pabyMutex[1] == 'r' && pabyMutex[2] == 'e' &&
     571             :               pabyMutex[3] == 'd');
     572             : 
     573             :     if (pabyMutex[0] < 1)
     574             :         CPLDebug("CPLMultiProc",
     575             :                  "CPLReleaseMutex() called on mutex with %d as ref count!",
     576             :                  pabyMutex[0]);
     577             : 
     578             :     pabyMutex[0] -= 1;
     579             : }
     580             : #endif
     581             : 
     582             : /************************************************************************/
     583             : /*                          CPLDestroyMutex()                           */
     584             : /************************************************************************/
     585             : 
     586             : #ifdef MUTEX_NONE
     587             : void CPLDestroyMutex(CPLMutex * /* hMutex */)
     588             : {
     589             : }
     590             : #else
     591             : void CPLDestroyMutex(CPLMutex *hMutex)
     592             : {
     593             :     unsigned char *pabyMutex = reinterpret_cast<unsigned char *>(hMutex);
     594             : 
     595             :     CPLAssert(pabyMutex[1] == 'r' && pabyMutex[2] == 'e' &&
     596             :               pabyMutex[3] == 'd');
     597             : 
     598             :     free(pabyMutex);
     599             : }
     600             : #endif
     601             : 
     602             : /************************************************************************/
     603             : /*                            CPLCreateCond()                           */
     604             : /************************************************************************/
     605             : 
     606             : CPLCond *CPLCreateCond()
     607             : {
     608             :     return nullptr;
     609             : }
     610             : 
     611             : /************************************************************************/
     612             : /*                            CPLCondWait()                             */
     613             : /************************************************************************/
     614             : 
     615             : void CPLCondWait(CPLCond * /* hCond */, CPLMutex * /* hMutex */)
     616             : {
     617             : }
     618             : 
     619             : /************************************************************************/
     620             : /*                         CPLCondTimedWait()                           */
     621             : /************************************************************************/
     622             : 
     623             : CPLCondTimedWaitReason CPLCondTimedWait(CPLCond * /* hCond */,
     624             :                                         CPLMutex * /* hMutex */, double)
     625             : {
     626             :     return COND_TIMED_WAIT_OTHER;
     627             : }
     628             : 
     629             : /************************************************************************/
     630             : /*                            CPLCondSignal()                           */
     631             : /************************************************************************/
     632             : 
     633             : void CPLCondSignal(CPLCond * /* hCond */)
     634             : {
     635             : }
     636             : 
     637             : /************************************************************************/
     638             : /*                           CPLCondBroadcast()                         */
     639             : /************************************************************************/
     640             : 
     641             : void CPLCondBroadcast(CPLCond * /* hCond */)
     642             : {
     643             : }
     644             : 
     645             : /************************************************************************/
     646             : /*                            CPLDestroyCond()                          */
     647             : /************************************************************************/
     648             : 
     649             : void CPLDestroyCond(CPLCond * /* hCond */)
     650             : {
     651             : }
     652             : 
     653             : /************************************************************************/
     654             : /*                            CPLLockFile()                             */
     655             : /*                                                                      */
     656             : /*      Lock a file.  This implementation has a terrible race           */
     657             : /*      condition.  If we don't succeed in opening the lock file, we    */
     658             : /*      assume we can create one and own the target file, but other     */
     659             : /*      processes might easily try creating the target file at the      */
     660             : /*      same time, overlapping us.  Death!  Mayhem!  The traditional    */
     661             : /*      solution is to use open() with _O_CREAT|_O_EXCL but this        */
     662             : /*      function and these arguments aren't trivially portable.         */
     663             : /*      Also, this still leaves a race condition on NFS drivers         */
     664             : /*      (apparently).                                                   */
     665             : /************************************************************************/
     666             : 
     667             : void *CPLLockFile(const char *pszPath, double dfWaitInSeconds)
     668             : 
     669             : {
     670             :     /* -------------------------------------------------------------------- */
     671             :     /*      We use a lock file with a name derived from the file we want    */
     672             :     /*      to lock to represent the file being locked.  Note that for      */
     673             :     /*      the stub implementation the target file does not even need      */
     674             :     /*      to exist to be locked.                                          */
     675             :     /* -------------------------------------------------------------------- */
     676             :     char *pszLockFilename =
     677             :         static_cast<char *>(CPLMalloc(strlen(pszPath) + 30));
     678             :     snprintf(pszLockFilename, strlen(pszPath) + 30, "%s.lock", pszPath);
     679             : 
     680             :     FILE *fpLock = fopen(pszLockFilename, "r");
     681             :     while (fpLock != nullptr && dfWaitInSeconds > 0.0)
     682             :     {
     683             :         fclose(fpLock);
     684             :         CPLSleep(std::min(dfWaitInSeconds, 0.5));
     685             :         dfWaitInSeconds -= 0.5;
     686             : 
     687             :         fpLock = fopen(pszLockFilename, "r");
     688             :     }
     689             : 
     690             :     if (fpLock != nullptr)
     691             :     {
     692             :         fclose(fpLock);
     693             :         CPLFree(pszLockFilename);
     694             :         return nullptr;
     695             :     }
     696             : 
     697             :     fpLock = fopen(pszLockFilename, "w");
     698             : 
     699             :     if (fpLock == nullptr)
     700             :     {
     701             :         CPLFree(pszLockFilename);
     702             :         return nullptr;
     703             :     }
     704             : 
     705             :     fwrite("held\n", 1, 5, fpLock);
     706             :     fclose(fpLock);
     707             : 
     708             :     return pszLockFilename;
     709             : }
     710             : 
     711             : /************************************************************************/
     712             : /*                           CPLUnlockFile()                            */
     713             : /************************************************************************/
     714             : 
     715             : void CPLUnlockFile(void *hLock)
     716             : 
     717             : {
     718             :     char *pszLockFilename = static_cast<char *>(hLock);
     719             : 
     720             :     if (hLock == nullptr)
     721             :         return;
     722             : 
     723             :     VSIUnlink(pszLockFilename);
     724             : 
     725             :     CPLFree(pszLockFilename);
     726             : }
     727             : 
     728             : /************************************************************************/
     729             : /*                             CPLGetPID()                              */
     730             : /************************************************************************/
     731             : 
     732             : GIntBig CPLGetPID()
     733             : 
     734             : {
     735             :     return 1;
     736             : }
     737             : 
     738             : /************************************************************************/
     739             : /*                          CPLCreateThread();                          */
     740             : /************************************************************************/
     741             : 
     742             : int CPLCreateThread(CPLThreadFunc /* pfnMain */, void * /* pArg */)
     743             : {
     744             :     CPLDebug("CPLCreateThread", "Fails to dummy implementation");
     745             : 
     746             :     return -1;
     747             : }
     748             : 
     749             : /************************************************************************/
     750             : /*                      CPLCreateJoinableThread()                       */
     751             : /************************************************************************/
     752             : 
     753             : CPLJoinableThread *CPLCreateJoinableThread(CPLThreadFunc /* pfnMain */,
     754             :                                            void * /* pThreadArg */)
     755             : {
     756             :     CPLDebug("CPLCreateJoinableThread", "Fails to dummy implementation");
     757             : 
     758             :     return nullptr;
     759             : }
     760             : 
     761             : /************************************************************************/
     762             : /*                          CPLJoinThread()                             */
     763             : /************************************************************************/
     764             : 
     765             : void CPLJoinThread(CPLJoinableThread * /* hJoinableThread */)
     766             : {
     767             : }
     768             : 
     769             : /************************************************************************/
     770             : /*                              CPLSleep()                              */
     771             : /************************************************************************/
     772             : 
     773             : void CPLSleep(double dfWaitInSeconds)
     774             : {
     775             :     time_t ltime;
     776             : 
     777             :     time(&ltime);
     778             :     const time_t ttime = ltime + static_cast<int>(dfWaitInSeconds + 0.5);
     779             : 
     780             :     for (; ltime < ttime; time(&ltime))
     781             :     {
     782             :         // Currently we just busy wait.  Perhaps we could at least block on io?
     783             :     }
     784             : }
     785             : 
     786             : /************************************************************************/
     787             : /*                           CPLGetTLSList()                            */
     788             : /************************************************************************/
     789             : 
     790             : static void **papTLSList = nullptr;
     791             : 
     792             : static void **CPLGetTLSList(int *pbMemoryErrorOccurred)
     793             : 
     794             : {
     795             :     if (pbMemoryErrorOccurred)
     796             :         *pbMemoryErrorOccurred = FALSE;
     797             :     if (papTLSList == nullptr)
     798             :     {
     799             :         papTLSList =
     800             :             static_cast<void **>(VSICalloc(sizeof(void *), CTLS_MAX * 2));
     801             :         if (papTLSList == nullptr)
     802             :         {
     803             :             if (pbMemoryErrorOccurred)
     804             :             {
     805             :                 *pbMemoryErrorOccurred = TRUE;
     806             :                 fprintf(stderr,
     807             :                         "CPLGetTLSList() failed to allocate TLS list!\n");
     808             :                 return nullptr;
     809             :             }
     810             :             CPLEmergencyError("CPLGetTLSList() failed to allocate TLS list!");
     811             :         }
     812             :     }
     813             : 
     814             :     return papTLSList;
     815             : }
     816             : 
     817             : /************************************************************************/
     818             : /*                             CPLFinalizeTLS()                         */
     819             : /************************************************************************/
     820             : 
     821             : void CPLFinalizeTLS()
     822             : {
     823             :     CPLCleanupTLS();
     824             : }
     825             : 
     826             : /************************************************************************/
     827             : /*                           CPLCleanupTLS()                            */
     828             : /************************************************************************/
     829             : 
     830             : void CPLCleanupTLS()
     831             : 
     832             : {
     833             :     CPLCleanupTLSList(papTLSList);
     834             :     papTLSList = nullptr;
     835             : }
     836             : 
     837             : // endif CPL_MULTIPROC_STUB
     838             : 
     839             : #elif defined(CPL_MULTIPROC_WIN32)
     840             : 
     841             : /************************************************************************/
     842             : /* ==================================================================== */
     843             : /*                        CPL_MULTIPROC_WIN32                           */
     844             : /*                                                                      */
     845             : /*    WIN32 Implementation of multiprocessing functions.                */
     846             : /* ==================================================================== */
     847             : /************************************************************************/
     848             : 
     849             : /* InitializeCriticalSectionAndSpinCount requires _WIN32_WINNT >= 0x403 */
     850             : #undef _WIN32_WINNT
     851             : #define _WIN32_WINNT 0x0500
     852             : 
     853             : #include <windows.h>
     854             : 
     855             : /************************************************************************/
     856             : /*                             CPLGetNumCPUs()                          */
     857             : /************************************************************************/
     858             : 
     859             : int CPLGetNumCPUs()
     860             : {
     861             :     SYSTEM_INFO info;
     862             :     GetSystemInfo(&info);
     863             :     const DWORD dwNum = info.dwNumberOfProcessors;
     864             :     if (dwNum < 1)
     865             :         return 1;
     866             :     return static_cast<int>(dwNum);
     867             : }
     868             : 
     869             : /************************************************************************/
     870             : /*                        CPLGetThreadingModel()                        */
     871             : /************************************************************************/
     872             : 
     873             : const char *CPLGetThreadingModel()
     874             : 
     875             : {
     876             :     return "win32";
     877             : }
     878             : 
     879             : /************************************************************************/
     880             : /*                           CPLCreateMutex()                           */
     881             : /************************************************************************/
     882             : 
     883             : CPLMutex *CPLCreateMutex()
     884             : 
     885             : {
     886             : #ifdef USE_WIN32_MUTEX
     887             :     HANDLE hMutex = CreateMutex(nullptr, TRUE, nullptr);
     888             : 
     889             :     return (CPLMutex *)hMutex;
     890             : #else
     891             : 
     892             :     // Do not use CPLMalloc() since its debugging infrastructure
     893             :     // can call the CPL*Mutex functions.
     894             :     CRITICAL_SECTION *pcs =
     895             :         static_cast<CRITICAL_SECTION *>(malloc(sizeof(*pcs)));
     896             :     if (pcs)
     897             :     {
     898             :         InitializeCriticalSectionAndSpinCount(pcs, 4000);
     899             :         EnterCriticalSection(pcs);
     900             :     }
     901             : 
     902             :     return reinterpret_cast<CPLMutex *>(pcs);
     903             : #endif
     904             : }
     905             : 
     906             : CPLMutex *CPLCreateMutexEx(int /* nOptions */)
     907             : 
     908             : {
     909             :     return CPLCreateMutex();
     910             : }
     911             : 
     912             : /************************************************************************/
     913             : /*                          CPLAcquireMutex()                           */
     914             : /************************************************************************/
     915             : 
     916             : int CPLAcquireMutex(CPLMutex *hMutexIn, double dfWaitInSeconds)
     917             : 
     918             : {
     919             : #ifdef USE_WIN32_MUTEX
     920             :     HANDLE hMutex = (HANDLE)hMutexIn;
     921             :     const DWORD hr =
     922             :         WaitForSingleObject(hMutex, static_cast<int>(dfWaitInSeconds * 1000));
     923             : 
     924             :     return hr != WAIT_TIMEOUT;
     925             : #else
     926             :     CRITICAL_SECTION *pcs = reinterpret_cast<CRITICAL_SECTION *>(hMutexIn);
     927             :     BOOL ret;
     928             : 
     929             :     if (dfWaitInSeconds >= 1000.0)
     930             :     {
     931             :         // We assume this is the synonymous for infinite, so it is more
     932             :         // efficient to use EnterCriticalSection() directly
     933             :         EnterCriticalSection(pcs);
     934             :         ret = TRUE;
     935             :     }
     936             :     else
     937             :     {
     938             :         while ((ret = TryEnterCriticalSection(pcs)) == 0 &&
     939             :                dfWaitInSeconds > 0.0)
     940             :         {
     941             :             CPLSleep(std::min(dfWaitInSeconds, 0.01));
     942             :             dfWaitInSeconds -= 0.01;
     943             :         }
     944             :     }
     945             : 
     946             :     return ret;
     947             : #endif
     948             : }
     949             : 
     950             : /************************************************************************/
     951             : /*                          CPLReleaseMutex()                           */
     952             : /************************************************************************/
     953             : 
     954             : void CPLReleaseMutex(CPLMutex *hMutexIn)
     955             : 
     956             : {
     957             : #ifdef USE_WIN32_MUTEX
     958             :     HANDLE hMutex = (HANDLE)hMutexIn;
     959             : 
     960             :     ReleaseMutex(hMutex);
     961             : #else
     962             :     CRITICAL_SECTION *pcs = reinterpret_cast<CRITICAL_SECTION *>(hMutexIn);
     963             : 
     964             :     LeaveCriticalSection(pcs);
     965             : #endif
     966             : }
     967             : 
     968             : /************************************************************************/
     969             : /*                          CPLDestroyMutex()                           */
     970             : /************************************************************************/
     971             : 
     972             : void CPLDestroyMutex(CPLMutex *hMutexIn)
     973             : 
     974             : {
     975             : #ifdef USE_WIN32_MUTEX
     976             :     HANDLE hMutex = (HANDLE)hMutexIn;
     977             : 
     978             :     CloseHandle(hMutex);
     979             : #else
     980             :     CRITICAL_SECTION *pcs = reinterpret_cast<CRITICAL_SECTION *>(hMutexIn);
     981             : 
     982             :     DeleteCriticalSection(pcs);
     983             :     free(pcs);
     984             : #endif
     985             : }
     986             : 
     987             : /************************************************************************/
     988             : /*                            CPLCreateCond()                           */
     989             : /************************************************************************/
     990             : 
     991             : struct _WaiterItem
     992             : {
     993             :     HANDLE hEvent;
     994             :     struct _WaiterItem *psNext;
     995             : };
     996             : typedef struct _WaiterItem WaiterItem;
     997             : 
     998             : typedef struct
     999             : {
    1000             :     CPLMutex *hInternalMutex;
    1001             :     WaiterItem *psWaiterList;
    1002             : } Win32Cond;
    1003             : 
    1004             : CPLCond *CPLCreateCond()
    1005             : {
    1006             :     Win32Cond *psCond = static_cast<Win32Cond *>(malloc(sizeof(Win32Cond)));
    1007             :     if (psCond == nullptr)
    1008             :         return nullptr;
    1009             :     psCond->hInternalMutex = CPLCreateMutex();
    1010             :     if (psCond->hInternalMutex == nullptr)
    1011             :     {
    1012             :         free(psCond);
    1013             :         return nullptr;
    1014             :     }
    1015             :     CPLReleaseMutex(psCond->hInternalMutex);
    1016             :     psCond->psWaiterList = nullptr;
    1017             :     return reinterpret_cast<CPLCond *>(psCond);
    1018             : }
    1019             : 
    1020             : /************************************************************************/
    1021             : /*                            CPLCondWait()                             */
    1022             : /************************************************************************/
    1023             : 
    1024             : static void CPLTLSFreeEvent(void *pData)
    1025             : {
    1026             :     CloseHandle(static_cast<HANDLE>(pData));
    1027             : }
    1028             : 
    1029             : void CPLCondWait(CPLCond *hCond, CPLMutex *hClientMutex)
    1030             : {
    1031             :     CPLCondTimedWait(hCond, hClientMutex, -1);
    1032             : }
    1033             : 
    1034             : /************************************************************************/
    1035             : /*                         CPLCondTimedWait()                           */
    1036             : /************************************************************************/
    1037             : 
    1038             : CPLCondTimedWaitReason CPLCondTimedWait(CPLCond *hCond, CPLMutex *hClientMutex,
    1039             :                                         double dfWaitInSeconds)
    1040             : {
    1041             :     Win32Cond *psCond = reinterpret_cast<Win32Cond *>(hCond);
    1042             : 
    1043             :     HANDLE hEvent = static_cast<HANDLE>(CPLGetTLS(CTLS_WIN32_COND));
    1044             :     if (hEvent == nullptr)
    1045             :     {
    1046             :         hEvent = CreateEvent(nullptr, /* security attributes */
    1047             :                              0,       /* manual reset = no */
    1048             :                              0,       /* initial state = unsignaled */
    1049             :                              nullptr /* no name */);
    1050             :         CPLAssert(hEvent != nullptr);
    1051             : 
    1052             :         CPLSetTLSWithFreeFunc(CTLS_WIN32_COND, hEvent, CPLTLSFreeEvent);
    1053             :     }
    1054             : 
    1055             :     /* Insert the waiter into the waiter list of the condition */
    1056             :     CPLAcquireMutex(psCond->hInternalMutex, 1000.0);
    1057             : 
    1058             :     WaiterItem *psItem = static_cast<WaiterItem *>(malloc(sizeof(WaiterItem)));
    1059             :     CPLAssert(psItem != nullptr);
    1060             : 
    1061             :     psItem->hEvent = hEvent;
    1062             :     psItem->psNext = psCond->psWaiterList;
    1063             : 
    1064             :     psCond->psWaiterList = psItem;
    1065             : 
    1066             :     CPLReleaseMutex(psCond->hInternalMutex);
    1067             : 
    1068             :     // Release the client mutex before waiting for the event being signaled.
    1069             :     CPLReleaseMutex(hClientMutex);
    1070             : 
    1071             :     // Ideally we would check that we do not get WAIT_FAILED but it is hard
    1072             :     // to report a failure.
    1073             :     auto ret = WaitForSingleObject(
    1074             :         hEvent, dfWaitInSeconds < 0 ? INFINITE
    1075             :                                     : static_cast<int>(dfWaitInSeconds * 1000));
    1076             : 
    1077             :     // Reacquire the client mutex.
    1078             :     CPLAcquireMutex(hClientMutex, 1000.0);
    1079             : 
    1080             :     if (ret == WAIT_OBJECT_0)
    1081             :         return COND_TIMED_WAIT_COND;
    1082             :     if (ret == WAIT_TIMEOUT)
    1083             :         return COND_TIMED_WAIT_TIME_OUT;
    1084             :     return COND_TIMED_WAIT_OTHER;
    1085             : }
    1086             : 
    1087             : /************************************************************************/
    1088             : /*                            CPLCondSignal()                           */
    1089             : /************************************************************************/
    1090             : 
    1091             : void CPLCondSignal(CPLCond *hCond)
    1092             : {
    1093             :     Win32Cond *psCond = reinterpret_cast<Win32Cond *>(hCond);
    1094             : 
    1095             :     // Signal the first registered event, and remove it from the list.
    1096             :     CPLAcquireMutex(psCond->hInternalMutex, 1000.0);
    1097             : 
    1098             :     WaiterItem *psIter = psCond->psWaiterList;
    1099             :     if (psIter != nullptr)
    1100             :     {
    1101             :         SetEvent(psIter->hEvent);
    1102             :         psCond->psWaiterList = psIter->psNext;
    1103             :         free(psIter);
    1104             :     }
    1105             : 
    1106             :     CPLReleaseMutex(psCond->hInternalMutex);
    1107             : }
    1108             : 
    1109             : /************************************************************************/
    1110             : /*                           CPLCondBroadcast()                         */
    1111             : /************************************************************************/
    1112             : 
    1113             : void CPLCondBroadcast(CPLCond *hCond)
    1114             : {
    1115             :     Win32Cond *psCond = reinterpret_cast<Win32Cond *>(hCond);
    1116             : 
    1117             :     // Signal all the registered events, and remove them from the list.
    1118             :     CPLAcquireMutex(psCond->hInternalMutex, 1000.0);
    1119             : 
    1120             :     WaiterItem *psIter = psCond->psWaiterList;
    1121             :     while (psIter != nullptr)
    1122             :     {
    1123             :         WaiterItem *psNext = psIter->psNext;
    1124             :         SetEvent(psIter->hEvent);
    1125             :         free(psIter);
    1126             :         psIter = psNext;
    1127             :     }
    1128             :     psCond->psWaiterList = nullptr;
    1129             : 
    1130             :     CPLReleaseMutex(psCond->hInternalMutex);
    1131             : }
    1132             : 
    1133             : /************************************************************************/
    1134             : /*                            CPLDestroyCond()                          */
    1135             : /************************************************************************/
    1136             : 
    1137             : void CPLDestroyCond(CPLCond *hCond)
    1138             : {
    1139             :     Win32Cond *psCond = reinterpret_cast<Win32Cond *>(hCond);
    1140             :     CPLDestroyMutex(psCond->hInternalMutex);
    1141             :     psCond->hInternalMutex = nullptr;
    1142             :     CPLAssert(psCond->psWaiterList == nullptr);
    1143             :     free(psCond);
    1144             : }
    1145             : 
    1146             : /************************************************************************/
    1147             : /*                            CPLLockFile()                             */
    1148             : /************************************************************************/
    1149             : 
    1150             : void *CPLLockFile(const char *pszPath, double dfWaitInSeconds)
    1151             : 
    1152             : {
    1153             :     char *pszLockFilename =
    1154             :         static_cast<char *>(CPLMalloc(strlen(pszPath) + 30));
    1155             :     snprintf(pszLockFilename, strlen(pszPath) + 30, "%s.lock", pszPath);
    1156             : 
    1157             :     // FIXME: use CreateFileW()
    1158             :     HANDLE hLockFile =
    1159             :         CreateFileA(pszLockFilename, GENERIC_WRITE, 0, nullptr, CREATE_NEW,
    1160             :                     FILE_ATTRIBUTE_NORMAL | FILE_FLAG_DELETE_ON_CLOSE, nullptr);
    1161             : 
    1162             :     while (GetLastError() == ERROR_ALREADY_EXISTS && dfWaitInSeconds > 0.0)
    1163             :     {
    1164             :         CloseHandle(hLockFile);
    1165             :         CPLSleep(std::min(dfWaitInSeconds, 0.125));
    1166             :         dfWaitInSeconds -= 0.125;
    1167             : 
    1168             :         hLockFile = CreateFileA(
    1169             :             pszLockFilename, GENERIC_WRITE, 0, nullptr, CREATE_NEW,
    1170             :             FILE_ATTRIBUTE_NORMAL | FILE_FLAG_DELETE_ON_CLOSE, nullptr);
    1171             :     }
    1172             : 
    1173             :     CPLFree(pszLockFilename);
    1174             : 
    1175             :     if (hLockFile == INVALID_HANDLE_VALUE)
    1176             :         return nullptr;
    1177             : 
    1178             :     if (GetLastError() == ERROR_ALREADY_EXISTS)
    1179             :     {
    1180             :         CloseHandle(hLockFile);
    1181             :         return nullptr;
    1182             :     }
    1183             : 
    1184             :     return static_cast<void *>(hLockFile);
    1185             : }
    1186             : 
    1187             : /************************************************************************/
    1188             : /*                           CPLUnlockFile()                            */
    1189             : /************************************************************************/
    1190             : 
    1191             : void CPLUnlockFile(void *hLock)
    1192             : 
    1193             : {
    1194             :     HANDLE hLockFile = static_cast<HANDLE>(hLock);
    1195             : 
    1196             :     CloseHandle(hLockFile);
    1197             : }
    1198             : 
    1199             : /************************************************************************/
    1200             : /*                             CPLGetPID()                              */
    1201             : /************************************************************************/
    1202             : 
    1203             : GIntBig CPLGetPID()
    1204             : 
    1205             : {
    1206             :     return static_cast<GIntBig>(GetCurrentThreadId());
    1207             : }
    1208             : 
    1209             : /************************************************************************/
    1210             : /*                       CPLStdCallThreadJacket()                       */
    1211             : /************************************************************************/
    1212             : 
    1213             : typedef struct
    1214             : {
    1215             :     void *pAppData;
    1216             :     CPLThreadFunc pfnMain;
    1217             :     HANDLE hThread;
    1218             : } CPLStdCallThreadInfo;
    1219             : 
    1220             : static DWORD WINAPI CPLStdCallThreadJacket(void *pData)
    1221             : 
    1222             : {
    1223             :     CPLStdCallThreadInfo *psInfo = static_cast<CPLStdCallThreadInfo *>(pData);
    1224             : 
    1225             :     psInfo->pfnMain(psInfo->pAppData);
    1226             : 
    1227             :     if (psInfo->hThread == nullptr)
    1228             :         CPLFree(psInfo);  // Only for detached threads.
    1229             : 
    1230             :     CPLCleanupTLS();
    1231             : 
    1232             :     return 0;
    1233             : }
    1234             : 
    1235             : /************************************************************************/
    1236             : /*                          CPLCreateThread()                           */
    1237             : /*                                                                      */
    1238             : /*      The WIN32 CreateThread() call requires an entry point that      */
    1239             : /*      has __stdcall conventions, so we provide a jacket function      */
    1240             : /*      to supply that.                                                 */
    1241             : /************************************************************************/
    1242             : 
    1243             : int CPLCreateThread(CPLThreadFunc pfnMain, void *pThreadArg)
    1244             : 
    1245             : {
    1246             :     CPLStdCallThreadInfo *psInfo = static_cast<CPLStdCallThreadInfo *>(
    1247             :         CPLCalloc(sizeof(CPLStdCallThreadInfo), 1));
    1248             :     psInfo->pAppData = pThreadArg;
    1249             :     psInfo->pfnMain = pfnMain;
    1250             :     psInfo->hThread = nullptr;
    1251             : 
    1252             :     DWORD nThreadId = 0;
    1253             :     HANDLE hThread =
    1254             :         CreateThread(nullptr, 0, CPLStdCallThreadJacket, psInfo, 0, &nThreadId);
    1255             : 
    1256             :     if (hThread == nullptr)
    1257             :         return -1;
    1258             : 
    1259             :     CloseHandle(hThread);
    1260             : 
    1261             :     return nThreadId;
    1262             : }
    1263             : 
    1264             : /************************************************************************/
    1265             : /*                      CPLCreateJoinableThread()                       */
    1266             : /************************************************************************/
    1267             : 
    1268             : CPLJoinableThread *CPLCreateJoinableThread(CPLThreadFunc pfnMain,
    1269             :                                            void *pThreadArg)
    1270             : 
    1271             : {
    1272             :     CPLStdCallThreadInfo *psInfo = static_cast<CPLStdCallThreadInfo *>(
    1273             :         CPLCalloc(sizeof(CPLStdCallThreadInfo), 1));
    1274             :     psInfo->pAppData = pThreadArg;
    1275             :     psInfo->pfnMain = pfnMain;
    1276             : 
    1277             :     DWORD nThreadId = 0;
    1278             :     HANDLE hThread =
    1279             :         CreateThread(nullptr, 0, CPLStdCallThreadJacket, psInfo, 0, &nThreadId);
    1280             : 
    1281             :     if (hThread == nullptr)
    1282             :         return nullptr;
    1283             : 
    1284             :     psInfo->hThread = hThread;
    1285             :     return reinterpret_cast<CPLJoinableThread *>(psInfo);
    1286             : }
    1287             : 
    1288             : /************************************************************************/
    1289             : /*                          CPLJoinThread()                             */
    1290             : /************************************************************************/
    1291             : 
    1292             : void CPLJoinThread(CPLJoinableThread *hJoinableThread)
    1293             : {
    1294             :     CPLStdCallThreadInfo *psInfo =
    1295             :         reinterpret_cast<CPLStdCallThreadInfo *>(hJoinableThread);
    1296             : 
    1297             :     WaitForSingleObject(psInfo->hThread, INFINITE);
    1298             :     CloseHandle(psInfo->hThread);
    1299             :     CPLFree(psInfo);
    1300             : }
    1301             : 
    1302             : /************************************************************************/
    1303             : /*                              CPLSleep()                              */
    1304             : /************************************************************************/
    1305             : 
    1306             : void CPLSleep(double dfWaitInSeconds)
    1307             : 
    1308             : {
    1309             :     Sleep(static_cast<DWORD>(dfWaitInSeconds * 1000.0));
    1310             : }
    1311             : 
    1312             : static bool bTLSKeySetup = false;
    1313             : static DWORD nTLSKey = 0;
    1314             : 
    1315             : /************************************************************************/
    1316             : /*                           CPLGetTLSList()                            */
    1317             : /************************************************************************/
    1318             : 
    1319             : static void **CPLGetTLSList(int *pbMemoryErrorOccurred)
    1320             : 
    1321             : {
    1322             :     void **papTLSList = nullptr;
    1323             : 
    1324             :     if (pbMemoryErrorOccurred)
    1325             :         *pbMemoryErrorOccurred = FALSE;
    1326             :     if (!bTLSKeySetup)
    1327             :     {
    1328             :         nTLSKey = TlsAlloc();
    1329             :         if (nTLSKey == TLS_OUT_OF_INDEXES)
    1330             :         {
    1331             :             if (pbMemoryErrorOccurred)
    1332             :             {
    1333             :                 *pbMemoryErrorOccurred = TRUE;
    1334             :                 fprintf(stderr, "CPLGetTLSList(): TlsAlloc() failed!\n");
    1335             :                 return nullptr;
    1336             :             }
    1337             :             CPLEmergencyError("CPLGetTLSList(): TlsAlloc() failed!");
    1338             :         }
    1339             :         bTLSKeySetup = true;
    1340             :     }
    1341             : 
    1342             :     papTLSList = static_cast<void **>(TlsGetValue(nTLSKey));
    1343             :     if (papTLSList == nullptr)
    1344             :     {
    1345             :         papTLSList =
    1346             :             static_cast<void **>(VSICalloc(sizeof(void *), CTLS_MAX * 2));
    1347             :         if (papTLSList == nullptr)
    1348             :         {
    1349             :             if (pbMemoryErrorOccurred)
    1350             :             {
    1351             :                 *pbMemoryErrorOccurred = TRUE;
    1352             :                 fprintf(stderr,
    1353             :                         "CPLGetTLSList() failed to allocate TLS list!\n");
    1354             :                 return nullptr;
    1355             :             }
    1356             :             CPLEmergencyError("CPLGetTLSList() failed to allocate TLS list!");
    1357             :         }
    1358             :         if (TlsSetValue(nTLSKey, papTLSList) == 0)
    1359             :         {
    1360             :             if (pbMemoryErrorOccurred)
    1361             :             {
    1362             :                 *pbMemoryErrorOccurred = TRUE;
    1363             :                 fprintf(stderr, "CPLGetTLSList(): TlsSetValue() failed!\n");
    1364             :                 return nullptr;
    1365             :             }
    1366             :             CPLEmergencyError("CPLGetTLSList(): TlsSetValue() failed!");
    1367             :         }
    1368             :     }
    1369             : 
    1370             :     return papTLSList;
    1371             : }
    1372             : 
    1373             : /************************************************************************/
    1374             : /*                             CPLFinalizeTLS()                         */
    1375             : /************************************************************************/
    1376             : 
    1377             : void CPLFinalizeTLS()
    1378             : {
    1379             :     CPLCleanupTLS();
    1380             : }
    1381             : 
    1382             : /************************************************************************/
    1383             : /*                           CPLCleanupTLS()                            */
    1384             : /************************************************************************/
    1385             : 
    1386             : void CPLCleanupTLS()
    1387             : 
    1388             : {
    1389             :     if (!bTLSKeySetup)
    1390             :         return;
    1391             : 
    1392             :     void **papTLSList = static_cast<void **>(TlsGetValue(nTLSKey));
    1393             :     if (papTLSList == nullptr)
    1394             :         return;
    1395             : 
    1396             :     TlsSetValue(nTLSKey, nullptr);
    1397             : 
    1398             :     CPLCleanupTLSList(papTLSList);
    1399             : }
    1400             : 
    1401             : // endif CPL_MULTIPROC_WIN32
    1402             : 
    1403             : #elif defined(CPL_MULTIPROC_PTHREAD)
    1404             : 
    1405             : #include <pthread.h>
    1406             : #include <time.h>
    1407             : #include <unistd.h>
    1408             : #include <sys/time.h>
    1409             : 
    1410             : #ifdef HAVE_SCHED_GETAFFINITY
    1411             : #include <sched.h>
    1412             : #endif
    1413             : 
    1414             : /************************************************************************/
    1415             : /* ==================================================================== */
    1416             : /*                        CPL_MULTIPROC_PTHREAD                         */
    1417             : /*                                                                      */
    1418             : /*    PTHREAD Implementation of multiprocessing functions.              */
    1419             : /* ==================================================================== */
    1420             : /************************************************************************/
    1421             : 
    1422             : /************************************************************************/
    1423             : /*                             CPLGetNumCPUs()                          */
    1424             : /************************************************************************/
    1425             : 
    1426        3025 : int CPLGetNumCPUs()
    1427             : {
    1428             :     int nCPUs;
    1429             : #ifdef _SC_NPROCESSORS_ONLN
    1430        3025 :     nCPUs = static_cast<int>(sysconf(_SC_NPROCESSORS_ONLN));
    1431             : #else
    1432             :     nCPUs = 1;
    1433             : #endif
    1434             : 
    1435             : #ifdef HAVE_SCHED_GETAFFINITY
    1436        3025 :     if (nCPUs > 1)
    1437             :     {
    1438        3025 :         cpu_set_t *set = CPU_ALLOC(nCPUs);
    1439        3025 :         if (set)
    1440             :         {
    1441        3025 :             size_t sizeof_set = CPU_ALLOC_SIZE(nCPUs);
    1442        3025 :             CPU_ZERO_S(sizeof_set, set);
    1443        3025 :             if (sched_getaffinity(getpid(), sizeof_set, set) == 0)
    1444        3025 :                 nCPUs = CPU_COUNT_S(sizeof_set, set);
    1445             :             else
    1446           0 :                 CPLDebug("CPL", "sched_getaffinity() failed");
    1447        3025 :             CPU_FREE(set);
    1448             :         }
    1449             :     }
    1450             : #endif
    1451             : 
    1452        3025 :     return nCPUs;
    1453             : }
    1454             : 
    1455             : /************************************************************************/
    1456             : /*                      CPLCreateOrAcquireMutex()                       */
    1457             : /************************************************************************/
    1458             : #ifdef HAVE_GCC_WARNING_ZERO_AS_NULL_POINTER_CONSTANT
    1459             : #pragma GCC diagnostic push
    1460             : #pragma GCC diagnostic ignored "-Wzero-as-null-pointer-constant"
    1461             : #endif
    1462             : static pthread_mutex_t global_mutex = PTHREAD_MUTEX_INITIALIZER;
    1463             : #ifdef HAVE_GCC_WARNING_ZERO_AS_NULL_POINTER_CONSTANT
    1464             : #pragma GCC diagnostic pop
    1465             : #endif
    1466             : 
    1467             : static CPLMutex *CPLCreateMutexInternal(bool bAlreadyInGlobalLock,
    1468             :                                         int nOptions);
    1469             : 
    1470    64765900 : int CPLCreateOrAcquireMutexEx(CPLMutex **phMutex, double dfWaitInSeconds,
    1471             :                               int nOptions)
    1472             : 
    1473             : {
    1474    64765900 :     pthread_mutex_lock(&global_mutex);
    1475    64770800 :     if (*phMutex == nullptr)
    1476             :     {
    1477       28461 :         *phMutex = CPLCreateMutexInternal(true, nOptions);
    1478       28461 :         const bool bSuccess = *phMutex != nullptr;
    1479       28461 :         pthread_mutex_unlock(&global_mutex);
    1480       28461 :         if (!bSuccess)
    1481           0 :             return false;
    1482             :     }
    1483             :     else
    1484             :     {
    1485    64742400 :         pthread_mutex_unlock(&global_mutex);
    1486             :     }
    1487             : 
    1488    64770500 :     return CPL_TO_BOOL(CPLAcquireMutex(*phMutex, dfWaitInSeconds));
    1489             : }
    1490             : 
    1491             : /************************************************************************/
    1492             : /*                   CPLCreateOrAcquireMutexInternal()                  */
    1493             : /************************************************************************/
    1494             : 
    1495        4719 : static bool CPLCreateOrAcquireMutexInternal(CPLLock **phLock,
    1496             :                                             double dfWaitInSeconds,
    1497             :                                             CPLLockType eType)
    1498             : {
    1499        4719 :     pthread_mutex_lock(&global_mutex);
    1500        4719 :     if (*phLock == nullptr)
    1501             :     {
    1502         503 :         *phLock = static_cast<CPLLock *>(calloc(1, sizeof(CPLLock)));
    1503         503 :         if (*phLock)
    1504             :         {
    1505         503 :             (*phLock)->eType = eType;
    1506        1006 :             (*phLock)->u.hMutex = CPLCreateMutexInternal(
    1507         503 :                 true, eType == LOCK_RECURSIVE_MUTEX ? CPL_MUTEX_RECURSIVE
    1508             :                                                     : CPL_MUTEX_ADAPTIVE);
    1509         503 :             if ((*phLock)->u.hMutex == nullptr)
    1510             :             {
    1511           0 :                 free(*phLock);
    1512           0 :                 *phLock = nullptr;
    1513             :             }
    1514             :         }
    1515         503 :         const bool bSuccess = *phLock != nullptr;
    1516         503 :         pthread_mutex_unlock(&global_mutex);
    1517         503 :         if (!bSuccess)
    1518           0 :             return false;
    1519             :     }
    1520             :     else
    1521             :     {
    1522        4216 :         pthread_mutex_unlock(&global_mutex);
    1523             :     }
    1524             : 
    1525        4719 :     return CPL_TO_BOOL(CPLAcquireMutex((*phLock)->u.hMutex, dfWaitInSeconds));
    1526             : }
    1527             : 
    1528             : /************************************************************************/
    1529             : /*                        CPLGetThreadingModel()                        */
    1530             : /************************************************************************/
    1531             : 
    1532          28 : const char *CPLGetThreadingModel()
    1533             : 
    1534             : {
    1535          28 :     return "pthread";
    1536             : }
    1537             : 
    1538             : /************************************************************************/
    1539             : /*                           CPLCreateMutex()                           */
    1540             : /************************************************************************/
    1541             : 
    1542             : typedef struct _MutexLinkedElt MutexLinkedElt;
    1543             : 
    1544             : struct _MutexLinkedElt
    1545             : {
    1546             :     pthread_mutex_t sMutex;
    1547             :     int nOptions;
    1548             :     _MutexLinkedElt *psPrev;
    1549             :     _MutexLinkedElt *psNext;
    1550             : };
    1551             : 
    1552             : static MutexLinkedElt *psMutexList = nullptr;
    1553             : 
    1554       96219 : static void CPLInitMutex(MutexLinkedElt *psItem)
    1555             : {
    1556       96219 :     if (psItem->nOptions == CPL_MUTEX_REGULAR)
    1557             :     {
    1558             : #ifdef HAVE_GCC_WARNING_ZERO_AS_NULL_POINTER_CONSTANT
    1559             : #pragma GCC diagnostic push
    1560             : #pragma GCC diagnostic ignored "-Wzero-as-null-pointer-constant"
    1561             : #endif
    1562           0 :         pthread_mutex_t tmp_mutex = PTHREAD_MUTEX_INITIALIZER;
    1563             : #ifdef HAVE_GCC_WARNING_ZERO_AS_NULL_POINTER_CONSTANT
    1564             : #pragma GCC diagnostic pop
    1565             : #endif
    1566           0 :         psItem->sMutex = tmp_mutex;
    1567           0 :         return;
    1568             :     }
    1569             : 
    1570             :     // When an adaptive mutex is required, we can safely fallback to regular
    1571             :     // mutex if we don't have HAVE_PTHREAD_MUTEX_ADAPTIVE_NP.
    1572       96219 :     if (psItem->nOptions == CPL_MUTEX_ADAPTIVE)
    1573             :     {
    1574             : #if defined(HAVE_PTHREAD_MUTEX_ADAPTIVE_NP)
    1575             :         pthread_mutexattr_t attr;
    1576         573 :         pthread_mutexattr_init(&attr);
    1577         573 :         pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ADAPTIVE_NP);
    1578         573 :         pthread_mutex_init(&(psItem->sMutex), &attr);
    1579             : #else
    1580             :         pthread_mutex_t tmp_mutex = PTHREAD_MUTEX_INITIALIZER;
    1581             :         psItem->sMutex = tmp_mutex;
    1582             : #endif
    1583         573 :         return;
    1584             :     }
    1585             : 
    1586             : #if defined(PTHREAD_MUTEX_RECURSIVE) || defined(HAVE_PTHREAD_MUTEX_RECURSIVE)
    1587             :     {
    1588             :         pthread_mutexattr_t attr;
    1589       95646 :         pthread_mutexattr_init(&attr);
    1590       95646 :         pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
    1591       95646 :         pthread_mutex_init(&(psItem->sMutex), &attr);
    1592             :     }
    1593             : // BSDs have PTHREAD_MUTEX_RECURSIVE as an enum, not a define.
    1594             : // But they have #define MUTEX_TYPE_COUNTING_FAST PTHREAD_MUTEX_RECURSIVE
    1595             : #elif defined(MUTEX_TYPE_COUNTING_FAST)
    1596             :     {
    1597             :         pthread_mutexattr_t attr;
    1598             :         pthread_mutexattr_init(&attr);
    1599             :         pthread_mutexattr_settype(&attr, MUTEX_TYPE_COUNTING_FAST);
    1600             :         pthread_mutex_init(&(psItem->sMutex), &attr);
    1601             :     }
    1602             : #elif defined(PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP)
    1603             :     pthread_mutex_t tmp_mutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
    1604             :     psItem->sMutex = tmp_mutex;
    1605             : #else
    1606             : #error "Recursive mutexes apparently unsupported, configure --without-threads"
    1607             : #endif
    1608             : }
    1609             : 
    1610       96218 : static CPLMutex *CPLCreateMutexInternal(bool bAlreadyInGlobalLock, int nOptions)
    1611             : {
    1612             :     MutexLinkedElt *psItem =
    1613       96218 :         static_cast<MutexLinkedElt *>(malloc(sizeof(MutexLinkedElt)));
    1614       96218 :     if (psItem == nullptr)
    1615             :     {
    1616           0 :         fprintf(stderr, "CPLCreateMutexInternal() failed.\n");
    1617           0 :         return nullptr;
    1618             :     }
    1619             : 
    1620       96218 :     if (!bAlreadyInGlobalLock)
    1621       67254 :         pthread_mutex_lock(&global_mutex);
    1622       96219 :     psItem->psPrev = nullptr;
    1623       96219 :     psItem->psNext = psMutexList;
    1624       96219 :     if (psMutexList)
    1625       94978 :         psMutexList->psPrev = psItem;
    1626       96219 :     psMutexList = psItem;
    1627       96219 :     if (!bAlreadyInGlobalLock)
    1628       67255 :         pthread_mutex_unlock(&global_mutex);
    1629             : 
    1630       96219 :     psItem->nOptions = nOptions;
    1631       96219 :     CPLInitMutex(psItem);
    1632             : 
    1633       96219 :     return reinterpret_cast<CPLMutex *>(psItem);
    1634             : }
    1635             : 
    1636       67184 : CPLMutex *CPLCreateMutex()
    1637             : {
    1638       67184 :     CPLMutex *mutex = CPLCreateMutexInternal(false, CPL_MUTEX_RECURSIVE);
    1639       67185 :     if (mutex)
    1640       67184 :         CPLAcquireMutex(mutex, 0);
    1641       67184 :     return mutex;
    1642             : }
    1643             : 
    1644          70 : CPLMutex *CPLCreateMutexEx(int nOptions)
    1645             : {
    1646          70 :     CPLMutex *mutex = CPLCreateMutexInternal(false, nOptions);
    1647          70 :     if (mutex)
    1648          70 :         CPLAcquireMutex(mutex, 0);
    1649          70 :     return mutex;
    1650             : }
    1651             : 
    1652             : /************************************************************************/
    1653             : /*                          CPLAcquireMutex()                           */
    1654             : /************************************************************************/
    1655             : 
    1656    89333200 : int CPLAcquireMutex(CPLMutex *hMutexIn, double /* dfWaitInSeconds */)
    1657             : {
    1658             :     // TODO: Need to add timeout support.
    1659    89333200 :     MutexLinkedElt *psItem = reinterpret_cast<MutexLinkedElt *>(hMutexIn);
    1660    89333200 :     const int err = pthread_mutex_lock(&(psItem->sMutex));
    1661             : 
    1662    89344600 :     if (err != 0)
    1663             :     {
    1664           0 :         if (err == EDEADLK)
    1665           0 :             fprintf(stderr, "CPLAcquireMutex: Error = %d/EDEADLK\n", err);
    1666             :         else
    1667           0 :             fprintf(stderr, "CPLAcquireMutex: Error = %d (%s)\n", err,
    1668             :                     strerror(err));
    1669             : 
    1670           0 :         return FALSE;
    1671             :     }
    1672             : 
    1673    89344600 :     return TRUE;
    1674             : }
    1675             : 
    1676             : /************************************************************************/
    1677             : /*                          CPLReleaseMutex()                           */
    1678             : /************************************************************************/
    1679             : 
    1680    89343500 : void CPLReleaseMutex(CPLMutex *hMutexIn)
    1681             : 
    1682             : {
    1683    89343500 :     MutexLinkedElt *psItem = reinterpret_cast<MutexLinkedElt *>(hMutexIn);
    1684    89343500 :     const int err = pthread_mutex_unlock(&(psItem->sMutex));
    1685    89344200 :     if (err != 0)
    1686             :     {
    1687           0 :         fprintf(stderr, "CPLReleaseMutex: Error = %d (%s)\n", err,
    1688             :                 strerror(err));
    1689             :     }
    1690    89344200 : }
    1691             : 
    1692             : /************************************************************************/
    1693             : /*                          CPLDestroyMutex()                           */
    1694             : /************************************************************************/
    1695             : 
    1696       91281 : void CPLDestroyMutex(CPLMutex *hMutexIn)
    1697             : 
    1698             : {
    1699       91281 :     MutexLinkedElt *psItem = reinterpret_cast<MutexLinkedElt *>(hMutexIn);
    1700       91281 :     const int err = pthread_mutex_destroy(&(psItem->sMutex));
    1701       91281 :     if (err != 0)
    1702             :     {
    1703           0 :         fprintf(stderr, "CPLDestroyMutex: Error = %d (%s)\n", err,
    1704             :                 strerror(err));
    1705             :     }
    1706       91281 :     pthread_mutex_lock(&global_mutex);
    1707       91281 :     if (psItem->psPrev)
    1708       56905 :         psItem->psPrev->psNext = psItem->psNext;
    1709       91281 :     if (psItem->psNext)
    1710       87880 :         psItem->psNext->psPrev = psItem->psPrev;
    1711       91281 :     if (psItem == psMutexList)
    1712       34376 :         psMutexList = psItem->psNext;
    1713       91281 :     pthread_mutex_unlock(&global_mutex);
    1714       91281 :     free(hMutexIn);
    1715       91281 : }
    1716             : 
    1717             : /************************************************************************/
    1718             : /*                          CPLReinitAllMutex()                         */
    1719             : /************************************************************************/
    1720             : 
    1721             : // Used by gdalclientserver.cpp just after forking, to avoid
    1722             : // deadlocks while mixing threads with fork.
    1723             : void CPLReinitAllMutex();  // TODO(schwehr): Put this in a header.
    1724             : 
    1725           0 : void CPLReinitAllMutex()
    1726             : {
    1727           0 :     MutexLinkedElt *psItem = psMutexList;
    1728           0 :     while (psItem != nullptr)
    1729             :     {
    1730           0 :         CPLInitMutex(psItem);
    1731           0 :         psItem = psItem->psNext;
    1732             :     }
    1733             : #ifdef HAVE_GCC_WARNING_ZERO_AS_NULL_POINTER_CONSTANT
    1734             : #pragma GCC diagnostic push
    1735             : #pragma GCC diagnostic ignored "-Wzero-as-null-pointer-constant"
    1736             : #endif
    1737           0 :     pthread_mutex_t tmp_global_mutex = PTHREAD_MUTEX_INITIALIZER;
    1738             : #ifdef HAVE_GCC_WARNING_ZERO_AS_NULL_POINTER_CONSTANT
    1739             : #pragma GCC diagnostic pop
    1740             : #endif
    1741           0 :     global_mutex = tmp_global_mutex;
    1742           0 : }
    1743             : 
    1744             : /************************************************************************/
    1745             : /*                            CPLCreateCond()                           */
    1746             : /************************************************************************/
    1747             : 
    1748       29295 : CPLCond *CPLCreateCond()
    1749             : {
    1750             :     pthread_cond_t *pCond =
    1751       29295 :         static_cast<pthread_cond_t *>(malloc(sizeof(pthread_cond_t)));
    1752       29295 :     if (pCond && pthread_cond_init(pCond, nullptr) == 0)
    1753       29296 :         return reinterpret_cast<CPLCond *>(pCond);
    1754           0 :     fprintf(stderr, "CPLCreateCond() failed.\n");
    1755           0 :     free(pCond);
    1756           0 :     return nullptr;
    1757             : }
    1758             : 
    1759             : /************************************************************************/
    1760             : /*                            CPLCondWait()                             */
    1761             : /************************************************************************/
    1762             : 
    1763        1534 : void CPLCondWait(CPLCond *hCond, CPLMutex *hMutex)
    1764             : {
    1765        1534 :     pthread_cond_t *pCond = reinterpret_cast<pthread_cond_t *>(hCond);
    1766        1534 :     MutexLinkedElt *psItem = reinterpret_cast<MutexLinkedElt *>(hMutex);
    1767        1534 :     pthread_mutex_t *pMutex = &(psItem->sMutex);
    1768        1534 :     pthread_cond_wait(pCond, pMutex);
    1769        1534 : }
    1770             : 
    1771             : /************************************************************************/
    1772             : /*                         CPLCondTimedWait()                           */
    1773             : /************************************************************************/
    1774             : 
    1775           0 : CPLCondTimedWaitReason CPLCondTimedWait(CPLCond *hCond, CPLMutex *hMutex,
    1776             :                                         double dfWaitInSeconds)
    1777             : {
    1778           0 :     pthread_cond_t *pCond = reinterpret_cast<pthread_cond_t *>(hCond);
    1779           0 :     MutexLinkedElt *psItem = reinterpret_cast<MutexLinkedElt *>(hMutex);
    1780           0 :     pthread_mutex_t *pMutex = &(psItem->sMutex);
    1781             :     struct timeval tv;
    1782             :     struct timespec ts;
    1783             : 
    1784           0 :     gettimeofday(&tv, nullptr);
    1785           0 :     ts.tv_sec = time(nullptr) + static_cast<int>(dfWaitInSeconds);
    1786           0 :     ts.tv_nsec = tv.tv_usec * 1000 + static_cast<int>(1000 * 1000 * 1000 *
    1787           0 :                                                       fmod(dfWaitInSeconds, 1));
    1788           0 :     ts.tv_sec += ts.tv_nsec / (1000 * 1000 * 1000);
    1789           0 :     ts.tv_nsec %= (1000 * 1000 * 1000);
    1790           0 :     int ret = pthread_cond_timedwait(pCond, pMutex, &ts);
    1791           0 :     if (ret == 0)
    1792           0 :         return COND_TIMED_WAIT_COND;
    1793           0 :     else if (ret == ETIMEDOUT)
    1794           0 :         return COND_TIMED_WAIT_TIME_OUT;
    1795             :     else
    1796           0 :         return COND_TIMED_WAIT_OTHER;
    1797             : }
    1798             : 
    1799             : /************************************************************************/
    1800             : /*                            CPLCondSignal()                           */
    1801             : /************************************************************************/
    1802             : 
    1803       32176 : void CPLCondSignal(CPLCond *hCond)
    1804             : {
    1805       32176 :     pthread_cond_t *pCond = reinterpret_cast<pthread_cond_t *>(hCond);
    1806       32176 :     pthread_cond_signal(pCond);
    1807       32176 : }
    1808             : 
    1809             : /************************************************************************/
    1810             : /*                           CPLCondBroadcast()                         */
    1811             : /************************************************************************/
    1812             : 
    1813         220 : void CPLCondBroadcast(CPLCond *hCond)
    1814             : {
    1815         220 :     pthread_cond_t *pCond = reinterpret_cast<pthread_cond_t *>(hCond);
    1816         220 :     pthread_cond_broadcast(pCond);
    1817         220 : }
    1818             : 
    1819             : /************************************************************************/
    1820             : /*                            CPLDestroyCond()                          */
    1821             : /************************************************************************/
    1822             : 
    1823       29296 : void CPLDestroyCond(CPLCond *hCond)
    1824             : {
    1825       29296 :     pthread_cond_t *pCond = reinterpret_cast<pthread_cond_t *>(hCond);
    1826       29296 :     pthread_cond_destroy(pCond);
    1827       29296 :     free(hCond);
    1828       29296 : }
    1829             : 
    1830             : /************************************************************************/
    1831             : /*                            CPLLockFile()                             */
    1832             : /*                                                                      */
    1833             : /*      This is really a stub implementation, see first                 */
    1834             : /*      CPLLockFile() for caveats.                                      */
    1835             : /************************************************************************/
    1836             : 
    1837           3 : void *CPLLockFile(const char *pszPath, double dfWaitInSeconds)
    1838             : 
    1839             : {
    1840             :     /* -------------------------------------------------------------------- */
    1841             :     /*      We use a lock file with a name derived from the file we want    */
    1842             :     /*      to lock to represent the file being locked.  Note that for      */
    1843             :     /*      the stub implementation the target file does not even need      */
    1844             :     /*      to exist to be locked.                                          */
    1845             :     /* -------------------------------------------------------------------- */
    1846           3 :     const size_t nLen = strlen(pszPath) + 30;
    1847           3 :     char *pszLockFilename = static_cast<char *>(CPLMalloc(nLen));
    1848           3 :     snprintf(pszLockFilename, nLen, "%s.lock", pszPath);
    1849             : 
    1850           3 :     FILE *fpLock = fopen(pszLockFilename, "r");
    1851           3 :     while (fpLock != nullptr && dfWaitInSeconds > 0.0)
    1852             :     {
    1853           0 :         fclose(fpLock);
    1854           0 :         CPLSleep(std::min(dfWaitInSeconds, 0.5));
    1855           0 :         dfWaitInSeconds -= 0.5;
    1856             : 
    1857           0 :         fpLock = fopen(pszLockFilename, "r");
    1858             :     }
    1859             : 
    1860           3 :     if (fpLock != nullptr)
    1861             :     {
    1862           0 :         fclose(fpLock);
    1863           0 :         CPLFree(pszLockFilename);
    1864           0 :         return nullptr;
    1865             :     }
    1866             : 
    1867           3 :     fpLock = fopen(pszLockFilename, "w");
    1868             : 
    1869           3 :     if (fpLock == nullptr)
    1870             :     {
    1871           0 :         CPLFree(pszLockFilename);
    1872           0 :         return nullptr;
    1873             :     }
    1874             : 
    1875           3 :     fwrite("held\n", 1, 5, fpLock);
    1876           3 :     fclose(fpLock);
    1877             : 
    1878           3 :     return pszLockFilename;
    1879             : }
    1880             : 
    1881             : /************************************************************************/
    1882             : /*                           CPLUnlockFile()                            */
    1883             : /************************************************************************/
    1884             : 
    1885           3 : void CPLUnlockFile(void *hLock)
    1886             : 
    1887             : {
    1888           3 :     char *pszLockFilename = static_cast<char *>(hLock);
    1889             : 
    1890           3 :     if (hLock == nullptr)
    1891           0 :         return;
    1892             : 
    1893           3 :     VSIUnlink(pszLockFilename);
    1894             : 
    1895           3 :     CPLFree(pszLockFilename);
    1896             : }
    1897             : 
    1898             : /************************************************************************/
    1899             : /*                             CPLGetPID()                              */
    1900             : /************************************************************************/
    1901             : 
    1902    19790000 : GIntBig CPLGetPID()
    1903             : 
    1904             : {
    1905    19790000 :     return reinterpret_cast<GIntBig>(reinterpret_cast<void *>(pthread_self()));
    1906             : }
    1907             : 
    1908             : static pthread_key_t oTLSKey;
    1909             : static pthread_once_t oTLSKeySetup = PTHREAD_ONCE_INIT;
    1910             : 
    1911             : /************************************************************************/
    1912             : /*                             CPLMake_key()                            */
    1913             : /************************************************************************/
    1914             : 
    1915        1241 : static void CPLMake_key()
    1916             : 
    1917             : {
    1918        1241 :     if (pthread_key_create(&oTLSKey, reinterpret_cast<void (*)(void *)>(
    1919        1241 :                                          CPLCleanupTLSList)) != 0)
    1920             :     {
    1921           0 :         CPLError(CE_Fatal, CPLE_AppDefined, "pthread_key_create() failed!");
    1922             :     }
    1923        1241 : }
    1924             : 
    1925             : /************************************************************************/
    1926             : /*                           CPLGetTLSList()                            */
    1927             : /************************************************************************/
    1928             : 
    1929    47677600 : static void **CPLGetTLSList(int *pbMemoryErrorOccurred)
    1930             : 
    1931             : {
    1932    47677600 :     if (pbMemoryErrorOccurred)
    1933    46628600 :         *pbMemoryErrorOccurred = FALSE;
    1934             : 
    1935    47677600 :     if (pthread_once(&oTLSKeySetup, CPLMake_key) != 0)
    1936             :     {
    1937           0 :         if (pbMemoryErrorOccurred)
    1938             :         {
    1939           0 :             fprintf(stderr, "CPLGetTLSList(): pthread_once() failed!\n");
    1940           0 :             *pbMemoryErrorOccurred = TRUE;
    1941           0 :             return nullptr;
    1942             :         }
    1943           0 :         CPLEmergencyError("CPLGetTLSList(): pthread_once() failed!");
    1944             :     }
    1945             : 
    1946    47681600 :     void **papTLSList = static_cast<void **>(pthread_getspecific(oTLSKey));
    1947    47681800 :     if (papTLSList == nullptr)
    1948             :     {
    1949             :         papTLSList =
    1950        3142 :             static_cast<void **>(VSICalloc(sizeof(void *), CTLS_MAX * 2));
    1951        2120 :         if (papTLSList == nullptr)
    1952             :         {
    1953           0 :             if (pbMemoryErrorOccurred)
    1954             :             {
    1955           0 :                 fprintf(stderr,
    1956             :                         "CPLGetTLSList() failed to allocate TLS list!\n");
    1957           0 :                 *pbMemoryErrorOccurred = TRUE;
    1958           0 :                 return nullptr;
    1959             :             }
    1960           0 :             CPLEmergencyError("CPLGetTLSList() failed to allocate TLS list!");
    1961             :         }
    1962        2120 :         if (pthread_setspecific(oTLSKey, papTLSList) != 0)
    1963             :         {
    1964           0 :             if (pbMemoryErrorOccurred)
    1965             :             {
    1966           0 :                 fprintf(stderr,
    1967             :                         "CPLGetTLSList(): pthread_setspecific() failed!\n");
    1968           0 :                 *pbMemoryErrorOccurred = TRUE;
    1969           0 :                 return nullptr;
    1970             :             }
    1971           0 :             CPLEmergencyError("CPLGetTLSList(): pthread_setspecific() failed!");
    1972             :         }
    1973             :     }
    1974             : 
    1975    47680800 :     return papTLSList;
    1976             : }
    1977             : 
    1978             : /************************************************************************/
    1979             : /*                       CPLStdCallThreadJacket()                       */
    1980             : /************************************************************************/
    1981             : 
    1982             : typedef struct
    1983             : {
    1984             :     void *pAppData;
    1985             :     CPLThreadFunc pfnMain;
    1986             :     pthread_t hThread;
    1987             :     bool bJoinable;
    1988             : #ifdef CHECK_THREAD_CAN_ALLOCATE_TLS
    1989             :     bool bInitSucceeded;
    1990             :     bool bInitDone;
    1991             :     pthread_mutex_t sMutex;
    1992             :     pthread_cond_t sCond;
    1993             : #endif
    1994             : } CPLStdCallThreadInfo;
    1995             : 
    1996        1303 : static void *CPLStdCallThreadJacket(void *pData)
    1997             : 
    1998             : {
    1999        1303 :     CPLStdCallThreadInfo *psInfo = static_cast<CPLStdCallThreadInfo *>(pData);
    2000             : 
    2001             : #ifdef CHECK_THREAD_CAN_ALLOCATE_TLS
    2002             :     int bMemoryError = FALSE;
    2003             :     CPLGetTLSList(&bMemoryError);
    2004             :     if (bMemoryError)
    2005             :         goto error;
    2006             : 
    2007             :     assert(pthread_mutex_lock(&(psInfo->sMutex)) == 0);
    2008             :     psInfo->bInitDone = true;
    2009             :     assert(pthread_cond_signal(&(psInfo->sCond)) == 0);
    2010             :     assert(pthread_mutex_unlock(&(psInfo->sMutex)) == 0);
    2011             : #endif
    2012             : 
    2013        1303 :     psInfo->pfnMain(psInfo->pAppData);
    2014             : 
    2015        1282 :     if (!psInfo->bJoinable)
    2016           1 :         CPLFree(psInfo);
    2017             : 
    2018        1282 :     return nullptr;
    2019             : 
    2020             : #ifdef CHECK_THREAD_CAN_ALLOCATE_TLS
    2021             : error:
    2022             :     assert(pthread_mutex_lock(&(psInfo->sMutex)) == 0);
    2023             :     psInfo->bInitSucceeded = false;
    2024             :     psInfo->bInitDone = true;
    2025             :     assert(pthread_cond_signal(&(psInfo->sCond)) == 0);
    2026             :     assert(pthread_mutex_unlock(&(psInfo->sMutex)) == 0);
    2027             :     return nullptr;
    2028             : #endif
    2029             : }
    2030             : 
    2031             : /************************************************************************/
    2032             : /*                          CPLCreateThread()                           */
    2033             : /*                                                                      */
    2034             : /*      The WIN32 CreateThread() call requires an entry point that      */
    2035             : /*      has __stdcall conventions, so we provide a jacket function      */
    2036             : /*      to supply that.                                                 */
    2037             : /************************************************************************/
    2038             : 
    2039           1 : int CPLCreateThread(CPLThreadFunc pfnMain, void *pThreadArg)
    2040             : 
    2041             : {
    2042             :     CPLStdCallThreadInfo *psInfo = static_cast<CPLStdCallThreadInfo *>(
    2043           1 :         VSI_CALLOC_VERBOSE(sizeof(CPLStdCallThreadInfo), 1));
    2044           1 :     if (psInfo == nullptr)
    2045           0 :         return -1;
    2046           1 :     psInfo->pAppData = pThreadArg;
    2047           1 :     psInfo->pfnMain = pfnMain;
    2048           1 :     psInfo->bJoinable = false;
    2049             : #ifdef CHECK_THREAD_CAN_ALLOCATE_TLS
    2050             :     psInfo->bInitSucceeded = true;
    2051             :     psInfo->bInitDone = false;
    2052             :     pthread_mutex_t sMutex = PTHREAD_MUTEX_INITIALIZER;
    2053             :     psInfo->sMutex = sMutex;
    2054             :     if (pthread_cond_init(&(psInfo->sCond), nullptr) != 0)
    2055             :     {
    2056             :         CPLFree(psInfo);
    2057             :         fprintf(stderr, "CPLCreateThread() failed.\n");
    2058             :         return -1;
    2059             :     }
    2060             : #endif
    2061             : 
    2062             :     pthread_attr_t hThreadAttr;
    2063           1 :     pthread_attr_init(&hThreadAttr);
    2064           1 :     pthread_attr_setdetachstate(&hThreadAttr, PTHREAD_CREATE_DETACHED);
    2065           1 :     if (pthread_create(&(psInfo->hThread), &hThreadAttr, CPLStdCallThreadJacket,
    2066           1 :                        static_cast<void *>(psInfo)) != 0)
    2067             :     {
    2068             : #ifdef CHECK_THREAD_CAN_ALLOCATE_TLS
    2069             :         pthread_cond_destroy(&(psInfo->sCond));
    2070             : #endif
    2071           0 :         CPLFree(psInfo);
    2072           0 :         fprintf(stderr, "CPLCreateThread() failed.\n");
    2073           0 :         return -1;
    2074             :     }
    2075             : 
    2076             : #ifdef CHECK_THREAD_CAN_ALLOCATE_TLS
    2077             :     bool bInitSucceeded;
    2078             :     while (true)
    2079             :     {
    2080             :         assert(pthread_mutex_lock(&(psInfo->sMutex)) == 0);
    2081             :         bool bInitDone = psInfo->bInitDone;
    2082             :         if (!bInitDone)
    2083             :             assert(pthread_cond_wait(&(psInfo->sCond), &(psInfo->sMutex)) == 0);
    2084             :         bInitSucceeded = psInfo->bInitSucceeded;
    2085             :         assert(pthread_mutex_unlock(&(psInfo->sMutex)) == 0);
    2086             :         if (bInitDone)
    2087             :             break;
    2088             :     }
    2089             : 
    2090             :     pthread_cond_destroy(&(psInfo->sCond));
    2091             : 
    2092             :     if (!bInitSucceeded)
    2093             :     {
    2094             :         CPLFree(psInfo);
    2095             :         fprintf(stderr, "CPLCreateThread() failed.\n");
    2096             :         return -1;
    2097             :     }
    2098             : #endif
    2099             : 
    2100           1 :     return 1;  // Can we return the actual thread pid?
    2101             : }
    2102             : 
    2103             : /************************************************************************/
    2104             : /*                      CPLCreateJoinableThread()                       */
    2105             : /************************************************************************/
    2106             : 
    2107        1302 : CPLJoinableThread *CPLCreateJoinableThread(CPLThreadFunc pfnMain,
    2108             :                                            void *pThreadArg)
    2109             : 
    2110             : {
    2111             :     CPLStdCallThreadInfo *psInfo = static_cast<CPLStdCallThreadInfo *>(
    2112        1302 :         VSI_CALLOC_VERBOSE(sizeof(CPLStdCallThreadInfo), 1));
    2113        1302 :     if (psInfo == nullptr)
    2114           0 :         return nullptr;
    2115        1302 :     psInfo->pAppData = pThreadArg;
    2116        1302 :     psInfo->pfnMain = pfnMain;
    2117        1302 :     psInfo->bJoinable = true;
    2118             : #ifdef CHECK_THREAD_CAN_ALLOCATE_TLS
    2119             :     psInfo->bInitSucceeded = true;
    2120             :     psInfo->bInitDone = false;
    2121             :     pthread_mutex_t sMutex = PTHREAD_MUTEX_INITIALIZER;
    2122             :     psInfo->sMutex = sMutex;
    2123             :     {
    2124             :         int err = pthread_cond_init(&(psInfo->sCond), nullptr);
    2125             :         if (err != 0)
    2126             :         {
    2127             :             CPLFree(psInfo);
    2128             :             fprintf(stderr, "CPLCreateJoinableThread() failed: %s.\n",
    2129             :                     strerror(err));
    2130             :             return nullptr;
    2131             :         }
    2132             :     }
    2133             : #endif
    2134             : 
    2135             :     pthread_attr_t hThreadAttr;
    2136        1302 :     pthread_attr_init(&hThreadAttr);
    2137        1302 :     pthread_attr_setdetachstate(&hThreadAttr, PTHREAD_CREATE_JOINABLE);
    2138             :     int err =
    2139        1302 :         pthread_create(&(psInfo->hThread), &hThreadAttr, CPLStdCallThreadJacket,
    2140             :                        static_cast<void *>(psInfo));
    2141        1302 :     if (err != 0)
    2142             :     {
    2143             : #ifdef CHECK_THREAD_CAN_ALLOCATE_TLS
    2144             :         pthread_cond_destroy(&(psInfo->sCond));
    2145             : #endif
    2146           0 :         CPLFree(psInfo);
    2147           0 :         fprintf(stderr, "CPLCreateJoinableThread() failed: %s.\n",
    2148             :                 strerror(err));
    2149           0 :         return nullptr;
    2150             :     }
    2151             : 
    2152             : #ifdef CHECK_THREAD_CAN_ALLOCATE_TLS
    2153             :     bool bInitSucceeded;
    2154             :     while (true)
    2155             :     {
    2156             :         assert(pthread_mutex_lock(&(psInfo->sMutex)) == 0);
    2157             :         bool bInitDone = psInfo->bInitDone;
    2158             :         if (!bInitDone)
    2159             :             assert(pthread_cond_wait(&(psInfo->sCond), &(psInfo->sMutex)) == 0);
    2160             :         bInitSucceeded = psInfo->bInitSucceeded;
    2161             :         assert(pthread_mutex_unlock(&(psInfo->sMutex)) == 0);
    2162             :         if (bInitDone)
    2163             :             break;
    2164             :     }
    2165             : 
    2166             :     pthread_cond_destroy(&(psInfo->sCond));
    2167             : 
    2168             :     if (!bInitSucceeded)
    2169             :     {
    2170             :         void *status;
    2171             :         pthread_join(psInfo->hThread, &status);
    2172             :         CPLFree(psInfo);
    2173             :         fprintf(stderr, "CPLCreateJoinableThread() failed.\n");
    2174             :         return nullptr;
    2175             :     }
    2176             : #endif
    2177             : 
    2178        1302 :     return reinterpret_cast<CPLJoinableThread *>(psInfo);
    2179             : }
    2180             : 
    2181             : /************************************************************************/
    2182             : /*                          CPLJoinThread()                             */
    2183             : /************************************************************************/
    2184             : 
    2185        1281 : void CPLJoinThread(CPLJoinableThread *hJoinableThread)
    2186             : {
    2187        1281 :     CPLStdCallThreadInfo *psInfo =
    2188             :         reinterpret_cast<CPLStdCallThreadInfo *>(hJoinableThread);
    2189        1281 :     if (psInfo == nullptr)
    2190           0 :         return;
    2191             : 
    2192             :     void *status;
    2193        1281 :     pthread_join(psInfo->hThread, &status);
    2194             : 
    2195        1281 :     CPLFree(psInfo);
    2196             : }
    2197             : 
    2198             : /************************************************************************/
    2199             : /*                              CPLSleep()                              */
    2200             : /************************************************************************/
    2201             : 
    2202          63 : void CPLSleep(double dfWaitInSeconds)
    2203             : 
    2204             : {
    2205             :     struct timespec sRequest;
    2206             :     struct timespec sRemain;
    2207             : 
    2208          63 :     sRequest.tv_sec = static_cast<int>(floor(dfWaitInSeconds));
    2209          63 :     sRequest.tv_nsec =
    2210          63 :         static_cast<int>((dfWaitInSeconds - sRequest.tv_sec) * 1000000000);
    2211          63 :     nanosleep(&sRequest, &sRemain);
    2212          63 : }
    2213             : 
    2214             : /************************************************************************/
    2215             : /*                             CPLFinalizeTLS()                         */
    2216             : /************************************************************************/
    2217             : 
    2218         380 : void CPLFinalizeTLS()
    2219             : {
    2220         380 :     CPLCleanupTLS();
    2221             :     // See #5509 for the explanation why this may be needed.
    2222         380 :     pthread_key_delete(oTLSKey);
    2223         380 : }
    2224             : 
    2225             : /************************************************************************/
    2226             : /*                             CPLCleanupTLS()                          */
    2227             : /************************************************************************/
    2228             : 
    2229        1235 : void CPLCleanupTLS()
    2230             : 
    2231             : {
    2232        1235 :     void **papTLSList = static_cast<void **>(pthread_getspecific(oTLSKey));
    2233        1235 :     if (papTLSList == nullptr)
    2234           4 :         return;
    2235             : 
    2236        1231 :     pthread_setspecific(oTLSKey, nullptr);
    2237             : 
    2238        1231 :     CPLCleanupTLSList(papTLSList);
    2239             : }
    2240             : 
    2241             : /************************************************************************/
    2242             : /*                          CPLCreateSpinLock()                         */
    2243             : /************************************************************************/
    2244             : 
    2245             : #if defined(HAVE_PTHREAD_SPIN_LOCK)
    2246             : #define HAVE_SPINLOCK_IMPL
    2247             : 
    2248             : struct _CPLSpinLock
    2249             : {
    2250             :     pthread_spinlock_t spin;
    2251             : };
    2252             : 
    2253             : CPLSpinLock *CPLCreateSpinLock()
    2254             : {
    2255             :     CPLSpinLock *psSpin =
    2256             :         static_cast<CPLSpinLock *>(malloc(sizeof(CPLSpinLock)));
    2257             :     if (psSpin != nullptr &&
    2258             :         pthread_spin_init(&(psSpin->spin), PTHREAD_PROCESS_PRIVATE) == 0)
    2259             :     {
    2260             :         return psSpin;
    2261             :     }
    2262             :     else
    2263             :     {
    2264             :         fprintf(stderr, "CPLCreateSpinLock() failed.\n");
    2265             :         free(psSpin);
    2266             :         return nullptr;
    2267             :     }
    2268             : }
    2269             : 
    2270             : /************************************************************************/
    2271             : /*                        CPLAcquireSpinLock()                          */
    2272             : /************************************************************************/
    2273             : 
    2274             : int CPLAcquireSpinLock(CPLSpinLock *psSpin)
    2275             : {
    2276             :     return pthread_spin_lock(&(psSpin->spin)) == 0;
    2277             : }
    2278             : 
    2279             : /************************************************************************/
    2280             : /*                   CPLCreateOrAcquireSpinLockInternal()               */
    2281             : /************************************************************************/
    2282             : 
    2283             : int CPLCreateOrAcquireSpinLockInternal(CPLLock **ppsLock)
    2284             : {
    2285             :     pthread_mutex_lock(&global_mutex);
    2286             :     if (*ppsLock == nullptr)
    2287             :     {
    2288             :         *ppsLock = static_cast<CPLLock *>(calloc(1, sizeof(CPLLock)));
    2289             :         if (*ppsLock != nullptr)
    2290             :         {
    2291             :             (*ppsLock)->eType = LOCK_SPIN;
    2292             :             (*ppsLock)->u.hSpinLock = CPLCreateSpinLock();
    2293             :             if ((*ppsLock)->u.hSpinLock == nullptr)
    2294             :             {
    2295             :                 free(*ppsLock);
    2296             :                 *ppsLock = nullptr;
    2297             :             }
    2298             :         }
    2299             :     }
    2300             :     pthread_mutex_unlock(&global_mutex);
    2301             :     // coverity[missing_unlock]
    2302             :     return (*ppsLock != nullptr && CPLAcquireSpinLock((*ppsLock)->u.hSpinLock));
    2303             : }
    2304             : 
    2305             : /************************************************************************/
    2306             : /*                       CPLReleaseSpinLock()                           */
    2307             : /************************************************************************/
    2308             : 
    2309             : void CPLReleaseSpinLock(CPLSpinLock *psSpin)
    2310             : {
    2311             :     pthread_spin_unlock(&(psSpin->spin));
    2312             : }
    2313             : 
    2314             : /************************************************************************/
    2315             : /*                        CPLDestroySpinLock()                          */
    2316             : /************************************************************************/
    2317             : 
    2318             : void CPLDestroySpinLock(CPLSpinLock *psSpin)
    2319             : {
    2320             :     pthread_spin_destroy(&(psSpin->spin));
    2321             :     free(psSpin);
    2322             : }
    2323             : #endif  // HAVE_PTHREAD_SPIN_LOCK
    2324             : 
    2325             : #endif  // def CPL_MULTIPROC_PTHREAD
    2326             : 
    2327             : /************************************************************************/
    2328             : /*                             CPLGetTLS()                              */
    2329             : /************************************************************************/
    2330             : 
    2331      983953 : void *CPLGetTLS(int nIndex)
    2332             : 
    2333             : {
    2334      983953 :     void **l_papTLSList = CPLGetTLSList(nullptr);
    2335             : 
    2336      983939 :     CPLAssert(nIndex >= 0 && nIndex < CTLS_MAX);
    2337             : 
    2338      983922 :     return l_papTLSList[nIndex];
    2339             : }
    2340             : 
    2341             : /************************************************************************/
    2342             : /*                            CPLGetTLSEx()                             */
    2343             : /************************************************************************/
    2344             : 
    2345    46627800 : void *CPLGetTLSEx(int nIndex, int *pbMemoryErrorOccurred)
    2346             : 
    2347             : {
    2348    46627800 :     void **l_papTLSList = CPLGetTLSList(pbMemoryErrorOccurred);
    2349    46626200 :     if (l_papTLSList == nullptr)
    2350           0 :         return nullptr;
    2351             : 
    2352    46626200 :     CPLAssert(nIndex >= 0 && nIndex < CTLS_MAX);
    2353             : 
    2354    46626000 :     return l_papTLSList[nIndex];
    2355             : }
    2356             : 
    2357             : /************************************************************************/
    2358             : /*                             CPLSetTLS()                              */
    2359             : /************************************************************************/
    2360             : 
    2361       15988 : void CPLSetTLS(int nIndex, void *pData, int bFreeOnExit)
    2362             : 
    2363             : {
    2364       15988 :     CPLSetTLSWithFreeFunc(nIndex, pData, (bFreeOnExit) ? CPLFree : nullptr);
    2365       15983 : }
    2366             : 
    2367             : /************************************************************************/
    2368             : /*                      CPLSetTLSWithFreeFunc()                         */
    2369             : /************************************************************************/
    2370             : 
    2371             : // Warning: The CPLTLSFreeFunc must not in any case directly or indirectly
    2372             : // use or fetch any TLS data, or a terminating thread will hang!
    2373       69331 : void CPLSetTLSWithFreeFunc(int nIndex, void *pData, CPLTLSFreeFunc pfnFree)
    2374             : 
    2375             : {
    2376       69331 :     void **l_papTLSList = CPLGetTLSList(nullptr);
    2377             : 
    2378       69314 :     CPLAssert(nIndex >= 0 && nIndex < CTLS_MAX);
    2379             : 
    2380       69294 :     l_papTLSList[nIndex] = pData;
    2381       69294 :     l_papTLSList[CTLS_MAX + nIndex] = reinterpret_cast<void *>(pfnFree);
    2382       69294 : }
    2383             : 
    2384             : /************************************************************************/
    2385             : /*                      CPLSetTLSWithFreeFuncEx()                       */
    2386             : /************************************************************************/
    2387             : 
    2388             : // Warning: the CPLTLSFreeFunc must not in any case directly or indirectly
    2389             : // use or fetch any TLS data, or a terminating thread will hang!
    2390        1257 : void CPLSetTLSWithFreeFuncEx(int nIndex, void *pData, CPLTLSFreeFunc pfnFree,
    2391             :                              int *pbMemoryErrorOccurred)
    2392             : 
    2393             : {
    2394        1257 :     void **l_papTLSList = CPLGetTLSList(pbMemoryErrorOccurred);
    2395             : 
    2396        1257 :     CPLAssert(nIndex >= 0 && nIndex < CTLS_MAX);
    2397             : 
    2398        1257 :     l_papTLSList[nIndex] = pData;
    2399        1257 :     l_papTLSList[CTLS_MAX + nIndex] = reinterpret_cast<void *>(pfnFree);
    2400        1257 : }
    2401             : #ifndef HAVE_SPINLOCK_IMPL
    2402             : 
    2403             : // No spinlock specific API? Fallback to mutex.
    2404             : 
    2405             : /************************************************************************/
    2406             : /*                          CPLCreateSpinLock()                         */
    2407             : /************************************************************************/
    2408             : 
    2409       29059 : CPLSpinLock *CPLCreateSpinLock(void)
    2410             : {
    2411       29059 :     CPLSpinLock *psSpin = reinterpret_cast<CPLSpinLock *>(CPLCreateMutex());
    2412       29059 :     if (psSpin)
    2413       29059 :         CPLReleaseSpinLock(psSpin);
    2414       29059 :     return psSpin;
    2415             : }
    2416             : 
    2417             : /************************************************************************/
    2418             : /*                     CPLCreateOrAcquireSpinLock()                     */
    2419             : /************************************************************************/
    2420             : 
    2421           2 : int CPLCreateOrAcquireSpinLockInternal(CPLLock **ppsLock)
    2422             : {
    2423           2 :     return CPLCreateOrAcquireMutexInternal(ppsLock, 1000, LOCK_ADAPTIVE_MUTEX);
    2424             : }
    2425             : 
    2426             : /************************************************************************/
    2427             : /*                        CPLAcquireSpinLock()                          */
    2428             : /************************************************************************/
    2429             : 
    2430     6164700 : int CPLAcquireSpinLock(CPLSpinLock *psSpin)
    2431             : {
    2432     6164700 :     return CPLAcquireMutex(reinterpret_cast<CPLMutex *>(psSpin), 1000);
    2433             : }
    2434             : 
    2435             : /************************************************************************/
    2436             : /*                       CPLReleaseSpinLock()                           */
    2437             : /************************************************************************/
    2438             : 
    2439     6193760 : void CPLReleaseSpinLock(CPLSpinLock *psSpin)
    2440             : {
    2441     6193760 :     CPLReleaseMutex(reinterpret_cast<CPLMutex *>(psSpin));
    2442     6193760 : }
    2443             : 
    2444             : /************************************************************************/
    2445             : /*                        CPLDestroySpinLock()                          */
    2446             : /************************************************************************/
    2447             : 
    2448       29060 : void CPLDestroySpinLock(CPLSpinLock *psSpin)
    2449             : {
    2450       29060 :     CPLDestroyMutex(reinterpret_cast<CPLMutex *>(psSpin));
    2451       29060 : }
    2452             : 
    2453             : #endif  // HAVE_SPINLOCK_IMPL
    2454             : 
    2455             : /************************************************************************/
    2456             : /*                            CPLCreateLock()                           */
    2457             : /************************************************************************/
    2458             : 
    2459       29130 : CPLLock *CPLCreateLock(CPLLockType eType)
    2460             : {
    2461       29130 :     switch (eType)
    2462             :     {
    2463          69 :         case LOCK_RECURSIVE_MUTEX:
    2464             :         case LOCK_ADAPTIVE_MUTEX:
    2465             :         {
    2466         138 :             CPLMutex *hMutex = CPLCreateMutexEx(eType == LOCK_RECURSIVE_MUTEX
    2467          69 :                                                     ? CPL_MUTEX_RECURSIVE
    2468             :                                                     : CPL_MUTEX_ADAPTIVE);
    2469          69 :             if (!hMutex)
    2470           0 :                 return nullptr;
    2471          69 :             CPLReleaseMutex(hMutex);
    2472          69 :             CPLLock *psLock = static_cast<CPLLock *>(malloc(sizeof(CPLLock)));
    2473          69 :             if (psLock == nullptr)
    2474             :             {
    2475           0 :                 fprintf(stderr, "CPLCreateLock() failed.\n");
    2476           0 :                 CPLDestroyMutex(hMutex);
    2477           0 :                 return nullptr;
    2478             :             }
    2479          70 :             psLock->eType = eType;
    2480          70 :             psLock->u.hMutex = hMutex;
    2481             : #ifdef DEBUG_CONTENTION
    2482          70 :             psLock->bDebugPerf = false;
    2483          70 :             psLock->bDebugPerfAsked = false;
    2484          70 :             psLock->nCurrentHolders = 0;
    2485          70 :             psLock->nStartTime = 0;
    2486             : #endif
    2487          70 :             return psLock;
    2488             :         }
    2489       29059 :         case LOCK_SPIN:
    2490             :         {
    2491       29059 :             CPLSpinLock *hSpinLock = CPLCreateSpinLock();
    2492       29060 :             if (!hSpinLock)
    2493           0 :                 return nullptr;
    2494       29060 :             CPLLock *psLock = static_cast<CPLLock *>(malloc(sizeof(CPLLock)));
    2495       29060 :             if (psLock == nullptr)
    2496             :             {
    2497           0 :                 fprintf(stderr, "CPLCreateLock() failed.\n");
    2498           0 :                 CPLDestroySpinLock(hSpinLock);
    2499           0 :                 return nullptr;
    2500             :             }
    2501       29060 :             psLock->eType = eType;
    2502       29060 :             psLock->u.hSpinLock = hSpinLock;
    2503             : #ifdef DEBUG_CONTENTION
    2504       29060 :             psLock->bDebugPerf = false;
    2505       29060 :             psLock->bDebugPerfAsked = false;
    2506       29060 :             psLock->nCurrentHolders = 0;
    2507       29060 :             psLock->nStartTime = 0;
    2508             : #endif
    2509       29060 :             return psLock;
    2510             :         }
    2511           2 :         default:
    2512           2 :             CPLAssert(false);
    2513             :             return nullptr;
    2514             :     }
    2515             : }
    2516             : 
    2517             : /************************************************************************/
    2518             : /*                       CPLCreateOrAcquireLock()                       */
    2519             : /************************************************************************/
    2520             : 
    2521        4719 : int CPLCreateOrAcquireLock(CPLLock **ppsLock, CPLLockType eType)
    2522             : {
    2523             : #ifdef DEBUG_CONTENTION
    2524        4719 :     GUIntBig nStartTime = 0;
    2525        4719 :     if ((*ppsLock) && (*ppsLock)->bDebugPerfAsked)
    2526           0 :         nStartTime = CPLrdtsc();
    2527             : #endif
    2528        4719 :     int ret = 0;
    2529             : 
    2530        4719 :     switch (eType)
    2531             :     {
    2532        4717 :         case LOCK_RECURSIVE_MUTEX:
    2533             :         case LOCK_ADAPTIVE_MUTEX:
    2534             :         {
    2535        4717 :             ret = CPLCreateOrAcquireMutexInternal(ppsLock, 1000, eType);
    2536        4717 :             break;
    2537             :         }
    2538           2 :         case LOCK_SPIN:
    2539             :         {
    2540           2 :             ret = CPLCreateOrAcquireSpinLockInternal(ppsLock);
    2541           2 :             break;
    2542             :         }
    2543           0 :         default:
    2544           0 :             CPLAssert(false);
    2545             :             return FALSE;
    2546             :     }
    2547             : #ifdef DEBUG_CONTENTION
    2548        4719 :     if (ret && (*ppsLock)->bDebugPerfAsked &&
    2549           0 :         CPLAtomicInc(&((*ppsLock)->nCurrentHolders)) == 1)
    2550             :     {
    2551           0 :         (*ppsLock)->bDebugPerf = true;
    2552           0 :         (*ppsLock)->nStartTime = nStartTime;
    2553             :     }
    2554             : #endif
    2555        4719 :     return ret;
    2556             : }
    2557             : 
    2558             : /************************************************************************/
    2559             : /*                          CPLAcquireLock()                            */
    2560             : /************************************************************************/
    2561             : 
    2562    23146100 : int CPLAcquireLock(CPLLock *psLock)
    2563             : {
    2564             : #ifdef DEBUG_CONTENTION
    2565    23146100 :     GUIntBig nStartTime = 0;
    2566    23146100 :     if (psLock->bDebugPerfAsked)
    2567     1952510 :         nStartTime = CPLrdtsc();
    2568             : #endif
    2569             :     int ret;
    2570    23146100 :     if (psLock->eType == LOCK_SPIN)
    2571     6164700 :         ret = CPLAcquireSpinLock(psLock->u.hSpinLock);
    2572             :     else
    2573    16981400 :         ret = CPLAcquireMutex(psLock->u.hMutex, 1000);
    2574             : #ifdef DEBUG_CONTENTION
    2575    25098700 :     if (ret && psLock->bDebugPerfAsked &&
    2576     1952510 :         CPLAtomicInc(&(psLock->nCurrentHolders)) == 1)
    2577             :     {
    2578     1952510 :         psLock->bDebugPerf = true;
    2579     1952510 :         psLock->nStartTime = nStartTime;
    2580             :     }
    2581             : #endif
    2582    23146200 :     return ret;
    2583             : }
    2584             : 
    2585             : /************************************************************************/
    2586             : /*                         CPLReleaseLock()                             */
    2587             : /************************************************************************/
    2588             : 
    2589    23150900 : void CPLReleaseLock(CPLLock *psLock)
    2590             : {
    2591             : #ifdef DEBUG_CONTENTION
    2592    23150900 :     bool bHitMaxDiff = false;
    2593    23150900 :     GIntBig nMaxDiff = 0;
    2594    23150900 :     double dfAvgDiff = 0;
    2595    23150900 :     if (psLock->bDebugPerf && CPLAtomicDec(&(psLock->nCurrentHolders)) == 0)
    2596             :     {
    2597     1952510 :         const GUIntBig nStopTime = CPLrdtscp();
    2598             :         // coverity[missing_lock:FALSE]
    2599     1952510 :         const GIntBig nDiffTime =
    2600     1952510 :             static_cast<GIntBig>(nStopTime - psLock->nStartTime);
    2601     1952510 :         if (nDiffTime > psLock->nMaxDiff)
    2602             :         {
    2603          30 :             bHitMaxDiff = true;
    2604          30 :             psLock->nMaxDiff = nDiffTime;
    2605             :         }
    2606     1952510 :         nMaxDiff = psLock->nMaxDiff;
    2607     1952510 :         psLock->nIters++;
    2608     1952510 :         psLock->dfAvgDiff += (nDiffTime - psLock->dfAvgDiff) / psLock->nIters;
    2609     1952510 :         dfAvgDiff = psLock->dfAvgDiff;
    2610             :     }
    2611             : #endif
    2612    23150900 :     if (psLock->eType == LOCK_SPIN)
    2613     6164700 :         CPLReleaseSpinLock(psLock->u.hSpinLock);
    2614             :     else
    2615    16986200 :         CPLReleaseMutex(psLock->u.hMutex);
    2616             : #ifdef DEBUG_CONTENTION
    2617    23150900 :     if (psLock->bDebugPerf &&
    2618     1952480 :         (bHitMaxDiff || (psLock->nIters % 1000000) == (1000000 - 1)))
    2619             :     {
    2620          30 :         CPLDebug("LOCK", "Lock contention : max = " CPL_FRMT_GIB ", avg = %.0f",
    2621             :                  nMaxDiff, dfAvgDiff);
    2622             :     }
    2623             : #endif
    2624    23150900 : }
    2625             : 
    2626             : /************************************************************************/
    2627             : /*                          CPLDestroyLock()                            */
    2628             : /************************************************************************/
    2629             : 
    2630       29499 : void CPLDestroyLock(CPLLock *psLock)
    2631             : {
    2632       29499 :     if (psLock->eType == LOCK_SPIN)
    2633       29060 :         CPLDestroySpinLock(psLock->u.hSpinLock);
    2634             :     else
    2635         439 :         CPLDestroyMutex(psLock->u.hMutex);
    2636       29499 :     free(psLock);
    2637       29499 : }
    2638             : 
    2639             : /************************************************************************/
    2640             : /*                       CPLLockSetDebugPerf()                          */
    2641             : /************************************************************************/
    2642             : 
    2643             : #ifdef DEBUG_CONTENTION
    2644        4719 : void CPLLockSetDebugPerf(CPLLock *psLock, int bEnableIn)
    2645             : {
    2646        4719 :     psLock->bDebugPerfAsked = CPL_TO_BOOL(bEnableIn);
    2647        4719 : }
    2648             : #else
    2649             : void CPLLockSetDebugPerf(CPLLock * /* psLock */, int bEnableIn)
    2650             : {
    2651             :     if (!bEnableIn)
    2652             :         return;
    2653             : 
    2654             :     static bool bOnce = false;
    2655             :     if (!bOnce)
    2656             :     {
    2657             :         bOnce = true;
    2658             :         CPLDebug("LOCK", "DEBUG_CONTENTION not available");
    2659             :     }
    2660             : }
    2661             : #endif
    2662             : 
    2663             : /************************************************************************/
    2664             : /*                           CPLLockHolder()                            */
    2665             : /************************************************************************/
    2666             : 
    2667        4719 : CPLLockHolder::CPLLockHolder(CPLLock **phLock, CPLLockType eType,
    2668        4719 :                              const char *pszFileIn, int nLineIn)
    2669             : 
    2670             : {
    2671             : #ifndef MUTEX_NONE
    2672        4719 :     pszFile = pszFileIn;
    2673        4719 :     nLine = nLineIn;
    2674             : 
    2675             : #ifdef DEBUG_MUTEX
    2676             :     // XXX: There is no way to use CPLDebug() here because it works with
    2677             :     // mutexes itself so we will fall in infinite recursion. Good old
    2678             :     // fprintf() will do the job right.
    2679             :     fprintf(stderr, "CPLLockHolder: Request %p for pid %ld at %d/%s.\n",
    2680             :             *phLock, static_cast<long>(CPLGetPID()), nLine, pszFile);
    2681             : #endif
    2682             : 
    2683        4719 :     if (!CPLCreateOrAcquireLock(phLock, eType))
    2684             :     {
    2685           0 :         fprintf(stderr, "CPLLockHolder: Failed to acquire lock!\n");
    2686           0 :         hLock = nullptr;
    2687             :     }
    2688             :     else
    2689             :     {
    2690             : #ifdef DEBUG_MUTEX
    2691             :         fprintf(stderr, "CPLLockHolder: Acquired %p for pid %ld at %d/%s.\n",
    2692             :                 *phLock, static_cast<long>(CPLGetPID()), nLine, pszFile);
    2693             : #endif
    2694             : 
    2695        4719 :         hLock = *phLock;
    2696             :     }
    2697             : #endif  // ndef MUTEX_NONE
    2698        4719 : }
    2699             : 
    2700             : /************************************************************************/
    2701             : /*                           CPLLockHolder()                            */
    2702             : /************************************************************************/
    2703             : 
    2704    23141300 : CPLLockHolder::CPLLockHolder(CPLLock *hLockIn, const char *pszFileIn,
    2705    23141300 :                              int nLineIn)
    2706             : 
    2707             : {
    2708             : #ifndef MUTEX_NONE
    2709    23141300 :     pszFile = pszFileIn;
    2710    23141300 :     nLine = nLineIn;
    2711    23141300 :     hLock = hLockIn;
    2712             : 
    2713    23141300 :     if (hLock != nullptr)
    2714             :     {
    2715    23141300 :         if (!CPLAcquireLock(hLock))
    2716             :         {
    2717           0 :             fprintf(stderr, "CPLLockHolder: Failed to acquire lock!\n");
    2718           0 :             hLock = nullptr;
    2719             :         }
    2720             :     }
    2721             : #endif  // ndef MUTEX_NONE
    2722    23141400 : }
    2723             : 
    2724             : /************************************************************************/
    2725             : /*                          ~CPLLockHolder()                            */
    2726             : /************************************************************************/
    2727             : 
    2728    46292200 : CPLLockHolder::~CPLLockHolder()
    2729             : 
    2730             : {
    2731             : #ifndef MUTEX_NONE
    2732    23146100 :     if (hLock != nullptr)
    2733             :     {
    2734             : #ifdef DEBUG_MUTEX
    2735             :         fprintf(stderr, "~CPLLockHolder: Release %p for pid %ld at %d/%s.\n",
    2736             :                 hLock, static_cast<long>(CPLGetPID()), nLine, pszFile);
    2737             : #endif
    2738    23146100 :         CPLReleaseLock(hLock);
    2739             :     }
    2740             : #endif  // ndef MUTEX_NONE
    2741    23146100 : }
    2742             : 
    2743             : /************************************************************************/
    2744             : /*                       CPLGetCurrentProcessID()                       */
    2745             : /************************************************************************/
    2746             : 
    2747             : #ifdef CPL_MULTIPROC_WIN32
    2748             : 
    2749             : int CPLGetCurrentProcessID()
    2750             : {
    2751             :     return GetCurrentProcessId();
    2752             : }
    2753             : 
    2754             : #else
    2755             : 
    2756             : #include <sys/types.h>
    2757             : #include <unistd.h>
    2758             : 
    2759        2313 : int CPLGetCurrentProcessID()
    2760             : {
    2761        2313 :     return getpid();
    2762             : }
    2763             : 
    2764             : #endif

Generated by: LCOV version 1.14