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