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