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( <ime );
766 const time_t ttime = ltime + static_cast<int>(dfWaitInSeconds + 0.5);
767
768 for( ; ltime < ttime; time(<ime) )
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