Line data Source code
1 : /**********************************************************************
2 : *
3 : * Project: CPL - Common Portability Library
4 : * Purpose: CPL Multi-Threading, and process handling portability functions.
5 : * Author: Frank Warmerdam, warmerdam@pobox.com
6 : *
7 : **********************************************************************
8 : * Copyright (c) 2002, Frank Warmerdam
9 : * Copyright (c) 2009-2013, Even Rouault <even dot rouault at spatialys.com>
10 : *
11 : * SPDX-License-Identifier: MIT
12 : ****************************************************************************/
13 :
14 : #ifndef _GNU_SOURCE
15 : #define _GNU_SOURCE
16 : #endif
17 :
18 : // Include cpl_config.h BEFORE cpl_multiproc.h, as the later may undefine
19 : // CPL_MULTIPROC_PTHREAD for mingw case.
20 :
21 : #include "cpl_config.h"
22 : #include "cpl_multiproc.h"
23 :
24 : #ifdef CHECK_THREAD_CAN_ALLOCATE_TLS
25 : #include <cassert>
26 : #endif
27 : #include <cerrno>
28 : #include <cmath>
29 : #include <cstddef>
30 : #include <cstdio>
31 : #include <cstdlib>
32 : #include <cstring>
33 : #include <ctime>
34 : #include <algorithm>
35 :
36 : #include "cpl_atomic_ops.h"
37 : #include "cpl_conv.h"
38 : #include "cpl_error.h"
39 : #include "cpl_string.h"
40 : #include "cpl_vsi.h"
41 :
42 : #if defined(CPL_MULTIPROC_STUB) && !defined(DEBUG)
43 : #define MUTEX_NONE
44 : #endif
45 :
46 : // #define DEBUG_MUTEX
47 :
48 : #if defined(DEBUG) && \
49 : (defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)))
50 : #ifndef DEBUG_CONTENTION
51 : #define DEBUG_CONTENTION
52 : #endif
53 : #endif
54 :
55 : typedef struct _CPLSpinLock CPLSpinLock;
56 :
57 : struct _CPLLock
58 : {
59 : CPLLockType eType;
60 :
61 : union
62 : {
63 : CPLMutex *hMutex;
64 : CPLSpinLock *hSpinLock;
65 : } u;
66 :
67 : #ifdef DEBUG_CONTENTION
68 : bool bDebugPerfAsked;
69 : bool bDebugPerf;
70 : volatile int nCurrentHolders;
71 : GUIntBig nStartTime;
72 : GIntBig nMaxDiff;
73 : double dfAvgDiff;
74 : GUIntBig nIters;
75 : #endif
76 : };
77 :
78 : #ifdef DEBUG_CONTENTION
79 :
80 : #if defined(__x86_64)
81 : #define GCC_CPUID(level, a, b, c, d) \
82 : __asm__ volatile("xchgq %%rbx, %q1\n" \
83 : "cpuid\n" \
84 : "xchgq %%rbx, %q1" \
85 : : "=a"(a), "=r"(b), "=c"(c), "=d"(d) \
86 : : "0"(level))
87 : #else
88 : #define GCC_CPUID(level, a, b, c, d) \
89 : __asm__ volatile("xchgl %%ebx, %1\n" \
90 : "cpuid\n" \
91 : "xchgl %%ebx, %1" \
92 : : "=a"(a), "=r"(b), "=c"(c), "=d"(d) \
93 : : "0"(level))
94 : #endif
95 :
96 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 1952510 : __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 69182300 : CPLMutexHolder::CPLMutexHolder(CPLMutex **phMutex, double dfWaitInSeconds,
155 69182300 : const char *pszFileIn, int nLineIn, int nOptions)
156 69182300 : : hMutex(nullptr), pszFile(pszFileIn), nLine(nLineIn)
157 : {
158 69182300 : if (phMutex == nullptr)
159 : {
160 0 : fprintf(stderr, "CPLMutexHolder: phMutex )) NULL !\n");
161 0 : hMutex = nullptr;
162 0 : return;
163 : }
164 :
165 : #ifdef DEBUG_MUTEX
166 : // There is no way to use CPLDebug() here because it works with
167 : // mutexes itself so we will fall in infinite recursion.
168 : // fprintf() will do the job right.
169 : fprintf(stderr, "CPLMutexHolder: Request %p for pid %ld at %d/%s.\n",
170 : *phMutex, static_cast<long>(CPLGetPID()), nLine, pszFile);
171 : #else
172 : // TODO(schwehr): Find a better way to do handle this.
173 : (void)pszFile;
174 : (void)nLine;
175 : #endif
176 :
177 69182300 : if (!CPLCreateOrAcquireMutexEx(phMutex, dfWaitInSeconds, nOptions))
178 : {
179 0 : 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 69189600 : 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 5267 : static CPLMutex *GetMutexHolderMutexMember(CPLMutex *hMutexIn,
207 : double dfWaitInSeconds)
208 : {
209 5267 : if (hMutexIn && !CPLAcquireMutex(hMutexIn, dfWaitInSeconds))
210 : {
211 0 : fprintf(stderr, "CPLMutexHolder: Failed to acquire mutex!\n");
212 0 : return nullptr;
213 : }
214 5267 : return hMutexIn;
215 : }
216 :
217 5267 : CPLMutexHolder::CPLMutexHolder(CPLMutex *hMutexIn, double dfWaitInSeconds,
218 5267 : const char *pszFileIn, int nLineIn)
219 5267 : : hMutex(GetMutexHolderMutexMember(hMutexIn, dfWaitInSeconds)),
220 5267 : pszFile(pszFileIn), nLine(nLineIn)
221 : {
222 5267 : }
223 : #endif // ndef MUTEX_NONE
224 :
225 : /************************************************************************/
226 : /* ~CPLMutexHolder() */
227 : /************************************************************************/
228 :
229 : #ifdef MUTEX_NONE
230 : CPLMutexHolder::~CPLMutexHolder()
231 : {
232 : }
233 : #else
234 138390000 : CPLMutexHolder::~CPLMutexHolder()
235 : {
236 69195000 : 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 69194900 : CPLReleaseMutex(hMutex);
243 : }
244 69194800 : }
245 : #endif // ndef MUTEX_NONE
246 :
247 1953660 : int CPLCreateOrAcquireMutex(CPLMutex **phMutex, double dfWaitInSeconds)
248 : {
249 1953660 : return CPLCreateOrAcquireMutexEx(phMutex, dfWaitInSeconds,
250 1956180 : 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 1537 : 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 1537 : }
425 :
426 : /************************************************************************/
427 : /* CPLCleanupTLSList() */
428 : /* */
429 : /* Free resources associated with a TLS vector (implementation */
430 : /* independent). */
431 : /************************************************************************/
432 :
433 3212 : static void CPLCleanupTLSList(void **papTLSList)
434 :
435 : {
436 : #ifdef DEBUG_VERBOSE
437 : printf("CPLCleanupTLSList(%p)\n", papTLSList); /*ok*/
438 : #endif
439 :
440 3212 : if (papTLSList == nullptr)
441 0 : return;
442 :
443 105976 : for (int i = 0; i < CTLS_MAX; i++)
444 : {
445 102764 : if (papTLSList[i] != nullptr && papTLSList[i + CTLS_MAX] != nullptr)
446 : {
447 6941 : CPLTLSFreeFunc pfnFree =
448 6941 : reinterpret_cast<CPLTLSFreeFunc>(papTLSList[i + CTLS_MAX]);
449 6941 : pfnFree(papTLSList[i]);
450 6941 : papTLSList[i] = nullptr;
451 : }
452 : }
453 :
454 3212 : 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 : } CPLStdCallThreadInfo;
1152 :
1153 : static DWORD WINAPI CPLStdCallThreadJacket(void *pData)
1154 :
1155 : {
1156 : CPLStdCallThreadInfo *psInfo = static_cast<CPLStdCallThreadInfo *>(pData);
1157 :
1158 : psInfo->pfnMain(psInfo->pAppData);
1159 :
1160 : if (psInfo->hThread == nullptr)
1161 : CPLFree(psInfo); // Only for detached threads.
1162 :
1163 : CPLCleanupTLS();
1164 :
1165 : return 0;
1166 : }
1167 :
1168 : /************************************************************************/
1169 : /* CPLCreateThread() */
1170 : /* */
1171 : /* The WIN32 CreateThread() call requires an entry point that */
1172 : /* has __stdcall conventions, so we provide a jacket function */
1173 : /* to supply that. */
1174 : /************************************************************************/
1175 :
1176 : int CPLCreateThread(CPLThreadFunc pfnMain, void *pThreadArg)
1177 :
1178 : {
1179 : CPLStdCallThreadInfo *psInfo = static_cast<CPLStdCallThreadInfo *>(
1180 : CPLCalloc(sizeof(CPLStdCallThreadInfo), 1));
1181 : psInfo->pAppData = pThreadArg;
1182 : psInfo->pfnMain = pfnMain;
1183 : psInfo->hThread = nullptr;
1184 :
1185 : DWORD nThreadId = 0;
1186 : HANDLE hThread =
1187 : CreateThread(nullptr, 0, CPLStdCallThreadJacket, psInfo, 0, &nThreadId);
1188 :
1189 : if (hThread == nullptr)
1190 : return -1;
1191 :
1192 : CloseHandle(hThread);
1193 :
1194 : return nThreadId;
1195 : }
1196 :
1197 : /************************************************************************/
1198 : /* CPLCreateJoinableThread() */
1199 : /************************************************************************/
1200 :
1201 : CPLJoinableThread *CPLCreateJoinableThread(CPLThreadFunc pfnMain,
1202 : void *pThreadArg)
1203 :
1204 : {
1205 : CPLStdCallThreadInfo *psInfo = static_cast<CPLStdCallThreadInfo *>(
1206 : CPLCalloc(sizeof(CPLStdCallThreadInfo), 1));
1207 : psInfo->pAppData = pThreadArg;
1208 : psInfo->pfnMain = pfnMain;
1209 :
1210 : DWORD nThreadId = 0;
1211 : HANDLE hThread =
1212 : CreateThread(nullptr, 0, CPLStdCallThreadJacket, psInfo, 0, &nThreadId);
1213 :
1214 : if (hThread == nullptr)
1215 : return nullptr;
1216 :
1217 : psInfo->hThread = hThread;
1218 : return reinterpret_cast<CPLJoinableThread *>(psInfo);
1219 : }
1220 :
1221 : /************************************************************************/
1222 : /* CPLJoinThread() */
1223 : /************************************************************************/
1224 :
1225 : void CPLJoinThread(CPLJoinableThread *hJoinableThread)
1226 : {
1227 : CPLStdCallThreadInfo *psInfo =
1228 : reinterpret_cast<CPLStdCallThreadInfo *>(hJoinableThread);
1229 :
1230 : WaitForSingleObject(psInfo->hThread, INFINITE);
1231 : CloseHandle(psInfo->hThread);
1232 : CPLFree(psInfo);
1233 : }
1234 :
1235 : /************************************************************************/
1236 : /* CPLSleep() */
1237 : /************************************************************************/
1238 :
1239 : void CPLSleep(double dfWaitInSeconds)
1240 :
1241 : {
1242 : Sleep(static_cast<DWORD>(dfWaitInSeconds * 1000.0));
1243 : }
1244 :
1245 : static bool bTLSKeySetup = false;
1246 : static DWORD nTLSKey = 0;
1247 :
1248 : /************************************************************************/
1249 : /* CPLGetTLSList() */
1250 : /************************************************************************/
1251 :
1252 : static void **CPLGetTLSList(int *pbMemoryErrorOccurred)
1253 :
1254 : {
1255 : void **papTLSList = nullptr;
1256 :
1257 : if (pbMemoryErrorOccurred)
1258 : *pbMemoryErrorOccurred = FALSE;
1259 : if (!bTLSKeySetup)
1260 : {
1261 : nTLSKey = TlsAlloc();
1262 : if (nTLSKey == TLS_OUT_OF_INDEXES)
1263 : {
1264 : if (pbMemoryErrorOccurred)
1265 : {
1266 : *pbMemoryErrorOccurred = TRUE;
1267 : fprintf(stderr, "CPLGetTLSList(): TlsAlloc() failed!\n");
1268 : return nullptr;
1269 : }
1270 : CPLEmergencyError("CPLGetTLSList(): TlsAlloc() failed!");
1271 : }
1272 : bTLSKeySetup = true;
1273 : }
1274 :
1275 : papTLSList = static_cast<void **>(TlsGetValue(nTLSKey));
1276 : if (papTLSList == nullptr)
1277 : {
1278 : papTLSList =
1279 : static_cast<void **>(VSICalloc(sizeof(void *), CTLS_MAX * 2));
1280 : if (papTLSList == nullptr)
1281 : {
1282 : if (pbMemoryErrorOccurred)
1283 : {
1284 : *pbMemoryErrorOccurred = TRUE;
1285 : fprintf(stderr,
1286 : "CPLGetTLSList() failed to allocate TLS list!\n");
1287 : return nullptr;
1288 : }
1289 : CPLEmergencyError("CPLGetTLSList() failed to allocate TLS list!");
1290 : }
1291 : if (TlsSetValue(nTLSKey, papTLSList) == 0)
1292 : {
1293 : if (pbMemoryErrorOccurred)
1294 : {
1295 : *pbMemoryErrorOccurred = TRUE;
1296 : fprintf(stderr, "CPLGetTLSList(): TlsSetValue() failed!\n");
1297 : return nullptr;
1298 : }
1299 : CPLEmergencyError("CPLGetTLSList(): TlsSetValue() failed!");
1300 : }
1301 : }
1302 :
1303 : return papTLSList;
1304 : }
1305 :
1306 : /************************************************************************/
1307 : /* CPLFinalizeTLS() */
1308 : /************************************************************************/
1309 :
1310 : void CPLFinalizeTLS()
1311 : {
1312 : CPLCleanupTLS();
1313 : }
1314 :
1315 : /************************************************************************/
1316 : /* CPLCleanupTLS() */
1317 : /************************************************************************/
1318 :
1319 : void CPLCleanupTLS()
1320 :
1321 : {
1322 : if (!bTLSKeySetup)
1323 : return;
1324 :
1325 : void **papTLSList = static_cast<void **>(TlsGetValue(nTLSKey));
1326 : if (papTLSList == nullptr)
1327 : return;
1328 :
1329 : TlsSetValue(nTLSKey, nullptr);
1330 :
1331 : CPLCleanupTLSList(papTLSList);
1332 : }
1333 :
1334 : // endif CPL_MULTIPROC_WIN32
1335 :
1336 : #elif defined(CPL_MULTIPROC_PTHREAD)
1337 :
1338 : #include <pthread.h>
1339 : #include <time.h>
1340 : #include <unistd.h>
1341 : #include <sys/time.h>
1342 :
1343 : #ifdef HAVE_SCHED_GETAFFINITY
1344 : #include <sched.h>
1345 : #endif
1346 :
1347 : /************************************************************************/
1348 : /* ==================================================================== */
1349 : /* CPL_MULTIPROC_PTHREAD */
1350 : /* */
1351 : /* PTHREAD Implementation of multiprocessing functions. */
1352 : /* ==================================================================== */
1353 : /************************************************************************/
1354 :
1355 : /************************************************************************/
1356 : /* CPLGetNumCPUs() */
1357 : /************************************************************************/
1358 :
1359 4744 : int CPLGetNumCPUs()
1360 : {
1361 : int nCPUs;
1362 : #ifdef _SC_NPROCESSORS_ONLN
1363 4744 : nCPUs = static_cast<int>(sysconf(_SC_NPROCESSORS_ONLN));
1364 : #else
1365 : nCPUs = 1;
1366 : #endif
1367 :
1368 : #ifdef HAVE_SCHED_GETAFFINITY
1369 4744 : if (nCPUs > 1)
1370 : {
1371 4744 : cpu_set_t *set = CPU_ALLOC(nCPUs);
1372 4744 : if (set)
1373 : {
1374 4744 : size_t sizeof_set = CPU_ALLOC_SIZE(nCPUs);
1375 4744 : CPU_ZERO_S(sizeof_set, set);
1376 4744 : if (sched_getaffinity(getpid(), sizeof_set, set) == 0)
1377 4744 : nCPUs = CPU_COUNT_S(sizeof_set, set);
1378 : else
1379 0 : CPLDebug("CPL", "sched_getaffinity() failed");
1380 4744 : CPU_FREE(set);
1381 : }
1382 : }
1383 : #endif
1384 :
1385 4744 : return nCPUs;
1386 : }
1387 :
1388 : /************************************************************************/
1389 : /* CPLCreateOrAcquireMutex() */
1390 : /************************************************************************/
1391 : #ifdef HAVE_GCC_WARNING_ZERO_AS_NULL_POINTER_CONSTANT
1392 : #pragma GCC diagnostic push
1393 : #pragma GCC diagnostic ignored "-Wzero-as-null-pointer-constant"
1394 : #endif
1395 : static pthread_mutex_t global_mutex = PTHREAD_MUTEX_INITIALIZER;
1396 : #ifdef HAVE_GCC_WARNING_ZERO_AS_NULL_POINTER_CONSTANT
1397 : #pragma GCC diagnostic pop
1398 : #endif
1399 :
1400 : static CPLMutex *CPLCreateMutexInternal(bool bAlreadyInGlobalLock,
1401 : int nOptions);
1402 :
1403 71134600 : int CPLCreateOrAcquireMutexEx(CPLMutex **phMutex, double dfWaitInSeconds,
1404 : int nOptions)
1405 :
1406 : {
1407 71134600 : pthread_mutex_lock(&global_mutex);
1408 71146400 : if (*phMutex == nullptr)
1409 : {
1410 38696 : *phMutex = CPLCreateMutexInternal(true, nOptions);
1411 38696 : const bool bSuccess = *phMutex != nullptr;
1412 38696 : pthread_mutex_unlock(&global_mutex);
1413 38696 : if (!bSuccess)
1414 0 : return false;
1415 : }
1416 : else
1417 : {
1418 71107700 : pthread_mutex_unlock(&global_mutex);
1419 : }
1420 :
1421 71143600 : return CPL_TO_BOOL(CPLAcquireMutex(*phMutex, dfWaitInSeconds));
1422 : }
1423 :
1424 : /************************************************************************/
1425 : /* CPLCreateOrAcquireMutexInternal() */
1426 : /************************************************************************/
1427 :
1428 4992 : static bool CPLCreateOrAcquireMutexInternal(CPLLock **phLock,
1429 : double dfWaitInSeconds,
1430 : CPLLockType eType)
1431 : {
1432 4992 : pthread_mutex_lock(&global_mutex);
1433 4992 : if (*phLock == nullptr)
1434 : {
1435 511 : *phLock = static_cast<CPLLock *>(calloc(1, sizeof(CPLLock)));
1436 511 : if (*phLock)
1437 : {
1438 511 : (*phLock)->eType = eType;
1439 1022 : (*phLock)->u.hMutex = CPLCreateMutexInternal(
1440 511 : true, eType == LOCK_RECURSIVE_MUTEX ? CPL_MUTEX_RECURSIVE
1441 : : CPL_MUTEX_ADAPTIVE);
1442 511 : if ((*phLock)->u.hMutex == nullptr)
1443 : {
1444 0 : free(*phLock);
1445 0 : *phLock = nullptr;
1446 : }
1447 : }
1448 511 : const bool bSuccess = *phLock != nullptr;
1449 511 : pthread_mutex_unlock(&global_mutex);
1450 511 : if (!bSuccess)
1451 0 : return false;
1452 : }
1453 : else
1454 : {
1455 4481 : pthread_mutex_unlock(&global_mutex);
1456 : }
1457 :
1458 4992 : return CPL_TO_BOOL(CPLAcquireMutex((*phLock)->u.hMutex, dfWaitInSeconds));
1459 : }
1460 :
1461 : /************************************************************************/
1462 : /* CPLGetThreadingModel() */
1463 : /************************************************************************/
1464 :
1465 29 : const char *CPLGetThreadingModel()
1466 :
1467 : {
1468 29 : return "pthread";
1469 : }
1470 :
1471 : /************************************************************************/
1472 : /* CPLCreateMutex() */
1473 : /************************************************************************/
1474 :
1475 : typedef struct _MutexLinkedElt MutexLinkedElt;
1476 :
1477 : struct _MutexLinkedElt
1478 : {
1479 : pthread_mutex_t sMutex;
1480 : int nOptions;
1481 : _MutexLinkedElt *psPrev;
1482 : _MutexLinkedElt *psNext;
1483 : };
1484 :
1485 : static MutexLinkedElt *psMutexList = nullptr;
1486 :
1487 127326 : static void CPLInitMutex(MutexLinkedElt *psItem)
1488 : {
1489 127326 : if (psItem->nOptions == CPL_MUTEX_REGULAR)
1490 : {
1491 : #ifdef HAVE_GCC_WARNING_ZERO_AS_NULL_POINTER_CONSTANT
1492 : #pragma GCC diagnostic push
1493 : #pragma GCC diagnostic ignored "-Wzero-as-null-pointer-constant"
1494 : #endif
1495 0 : pthread_mutex_t tmp_mutex = PTHREAD_MUTEX_INITIALIZER;
1496 : #ifdef HAVE_GCC_WARNING_ZERO_AS_NULL_POINTER_CONSTANT
1497 : #pragma GCC diagnostic pop
1498 : #endif
1499 0 : psItem->sMutex = tmp_mutex;
1500 0 : return;
1501 : }
1502 :
1503 : // When an adaptive mutex is required, we can safely fallback to regular
1504 : // mutex if we don't have HAVE_PTHREAD_MUTEX_ADAPTIVE_NP.
1505 127326 : if (psItem->nOptions == CPL_MUTEX_ADAPTIVE)
1506 : {
1507 : #if defined(HAVE_PTHREAD_MUTEX_ADAPTIVE_NP)
1508 : pthread_mutexattr_t attr;
1509 581 : pthread_mutexattr_init(&attr);
1510 581 : pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ADAPTIVE_NP);
1511 581 : pthread_mutex_init(&(psItem->sMutex), &attr);
1512 : #else
1513 : pthread_mutex_t tmp_mutex = PTHREAD_MUTEX_INITIALIZER;
1514 : psItem->sMutex = tmp_mutex;
1515 : #endif
1516 581 : return;
1517 : }
1518 :
1519 : #if defined(PTHREAD_MUTEX_RECURSIVE) || defined(HAVE_PTHREAD_MUTEX_RECURSIVE)
1520 : {
1521 : pthread_mutexattr_t attr;
1522 126745 : pthread_mutexattr_init(&attr);
1523 126744 : pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
1524 126744 : pthread_mutex_init(&(psItem->sMutex), &attr);
1525 : }
1526 : // BSDs have PTHREAD_MUTEX_RECURSIVE as an enum, not a define.
1527 : // But they have #define MUTEX_TYPE_COUNTING_FAST PTHREAD_MUTEX_RECURSIVE
1528 : #elif defined(MUTEX_TYPE_COUNTING_FAST)
1529 : {
1530 : pthread_mutexattr_t attr;
1531 : pthread_mutexattr_init(&attr);
1532 : pthread_mutexattr_settype(&attr, MUTEX_TYPE_COUNTING_FAST);
1533 : pthread_mutex_init(&(psItem->sMutex), &attr);
1534 : }
1535 : #elif defined(PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP)
1536 : pthread_mutex_t tmp_mutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
1537 : psItem->sMutex = tmp_mutex;
1538 : #else
1539 : #error "Recursive mutexes apparently unsupported, configure --without-threads"
1540 : #endif
1541 : }
1542 :
1543 127322 : static CPLMutex *CPLCreateMutexInternal(bool bAlreadyInGlobalLock, int nOptions)
1544 : {
1545 : MutexLinkedElt *psItem =
1546 127322 : static_cast<MutexLinkedElt *>(malloc(sizeof(MutexLinkedElt)));
1547 127322 : if (psItem == nullptr)
1548 : {
1549 0 : fprintf(stderr, "CPLCreateMutexInternal() failed.\n");
1550 0 : return nullptr;
1551 : }
1552 :
1553 127322 : if (!bAlreadyInGlobalLock)
1554 88115 : pthread_mutex_lock(&global_mutex);
1555 127326 : psItem->psPrev = nullptr;
1556 127326 : psItem->psNext = psMutexList;
1557 127326 : if (psMutexList)
1558 125690 : psMutexList->psPrev = psItem;
1559 127326 : psMutexList = psItem;
1560 127326 : if (!bAlreadyInGlobalLock)
1561 88119 : pthread_mutex_unlock(&global_mutex);
1562 :
1563 127326 : psItem->nOptions = nOptions;
1564 127326 : CPLInitMutex(psItem);
1565 :
1566 127325 : return reinterpret_cast<CPLMutex *>(psItem);
1567 : }
1568 :
1569 88045 : CPLMutex *CPLCreateMutex()
1570 : {
1571 88045 : CPLMutex *mutex = CPLCreateMutexInternal(false, CPL_MUTEX_RECURSIVE);
1572 88048 : if (mutex)
1573 88048 : CPLAcquireMutex(mutex, 0);
1574 88048 : return mutex;
1575 : }
1576 :
1577 70 : CPLMutex *CPLCreateMutexEx(int nOptions)
1578 : {
1579 70 : CPLMutex *mutex = CPLCreateMutexInternal(false, nOptions);
1580 70 : if (mutex)
1581 70 : CPLAcquireMutex(mutex, 0);
1582 70 : return mutex;
1583 : }
1584 :
1585 : /************************************************************************/
1586 : /* CPLAcquireMutex() */
1587 : /************************************************************************/
1588 :
1589 97731000 : int CPLAcquireMutex(CPLMutex *hMutexIn, double /* dfWaitInSeconds */)
1590 : {
1591 : // TODO: Need to add timeout support.
1592 97731000 : MutexLinkedElt *psItem = reinterpret_cast<MutexLinkedElt *>(hMutexIn);
1593 97731000 : const int err = pthread_mutex_lock(&(psItem->sMutex));
1594 :
1595 97739700 : if (err != 0)
1596 : {
1597 0 : if (err == EDEADLK)
1598 0 : fprintf(stderr, "CPLAcquireMutex: Error = %d/EDEADLK\n", err);
1599 : else
1600 0 : fprintf(stderr, "CPLAcquireMutex: Error = %d (%s)\n", err,
1601 : strerror(err));
1602 :
1603 0 : return FALSE;
1604 : }
1605 :
1606 97739700 : return TRUE;
1607 : }
1608 :
1609 : /************************************************************************/
1610 : /* CPLReleaseMutex() */
1611 : /************************************************************************/
1612 :
1613 97738600 : void CPLReleaseMutex(CPLMutex *hMutexIn)
1614 :
1615 : {
1616 97738600 : MutexLinkedElt *psItem = reinterpret_cast<MutexLinkedElt *>(hMutexIn);
1617 97738600 : const int err = pthread_mutex_unlock(&(psItem->sMutex));
1618 97737400 : if (err != 0)
1619 : {
1620 0 : fprintf(stderr, "CPLReleaseMutex: Error = %d (%s)\n", err,
1621 : strerror(err));
1622 : }
1623 97737400 : }
1624 :
1625 : /************************************************************************/
1626 : /* CPLDestroyMutex() */
1627 : /************************************************************************/
1628 :
1629 121070 : void CPLDestroyMutex(CPLMutex *hMutexIn)
1630 :
1631 : {
1632 121070 : MutexLinkedElt *psItem = reinterpret_cast<MutexLinkedElt *>(hMutexIn);
1633 121070 : const int err = pthread_mutex_destroy(&(psItem->sMutex));
1634 121070 : if (err != 0)
1635 : {
1636 0 : fprintf(stderr, "CPLDestroyMutex: Error = %d (%s)\n", err,
1637 : strerror(err));
1638 : }
1639 121070 : pthread_mutex_lock(&global_mutex);
1640 121071 : if (psItem->psPrev)
1641 77785 : psItem->psPrev->psNext = psItem->psNext;
1642 121071 : if (psItem->psNext)
1643 117049 : psItem->psNext->psPrev = psItem->psPrev;
1644 121071 : if (psItem == psMutexList)
1645 43286 : psMutexList = psItem->psNext;
1646 121071 : pthread_mutex_unlock(&global_mutex);
1647 121071 : free(hMutexIn);
1648 121071 : }
1649 :
1650 : /************************************************************************/
1651 : /* CPLReinitAllMutex() */
1652 : /************************************************************************/
1653 :
1654 : // Used by gdalclientserver.cpp just after forking, to avoid
1655 : // deadlocks while mixing threads with fork.
1656 : void CPLReinitAllMutex(); // TODO(schwehr): Put this in a header.
1657 :
1658 0 : void CPLReinitAllMutex()
1659 : {
1660 0 : MutexLinkedElt *psItem = psMutexList;
1661 0 : while (psItem != nullptr)
1662 : {
1663 0 : CPLInitMutex(psItem);
1664 0 : psItem = psItem->psNext;
1665 : }
1666 : #ifdef HAVE_GCC_WARNING_ZERO_AS_NULL_POINTER_CONSTANT
1667 : #pragma GCC diagnostic push
1668 : #pragma GCC diagnostic ignored "-Wzero-as-null-pointer-constant"
1669 : #endif
1670 0 : pthread_mutex_t tmp_global_mutex = PTHREAD_MUTEX_INITIALIZER;
1671 : #ifdef HAVE_GCC_WARNING_ZERO_AS_NULL_POINTER_CONSTANT
1672 : #pragma GCC diagnostic pop
1673 : #endif
1674 0 : global_mutex = tmp_global_mutex;
1675 0 : }
1676 :
1677 : /************************************************************************/
1678 : /* CPLCreateCond() */
1679 : /************************************************************************/
1680 :
1681 38522 : CPLCond *CPLCreateCond()
1682 : {
1683 : pthread_cond_t *pCond =
1684 38522 : static_cast<pthread_cond_t *>(malloc(sizeof(pthread_cond_t)));
1685 38522 : if (pCond && pthread_cond_init(pCond, nullptr) == 0)
1686 38520 : return reinterpret_cast<CPLCond *>(pCond);
1687 3 : fprintf(stderr, "CPLCreateCond() failed.\n");
1688 0 : free(pCond);
1689 0 : return nullptr;
1690 : }
1691 :
1692 : /************************************************************************/
1693 : /* CPLCondWait() */
1694 : /************************************************************************/
1695 :
1696 9533 : void CPLCondWait(CPLCond *hCond, CPLMutex *hMutex)
1697 : {
1698 9533 : pthread_cond_t *pCond = reinterpret_cast<pthread_cond_t *>(hCond);
1699 9533 : MutexLinkedElt *psItem = reinterpret_cast<MutexLinkedElt *>(hMutex);
1700 9533 : pthread_mutex_t *pMutex = &(psItem->sMutex);
1701 9533 : pthread_cond_wait(pCond, pMutex);
1702 9533 : }
1703 :
1704 : /************************************************************************/
1705 : /* CPLCondTimedWait() */
1706 : /************************************************************************/
1707 :
1708 0 : CPLCondTimedWaitReason CPLCondTimedWait(CPLCond *hCond, CPLMutex *hMutex,
1709 : double dfWaitInSeconds)
1710 : {
1711 0 : pthread_cond_t *pCond = reinterpret_cast<pthread_cond_t *>(hCond);
1712 0 : MutexLinkedElt *psItem = reinterpret_cast<MutexLinkedElt *>(hMutex);
1713 0 : pthread_mutex_t *pMutex = &(psItem->sMutex);
1714 : struct timeval tv;
1715 : struct timespec ts;
1716 :
1717 0 : gettimeofday(&tv, nullptr);
1718 0 : ts.tv_sec = time(nullptr) + static_cast<int>(dfWaitInSeconds);
1719 0 : ts.tv_nsec =
1720 0 : static_cast<int>(tv.tv_usec) * 1000 +
1721 0 : static_cast<int>(1000 * 1000 * 1000 * fmod(dfWaitInSeconds, 1));
1722 0 : ts.tv_sec += ts.tv_nsec / (1000 * 1000 * 1000);
1723 0 : ts.tv_nsec %= (1000 * 1000 * 1000);
1724 0 : int ret = pthread_cond_timedwait(pCond, pMutex, &ts);
1725 0 : if (ret == 0)
1726 0 : return COND_TIMED_WAIT_COND;
1727 0 : else if (ret == ETIMEDOUT)
1728 0 : return COND_TIMED_WAIT_TIME_OUT;
1729 : else
1730 0 : return COND_TIMED_WAIT_OTHER;
1731 : }
1732 :
1733 : /************************************************************************/
1734 : /* CPLCondSignal() */
1735 : /************************************************************************/
1736 :
1737 51834 : void CPLCondSignal(CPLCond *hCond)
1738 : {
1739 51834 : pthread_cond_t *pCond = reinterpret_cast<pthread_cond_t *>(hCond);
1740 51834 : pthread_cond_signal(pCond);
1741 51834 : }
1742 :
1743 : /************************************************************************/
1744 : /* CPLCondBroadcast() */
1745 : /************************************************************************/
1746 :
1747 49839 : void CPLCondBroadcast(CPLCond *hCond)
1748 : {
1749 49839 : pthread_cond_t *pCond = reinterpret_cast<pthread_cond_t *>(hCond);
1750 49839 : pthread_cond_broadcast(pCond);
1751 49839 : }
1752 :
1753 : /************************************************************************/
1754 : /* CPLDestroyCond() */
1755 : /************************************************************************/
1756 :
1757 38522 : void CPLDestroyCond(CPLCond *hCond)
1758 : {
1759 38522 : pthread_cond_t *pCond = reinterpret_cast<pthread_cond_t *>(hCond);
1760 38522 : pthread_cond_destroy(pCond);
1761 38522 : free(hCond);
1762 38522 : }
1763 :
1764 : /************************************************************************/
1765 : /* CPLLockFile() */
1766 : /* */
1767 : /* This is really a stub implementation, see first */
1768 : /* CPLLockFile() for caveats. */
1769 : /************************************************************************/
1770 :
1771 3 : void *CPLLockFile(const char *pszPath, double dfWaitInSeconds)
1772 :
1773 : {
1774 : /* -------------------------------------------------------------------- */
1775 : /* We use a lock file with a name derived from the file we want */
1776 : /* to lock to represent the file being locked. Note that for */
1777 : /* the stub implementation the target file does not even need */
1778 : /* to exist to be locked. */
1779 : /* -------------------------------------------------------------------- */
1780 3 : const size_t nLen = strlen(pszPath) + 30;
1781 3 : char *pszLockFilename = static_cast<char *>(CPLMalloc(nLen));
1782 3 : snprintf(pszLockFilename, nLen, "%s.lock", pszPath);
1783 :
1784 3 : FILE *fpLock = fopen(pszLockFilename, "r");
1785 3 : while (fpLock != nullptr && dfWaitInSeconds > 0.0)
1786 : {
1787 0 : fclose(fpLock);
1788 0 : CPLSleep(std::min(dfWaitInSeconds, 0.5));
1789 0 : dfWaitInSeconds -= 0.5;
1790 :
1791 0 : fpLock = fopen(pszLockFilename, "r");
1792 : }
1793 :
1794 3 : if (fpLock != nullptr)
1795 : {
1796 0 : fclose(fpLock);
1797 0 : CPLFree(pszLockFilename);
1798 0 : return nullptr;
1799 : }
1800 :
1801 3 : fpLock = fopen(pszLockFilename, "w");
1802 :
1803 3 : if (fpLock == nullptr)
1804 : {
1805 0 : CPLFree(pszLockFilename);
1806 0 : return nullptr;
1807 : }
1808 :
1809 3 : fwrite("held\n", 1, 5, fpLock);
1810 3 : fclose(fpLock);
1811 :
1812 3 : return pszLockFilename;
1813 : }
1814 :
1815 : /************************************************************************/
1816 : /* CPLUnlockFile() */
1817 : /************************************************************************/
1818 :
1819 3 : void CPLUnlockFile(void *hLock)
1820 :
1821 : {
1822 3 : char *pszLockFilename = static_cast<char *>(hLock);
1823 :
1824 3 : if (hLock == nullptr)
1825 0 : return;
1826 :
1827 3 : VSIUnlink(pszLockFilename);
1828 :
1829 3 : CPLFree(pszLockFilename);
1830 : }
1831 :
1832 : /************************************************************************/
1833 : /* CPLGetPID() */
1834 : /************************************************************************/
1835 :
1836 21616800 : GIntBig CPLGetPID()
1837 :
1838 : {
1839 21616800 : return reinterpret_cast<GIntBig>(reinterpret_cast<void *>(pthread_self()));
1840 : }
1841 :
1842 : static pthread_key_t oTLSKey;
1843 : static pthread_once_t oTLSKeySetup = PTHREAD_ONCE_INIT;
1844 :
1845 : /************************************************************************/
1846 : /* CPLMake_key() */
1847 : /************************************************************************/
1848 :
1849 1438 : static void CPLMake_key()
1850 :
1851 : {
1852 1438 : if (pthread_key_create(&oTLSKey, reinterpret_cast<void (*)(void *)>(
1853 1438 : CPLCleanupTLSList)) != 0)
1854 : {
1855 0 : CPLError(CE_Fatal, CPLE_AppDefined, "pthread_key_create() failed!");
1856 : }
1857 1438 : }
1858 :
1859 : /************************************************************************/
1860 : /* CPLGetTLSList() */
1861 : /************************************************************************/
1862 :
1863 62793100 : static void **CPLGetTLSList(int *pbMemoryErrorOccurred)
1864 :
1865 : {
1866 62793100 : if (pbMemoryErrorOccurred)
1867 59450800 : *pbMemoryErrorOccurred = FALSE;
1868 :
1869 62793100 : if (pthread_once(&oTLSKeySetup, CPLMake_key) != 0)
1870 : {
1871 0 : if (pbMemoryErrorOccurred)
1872 : {
1873 0 : fprintf(stderr, "CPLGetTLSList(): pthread_once() failed!\n");
1874 0 : *pbMemoryErrorOccurred = TRUE;
1875 0 : return nullptr;
1876 : }
1877 0 : CPLEmergencyError("CPLGetTLSList(): pthread_once() failed!");
1878 : }
1879 :
1880 62745600 : void **papTLSList = static_cast<void **>(pthread_getspecific(oTLSKey));
1881 62796100 : if (papTLSList == nullptr)
1882 : {
1883 : papTLSList =
1884 4224 : static_cast<void **>(VSICalloc(sizeof(void *), CTLS_MAX * 2));
1885 4322 : if (papTLSList == nullptr)
1886 : {
1887 0 : if (pbMemoryErrorOccurred)
1888 : {
1889 0 : fprintf(stderr,
1890 : "CPLGetTLSList() failed to allocate TLS list!\n");
1891 0 : *pbMemoryErrorOccurred = TRUE;
1892 0 : return nullptr;
1893 : }
1894 0 : CPLEmergencyError("CPLGetTLSList() failed to allocate TLS list!");
1895 : }
1896 4322 : if (pthread_setspecific(oTLSKey, papTLSList) != 0)
1897 : {
1898 0 : if (pbMemoryErrorOccurred)
1899 : {
1900 0 : fprintf(stderr,
1901 : "CPLGetTLSList(): pthread_setspecific() failed!\n");
1902 0 : *pbMemoryErrorOccurred = TRUE;
1903 0 : return nullptr;
1904 : }
1905 0 : CPLEmergencyError("CPLGetTLSList(): pthread_setspecific() failed!");
1906 : }
1907 : }
1908 :
1909 62796200 : return papTLSList;
1910 : }
1911 :
1912 : /************************************************************************/
1913 : /* CPLStdCallThreadJacket() */
1914 : /************************************************************************/
1915 :
1916 : typedef struct
1917 : {
1918 : void *pAppData;
1919 : CPLThreadFunc pfnMain;
1920 : pthread_t hThread;
1921 : bool bJoinable;
1922 : #ifdef CHECK_THREAD_CAN_ALLOCATE_TLS
1923 : bool bInitSucceeded;
1924 : bool bInitDone;
1925 : pthread_mutex_t sMutex;
1926 : pthread_cond_t sCond;
1927 : #endif
1928 : } CPLStdCallThreadInfo;
1929 :
1930 3728 : static void *CPLStdCallThreadJacket(void *pData)
1931 :
1932 : {
1933 3728 : CPLStdCallThreadInfo *psInfo = static_cast<CPLStdCallThreadInfo *>(pData);
1934 :
1935 : #ifdef CHECK_THREAD_CAN_ALLOCATE_TLS
1936 : int bMemoryError = FALSE;
1937 : CPLGetTLSList(&bMemoryError);
1938 : if (bMemoryError)
1939 : goto error;
1940 :
1941 : assert(pthread_mutex_lock(&(psInfo->sMutex)) == 0);
1942 : psInfo->bInitDone = true;
1943 : assert(pthread_cond_signal(&(psInfo->sCond)) == 0);
1944 : assert(pthread_mutex_unlock(&(psInfo->sMutex)) == 0);
1945 : #endif
1946 :
1947 3728 : psInfo->pfnMain(psInfo->pAppData);
1948 :
1949 2689 : if (!psInfo->bJoinable)
1950 1 : CPLFree(psInfo);
1951 :
1952 2689 : return nullptr;
1953 :
1954 : #ifdef CHECK_THREAD_CAN_ALLOCATE_TLS
1955 : error:
1956 : assert(pthread_mutex_lock(&(psInfo->sMutex)) == 0);
1957 : psInfo->bInitSucceeded = false;
1958 : psInfo->bInitDone = true;
1959 : assert(pthread_cond_signal(&(psInfo->sCond)) == 0);
1960 : assert(pthread_mutex_unlock(&(psInfo->sMutex)) == 0);
1961 : return nullptr;
1962 : #endif
1963 : }
1964 :
1965 : /************************************************************************/
1966 : /* CPLCreateThread() */
1967 : /* */
1968 : /* The WIN32 CreateThread() call requires an entry point that */
1969 : /* has __stdcall conventions, so we provide a jacket function */
1970 : /* to supply that. */
1971 : /************************************************************************/
1972 :
1973 1 : int CPLCreateThread(CPLThreadFunc pfnMain, void *pThreadArg)
1974 :
1975 : {
1976 : CPLStdCallThreadInfo *psInfo = static_cast<CPLStdCallThreadInfo *>(
1977 1 : VSI_CALLOC_VERBOSE(sizeof(CPLStdCallThreadInfo), 1));
1978 1 : if (psInfo == nullptr)
1979 0 : return -1;
1980 1 : psInfo->pAppData = pThreadArg;
1981 1 : psInfo->pfnMain = pfnMain;
1982 1 : psInfo->bJoinable = false;
1983 : #ifdef CHECK_THREAD_CAN_ALLOCATE_TLS
1984 : psInfo->bInitSucceeded = true;
1985 : psInfo->bInitDone = false;
1986 : pthread_mutex_t sMutex = PTHREAD_MUTEX_INITIALIZER;
1987 : psInfo->sMutex = sMutex;
1988 : if (pthread_cond_init(&(psInfo->sCond), nullptr) != 0)
1989 : {
1990 : CPLFree(psInfo);
1991 : fprintf(stderr, "CPLCreateThread() failed.\n");
1992 : return -1;
1993 : }
1994 : #endif
1995 :
1996 : pthread_attr_t hThreadAttr;
1997 1 : pthread_attr_init(&hThreadAttr);
1998 1 : pthread_attr_setdetachstate(&hThreadAttr, PTHREAD_CREATE_DETACHED);
1999 1 : if (pthread_create(&(psInfo->hThread), &hThreadAttr, CPLStdCallThreadJacket,
2000 1 : static_cast<void *>(psInfo)) != 0)
2001 : {
2002 : #ifdef CHECK_THREAD_CAN_ALLOCATE_TLS
2003 : pthread_cond_destroy(&(psInfo->sCond));
2004 : #endif
2005 0 : CPLFree(psInfo);
2006 0 : fprintf(stderr, "CPLCreateThread() failed.\n");
2007 0 : return -1;
2008 : }
2009 :
2010 : #ifdef CHECK_THREAD_CAN_ALLOCATE_TLS
2011 : bool bInitSucceeded;
2012 : while (true)
2013 : {
2014 : assert(pthread_mutex_lock(&(psInfo->sMutex)) == 0);
2015 : bool bInitDone = psInfo->bInitDone;
2016 : if (!bInitDone)
2017 : assert(pthread_cond_wait(&(psInfo->sCond), &(psInfo->sMutex)) == 0);
2018 : bInitSucceeded = psInfo->bInitSucceeded;
2019 : assert(pthread_mutex_unlock(&(psInfo->sMutex)) == 0);
2020 : if (bInitDone)
2021 : break;
2022 : }
2023 :
2024 : pthread_cond_destroy(&(psInfo->sCond));
2025 :
2026 : if (!bInitSucceeded)
2027 : {
2028 : CPLFree(psInfo);
2029 : fprintf(stderr, "CPLCreateThread() failed.\n");
2030 : return -1;
2031 : }
2032 : #endif
2033 :
2034 1 : return 1; // Can we return the actual thread pid?
2035 : }
2036 :
2037 : /************************************************************************/
2038 : /* CPLCreateJoinableThread() */
2039 : /************************************************************************/
2040 :
2041 3729 : CPLJoinableThread *CPLCreateJoinableThread(CPLThreadFunc pfnMain,
2042 : void *pThreadArg)
2043 :
2044 : {
2045 : CPLStdCallThreadInfo *psInfo = static_cast<CPLStdCallThreadInfo *>(
2046 3729 : VSI_CALLOC_VERBOSE(sizeof(CPLStdCallThreadInfo), 1));
2047 3729 : if (psInfo == nullptr)
2048 0 : return nullptr;
2049 3729 : psInfo->pAppData = pThreadArg;
2050 3729 : psInfo->pfnMain = pfnMain;
2051 3729 : psInfo->bJoinable = true;
2052 : #ifdef CHECK_THREAD_CAN_ALLOCATE_TLS
2053 : psInfo->bInitSucceeded = true;
2054 : psInfo->bInitDone = false;
2055 : pthread_mutex_t sMutex = PTHREAD_MUTEX_INITIALIZER;
2056 : psInfo->sMutex = sMutex;
2057 : {
2058 : int err = pthread_cond_init(&(psInfo->sCond), nullptr);
2059 : if (err != 0)
2060 : {
2061 : CPLFree(psInfo);
2062 : fprintf(stderr, "CPLCreateJoinableThread() failed: %s.\n",
2063 : strerror(err));
2064 : return nullptr;
2065 : }
2066 : }
2067 : #endif
2068 :
2069 : pthread_attr_t hThreadAttr;
2070 3729 : pthread_attr_init(&hThreadAttr);
2071 3729 : pthread_attr_setdetachstate(&hThreadAttr, PTHREAD_CREATE_JOINABLE);
2072 : int err =
2073 3729 : pthread_create(&(psInfo->hThread), &hThreadAttr, CPLStdCallThreadJacket,
2074 : static_cast<void *>(psInfo));
2075 3728 : if (err != 0)
2076 : {
2077 : #ifdef CHECK_THREAD_CAN_ALLOCATE_TLS
2078 : pthread_cond_destroy(&(psInfo->sCond));
2079 : #endif
2080 0 : CPLFree(psInfo);
2081 0 : fprintf(stderr, "CPLCreateJoinableThread() failed: %s.\n",
2082 : strerror(err));
2083 0 : return nullptr;
2084 : }
2085 :
2086 : #ifdef CHECK_THREAD_CAN_ALLOCATE_TLS
2087 : bool bInitSucceeded;
2088 : while (true)
2089 : {
2090 : assert(pthread_mutex_lock(&(psInfo->sMutex)) == 0);
2091 : bool bInitDone = psInfo->bInitDone;
2092 : if (!bInitDone)
2093 : assert(pthread_cond_wait(&(psInfo->sCond), &(psInfo->sMutex)) == 0);
2094 : bInitSucceeded = psInfo->bInitSucceeded;
2095 : assert(pthread_mutex_unlock(&(psInfo->sMutex)) == 0);
2096 : if (bInitDone)
2097 : break;
2098 : }
2099 :
2100 : pthread_cond_destroy(&(psInfo->sCond));
2101 :
2102 : if (!bInitSucceeded)
2103 : {
2104 : void *status;
2105 : pthread_join(psInfo->hThread, &status);
2106 : CPLFree(psInfo);
2107 : fprintf(stderr, "CPLCreateJoinableThread() failed.\n");
2108 : return nullptr;
2109 : }
2110 : #endif
2111 :
2112 3728 : return reinterpret_cast<CPLJoinableThread *>(psInfo);
2113 : }
2114 :
2115 : /************************************************************************/
2116 : /* CPLJoinThread() */
2117 : /************************************************************************/
2118 :
2119 2688 : void CPLJoinThread(CPLJoinableThread *hJoinableThread)
2120 : {
2121 2688 : CPLStdCallThreadInfo *psInfo =
2122 : reinterpret_cast<CPLStdCallThreadInfo *>(hJoinableThread);
2123 2688 : if (psInfo == nullptr)
2124 0 : return;
2125 :
2126 : void *status;
2127 2688 : pthread_join(psInfo->hThread, &status);
2128 :
2129 2688 : CPLFree(psInfo);
2130 : }
2131 :
2132 : /************************************************************************/
2133 : /* CPLSleep() */
2134 : /************************************************************************/
2135 :
2136 86 : void CPLSleep(double dfWaitInSeconds)
2137 :
2138 : {
2139 : struct timespec sRequest;
2140 : struct timespec sRemain;
2141 :
2142 86 : sRequest.tv_sec = static_cast<int>(floor(dfWaitInSeconds));
2143 86 : sRequest.tv_nsec =
2144 86 : static_cast<int>((dfWaitInSeconds - sRequest.tv_sec) * 1000000000);
2145 86 : nanosleep(&sRequest, &sRemain);
2146 86 : }
2147 :
2148 : /************************************************************************/
2149 : /* CPLFinalizeTLS() */
2150 : /************************************************************************/
2151 :
2152 426 : void CPLFinalizeTLS()
2153 : {
2154 426 : CPLCleanupTLS();
2155 : // See #5509 for the explanation why this may be needed.
2156 426 : pthread_key_delete(oTLSKey);
2157 426 : }
2158 :
2159 : /************************************************************************/
2160 : /* CPLCleanupTLS() */
2161 : /************************************************************************/
2162 :
2163 1538 : void CPLCleanupTLS()
2164 :
2165 : {
2166 1538 : void **papTLSList = static_cast<void **>(pthread_getspecific(oTLSKey));
2167 1538 : if (papTLSList == nullptr)
2168 1 : return;
2169 :
2170 1537 : pthread_setspecific(oTLSKey, nullptr);
2171 :
2172 1537 : CPLCleanupTLSList(papTLSList);
2173 : }
2174 :
2175 : /************************************************************************/
2176 : /* CPLCreateSpinLock() */
2177 : /************************************************************************/
2178 :
2179 : #if defined(HAVE_PTHREAD_SPIN_LOCK)
2180 : #define HAVE_SPINLOCK_IMPL
2181 :
2182 : struct _CPLSpinLock
2183 : {
2184 : pthread_spinlock_t spin;
2185 : };
2186 :
2187 : CPLSpinLock *CPLCreateSpinLock()
2188 : {
2189 : CPLSpinLock *psSpin =
2190 : static_cast<CPLSpinLock *>(malloc(sizeof(CPLSpinLock)));
2191 : if (psSpin != nullptr &&
2192 : pthread_spin_init(&(psSpin->spin), PTHREAD_PROCESS_PRIVATE) == 0)
2193 : {
2194 : return psSpin;
2195 : }
2196 : else
2197 : {
2198 : fprintf(stderr, "CPLCreateSpinLock() failed.\n");
2199 : free(psSpin);
2200 : return nullptr;
2201 : }
2202 : }
2203 :
2204 : /************************************************************************/
2205 : /* CPLAcquireSpinLock() */
2206 : /************************************************************************/
2207 :
2208 : int CPLAcquireSpinLock(CPLSpinLock *psSpin)
2209 : {
2210 : return pthread_spin_lock(&(psSpin->spin)) == 0;
2211 : }
2212 :
2213 : /************************************************************************/
2214 : /* CPLCreateOrAcquireSpinLockInternal() */
2215 : /************************************************************************/
2216 :
2217 : int CPLCreateOrAcquireSpinLockInternal(CPLLock **ppsLock)
2218 : {
2219 : pthread_mutex_lock(&global_mutex);
2220 : if (*ppsLock == nullptr)
2221 : {
2222 : *ppsLock = static_cast<CPLLock *>(calloc(1, sizeof(CPLLock)));
2223 : if (*ppsLock != nullptr)
2224 : {
2225 : (*ppsLock)->eType = LOCK_SPIN;
2226 : (*ppsLock)->u.hSpinLock = CPLCreateSpinLock();
2227 : if ((*ppsLock)->u.hSpinLock == nullptr)
2228 : {
2229 : free(*ppsLock);
2230 : *ppsLock = nullptr;
2231 : }
2232 : }
2233 : }
2234 : pthread_mutex_unlock(&global_mutex);
2235 : // coverity[missing_unlock]
2236 : return (*ppsLock != nullptr && CPLAcquireSpinLock((*ppsLock)->u.hSpinLock));
2237 : }
2238 :
2239 : /************************************************************************/
2240 : /* CPLReleaseSpinLock() */
2241 : /************************************************************************/
2242 :
2243 : void CPLReleaseSpinLock(CPLSpinLock *psSpin)
2244 : {
2245 : pthread_spin_unlock(&(psSpin->spin));
2246 : }
2247 :
2248 : /************************************************************************/
2249 : /* CPLDestroySpinLock() */
2250 : /************************************************************************/
2251 :
2252 : void CPLDestroySpinLock(CPLSpinLock *psSpin)
2253 : {
2254 : pthread_spin_destroy(&(psSpin->spin));
2255 : free(psSpin);
2256 : }
2257 : #endif // HAVE_PTHREAD_SPIN_LOCK
2258 :
2259 : #endif // def CPL_MULTIPROC_PTHREAD
2260 :
2261 : /************************************************************************/
2262 : /* CPLGetTLS() */
2263 : /************************************************************************/
2264 :
2265 1803090 : void *CPLGetTLS(int nIndex)
2266 :
2267 : {
2268 1803090 : void **l_papTLSList = CPLGetTLSList(nullptr);
2269 :
2270 1803080 : CPLAssert(nIndex >= 0 && nIndex < CTLS_MAX);
2271 :
2272 1803080 : return l_papTLSList[nIndex];
2273 : }
2274 :
2275 : /************************************************************************/
2276 : /* CPLGetTLSEx() */
2277 : /************************************************************************/
2278 :
2279 59505500 : void *CPLGetTLSEx(int nIndex, int *pbMemoryErrorOccurred)
2280 :
2281 : {
2282 59505500 : void **l_papTLSList = CPLGetTLSList(pbMemoryErrorOccurred);
2283 59484200 : if (l_papTLSList == nullptr)
2284 0 : return nullptr;
2285 :
2286 59484200 : CPLAssert(nIndex >= 0 && nIndex < CTLS_MAX);
2287 :
2288 59432300 : return l_papTLSList[nIndex];
2289 : }
2290 :
2291 : /************************************************************************/
2292 : /* CPLSetTLS() */
2293 : /************************************************************************/
2294 :
2295 20951 : void CPLSetTLS(int nIndex, void *pData, int bFreeOnExit)
2296 :
2297 : {
2298 20951 : CPLSetTLSWithFreeFunc(nIndex, pData, (bFreeOnExit) ? CPLFree : nullptr);
2299 20950 : }
2300 :
2301 : /************************************************************************/
2302 : /* CPLSetTLSWithFreeFunc() */
2303 : /************************************************************************/
2304 :
2305 : // Warning: The CPLTLSFreeFunc must not in any case directly or indirectly
2306 : // use or fetch any TLS data, or a terminating thread will hang!
2307 1505750 : void CPLSetTLSWithFreeFunc(int nIndex, void *pData, CPLTLSFreeFunc pfnFree)
2308 :
2309 : {
2310 1505750 : void **l_papTLSList = CPLGetTLSList(nullptr);
2311 :
2312 1501340 : CPLAssert(nIndex >= 0 && nIndex < CTLS_MAX);
2313 :
2314 1486250 : l_papTLSList[nIndex] = pData;
2315 1486250 : l_papTLSList[CTLS_MAX + nIndex] = reinterpret_cast<void *>(pfnFree);
2316 1486250 : }
2317 :
2318 : /************************************************************************/
2319 : /* CPLSetTLSWithFreeFuncEx() */
2320 : /************************************************************************/
2321 :
2322 : // Warning: the CPLTLSFreeFunc must not in any case directly or indirectly
2323 : // use or fetch any TLS data, or a terminating thread will hang!
2324 1529 : void CPLSetTLSWithFreeFuncEx(int nIndex, void *pData, CPLTLSFreeFunc pfnFree,
2325 : int *pbMemoryErrorOccurred)
2326 :
2327 : {
2328 1529 : void **l_papTLSList = CPLGetTLSList(pbMemoryErrorOccurred);
2329 :
2330 1529 : CPLAssert(nIndex >= 0 && nIndex < CTLS_MAX);
2331 :
2332 1529 : l_papTLSList[nIndex] = pData;
2333 1529 : l_papTLSList[CTLS_MAX + nIndex] = reinterpret_cast<void *>(pfnFree);
2334 1529 : }
2335 : #ifndef HAVE_SPINLOCK_IMPL
2336 :
2337 : // No spinlock specific API? Fallback to mutex.
2338 :
2339 : /************************************************************************/
2340 : /* CPLCreateSpinLock() */
2341 : /************************************************************************/
2342 :
2343 38205 : CPLSpinLock *CPLCreateSpinLock(void)
2344 : {
2345 38205 : CPLSpinLock *psSpin = reinterpret_cast<CPLSpinLock *>(CPLCreateMutex());
2346 38204 : if (psSpin)
2347 38204 : CPLReleaseSpinLock(psSpin);
2348 38203 : return psSpin;
2349 : }
2350 :
2351 : /************************************************************************/
2352 : /* CPLCreateOrAcquireSpinLock() */
2353 : /************************************************************************/
2354 :
2355 4 : int CPLCreateOrAcquireSpinLockInternal(CPLLock **ppsLock)
2356 : {
2357 4 : return CPLCreateOrAcquireMutexInternal(ppsLock, 1000, LOCK_ADAPTIVE_MUTEX);
2358 : }
2359 :
2360 : /************************************************************************/
2361 : /* CPLAcquireSpinLock() */
2362 : /************************************************************************/
2363 :
2364 6597550 : int CPLAcquireSpinLock(CPLSpinLock *psSpin)
2365 : {
2366 6597550 : return CPLAcquireMutex(reinterpret_cast<CPLMutex *>(psSpin), 1000);
2367 : }
2368 :
2369 : /************************************************************************/
2370 : /* CPLReleaseSpinLock() */
2371 : /************************************************************************/
2372 :
2373 6635740 : void CPLReleaseSpinLock(CPLSpinLock *psSpin)
2374 : {
2375 6635740 : CPLReleaseMutex(reinterpret_cast<CPLMutex *>(psSpin));
2376 6635770 : }
2377 :
2378 : /************************************************************************/
2379 : /* CPLDestroySpinLock() */
2380 : /************************************************************************/
2381 :
2382 38195 : void CPLDestroySpinLock(CPLSpinLock *psSpin)
2383 : {
2384 38195 : CPLDestroyMutex(reinterpret_cast<CPLMutex *>(psSpin));
2385 38205 : }
2386 :
2387 : #endif // HAVE_SPINLOCK_IMPL
2388 :
2389 : /************************************************************************/
2390 : /* CPLCreateLock() */
2391 : /************************************************************************/
2392 :
2393 38275 : CPLLock *CPLCreateLock(CPLLockType eType)
2394 : {
2395 38275 : switch (eType)
2396 : {
2397 70 : case LOCK_RECURSIVE_MUTEX:
2398 : case LOCK_ADAPTIVE_MUTEX:
2399 : {
2400 140 : CPLMutex *hMutex = CPLCreateMutexEx(eType == LOCK_RECURSIVE_MUTEX
2401 70 : ? CPL_MUTEX_RECURSIVE
2402 : : CPL_MUTEX_ADAPTIVE);
2403 70 : if (!hMutex)
2404 0 : return nullptr;
2405 70 : CPLReleaseMutex(hMutex);
2406 70 : CPLLock *psLock = static_cast<CPLLock *>(malloc(sizeof(CPLLock)));
2407 70 : if (psLock == nullptr)
2408 : {
2409 0 : fprintf(stderr, "CPLCreateLock() failed.\n");
2410 0 : CPLDestroyMutex(hMutex);
2411 0 : return nullptr;
2412 : }
2413 70 : psLock->eType = eType;
2414 70 : psLock->u.hMutex = hMutex;
2415 : #ifdef DEBUG_CONTENTION
2416 70 : psLock->bDebugPerf = false;
2417 70 : psLock->bDebugPerfAsked = false;
2418 70 : psLock->nCurrentHolders = 0;
2419 70 : psLock->nStartTime = 0;
2420 : #endif
2421 70 : return psLock;
2422 : }
2423 38205 : case LOCK_SPIN:
2424 : {
2425 38205 : CPLSpinLock *hSpinLock = CPLCreateSpinLock();
2426 38204 : if (!hSpinLock)
2427 0 : return nullptr;
2428 38204 : CPLLock *psLock = static_cast<CPLLock *>(malloc(sizeof(CPLLock)));
2429 38204 : if (psLock == nullptr)
2430 : {
2431 0 : fprintf(stderr, "CPLCreateLock() failed.\n");
2432 0 : CPLDestroySpinLock(hSpinLock);
2433 0 : return nullptr;
2434 : }
2435 38204 : psLock->eType = eType;
2436 38204 : psLock->u.hSpinLock = hSpinLock;
2437 : #ifdef DEBUG_CONTENTION
2438 38204 : psLock->bDebugPerf = false;
2439 38204 : psLock->bDebugPerfAsked = false;
2440 38204 : psLock->nCurrentHolders = 0;
2441 38204 : psLock->nStartTime = 0;
2442 : #endif
2443 38204 : return psLock;
2444 : }
2445 0 : default:
2446 0 : CPLAssert(false);
2447 : return nullptr;
2448 : }
2449 : }
2450 :
2451 : /************************************************************************/
2452 : /* CPLCreateOrAcquireLock() */
2453 : /************************************************************************/
2454 :
2455 4992 : int CPLCreateOrAcquireLock(CPLLock **ppsLock, CPLLockType eType)
2456 : {
2457 : #ifdef DEBUG_CONTENTION
2458 4992 : GUIntBig nStartTime = 0;
2459 4992 : if ((*ppsLock) && (*ppsLock)->bDebugPerfAsked)
2460 4 : nStartTime = CPLrdtsc();
2461 : #endif
2462 4992 : int ret = 0;
2463 :
2464 4992 : switch (eType)
2465 : {
2466 4988 : case LOCK_RECURSIVE_MUTEX:
2467 : case LOCK_ADAPTIVE_MUTEX:
2468 : {
2469 4988 : ret = CPLCreateOrAcquireMutexInternal(ppsLock, 1000, eType);
2470 4988 : break;
2471 : }
2472 4 : case LOCK_SPIN:
2473 : {
2474 4 : ret = CPLCreateOrAcquireSpinLockInternal(ppsLock);
2475 4 : break;
2476 : }
2477 0 : default:
2478 0 : CPLAssert(false);
2479 : return FALSE;
2480 : }
2481 : #ifdef DEBUG_CONTENTION
2482 4996 : if (ret && (*ppsLock)->bDebugPerfAsked &&
2483 4 : CPLAtomicInc(&((*ppsLock)->nCurrentHolders)) == 1)
2484 : {
2485 4 : (*ppsLock)->bDebugPerf = true;
2486 4 : (*ppsLock)->nStartTime = nStartTime;
2487 : }
2488 : #endif
2489 4992 : return ret;
2490 : }
2491 :
2492 : /************************************************************************/
2493 : /* CPLAcquireLock() */
2494 : /************************************************************************/
2495 :
2496 24577800 : int CPLAcquireLock(CPLLock *psLock)
2497 : {
2498 : #ifdef DEBUG_CONTENTION
2499 24577800 : GUIntBig nStartTime = 0;
2500 24577800 : if (psLock->bDebugPerfAsked)
2501 1952510 : nStartTime = CPLrdtsc();
2502 : #endif
2503 : int ret;
2504 24577000 : if (psLock->eType == LOCK_SPIN)
2505 6597560 : ret = CPLAcquireSpinLock(psLock->u.hSpinLock);
2506 : else
2507 17979500 : ret = CPLAcquireMutex(psLock->u.hMutex, 1000);
2508 : #ifdef DEBUG_CONTENTION
2509 26532800 : if (ret && psLock->bDebugPerfAsked &&
2510 1952510 : CPLAtomicInc(&(psLock->nCurrentHolders)) == 1)
2511 : {
2512 1952510 : psLock->bDebugPerf = true;
2513 1952510 : psLock->nStartTime = nStartTime;
2514 : }
2515 : #endif
2516 24580200 : return ret;
2517 : }
2518 :
2519 : /************************************************************************/
2520 : /* CPLReleaseLock() */
2521 : /************************************************************************/
2522 :
2523 24585200 : void CPLReleaseLock(CPLLock *psLock)
2524 : {
2525 : #ifdef DEBUG_CONTENTION
2526 24585200 : bool bHitMaxDiff = false;
2527 24585200 : GIntBig nMaxDiff = 0;
2528 24585200 : double dfAvgDiff = 0;
2529 24585200 : if (psLock->bDebugPerf && CPLAtomicDec(&(psLock->nCurrentHolders)) == 0)
2530 : {
2531 1952520 : const GUIntBig nStopTime = CPLrdtscp();
2532 : // coverity[missing_lock:FALSE]
2533 1952520 : const GIntBig nDiffTime =
2534 1952520 : static_cast<GIntBig>(nStopTime - psLock->nStartTime);
2535 1952520 : if (nDiffTime > psLock->nMaxDiff)
2536 : {
2537 40 : bHitMaxDiff = true;
2538 40 : psLock->nMaxDiff = nDiffTime;
2539 : }
2540 1952520 : nMaxDiff = psLock->nMaxDiff;
2541 1952520 : psLock->nIters++;
2542 1952520 : psLock->dfAvgDiff += (nDiffTime - psLock->dfAvgDiff) / psLock->nIters;
2543 1952520 : dfAvgDiff = psLock->dfAvgDiff;
2544 : }
2545 : #endif
2546 24585200 : if (psLock->eType == LOCK_SPIN)
2547 6597530 : CPLReleaseSpinLock(psLock->u.hSpinLock);
2548 : else
2549 17987700 : CPLReleaseMutex(psLock->u.hMutex);
2550 : #ifdef DEBUG_CONTENTION
2551 24585200 : if (psLock->bDebugPerf &&
2552 1952480 : (bHitMaxDiff || (psLock->nIters % 1000000) == (1000000 - 1)))
2553 : {
2554 40 : CPLDebug("LOCK", "Lock contention : max = " CPL_FRMT_GIB ", avg = %.0f",
2555 : nMaxDiff, dfAvgDiff);
2556 : }
2557 : #endif
2558 24585200 : }
2559 :
2560 : /************************************************************************/
2561 : /* CPLDestroyLock() */
2562 : /************************************************************************/
2563 :
2564 38645 : void CPLDestroyLock(CPLLock *psLock)
2565 : {
2566 38645 : if (psLock->eType == LOCK_SPIN)
2567 38205 : CPLDestroySpinLock(psLock->u.hSpinLock);
2568 : else
2569 440 : CPLDestroyMutex(psLock->u.hMutex);
2570 38645 : free(psLock);
2571 38645 : }
2572 :
2573 : /************************************************************************/
2574 : /* CPLLockSetDebugPerf() */
2575 : /************************************************************************/
2576 :
2577 : #ifdef DEBUG_CONTENTION
2578 4992 : void CPLLockSetDebugPerf(CPLLock *psLock, int bEnableIn)
2579 : {
2580 4992 : psLock->bDebugPerfAsked = CPL_TO_BOOL(bEnableIn);
2581 4992 : }
2582 : #else
2583 : void CPLLockSetDebugPerf(CPLLock * /* psLock */, int bEnableIn)
2584 : {
2585 : if (!bEnableIn)
2586 : return;
2587 :
2588 : static bool bOnce = false;
2589 : if (!bOnce)
2590 : {
2591 : bOnce = true;
2592 : CPLDebug("LOCK", "DEBUG_CONTENTION not available");
2593 : }
2594 : }
2595 : #endif
2596 :
2597 : /************************************************************************/
2598 : /* CPLLockHolder() */
2599 : /************************************************************************/
2600 :
2601 4992 : CPLLockHolder::CPLLockHolder(CPLLock **phLock, CPLLockType eType,
2602 4992 : const char *pszFileIn, int nLineIn)
2603 :
2604 : {
2605 : #ifndef MUTEX_NONE
2606 4992 : pszFile = pszFileIn;
2607 4992 : nLine = nLineIn;
2608 :
2609 : #ifdef DEBUG_MUTEX
2610 : // XXX: There is no way to use CPLDebug() here because it works with
2611 : // mutexes itself so we will fall in infinite recursion. Good old
2612 : // fprintf() will do the job right.
2613 : fprintf(stderr, "CPLLockHolder: Request %p for pid %ld at %d/%s.\n",
2614 : *phLock, static_cast<long>(CPLGetPID()), nLine, pszFile);
2615 : #endif
2616 :
2617 4992 : if (!CPLCreateOrAcquireLock(phLock, eType))
2618 : {
2619 0 : fprintf(stderr, "CPLLockHolder: Failed to acquire lock!\n");
2620 0 : hLock = nullptr;
2621 : }
2622 : else
2623 : {
2624 : #ifdef DEBUG_MUTEX
2625 : fprintf(stderr, "CPLLockHolder: Acquired %p for pid %ld at %d/%s.\n",
2626 : *phLock, static_cast<long>(CPLGetPID()), nLine, pszFile);
2627 : #endif
2628 :
2629 4992 : hLock = *phLock;
2630 : }
2631 : #endif // ndef MUTEX_NONE
2632 4992 : }
2633 :
2634 : /************************************************************************/
2635 : /* CPLLockHolder() */
2636 : /************************************************************************/
2637 :
2638 24574400 : CPLLockHolder::CPLLockHolder(CPLLock *hLockIn, const char *pszFileIn,
2639 24574400 : int nLineIn)
2640 :
2641 : {
2642 : #ifndef MUTEX_NONE
2643 24574400 : pszFile = pszFileIn;
2644 24574400 : nLine = nLineIn;
2645 24574400 : hLock = hLockIn;
2646 :
2647 24574400 : if (hLock != nullptr)
2648 : {
2649 24572900 : if (!CPLAcquireLock(hLock))
2650 : {
2651 0 : fprintf(stderr, "CPLLockHolder: Failed to acquire lock!\n");
2652 0 : hLock = nullptr;
2653 : }
2654 : }
2655 : #endif // ndef MUTEX_NONE
2656 24577000 : }
2657 :
2658 : /************************************************************************/
2659 : /* ~CPLLockHolder() */
2660 : /************************************************************************/
2661 :
2662 49160900 : CPLLockHolder::~CPLLockHolder()
2663 :
2664 : {
2665 : #ifndef MUTEX_NONE
2666 24580400 : if (hLock != nullptr)
2667 : {
2668 : #ifdef DEBUG_MUTEX
2669 : fprintf(stderr, "~CPLLockHolder: Release %p for pid %ld at %d/%s.\n",
2670 : hLock, static_cast<long>(CPLGetPID()), nLine, pszFile);
2671 : #endif
2672 24580400 : CPLReleaseLock(hLock);
2673 : }
2674 : #endif // ndef MUTEX_NONE
2675 24580400 : }
2676 :
2677 : /************************************************************************/
2678 : /* CPLGetCurrentProcessID() */
2679 : /************************************************************************/
2680 :
2681 : #ifdef CPL_MULTIPROC_WIN32
2682 :
2683 : int CPLGetCurrentProcessID()
2684 : {
2685 : return GetCurrentProcessId();
2686 : }
2687 :
2688 : #else
2689 :
2690 : #include <sys/types.h>
2691 : #include <unistd.h>
2692 :
2693 2465 : int CPLGetCurrentProcessID()
2694 : {
2695 2465 : return getpid();
2696 : }
2697 :
2698 : #endif
|