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 1952510 : 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 1952510 : GCC_CPUID(0, unused1, unused2, unused3, unused4);
105 1952510 : __asm__ volatile("rdtsc" : "=a"(a), "=d"(d));
106 1952510 : return static_cast<GUIntBig>(a) | (static_cast<GUIntBig>(d) << 32);
107 : }
108 :
109 1952510 : 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 1952510 : __asm__ volatile("rdtscp" : "=a"(a), "=d"(d));
118 1952510 : GCC_CPUID(0, unused1, unused2, unused3, unused4);
119 1952510 : 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 66456700 : CPLMutexHolder::CPLMutexHolder(CPLMutex **phMutex, double dfWaitInSeconds,
155 66456700 : const char *pszFileIn, int nLineIn, int nOptions)
156 66456700 : : hMutex(nullptr), pszFile(pszFileIn), nLine(nLineIn)
157 : {
158 66456700 : 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 66456700 : if (!CPLCreateOrAcquireMutexEx(phMutex, dfWaitInSeconds, nOptions))
178 : {
179 13 : 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 66467400 : 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 15091 : static CPLMutex *GetMutexHolderMutexMember(CPLMutex *hMutexIn,
207 : double dfWaitInSeconds)
208 : {
209 15091 : if (hMutexIn && !CPLAcquireMutex(hMutexIn, dfWaitInSeconds))
210 : {
211 0 : fprintf(stderr, "CPLMutexHolder: Failed to acquire mutex!\n");
212 0 : return nullptr;
213 : }
214 15091 : return hMutexIn;
215 : }
216 :
217 15091 : CPLMutexHolder::CPLMutexHolder(CPLMutex *hMutexIn, double dfWaitInSeconds,
218 15091 : const char *pszFileIn, int nLineIn)
219 15091 : : hMutex(GetMutexHolderMutexMember(hMutexIn, dfWaitInSeconds)),
220 15091 : pszFile(pszFileIn), nLine(nLineIn)
221 : {
222 15091 : }
223 : #endif // ndef MUTEX_NONE
224 :
225 : /************************************************************************/
226 : /* ~CPLMutexHolder() */
227 : /************************************************************************/
228 :
229 : #ifdef MUTEX_NONE
230 : CPLMutexHolder::~CPLMutexHolder()
231 : {
232 : }
233 : #else
234 132965000 : CPLMutexHolder::~CPLMutexHolder()
235 : {
236 66482600 : 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 66482500 : CPLReleaseMutex(hMutex);
243 : }
244 66482300 : }
245 : #endif // ndef MUTEX_NONE
246 :
247 1323850 : int CPLCreateOrAcquireMutex(CPLMutex **phMutex, double dfWaitInSeconds)
248 : {
249 1323850 : return CPLCreateOrAcquireMutexEx(phMutex, dfWaitInSeconds,
250 1323850 : 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 1370 : 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 1370 : }
425 :
426 : /************************************************************************/
427 : /* CPLCleanupTLSList() */
428 : /* */
429 : /* Free resources associated with a TLS vector (implementation */
430 : /* independent). */
431 : /************************************************************************/
432 :
433 2985 : static void CPLCleanupTLSList(void **papTLSList)
434 :
435 : {
436 : #ifdef DEBUG_VERBOSE
437 : printf("CPLCleanupTLSList(%p)\n", papTLSList); /*ok*/
438 : #endif
439 :
440 2985 : if (papTLSList == nullptr)
441 0 : return;
442 :
443 98498 : for (int i = 0; i < CTLS_MAX; i++)
444 : {
445 95513 : if (papTLSList[i] != nullptr && papTLSList[i + CTLS_MAX] != nullptr)
446 : {
447 6823 : CPLTLSFreeFunc pfnFree =
448 6823 : reinterpret_cast<CPLTLSFreeFunc>(papTLSList[i + CTLS_MAX]);
449 6823 : pfnFree(papTLSList[i]);
450 6823 : papTLSList[i] = nullptr;
451 : }
452 : }
453 :
454 2985 : 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 : /* Lock a file. This implementation has a terrible race */
641 : /* condition. If we don't succeed in opening the lock file, we */
642 : /* assume we can create one and own the target file, but other */
643 : /* processes might easily try creating the target file at the */
644 : /* same time, overlapping us. Death! Mayhem! The traditional */
645 : /* solution is to use open() with _O_CREAT|_O_EXCL but this */
646 : /* function and these arguments aren't trivially portable. */
647 : /* Also, this still leaves a race condition on NFS drivers */
648 : /* (apparently). */
649 : /************************************************************************/
650 :
651 : void *CPLLockFile(const char *pszPath, double dfWaitInSeconds)
652 :
653 : {
654 : /* -------------------------------------------------------------------- */
655 : /* We use a lock file with a name derived from the file we want */
656 : /* to lock to represent the file being locked. Note that for */
657 : /* the stub implementation the target file does not even need */
658 : /* to exist to be locked. */
659 : /* -------------------------------------------------------------------- */
660 : char *pszLockFilename =
661 : static_cast<char *>(CPLMalloc(strlen(pszPath) + 30));
662 : snprintf(pszLockFilename, strlen(pszPath) + 30, "%s.lock", pszPath);
663 :
664 : FILE *fpLock = fopen(pszLockFilename, "r");
665 : while (fpLock != nullptr && dfWaitInSeconds > 0.0)
666 : {
667 : fclose(fpLock);
668 : CPLSleep(std::min(dfWaitInSeconds, 0.5));
669 : dfWaitInSeconds -= 0.5;
670 :
671 : fpLock = fopen(pszLockFilename, "r");
672 : }
673 :
674 : if (fpLock != nullptr)
675 : {
676 : fclose(fpLock);
677 : CPLFree(pszLockFilename);
678 : return nullptr;
679 : }
680 :
681 : fpLock = fopen(pszLockFilename, "w");
682 :
683 : if (fpLock == nullptr)
684 : {
685 : CPLFree(pszLockFilename);
686 : return nullptr;
687 : }
688 :
689 : fwrite("held\n", 1, 5, fpLock);
690 : fclose(fpLock);
691 :
692 : return pszLockFilename;
693 : }
694 :
695 : /************************************************************************/
696 : /* CPLUnlockFile() */
697 : /************************************************************************/
698 :
699 : void CPLUnlockFile(void *hLock)
700 :
701 : {
702 : char *pszLockFilename = static_cast<char *>(hLock);
703 :
704 : if (hLock == nullptr)
705 : return;
706 :
707 : VSIUnlink(pszLockFilename);
708 :
709 : CPLFree(pszLockFilename);
710 : }
711 :
712 : /************************************************************************/
713 : /* CPLGetPID() */
714 : /************************************************************************/
715 :
716 : GIntBig CPLGetPID()
717 :
718 : {
719 : return 1;
720 : }
721 :
722 : /************************************************************************/
723 : /* CPLCreateThread(); */
724 : /************************************************************************/
725 :
726 : int CPLCreateThread(CPLThreadFunc /* pfnMain */, void * /* pArg */)
727 : {
728 : CPLDebug("CPLCreateThread", "Fails to dummy implementation");
729 :
730 : return -1;
731 : }
732 :
733 : /************************************************************************/
734 : /* CPLCreateJoinableThread() */
735 : /************************************************************************/
736 :
737 : CPLJoinableThread *CPLCreateJoinableThread(CPLThreadFunc /* pfnMain */,
738 : void * /* pThreadArg */)
739 : {
740 : CPLDebug("CPLCreateJoinableThread", "Fails to dummy implementation");
741 :
742 : return nullptr;
743 : }
744 :
745 : /************************************************************************/
746 : /* CPLJoinThread() */
747 : /************************************************************************/
748 :
749 : void CPLJoinThread(CPLJoinableThread * /* hJoinableThread */)
750 : {
751 : }
752 :
753 : /************************************************************************/
754 : /* CPLSleep() */
755 : /************************************************************************/
756 :
757 : void CPLSleep(double dfWaitInSeconds)
758 : {
759 : time_t ltime;
760 :
761 : time(<ime);
762 : const time_t ttime = ltime + static_cast<int>(dfWaitInSeconds + 0.5);
763 :
764 : for (; ltime < ttime; time(<ime))
765 : {
766 : // Currently we just busy wait. Perhaps we could at least block on io?
767 : }
768 : }
769 :
770 : /************************************************************************/
771 : /* CPLGetTLSList() */
772 : /************************************************************************/
773 :
774 : static void **papTLSList = nullptr;
775 :
776 : static void **CPLGetTLSList(int *pbMemoryErrorOccurred)
777 :
778 : {
779 : if (pbMemoryErrorOccurred)
780 : *pbMemoryErrorOccurred = FALSE;
781 : if (papTLSList == nullptr)
782 : {
783 : papTLSList =
784 : static_cast<void **>(VSICalloc(sizeof(void *), CTLS_MAX * 2));
785 : if (papTLSList == nullptr)
786 : {
787 : if (pbMemoryErrorOccurred)
788 : {
789 : *pbMemoryErrorOccurred = TRUE;
790 : fprintf(stderr,
791 : "CPLGetTLSList() failed to allocate TLS list!\n");
792 : return nullptr;
793 : }
794 : CPLEmergencyError("CPLGetTLSList() failed to allocate TLS list!");
795 : }
796 : }
797 :
798 : return papTLSList;
799 : }
800 :
801 : /************************************************************************/
802 : /* CPLFinalizeTLS() */
803 : /************************************************************************/
804 :
805 : void CPLFinalizeTLS()
806 : {
807 : CPLCleanupTLS();
808 : }
809 :
810 : /************************************************************************/
811 : /* CPLCleanupTLS() */
812 : /************************************************************************/
813 :
814 : void CPLCleanupTLS()
815 :
816 : {
817 : CPLCleanupTLSList(papTLSList);
818 : papTLSList = nullptr;
819 : }
820 :
821 : // endif CPL_MULTIPROC_STUB
822 :
823 : #elif defined(CPL_MULTIPROC_WIN32)
824 :
825 : /************************************************************************/
826 : /* ==================================================================== */
827 : /* CPL_MULTIPROC_WIN32 */
828 : /* */
829 : /* WIN32 Implementation of multiprocessing functions. */
830 : /* ==================================================================== */
831 : /************************************************************************/
832 :
833 : /* InitializeCriticalSectionAndSpinCount requires _WIN32_WINNT >= 0x403 */
834 : #undef _WIN32_WINNT
835 : #define _WIN32_WINNT 0x0500
836 :
837 : #include <windows.h>
838 :
839 : /************************************************************************/
840 : /* CPLGetNumCPUs() */
841 : /************************************************************************/
842 :
843 : int CPLGetNumCPUs()
844 : {
845 : SYSTEM_INFO info;
846 : GetSystemInfo(&info);
847 : const DWORD dwNum = info.dwNumberOfProcessors;
848 : if (dwNum < 1)
849 : return 1;
850 : return static_cast<int>(dwNum);
851 : }
852 :
853 : /************************************************************************/
854 : /* CPLGetThreadingModel() */
855 : /************************************************************************/
856 :
857 : const char *CPLGetThreadingModel()
858 :
859 : {
860 : return "win32";
861 : }
862 :
863 : /************************************************************************/
864 : /* CPLCreateMutex() */
865 : /************************************************************************/
866 :
867 : CPLMutex *CPLCreateMutex()
868 :
869 : {
870 : #ifdef USE_WIN32_MUTEX
871 : HANDLE hMutex = CreateMutex(nullptr, TRUE, nullptr);
872 :
873 : return (CPLMutex *)hMutex;
874 : #else
875 :
876 : // Do not use CPLMalloc() since its debugging infrastructure
877 : // can call the CPL*Mutex functions.
878 : CRITICAL_SECTION *pcs =
879 : static_cast<CRITICAL_SECTION *>(malloc(sizeof(*pcs)));
880 : if (pcs)
881 : {
882 : InitializeCriticalSectionAndSpinCount(pcs, 4000);
883 : EnterCriticalSection(pcs);
884 : }
885 :
886 : return reinterpret_cast<CPLMutex *>(pcs);
887 : #endif
888 : }
889 :
890 : CPLMutex *CPLCreateMutexEx(int /* nOptions */)
891 :
892 : {
893 : return CPLCreateMutex();
894 : }
895 :
896 : /************************************************************************/
897 : /* CPLAcquireMutex() */
898 : /************************************************************************/
899 :
900 : int CPLAcquireMutex(CPLMutex *hMutexIn, double dfWaitInSeconds)
901 :
902 : {
903 : #ifdef USE_WIN32_MUTEX
904 : HANDLE hMutex = (HANDLE)hMutexIn;
905 : const DWORD hr =
906 : WaitForSingleObject(hMutex, static_cast<int>(dfWaitInSeconds * 1000));
907 :
908 : return hr != WAIT_TIMEOUT;
909 : #else
910 : CRITICAL_SECTION *pcs = reinterpret_cast<CRITICAL_SECTION *>(hMutexIn);
911 : BOOL ret;
912 :
913 : if (dfWaitInSeconds >= 1000.0)
914 : {
915 : // We assume this is the synonymous for infinite, so it is more
916 : // efficient to use EnterCriticalSection() directly
917 : EnterCriticalSection(pcs);
918 : ret = TRUE;
919 : }
920 : else
921 : {
922 : while ((ret = TryEnterCriticalSection(pcs)) == 0 &&
923 : dfWaitInSeconds > 0.0)
924 : {
925 : CPLSleep(std::min(dfWaitInSeconds, 0.01));
926 : dfWaitInSeconds -= 0.01;
927 : }
928 : }
929 :
930 : return ret;
931 : #endif
932 : }
933 :
934 : /************************************************************************/
935 : /* CPLReleaseMutex() */
936 : /************************************************************************/
937 :
938 : void CPLReleaseMutex(CPLMutex *hMutexIn)
939 :
940 : {
941 : #ifdef USE_WIN32_MUTEX
942 : HANDLE hMutex = (HANDLE)hMutexIn;
943 :
944 : ReleaseMutex(hMutex);
945 : #else
946 : CRITICAL_SECTION *pcs = reinterpret_cast<CRITICAL_SECTION *>(hMutexIn);
947 :
948 : LeaveCriticalSection(pcs);
949 : #endif
950 : }
951 :
952 : /************************************************************************/
953 : /* CPLDestroyMutex() */
954 : /************************************************************************/
955 :
956 : void CPLDestroyMutex(CPLMutex *hMutexIn)
957 :
958 : {
959 : #ifdef USE_WIN32_MUTEX
960 : HANDLE hMutex = (HANDLE)hMutexIn;
961 :
962 : CloseHandle(hMutex);
963 : #else
964 : CRITICAL_SECTION *pcs = reinterpret_cast<CRITICAL_SECTION *>(hMutexIn);
965 :
966 : DeleteCriticalSection(pcs);
967 : free(pcs);
968 : #endif
969 : }
970 :
971 : /************************************************************************/
972 : /* CPLCreateCond() */
973 : /************************************************************************/
974 :
975 : struct _WaiterItem
976 : {
977 : HANDLE hEvent;
978 : struct _WaiterItem *psNext;
979 : };
980 : typedef struct _WaiterItem WaiterItem;
981 :
982 : typedef struct
983 : {
984 : CPLMutex *hInternalMutex;
985 : WaiterItem *psWaiterList;
986 : } Win32Cond;
987 :
988 : CPLCond *CPLCreateCond()
989 : {
990 : Win32Cond *psCond = static_cast<Win32Cond *>(malloc(sizeof(Win32Cond)));
991 : if (psCond == nullptr)
992 : return nullptr;
993 : psCond->hInternalMutex = CPLCreateMutex();
994 : if (psCond->hInternalMutex == nullptr)
995 : {
996 : free(psCond);
997 : return nullptr;
998 : }
999 : CPLReleaseMutex(psCond->hInternalMutex);
1000 : psCond->psWaiterList = nullptr;
1001 : return reinterpret_cast<CPLCond *>(psCond);
1002 : }
1003 :
1004 : /************************************************************************/
1005 : /* CPLCondWait() */
1006 : /************************************************************************/
1007 :
1008 : static void CPLTLSFreeEvent(void *pData)
1009 : {
1010 : CloseHandle(static_cast<HANDLE>(pData));
1011 : }
1012 :
1013 : void CPLCondWait(CPLCond *hCond, CPLMutex *hClientMutex)
1014 : {
1015 : CPLCondTimedWait(hCond, hClientMutex, -1);
1016 : }
1017 :
1018 : /************************************************************************/
1019 : /* CPLCondTimedWait() */
1020 : /************************************************************************/
1021 :
1022 : CPLCondTimedWaitReason CPLCondTimedWait(CPLCond *hCond, CPLMutex *hClientMutex,
1023 : double dfWaitInSeconds)
1024 : {
1025 : Win32Cond *psCond = reinterpret_cast<Win32Cond *>(hCond);
1026 :
1027 : HANDLE hEvent = static_cast<HANDLE>(CPLGetTLS(CTLS_WIN32_COND));
1028 : if (hEvent == nullptr)
1029 : {
1030 : hEvent = CreateEvent(nullptr, /* security attributes */
1031 : 0, /* manual reset = no */
1032 : 0, /* initial state = unsignaled */
1033 : nullptr /* no name */);
1034 : CPLAssert(hEvent != nullptr);
1035 :
1036 : CPLSetTLSWithFreeFunc(CTLS_WIN32_COND, hEvent, CPLTLSFreeEvent);
1037 : }
1038 :
1039 : /* Insert the waiter into the waiter list of the condition */
1040 : CPLAcquireMutex(psCond->hInternalMutex, 1000.0);
1041 :
1042 : WaiterItem *psItem = static_cast<WaiterItem *>(malloc(sizeof(WaiterItem)));
1043 : CPLAssert(psItem != nullptr);
1044 :
1045 : psItem->hEvent = hEvent;
1046 : psItem->psNext = psCond->psWaiterList;
1047 :
1048 : psCond->psWaiterList = psItem;
1049 :
1050 : CPLReleaseMutex(psCond->hInternalMutex);
1051 :
1052 : // Release the client mutex before waiting for the event being signaled.
1053 : CPLReleaseMutex(hClientMutex);
1054 :
1055 : // Ideally we would check that we do not get WAIT_FAILED but it is hard
1056 : // to report a failure.
1057 : auto ret = WaitForSingleObject(
1058 : hEvent, dfWaitInSeconds < 0 ? INFINITE
1059 : : static_cast<int>(dfWaitInSeconds * 1000));
1060 :
1061 : // Reacquire the client mutex.
1062 : CPLAcquireMutex(hClientMutex, 1000.0);
1063 :
1064 : if (ret == WAIT_OBJECT_0)
1065 : return COND_TIMED_WAIT_COND;
1066 : if (ret == WAIT_TIMEOUT)
1067 : return COND_TIMED_WAIT_TIME_OUT;
1068 : return COND_TIMED_WAIT_OTHER;
1069 : }
1070 :
1071 : /************************************************************************/
1072 : /* CPLCondSignal() */
1073 : /************************************************************************/
1074 :
1075 : void CPLCondSignal(CPLCond *hCond)
1076 : {
1077 : Win32Cond *psCond = reinterpret_cast<Win32Cond *>(hCond);
1078 :
1079 : // Signal the first registered event, and remove it from the list.
1080 : CPLAcquireMutex(psCond->hInternalMutex, 1000.0);
1081 :
1082 : WaiterItem *psIter = psCond->psWaiterList;
1083 : if (psIter != nullptr)
1084 : {
1085 : SetEvent(psIter->hEvent);
1086 : psCond->psWaiterList = psIter->psNext;
1087 : free(psIter);
1088 : }
1089 :
1090 : CPLReleaseMutex(psCond->hInternalMutex);
1091 : }
1092 :
1093 : /************************************************************************/
1094 : /* CPLCondBroadcast() */
1095 : /************************************************************************/
1096 :
1097 : void CPLCondBroadcast(CPLCond *hCond)
1098 : {
1099 : Win32Cond *psCond = reinterpret_cast<Win32Cond *>(hCond);
1100 :
1101 : // Signal all the registered events, and remove them from the list.
1102 : CPLAcquireMutex(psCond->hInternalMutex, 1000.0);
1103 :
1104 : WaiterItem *psIter = psCond->psWaiterList;
1105 : while (psIter != nullptr)
1106 : {
1107 : WaiterItem *psNext = psIter->psNext;
1108 : SetEvent(psIter->hEvent);
1109 : free(psIter);
1110 : psIter = psNext;
1111 : }
1112 : psCond->psWaiterList = nullptr;
1113 :
1114 : CPLReleaseMutex(psCond->hInternalMutex);
1115 : }
1116 :
1117 : /************************************************************************/
1118 : /* CPLDestroyCond() */
1119 : /************************************************************************/
1120 :
1121 : void CPLDestroyCond(CPLCond *hCond)
1122 : {
1123 : Win32Cond *psCond = reinterpret_cast<Win32Cond *>(hCond);
1124 : CPLDestroyMutex(psCond->hInternalMutex);
1125 : psCond->hInternalMutex = nullptr;
1126 : CPLAssert(psCond->psWaiterList == nullptr);
1127 : free(psCond);
1128 : }
1129 :
1130 : /************************************************************************/
1131 : /* CPLLockFile() */
1132 : /************************************************************************/
1133 :
1134 : void *CPLLockFile(const char *pszPath, double dfWaitInSeconds)
1135 :
1136 : {
1137 : char *pszLockFilename =
1138 : static_cast<char *>(CPLMalloc(strlen(pszPath) + 30));
1139 : snprintf(pszLockFilename, strlen(pszPath) + 30, "%s.lock", pszPath);
1140 :
1141 : // FIXME: use CreateFileW()
1142 : HANDLE hLockFile =
1143 : CreateFileA(pszLockFilename, GENERIC_WRITE, 0, nullptr, CREATE_NEW,
1144 : FILE_ATTRIBUTE_NORMAL | FILE_FLAG_DELETE_ON_CLOSE, nullptr);
1145 :
1146 : while (GetLastError() == ERROR_ALREADY_EXISTS && dfWaitInSeconds > 0.0)
1147 : {
1148 : CloseHandle(hLockFile);
1149 : CPLSleep(std::min(dfWaitInSeconds, 0.125));
1150 : dfWaitInSeconds -= 0.125;
1151 :
1152 : hLockFile = CreateFileA(
1153 : pszLockFilename, GENERIC_WRITE, 0, nullptr, CREATE_NEW,
1154 : FILE_ATTRIBUTE_NORMAL | FILE_FLAG_DELETE_ON_CLOSE, nullptr);
1155 : }
1156 :
1157 : CPLFree(pszLockFilename);
1158 :
1159 : if (hLockFile == INVALID_HANDLE_VALUE)
1160 : return nullptr;
1161 :
1162 : if (GetLastError() == ERROR_ALREADY_EXISTS)
1163 : {
1164 : CloseHandle(hLockFile);
1165 : return nullptr;
1166 : }
1167 :
1168 : return static_cast<void *>(hLockFile);
1169 : }
1170 :
1171 : /************************************************************************/
1172 : /* CPLUnlockFile() */
1173 : /************************************************************************/
1174 :
1175 : void CPLUnlockFile(void *hLock)
1176 :
1177 : {
1178 : HANDLE hLockFile = static_cast<HANDLE>(hLock);
1179 :
1180 : CloseHandle(hLockFile);
1181 : }
1182 :
1183 : /************************************************************************/
1184 : /* CPLGetPID() */
1185 : /************************************************************************/
1186 :
1187 : GIntBig CPLGetPID()
1188 :
1189 : {
1190 : return static_cast<GIntBig>(GetCurrentThreadId());
1191 : }
1192 :
1193 : /************************************************************************/
1194 : /* CPLStdCallThreadJacket() */
1195 : /************************************************************************/
1196 :
1197 : typedef struct
1198 : {
1199 : void *pAppData;
1200 : CPLThreadFunc pfnMain;
1201 : HANDLE hThread;
1202 : } CPLStdCallThreadInfo;
1203 :
1204 : static DWORD WINAPI CPLStdCallThreadJacket(void *pData)
1205 :
1206 : {
1207 : CPLStdCallThreadInfo *psInfo = static_cast<CPLStdCallThreadInfo *>(pData);
1208 :
1209 : psInfo->pfnMain(psInfo->pAppData);
1210 :
1211 : if (psInfo->hThread == nullptr)
1212 : CPLFree(psInfo); // Only for detached threads.
1213 :
1214 : CPLCleanupTLS();
1215 :
1216 : return 0;
1217 : }
1218 :
1219 : /************************************************************************/
1220 : /* CPLCreateThread() */
1221 : /* */
1222 : /* The WIN32 CreateThread() call requires an entry point that */
1223 : /* has __stdcall conventions, so we provide a jacket function */
1224 : /* to supply that. */
1225 : /************************************************************************/
1226 :
1227 : int CPLCreateThread(CPLThreadFunc pfnMain, void *pThreadArg)
1228 :
1229 : {
1230 : CPLStdCallThreadInfo *psInfo = static_cast<CPLStdCallThreadInfo *>(
1231 : CPLCalloc(sizeof(CPLStdCallThreadInfo), 1));
1232 : psInfo->pAppData = pThreadArg;
1233 : psInfo->pfnMain = pfnMain;
1234 : psInfo->hThread = nullptr;
1235 :
1236 : DWORD nThreadId = 0;
1237 : HANDLE hThread =
1238 : CreateThread(nullptr, 0, CPLStdCallThreadJacket, psInfo, 0, &nThreadId);
1239 :
1240 : if (hThread == nullptr)
1241 : return -1;
1242 :
1243 : CloseHandle(hThread);
1244 :
1245 : return nThreadId;
1246 : }
1247 :
1248 : /************************************************************************/
1249 : /* CPLCreateJoinableThread() */
1250 : /************************************************************************/
1251 :
1252 : CPLJoinableThread *CPLCreateJoinableThread(CPLThreadFunc pfnMain,
1253 : void *pThreadArg)
1254 :
1255 : {
1256 : CPLStdCallThreadInfo *psInfo = static_cast<CPLStdCallThreadInfo *>(
1257 : CPLCalloc(sizeof(CPLStdCallThreadInfo), 1));
1258 : psInfo->pAppData = pThreadArg;
1259 : psInfo->pfnMain = pfnMain;
1260 :
1261 : DWORD nThreadId = 0;
1262 : HANDLE hThread =
1263 : CreateThread(nullptr, 0, CPLStdCallThreadJacket, psInfo, 0, &nThreadId);
1264 :
1265 : if (hThread == nullptr)
1266 : return nullptr;
1267 :
1268 : psInfo->hThread = hThread;
1269 : return reinterpret_cast<CPLJoinableThread *>(psInfo);
1270 : }
1271 :
1272 : /************************************************************************/
1273 : /* CPLJoinThread() */
1274 : /************************************************************************/
1275 :
1276 : void CPLJoinThread(CPLJoinableThread *hJoinableThread)
1277 : {
1278 : CPLStdCallThreadInfo *psInfo =
1279 : reinterpret_cast<CPLStdCallThreadInfo *>(hJoinableThread);
1280 :
1281 : WaitForSingleObject(psInfo->hThread, INFINITE);
1282 : CloseHandle(psInfo->hThread);
1283 : CPLFree(psInfo);
1284 : }
1285 :
1286 : /************************************************************************/
1287 : /* CPLSleep() */
1288 : /************************************************************************/
1289 :
1290 : void CPLSleep(double dfWaitInSeconds)
1291 :
1292 : {
1293 : Sleep(static_cast<DWORD>(dfWaitInSeconds * 1000.0));
1294 : }
1295 :
1296 : static bool bTLSKeySetup = false;
1297 : static DWORD nTLSKey = 0;
1298 :
1299 : /************************************************************************/
1300 : /* CPLGetTLSList() */
1301 : /************************************************************************/
1302 :
1303 : static void **CPLGetTLSList(int *pbMemoryErrorOccurred)
1304 :
1305 : {
1306 : void **papTLSList = nullptr;
1307 :
1308 : if (pbMemoryErrorOccurred)
1309 : *pbMemoryErrorOccurred = FALSE;
1310 : if (!bTLSKeySetup)
1311 : {
1312 : nTLSKey = TlsAlloc();
1313 : if (nTLSKey == TLS_OUT_OF_INDEXES)
1314 : {
1315 : if (pbMemoryErrorOccurred)
1316 : {
1317 : *pbMemoryErrorOccurred = TRUE;
1318 : fprintf(stderr, "CPLGetTLSList(): TlsAlloc() failed!\n");
1319 : return nullptr;
1320 : }
1321 : CPLEmergencyError("CPLGetTLSList(): TlsAlloc() failed!");
1322 : }
1323 : bTLSKeySetup = true;
1324 : }
1325 :
1326 : papTLSList = static_cast<void **>(TlsGetValue(nTLSKey));
1327 : if (papTLSList == nullptr)
1328 : {
1329 : papTLSList =
1330 : static_cast<void **>(VSICalloc(sizeof(void *), CTLS_MAX * 2));
1331 : if (papTLSList == nullptr)
1332 : {
1333 : if (pbMemoryErrorOccurred)
1334 : {
1335 : *pbMemoryErrorOccurred = TRUE;
1336 : fprintf(stderr,
1337 : "CPLGetTLSList() failed to allocate TLS list!\n");
1338 : return nullptr;
1339 : }
1340 : CPLEmergencyError("CPLGetTLSList() failed to allocate TLS list!");
1341 : }
1342 : if (TlsSetValue(nTLSKey, papTLSList) == 0)
1343 : {
1344 : if (pbMemoryErrorOccurred)
1345 : {
1346 : *pbMemoryErrorOccurred = TRUE;
1347 : fprintf(stderr, "CPLGetTLSList(): TlsSetValue() failed!\n");
1348 : return nullptr;
1349 : }
1350 : CPLEmergencyError("CPLGetTLSList(): TlsSetValue() failed!");
1351 : }
1352 : }
1353 :
1354 : return papTLSList;
1355 : }
1356 :
1357 : /************************************************************************/
1358 : /* CPLFinalizeTLS() */
1359 : /************************************************************************/
1360 :
1361 : void CPLFinalizeTLS()
1362 : {
1363 : CPLCleanupTLS();
1364 : }
1365 :
1366 : /************************************************************************/
1367 : /* CPLCleanupTLS() */
1368 : /************************************************************************/
1369 :
1370 : void CPLCleanupTLS()
1371 :
1372 : {
1373 : if (!bTLSKeySetup)
1374 : return;
1375 :
1376 : void **papTLSList = static_cast<void **>(TlsGetValue(nTLSKey));
1377 : if (papTLSList == nullptr)
1378 : return;
1379 :
1380 : TlsSetValue(nTLSKey, nullptr);
1381 :
1382 : CPLCleanupTLSList(papTLSList);
1383 : }
1384 :
1385 : // endif CPL_MULTIPROC_WIN32
1386 :
1387 : #elif defined(CPL_MULTIPROC_PTHREAD)
1388 :
1389 : #include <pthread.h>
1390 : #include <time.h>
1391 : #include <unistd.h>
1392 : #include <sys/time.h>
1393 :
1394 : #ifdef HAVE_SCHED_GETAFFINITY
1395 : #include <sched.h>
1396 : #endif
1397 :
1398 : /************************************************************************/
1399 : /* ==================================================================== */
1400 : /* CPL_MULTIPROC_PTHREAD */
1401 : /* */
1402 : /* PTHREAD Implementation of multiprocessing functions. */
1403 : /* ==================================================================== */
1404 : /************************************************************************/
1405 :
1406 : /************************************************************************/
1407 : /* CPLGetNumCPUs() */
1408 : /************************************************************************/
1409 :
1410 4160 : int CPLGetNumCPUs()
1411 : {
1412 : int nCPUs;
1413 : #ifdef _SC_NPROCESSORS_ONLN
1414 4160 : nCPUs = static_cast<int>(sysconf(_SC_NPROCESSORS_ONLN));
1415 : #else
1416 : nCPUs = 1;
1417 : #endif
1418 :
1419 : #ifdef HAVE_SCHED_GETAFFINITY
1420 4160 : if (nCPUs > 1)
1421 : {
1422 4160 : cpu_set_t *set = CPU_ALLOC(nCPUs);
1423 4160 : if (set)
1424 : {
1425 4160 : size_t sizeof_set = CPU_ALLOC_SIZE(nCPUs);
1426 4160 : CPU_ZERO_S(sizeof_set, set);
1427 4160 : if (sched_getaffinity(getpid(), sizeof_set, set) == 0)
1428 4160 : nCPUs = CPU_COUNT_S(sizeof_set, set);
1429 : else
1430 0 : CPLDebug("CPL", "sched_getaffinity() failed");
1431 4160 : CPU_FREE(set);
1432 : }
1433 : }
1434 : #endif
1435 :
1436 4160 : return nCPUs;
1437 : }
1438 :
1439 : /************************************************************************/
1440 : /* CPLCreateOrAcquireMutex() */
1441 : /************************************************************************/
1442 : #ifdef HAVE_GCC_WARNING_ZERO_AS_NULL_POINTER_CONSTANT
1443 : #pragma GCC diagnostic push
1444 : #pragma GCC diagnostic ignored "-Wzero-as-null-pointer-constant"
1445 : #endif
1446 : static pthread_mutex_t global_mutex = PTHREAD_MUTEX_INITIALIZER;
1447 : #ifdef HAVE_GCC_WARNING_ZERO_AS_NULL_POINTER_CONSTANT
1448 : #pragma GCC diagnostic pop
1449 : #endif
1450 :
1451 : static CPLMutex *CPLCreateMutexInternal(bool bAlreadyInGlobalLock,
1452 : int nOptions);
1453 :
1454 67779100 : int CPLCreateOrAcquireMutexEx(CPLMutex **phMutex, double dfWaitInSeconds,
1455 : int nOptions)
1456 :
1457 : {
1458 67779100 : pthread_mutex_lock(&global_mutex);
1459 67791500 : if (*phMutex == nullptr)
1460 : {
1461 31794 : *phMutex = CPLCreateMutexInternal(true, nOptions);
1462 31794 : const bool bSuccess = *phMutex != nullptr;
1463 31794 : pthread_mutex_unlock(&global_mutex);
1464 31794 : if (!bSuccess)
1465 0 : return false;
1466 : }
1467 : else
1468 : {
1469 67759700 : pthread_mutex_unlock(&global_mutex);
1470 : }
1471 :
1472 67791000 : return CPL_TO_BOOL(CPLAcquireMutex(*phMutex, dfWaitInSeconds));
1473 : }
1474 :
1475 : /************************************************************************/
1476 : /* CPLCreateOrAcquireMutexInternal() */
1477 : /************************************************************************/
1478 :
1479 4762 : static bool CPLCreateOrAcquireMutexInternal(CPLLock **phLock,
1480 : double dfWaitInSeconds,
1481 : CPLLockType eType)
1482 : {
1483 4762 : pthread_mutex_lock(&global_mutex);
1484 4762 : if (*phLock == nullptr)
1485 : {
1486 546 : *phLock = static_cast<CPLLock *>(calloc(1, sizeof(CPLLock)));
1487 546 : if (*phLock)
1488 : {
1489 546 : (*phLock)->eType = eType;
1490 1092 : (*phLock)->u.hMutex = CPLCreateMutexInternal(
1491 546 : true, eType == LOCK_RECURSIVE_MUTEX ? CPL_MUTEX_RECURSIVE
1492 : : CPL_MUTEX_ADAPTIVE);
1493 546 : if ((*phLock)->u.hMutex == nullptr)
1494 : {
1495 0 : free(*phLock);
1496 0 : *phLock = nullptr;
1497 : }
1498 : }
1499 546 : const bool bSuccess = *phLock != nullptr;
1500 546 : pthread_mutex_unlock(&global_mutex);
1501 546 : if (!bSuccess)
1502 0 : return false;
1503 : }
1504 : else
1505 : {
1506 4216 : pthread_mutex_unlock(&global_mutex);
1507 : }
1508 :
1509 4762 : return CPL_TO_BOOL(CPLAcquireMutex((*phLock)->u.hMutex, dfWaitInSeconds));
1510 : }
1511 :
1512 : /************************************************************************/
1513 : /* CPLGetThreadingModel() */
1514 : /************************************************************************/
1515 :
1516 11 : const char *CPLGetThreadingModel()
1517 :
1518 : {
1519 11 : return "pthread";
1520 : }
1521 :
1522 : /************************************************************************/
1523 : /* CPLCreateMutex() */
1524 : /************************************************************************/
1525 :
1526 : typedef struct _MutexLinkedElt MutexLinkedElt;
1527 :
1528 : struct _MutexLinkedElt
1529 : {
1530 : pthread_mutex_t sMutex;
1531 : int nOptions;
1532 : _MutexLinkedElt *psPrev;
1533 : _MutexLinkedElt *psNext;
1534 : };
1535 :
1536 : static MutexLinkedElt *psMutexList = nullptr;
1537 :
1538 107987 : static void CPLInitMutex(MutexLinkedElt *psItem)
1539 : {
1540 107987 : if (psItem->nOptions == CPL_MUTEX_REGULAR)
1541 : {
1542 : #ifdef HAVE_GCC_WARNING_ZERO_AS_NULL_POINTER_CONSTANT
1543 : #pragma GCC diagnostic push
1544 : #pragma GCC diagnostic ignored "-Wzero-as-null-pointer-constant"
1545 : #endif
1546 0 : pthread_mutex_t tmp_mutex = PTHREAD_MUTEX_INITIALIZER;
1547 : #ifdef HAVE_GCC_WARNING_ZERO_AS_NULL_POINTER_CONSTANT
1548 : #pragma GCC diagnostic pop
1549 : #endif
1550 0 : psItem->sMutex = tmp_mutex;
1551 0 : return;
1552 : }
1553 :
1554 : // When an adaptive mutex is required, we can safely fallback to regular
1555 : // mutex if we don't have HAVE_PTHREAD_MUTEX_ADAPTIVE_NP.
1556 107987 : if (psItem->nOptions == CPL_MUTEX_ADAPTIVE)
1557 : {
1558 : #if defined(HAVE_PTHREAD_MUTEX_ADAPTIVE_NP)
1559 : pthread_mutexattr_t attr;
1560 616 : pthread_mutexattr_init(&attr);
1561 616 : pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ADAPTIVE_NP);
1562 616 : pthread_mutex_init(&(psItem->sMutex), &attr);
1563 : #else
1564 : pthread_mutex_t tmp_mutex = PTHREAD_MUTEX_INITIALIZER;
1565 : psItem->sMutex = tmp_mutex;
1566 : #endif
1567 616 : return;
1568 : }
1569 :
1570 : #if defined(PTHREAD_MUTEX_RECURSIVE) || defined(HAVE_PTHREAD_MUTEX_RECURSIVE)
1571 : {
1572 : pthread_mutexattr_t attr;
1573 107371 : pthread_mutexattr_init(&attr);
1574 107370 : pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
1575 107370 : pthread_mutex_init(&(psItem->sMutex), &attr);
1576 : }
1577 : // BSDs have PTHREAD_MUTEX_RECURSIVE as an enum, not a define.
1578 : // But they have #define MUTEX_TYPE_COUNTING_FAST PTHREAD_MUTEX_RECURSIVE
1579 : #elif defined(MUTEX_TYPE_COUNTING_FAST)
1580 : {
1581 : pthread_mutexattr_t attr;
1582 : pthread_mutexattr_init(&attr);
1583 : pthread_mutexattr_settype(&attr, MUTEX_TYPE_COUNTING_FAST);
1584 : pthread_mutex_init(&(psItem->sMutex), &attr);
1585 : }
1586 : #elif defined(PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP)
1587 : pthread_mutex_t tmp_mutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
1588 : psItem->sMutex = tmp_mutex;
1589 : #else
1590 : #error "Recursive mutexes apparently unsupported, configure --without-threads"
1591 : #endif
1592 : }
1593 :
1594 107985 : static CPLMutex *CPLCreateMutexInternal(bool bAlreadyInGlobalLock, int nOptions)
1595 : {
1596 : MutexLinkedElt *psItem =
1597 107985 : static_cast<MutexLinkedElt *>(malloc(sizeof(MutexLinkedElt)));
1598 107985 : if (psItem == nullptr)
1599 : {
1600 0 : fprintf(stderr, "CPLCreateMutexInternal() failed.\n");
1601 0 : return nullptr;
1602 : }
1603 :
1604 107985 : if (!bAlreadyInGlobalLock)
1605 75644 : pthread_mutex_lock(&global_mutex);
1606 107988 : psItem->psPrev = nullptr;
1607 107988 : psItem->psNext = psMutexList;
1608 107988 : if (psMutexList)
1609 106672 : psMutexList->psPrev = psItem;
1610 107988 : psMutexList = psItem;
1611 107988 : if (!bAlreadyInGlobalLock)
1612 75647 : pthread_mutex_unlock(&global_mutex);
1613 :
1614 107988 : psItem->nOptions = nOptions;
1615 107988 : CPLInitMutex(psItem);
1616 :
1617 107986 : return reinterpret_cast<CPLMutex *>(psItem);
1618 : }
1619 :
1620 75575 : CPLMutex *CPLCreateMutex()
1621 : {
1622 75575 : CPLMutex *mutex = CPLCreateMutexInternal(false, CPL_MUTEX_RECURSIVE);
1623 75576 : if (mutex)
1624 75576 : CPLAcquireMutex(mutex, 0);
1625 75577 : return mutex;
1626 : }
1627 :
1628 70 : CPLMutex *CPLCreateMutexEx(int nOptions)
1629 : {
1630 70 : CPLMutex *mutex = CPLCreateMutexInternal(false, nOptions);
1631 70 : if (mutex)
1632 70 : CPLAcquireMutex(mutex, 0);
1633 70 : return mutex;
1634 : }
1635 :
1636 : /************************************************************************/
1637 : /* CPLAcquireMutex() */
1638 : /************************************************************************/
1639 :
1640 93437500 : int CPLAcquireMutex(CPLMutex *hMutexIn, double /* dfWaitInSeconds */)
1641 : {
1642 : // TODO: Need to add timeout support.
1643 93437500 : MutexLinkedElt *psItem = reinterpret_cast<MutexLinkedElt *>(hMutexIn);
1644 93437500 : const int err = pthread_mutex_lock(&(psItem->sMutex));
1645 :
1646 93443000 : if (err != 0)
1647 : {
1648 0 : if (err == EDEADLK)
1649 0 : fprintf(stderr, "CPLAcquireMutex: Error = %d/EDEADLK\n", err);
1650 : else
1651 0 : fprintf(stderr, "CPLAcquireMutex: Error = %d (%s)\n", err,
1652 : strerror(err));
1653 :
1654 0 : return FALSE;
1655 : }
1656 :
1657 93443000 : return TRUE;
1658 : }
1659 :
1660 : /************************************************************************/
1661 : /* CPLReleaseMutex() */
1662 : /************************************************************************/
1663 :
1664 93442700 : void CPLReleaseMutex(CPLMutex *hMutexIn)
1665 :
1666 : {
1667 93442700 : MutexLinkedElt *psItem = reinterpret_cast<MutexLinkedElt *>(hMutexIn);
1668 93442700 : const int err = pthread_mutex_unlock(&(psItem->sMutex));
1669 93442700 : if (err != 0)
1670 : {
1671 0 : fprintf(stderr, "CPLReleaseMutex: Error = %d (%s)\n", err,
1672 : strerror(err));
1673 : }
1674 93442700 : }
1675 :
1676 : /************************************************************************/
1677 : /* CPLDestroyMutex() */
1678 : /************************************************************************/
1679 :
1680 103094 : void CPLDestroyMutex(CPLMutex *hMutexIn)
1681 :
1682 : {
1683 103094 : MutexLinkedElt *psItem = reinterpret_cast<MutexLinkedElt *>(hMutexIn);
1684 103094 : const int err = pthread_mutex_destroy(&(psItem->sMutex));
1685 103091 : if (err != 0)
1686 : {
1687 0 : fprintf(stderr, "CPLDestroyMutex: Error = %d (%s)\n", err,
1688 : strerror(err));
1689 : }
1690 103091 : pthread_mutex_lock(&global_mutex);
1691 103094 : if (psItem->psPrev)
1692 67372 : psItem->psPrev->psNext = psItem->psNext;
1693 103094 : if (psItem->psNext)
1694 99335 : psItem->psNext->psPrev = psItem->psPrev;
1695 103094 : if (psItem == psMutexList)
1696 35722 : psMutexList = psItem->psNext;
1697 103094 : pthread_mutex_unlock(&global_mutex);
1698 103094 : free(hMutexIn);
1699 103094 : }
1700 :
1701 : /************************************************************************/
1702 : /* CPLReinitAllMutex() */
1703 : /************************************************************************/
1704 :
1705 : // Used by gdalclientserver.cpp just after forking, to avoid
1706 : // deadlocks while mixing threads with fork.
1707 : void CPLReinitAllMutex(); // TODO(schwehr): Put this in a header.
1708 :
1709 0 : void CPLReinitAllMutex()
1710 : {
1711 0 : MutexLinkedElt *psItem = psMutexList;
1712 0 : while (psItem != nullptr)
1713 : {
1714 0 : CPLInitMutex(psItem);
1715 0 : psItem = psItem->psNext;
1716 : }
1717 : #ifdef HAVE_GCC_WARNING_ZERO_AS_NULL_POINTER_CONSTANT
1718 : #pragma GCC diagnostic push
1719 : #pragma GCC diagnostic ignored "-Wzero-as-null-pointer-constant"
1720 : #endif
1721 0 : pthread_mutex_t tmp_global_mutex = PTHREAD_MUTEX_INITIALIZER;
1722 : #ifdef HAVE_GCC_WARNING_ZERO_AS_NULL_POINTER_CONSTANT
1723 : #pragma GCC diagnostic pop
1724 : #endif
1725 0 : global_mutex = tmp_global_mutex;
1726 0 : }
1727 :
1728 : /************************************************************************/
1729 : /* CPLCreateCond() */
1730 : /************************************************************************/
1731 :
1732 33264 : CPLCond *CPLCreateCond()
1733 : {
1734 : pthread_cond_t *pCond =
1735 33264 : static_cast<pthread_cond_t *>(malloc(sizeof(pthread_cond_t)));
1736 33264 : if (pCond && pthread_cond_init(pCond, nullptr) == 0)
1737 33263 : return reinterpret_cast<CPLCond *>(pCond);
1738 0 : fprintf(stderr, "CPLCreateCond() failed.\n");
1739 0 : free(pCond);
1740 0 : return nullptr;
1741 : }
1742 :
1743 : /************************************************************************/
1744 : /* CPLCondWait() */
1745 : /************************************************************************/
1746 :
1747 1108 : void CPLCondWait(CPLCond *hCond, CPLMutex *hMutex)
1748 : {
1749 1108 : pthread_cond_t *pCond = reinterpret_cast<pthread_cond_t *>(hCond);
1750 1108 : MutexLinkedElt *psItem = reinterpret_cast<MutexLinkedElt *>(hMutex);
1751 1108 : pthread_mutex_t *pMutex = &(psItem->sMutex);
1752 1108 : pthread_cond_wait(pCond, pMutex);
1753 1108 : }
1754 :
1755 : /************************************************************************/
1756 : /* CPLCondTimedWait() */
1757 : /************************************************************************/
1758 :
1759 0 : CPLCondTimedWaitReason CPLCondTimedWait(CPLCond *hCond, CPLMutex *hMutex,
1760 : double dfWaitInSeconds)
1761 : {
1762 0 : pthread_cond_t *pCond = reinterpret_cast<pthread_cond_t *>(hCond);
1763 0 : MutexLinkedElt *psItem = reinterpret_cast<MutexLinkedElt *>(hMutex);
1764 0 : pthread_mutex_t *pMutex = &(psItem->sMutex);
1765 : struct timeval tv;
1766 : struct timespec ts;
1767 :
1768 0 : gettimeofday(&tv, nullptr);
1769 0 : ts.tv_sec = time(nullptr) + static_cast<int>(dfWaitInSeconds);
1770 0 : ts.tv_nsec =
1771 0 : static_cast<int>(tv.tv_usec) * 1000 +
1772 0 : static_cast<int>(1000 * 1000 * 1000 * fmod(dfWaitInSeconds, 1));
1773 0 : ts.tv_sec += ts.tv_nsec / (1000 * 1000 * 1000);
1774 0 : ts.tv_nsec %= (1000 * 1000 * 1000);
1775 0 : int ret = pthread_cond_timedwait(pCond, pMutex, &ts);
1776 0 : if (ret == 0)
1777 0 : return COND_TIMED_WAIT_COND;
1778 0 : else if (ret == ETIMEDOUT)
1779 0 : return COND_TIMED_WAIT_TIME_OUT;
1780 : else
1781 0 : return COND_TIMED_WAIT_OTHER;
1782 : }
1783 :
1784 : /************************************************************************/
1785 : /* CPLCondSignal() */
1786 : /************************************************************************/
1787 :
1788 31869 : void CPLCondSignal(CPLCond *hCond)
1789 : {
1790 31869 : pthread_cond_t *pCond = reinterpret_cast<pthread_cond_t *>(hCond);
1791 31869 : pthread_cond_signal(pCond);
1792 31869 : }
1793 :
1794 : /************************************************************************/
1795 : /* CPLCondBroadcast() */
1796 : /************************************************************************/
1797 :
1798 69906 : void CPLCondBroadcast(CPLCond *hCond)
1799 : {
1800 69906 : pthread_cond_t *pCond = reinterpret_cast<pthread_cond_t *>(hCond);
1801 69906 : pthread_cond_broadcast(pCond);
1802 69906 : }
1803 :
1804 : /************************************************************************/
1805 : /* CPLDestroyCond() */
1806 : /************************************************************************/
1807 :
1808 33263 : void CPLDestroyCond(CPLCond *hCond)
1809 : {
1810 33263 : pthread_cond_t *pCond = reinterpret_cast<pthread_cond_t *>(hCond);
1811 33263 : pthread_cond_destroy(pCond);
1812 33264 : free(hCond);
1813 33264 : }
1814 :
1815 : /************************************************************************/
1816 : /* CPLLockFile() */
1817 : /* */
1818 : /* This is really a stub implementation, see first */
1819 : /* CPLLockFile() for caveats. */
1820 : /************************************************************************/
1821 :
1822 3 : void *CPLLockFile(const char *pszPath, double dfWaitInSeconds)
1823 :
1824 : {
1825 : /* -------------------------------------------------------------------- */
1826 : /* We use a lock file with a name derived from the file we want */
1827 : /* to lock to represent the file being locked. Note that for */
1828 : /* the stub implementation the target file does not even need */
1829 : /* to exist to be locked. */
1830 : /* -------------------------------------------------------------------- */
1831 3 : const size_t nLen = strlen(pszPath) + 30;
1832 3 : char *pszLockFilename = static_cast<char *>(CPLMalloc(nLen));
1833 3 : snprintf(pszLockFilename, nLen, "%s.lock", pszPath);
1834 :
1835 3 : FILE *fpLock = fopen(pszLockFilename, "r");
1836 3 : while (fpLock != nullptr && dfWaitInSeconds > 0.0)
1837 : {
1838 0 : fclose(fpLock);
1839 0 : CPLSleep(std::min(dfWaitInSeconds, 0.5));
1840 0 : dfWaitInSeconds -= 0.5;
1841 :
1842 0 : fpLock = fopen(pszLockFilename, "r");
1843 : }
1844 :
1845 3 : if (fpLock != nullptr)
1846 : {
1847 0 : fclose(fpLock);
1848 0 : CPLFree(pszLockFilename);
1849 0 : return nullptr;
1850 : }
1851 :
1852 3 : fpLock = fopen(pszLockFilename, "w");
1853 :
1854 3 : if (fpLock == nullptr)
1855 : {
1856 0 : CPLFree(pszLockFilename);
1857 0 : return nullptr;
1858 : }
1859 :
1860 3 : fwrite("held\n", 1, 5, fpLock);
1861 3 : fclose(fpLock);
1862 :
1863 3 : return pszLockFilename;
1864 : }
1865 :
1866 : /************************************************************************/
1867 : /* CPLUnlockFile() */
1868 : /************************************************************************/
1869 :
1870 3 : void CPLUnlockFile(void *hLock)
1871 :
1872 : {
1873 3 : char *pszLockFilename = static_cast<char *>(hLock);
1874 :
1875 3 : if (hLock == nullptr)
1876 0 : return;
1877 :
1878 3 : VSIUnlink(pszLockFilename);
1879 :
1880 3 : CPLFree(pszLockFilename);
1881 : }
1882 :
1883 : /************************************************************************/
1884 : /* CPLGetPID() */
1885 : /************************************************************************/
1886 :
1887 19886200 : GIntBig CPLGetPID()
1888 :
1889 : {
1890 19886200 : return reinterpret_cast<GIntBig>(reinterpret_cast<void *>(pthread_self()));
1891 : }
1892 :
1893 : static pthread_key_t oTLSKey;
1894 : static pthread_once_t oTLSKeySetup = PTHREAD_ONCE_INIT;
1895 :
1896 : /************************************************************************/
1897 : /* CPLMake_key() */
1898 : /************************************************************************/
1899 :
1900 1315 : static void CPLMake_key()
1901 :
1902 : {
1903 1315 : if (pthread_key_create(&oTLSKey, reinterpret_cast<void (*)(void *)>(
1904 1315 : CPLCleanupTLSList)) != 0)
1905 : {
1906 0 : CPLError(CE_Fatal, CPLE_AppDefined, "pthread_key_create() failed!");
1907 : }
1908 1315 : }
1909 :
1910 : /************************************************************************/
1911 : /* CPLGetTLSList() */
1912 : /************************************************************************/
1913 :
1914 62816300 : static void **CPLGetTLSList(int *pbMemoryErrorOccurred)
1915 :
1916 : {
1917 62816300 : if (pbMemoryErrorOccurred)
1918 59803800 : *pbMemoryErrorOccurred = FALSE;
1919 :
1920 62816300 : if (pthread_once(&oTLSKeySetup, CPLMake_key) != 0)
1921 : {
1922 0 : if (pbMemoryErrorOccurred)
1923 : {
1924 0 : fprintf(stderr, "CPLGetTLSList(): pthread_once() failed!\n");
1925 0 : *pbMemoryErrorOccurred = TRUE;
1926 0 : return nullptr;
1927 : }
1928 0 : CPLEmergencyError("CPLGetTLSList(): pthread_once() failed!");
1929 : }
1930 :
1931 62810500 : void **papTLSList = static_cast<void **>(pthread_getspecific(oTLSKey));
1932 62817000 : if (papTLSList == nullptr)
1933 : {
1934 : papTLSList =
1935 5323 : static_cast<void **>(VSICalloc(sizeof(void *), CTLS_MAX * 2));
1936 3387 : if (papTLSList == nullptr)
1937 : {
1938 0 : if (pbMemoryErrorOccurred)
1939 : {
1940 0 : fprintf(stderr,
1941 : "CPLGetTLSList() failed to allocate TLS list!\n");
1942 0 : *pbMemoryErrorOccurred = TRUE;
1943 0 : return nullptr;
1944 : }
1945 0 : CPLEmergencyError("CPLGetTLSList() failed to allocate TLS list!");
1946 : }
1947 3387 : if (pthread_setspecific(oTLSKey, papTLSList) != 0)
1948 : {
1949 0 : if (pbMemoryErrorOccurred)
1950 : {
1951 0 : fprintf(stderr,
1952 : "CPLGetTLSList(): pthread_setspecific() failed!\n");
1953 0 : *pbMemoryErrorOccurred = TRUE;
1954 0 : return nullptr;
1955 : }
1956 0 : CPLEmergencyError("CPLGetTLSList(): pthread_setspecific() failed!");
1957 : }
1958 : }
1959 :
1960 62815000 : return papTLSList;
1961 : }
1962 :
1963 : /************************************************************************/
1964 : /* CPLStdCallThreadJacket() */
1965 : /************************************************************************/
1966 :
1967 : typedef struct
1968 : {
1969 : void *pAppData;
1970 : CPLThreadFunc pfnMain;
1971 : pthread_t hThread;
1972 : bool bJoinable;
1973 : #ifdef CHECK_THREAD_CAN_ALLOCATE_TLS
1974 : bool bInitSucceeded;
1975 : bool bInitDone;
1976 : pthread_mutex_t sMutex;
1977 : pthread_cond_t sCond;
1978 : #endif
1979 : } CPLStdCallThreadInfo;
1980 :
1981 3807 : static void *CPLStdCallThreadJacket(void *pData)
1982 :
1983 : {
1984 3807 : CPLStdCallThreadInfo *psInfo = static_cast<CPLStdCallThreadInfo *>(pData);
1985 :
1986 : #ifdef CHECK_THREAD_CAN_ALLOCATE_TLS
1987 : int bMemoryError = FALSE;
1988 : CPLGetTLSList(&bMemoryError);
1989 : if (bMemoryError)
1990 : goto error;
1991 :
1992 : assert(pthread_mutex_lock(&(psInfo->sMutex)) == 0);
1993 : psInfo->bInitDone = true;
1994 : assert(pthread_cond_signal(&(psInfo->sCond)) == 0);
1995 : assert(pthread_mutex_unlock(&(psInfo->sMutex)) == 0);
1996 : #endif
1997 :
1998 3807 : psInfo->pfnMain(psInfo->pAppData);
1999 :
2000 3785 : if (!psInfo->bJoinable)
2001 1 : CPLFree(psInfo);
2002 :
2003 3785 : return nullptr;
2004 :
2005 : #ifdef CHECK_THREAD_CAN_ALLOCATE_TLS
2006 : error:
2007 : assert(pthread_mutex_lock(&(psInfo->sMutex)) == 0);
2008 : psInfo->bInitSucceeded = false;
2009 : psInfo->bInitDone = true;
2010 : assert(pthread_cond_signal(&(psInfo->sCond)) == 0);
2011 : assert(pthread_mutex_unlock(&(psInfo->sMutex)) == 0);
2012 : return nullptr;
2013 : #endif
2014 : }
2015 :
2016 : /************************************************************************/
2017 : /* CPLCreateThread() */
2018 : /* */
2019 : /* The WIN32 CreateThread() call requires an entry point that */
2020 : /* has __stdcall conventions, so we provide a jacket function */
2021 : /* to supply that. */
2022 : /************************************************************************/
2023 :
2024 1 : int CPLCreateThread(CPLThreadFunc pfnMain, void *pThreadArg)
2025 :
2026 : {
2027 : CPLStdCallThreadInfo *psInfo = static_cast<CPLStdCallThreadInfo *>(
2028 1 : VSI_CALLOC_VERBOSE(sizeof(CPLStdCallThreadInfo), 1));
2029 1 : if (psInfo == nullptr)
2030 0 : return -1;
2031 1 : psInfo->pAppData = pThreadArg;
2032 1 : psInfo->pfnMain = pfnMain;
2033 1 : psInfo->bJoinable = false;
2034 : #ifdef CHECK_THREAD_CAN_ALLOCATE_TLS
2035 : psInfo->bInitSucceeded = true;
2036 : psInfo->bInitDone = false;
2037 : pthread_mutex_t sMutex = PTHREAD_MUTEX_INITIALIZER;
2038 : psInfo->sMutex = sMutex;
2039 : if (pthread_cond_init(&(psInfo->sCond), nullptr) != 0)
2040 : {
2041 : CPLFree(psInfo);
2042 : fprintf(stderr, "CPLCreateThread() failed.\n");
2043 : return -1;
2044 : }
2045 : #endif
2046 :
2047 : pthread_attr_t hThreadAttr;
2048 1 : pthread_attr_init(&hThreadAttr);
2049 1 : pthread_attr_setdetachstate(&hThreadAttr, PTHREAD_CREATE_DETACHED);
2050 1 : if (pthread_create(&(psInfo->hThread), &hThreadAttr, CPLStdCallThreadJacket,
2051 1 : static_cast<void *>(psInfo)) != 0)
2052 : {
2053 : #ifdef CHECK_THREAD_CAN_ALLOCATE_TLS
2054 : pthread_cond_destroy(&(psInfo->sCond));
2055 : #endif
2056 0 : CPLFree(psInfo);
2057 0 : fprintf(stderr, "CPLCreateThread() failed.\n");
2058 0 : return -1;
2059 : }
2060 :
2061 : #ifdef CHECK_THREAD_CAN_ALLOCATE_TLS
2062 : bool bInitSucceeded;
2063 : while (true)
2064 : {
2065 : assert(pthread_mutex_lock(&(psInfo->sMutex)) == 0);
2066 : bool bInitDone = psInfo->bInitDone;
2067 : if (!bInitDone)
2068 : assert(pthread_cond_wait(&(psInfo->sCond), &(psInfo->sMutex)) == 0);
2069 : bInitSucceeded = psInfo->bInitSucceeded;
2070 : assert(pthread_mutex_unlock(&(psInfo->sMutex)) == 0);
2071 : if (bInitDone)
2072 : break;
2073 : }
2074 :
2075 : pthread_cond_destroy(&(psInfo->sCond));
2076 :
2077 : if (!bInitSucceeded)
2078 : {
2079 : CPLFree(psInfo);
2080 : fprintf(stderr, "CPLCreateThread() failed.\n");
2081 : return -1;
2082 : }
2083 : #endif
2084 :
2085 1 : return 1; // Can we return the actual thread pid?
2086 : }
2087 :
2088 : /************************************************************************/
2089 : /* CPLCreateJoinableThread() */
2090 : /************************************************************************/
2091 :
2092 3807 : CPLJoinableThread *CPLCreateJoinableThread(CPLThreadFunc pfnMain,
2093 : void *pThreadArg)
2094 :
2095 : {
2096 : CPLStdCallThreadInfo *psInfo = static_cast<CPLStdCallThreadInfo *>(
2097 3807 : VSI_CALLOC_VERBOSE(sizeof(CPLStdCallThreadInfo), 1));
2098 3806 : if (psInfo == nullptr)
2099 0 : return nullptr;
2100 3806 : psInfo->pAppData = pThreadArg;
2101 3806 : psInfo->pfnMain = pfnMain;
2102 3806 : psInfo->bJoinable = true;
2103 : #ifdef CHECK_THREAD_CAN_ALLOCATE_TLS
2104 : psInfo->bInitSucceeded = true;
2105 : psInfo->bInitDone = false;
2106 : pthread_mutex_t sMutex = PTHREAD_MUTEX_INITIALIZER;
2107 : psInfo->sMutex = sMutex;
2108 : {
2109 : int err = pthread_cond_init(&(psInfo->sCond), nullptr);
2110 : if (err != 0)
2111 : {
2112 : CPLFree(psInfo);
2113 : fprintf(stderr, "CPLCreateJoinableThread() failed: %s.\n",
2114 : strerror(err));
2115 : return nullptr;
2116 : }
2117 : }
2118 : #endif
2119 :
2120 : pthread_attr_t hThreadAttr;
2121 3806 : pthread_attr_init(&hThreadAttr);
2122 3807 : pthread_attr_setdetachstate(&hThreadAttr, PTHREAD_CREATE_JOINABLE);
2123 : int err =
2124 3806 : pthread_create(&(psInfo->hThread), &hThreadAttr, CPLStdCallThreadJacket,
2125 : static_cast<void *>(psInfo));
2126 3807 : if (err != 0)
2127 : {
2128 : #ifdef CHECK_THREAD_CAN_ALLOCATE_TLS
2129 : pthread_cond_destroy(&(psInfo->sCond));
2130 : #endif
2131 0 : CPLFree(psInfo);
2132 0 : fprintf(stderr, "CPLCreateJoinableThread() failed: %s.\n",
2133 : strerror(err));
2134 0 : return nullptr;
2135 : }
2136 :
2137 : #ifdef CHECK_THREAD_CAN_ALLOCATE_TLS
2138 : bool bInitSucceeded;
2139 : while (true)
2140 : {
2141 : assert(pthread_mutex_lock(&(psInfo->sMutex)) == 0);
2142 : bool bInitDone = psInfo->bInitDone;
2143 : if (!bInitDone)
2144 : assert(pthread_cond_wait(&(psInfo->sCond), &(psInfo->sMutex)) == 0);
2145 : bInitSucceeded = psInfo->bInitSucceeded;
2146 : assert(pthread_mutex_unlock(&(psInfo->sMutex)) == 0);
2147 : if (bInitDone)
2148 : break;
2149 : }
2150 :
2151 : pthread_cond_destroy(&(psInfo->sCond));
2152 :
2153 : if (!bInitSucceeded)
2154 : {
2155 : void *status;
2156 : pthread_join(psInfo->hThread, &status);
2157 : CPLFree(psInfo);
2158 : fprintf(stderr, "CPLCreateJoinableThread() failed.\n");
2159 : return nullptr;
2160 : }
2161 : #endif
2162 :
2163 3807 : return reinterpret_cast<CPLJoinableThread *>(psInfo);
2164 : }
2165 :
2166 : /************************************************************************/
2167 : /* CPLJoinThread() */
2168 : /************************************************************************/
2169 :
2170 3784 : void CPLJoinThread(CPLJoinableThread *hJoinableThread)
2171 : {
2172 3784 : CPLStdCallThreadInfo *psInfo =
2173 : reinterpret_cast<CPLStdCallThreadInfo *>(hJoinableThread);
2174 3784 : if (psInfo == nullptr)
2175 0 : return;
2176 :
2177 : void *status;
2178 3784 : pthread_join(psInfo->hThread, &status);
2179 :
2180 3784 : CPLFree(psInfo);
2181 : }
2182 :
2183 : /************************************************************************/
2184 : /* CPLSleep() */
2185 : /************************************************************************/
2186 :
2187 66 : void CPLSleep(double dfWaitInSeconds)
2188 :
2189 : {
2190 : struct timespec sRequest;
2191 : struct timespec sRemain;
2192 :
2193 66 : sRequest.tv_sec = static_cast<int>(floor(dfWaitInSeconds));
2194 66 : sRequest.tv_nsec =
2195 66 : static_cast<int>((dfWaitInSeconds - sRequest.tv_sec) * 1000000000);
2196 66 : nanosleep(&sRequest, &sRemain);
2197 66 : }
2198 :
2199 : /************************************************************************/
2200 : /* CPLFinalizeTLS() */
2201 : /************************************************************************/
2202 :
2203 437 : void CPLFinalizeTLS()
2204 : {
2205 437 : CPLCleanupTLS();
2206 : // See #5509 for the explanation why this may be needed.
2207 437 : pthread_key_delete(oTLSKey);
2208 437 : }
2209 :
2210 : /************************************************************************/
2211 : /* CPLCleanupTLS() */
2212 : /************************************************************************/
2213 :
2214 1371 : void CPLCleanupTLS()
2215 :
2216 : {
2217 1371 : void **papTLSList = static_cast<void **>(pthread_getspecific(oTLSKey));
2218 1371 : if (papTLSList == nullptr)
2219 1 : return;
2220 :
2221 1370 : pthread_setspecific(oTLSKey, nullptr);
2222 :
2223 1370 : CPLCleanupTLSList(papTLSList);
2224 : }
2225 :
2226 : /************************************************************************/
2227 : /* CPLCreateSpinLock() */
2228 : /************************************************************************/
2229 :
2230 : #if defined(HAVE_PTHREAD_SPIN_LOCK)
2231 : #define HAVE_SPINLOCK_IMPL
2232 :
2233 : struct _CPLSpinLock
2234 : {
2235 : pthread_spinlock_t spin;
2236 : };
2237 :
2238 : CPLSpinLock *CPLCreateSpinLock()
2239 : {
2240 : CPLSpinLock *psSpin =
2241 : static_cast<CPLSpinLock *>(malloc(sizeof(CPLSpinLock)));
2242 : if (psSpin != nullptr &&
2243 : pthread_spin_init(&(psSpin->spin), PTHREAD_PROCESS_PRIVATE) == 0)
2244 : {
2245 : return psSpin;
2246 : }
2247 : else
2248 : {
2249 : fprintf(stderr, "CPLCreateSpinLock() failed.\n");
2250 : free(psSpin);
2251 : return nullptr;
2252 : }
2253 : }
2254 :
2255 : /************************************************************************/
2256 : /* CPLAcquireSpinLock() */
2257 : /************************************************************************/
2258 :
2259 : int CPLAcquireSpinLock(CPLSpinLock *psSpin)
2260 : {
2261 : return pthread_spin_lock(&(psSpin->spin)) == 0;
2262 : }
2263 :
2264 : /************************************************************************/
2265 : /* CPLCreateOrAcquireSpinLockInternal() */
2266 : /************************************************************************/
2267 :
2268 : int CPLCreateOrAcquireSpinLockInternal(CPLLock **ppsLock)
2269 : {
2270 : pthread_mutex_lock(&global_mutex);
2271 : if (*ppsLock == nullptr)
2272 : {
2273 : *ppsLock = static_cast<CPLLock *>(calloc(1, sizeof(CPLLock)));
2274 : if (*ppsLock != nullptr)
2275 : {
2276 : (*ppsLock)->eType = LOCK_SPIN;
2277 : (*ppsLock)->u.hSpinLock = CPLCreateSpinLock();
2278 : if ((*ppsLock)->u.hSpinLock == nullptr)
2279 : {
2280 : free(*ppsLock);
2281 : *ppsLock = nullptr;
2282 : }
2283 : }
2284 : }
2285 : pthread_mutex_unlock(&global_mutex);
2286 : // coverity[missing_unlock]
2287 : return (*ppsLock != nullptr && CPLAcquireSpinLock((*ppsLock)->u.hSpinLock));
2288 : }
2289 :
2290 : /************************************************************************/
2291 : /* CPLReleaseSpinLock() */
2292 : /************************************************************************/
2293 :
2294 : void CPLReleaseSpinLock(CPLSpinLock *psSpin)
2295 : {
2296 : pthread_spin_unlock(&(psSpin->spin));
2297 : }
2298 :
2299 : /************************************************************************/
2300 : /* CPLDestroySpinLock() */
2301 : /************************************************************************/
2302 :
2303 : void CPLDestroySpinLock(CPLSpinLock *psSpin)
2304 : {
2305 : pthread_spin_destroy(&(psSpin->spin));
2306 : free(psSpin);
2307 : }
2308 : #endif // HAVE_PTHREAD_SPIN_LOCK
2309 :
2310 : #endif // def CPL_MULTIPROC_PTHREAD
2311 :
2312 : /************************************************************************/
2313 : /* CPLGetTLS() */
2314 : /************************************************************************/
2315 :
2316 1453950 : void *CPLGetTLS(int nIndex)
2317 :
2318 : {
2319 1453950 : void **l_papTLSList = CPLGetTLSList(nullptr);
2320 :
2321 1454050 : CPLAssert(nIndex >= 0 && nIndex < CTLS_MAX);
2322 :
2323 1454020 : return l_papTLSList[nIndex];
2324 : }
2325 :
2326 : /************************************************************************/
2327 : /* CPLGetTLSEx() */
2328 : /************************************************************************/
2329 :
2330 59807800 : void *CPLGetTLSEx(int nIndex, int *pbMemoryErrorOccurred)
2331 :
2332 : {
2333 59807800 : void **l_papTLSList = CPLGetTLSList(pbMemoryErrorOccurred);
2334 59796300 : if (l_papTLSList == nullptr)
2335 0 : return nullptr;
2336 :
2337 59796300 : CPLAssert(nIndex >= 0 && nIndex < CTLS_MAX);
2338 :
2339 59788400 : return l_papTLSList[nIndex];
2340 : }
2341 :
2342 : /************************************************************************/
2343 : /* CPLSetTLS() */
2344 : /************************************************************************/
2345 :
2346 18067 : void CPLSetTLS(int nIndex, void *pData, int bFreeOnExit)
2347 :
2348 : {
2349 18067 : CPLSetTLSWithFreeFunc(nIndex, pData, (bFreeOnExit) ? CPLFree : nullptr);
2350 18063 : }
2351 :
2352 : /************************************************************************/
2353 : /* CPLSetTLSWithFreeFunc() */
2354 : /************************************************************************/
2355 :
2356 : // Warning: The CPLTLSFreeFunc must not in any case directly or indirectly
2357 : // use or fetch any TLS data, or a terminating thread will hang!
2358 1562260 : void CPLSetTLSWithFreeFunc(int nIndex, void *pData, CPLTLSFreeFunc pfnFree)
2359 :
2360 : {
2361 1562260 : void **l_papTLSList = CPLGetTLSList(nullptr);
2362 :
2363 1557540 : CPLAssert(nIndex >= 0 && nIndex < CTLS_MAX);
2364 :
2365 1555380 : l_papTLSList[nIndex] = pData;
2366 1555380 : l_papTLSList[CTLS_MAX + nIndex] = reinterpret_cast<void *>(pfnFree);
2367 1555380 : }
2368 :
2369 : /************************************************************************/
2370 : /* CPLSetTLSWithFreeFuncEx() */
2371 : /************************************************************************/
2372 :
2373 : // Warning: the CPLTLSFreeFunc must not in any case directly or indirectly
2374 : // use or fetch any TLS data, or a terminating thread will hang!
2375 1357 : void CPLSetTLSWithFreeFuncEx(int nIndex, void *pData, CPLTLSFreeFunc pfnFree,
2376 : int *pbMemoryErrorOccurred)
2377 :
2378 : {
2379 1357 : void **l_papTLSList = CPLGetTLSList(pbMemoryErrorOccurred);
2380 :
2381 1357 : CPLAssert(nIndex >= 0 && nIndex < CTLS_MAX);
2382 :
2383 1357 : l_papTLSList[nIndex] = pData;
2384 1357 : l_papTLSList[CTLS_MAX + nIndex] = reinterpret_cast<void *>(pfnFree);
2385 1357 : }
2386 : #ifndef HAVE_SPINLOCK_IMPL
2387 :
2388 : // No spinlock specific API? Fallback to mutex.
2389 :
2390 : /************************************************************************/
2391 : /* CPLCreateSpinLock() */
2392 : /************************************************************************/
2393 :
2394 33024 : CPLSpinLock *CPLCreateSpinLock(void)
2395 : {
2396 33024 : CPLSpinLock *psSpin = reinterpret_cast<CPLSpinLock *>(CPLCreateMutex());
2397 33024 : if (psSpin)
2398 33024 : CPLReleaseSpinLock(psSpin);
2399 33023 : return psSpin;
2400 : }
2401 :
2402 : /************************************************************************/
2403 : /* CPLCreateOrAcquireSpinLock() */
2404 : /************************************************************************/
2405 :
2406 2 : int CPLCreateOrAcquireSpinLockInternal(CPLLock **ppsLock)
2407 : {
2408 2 : return CPLCreateOrAcquireMutexInternal(ppsLock, 1000, LOCK_ADAPTIVE_MUTEX);
2409 : }
2410 :
2411 : /************************************************************************/
2412 : /* CPLAcquireSpinLock() */
2413 : /************************************************************************/
2414 :
2415 6505590 : int CPLAcquireSpinLock(CPLSpinLock *psSpin)
2416 : {
2417 6505590 : return CPLAcquireMutex(reinterpret_cast<CPLMutex *>(psSpin), 1000);
2418 : }
2419 :
2420 : /************************************************************************/
2421 : /* CPLReleaseSpinLock() */
2422 : /************************************************************************/
2423 :
2424 6538610 : void CPLReleaseSpinLock(CPLSpinLock *psSpin)
2425 : {
2426 6538610 : CPLReleaseMutex(reinterpret_cast<CPLMutex *>(psSpin));
2427 6538650 : }
2428 :
2429 : /************************************************************************/
2430 : /* CPLDestroySpinLock() */
2431 : /************************************************************************/
2432 :
2433 33023 : void CPLDestroySpinLock(CPLSpinLock *psSpin)
2434 : {
2435 33023 : CPLDestroyMutex(reinterpret_cast<CPLMutex *>(psSpin));
2436 33024 : }
2437 :
2438 : #endif // HAVE_SPINLOCK_IMPL
2439 :
2440 : /************************************************************************/
2441 : /* CPLCreateLock() */
2442 : /************************************************************************/
2443 :
2444 33092 : CPLLock *CPLCreateLock(CPLLockType eType)
2445 : {
2446 33092 : switch (eType)
2447 : {
2448 69 : case LOCK_RECURSIVE_MUTEX:
2449 : case LOCK_ADAPTIVE_MUTEX:
2450 : {
2451 139 : CPLMutex *hMutex = CPLCreateMutexEx(eType == LOCK_RECURSIVE_MUTEX
2452 69 : ? CPL_MUTEX_RECURSIVE
2453 : : CPL_MUTEX_ADAPTIVE);
2454 70 : if (!hMutex)
2455 0 : return nullptr;
2456 70 : CPLReleaseMutex(hMutex);
2457 70 : CPLLock *psLock = static_cast<CPLLock *>(malloc(sizeof(CPLLock)));
2458 70 : if (psLock == nullptr)
2459 : {
2460 0 : fprintf(stderr, "CPLCreateLock() failed.\n");
2461 0 : CPLDestroyMutex(hMutex);
2462 0 : return nullptr;
2463 : }
2464 70 : psLock->eType = eType;
2465 70 : psLock->u.hMutex = hMutex;
2466 : #ifdef DEBUG_CONTENTION
2467 70 : psLock->bDebugPerf = false;
2468 70 : psLock->bDebugPerfAsked = false;
2469 70 : psLock->nCurrentHolders = 0;
2470 70 : psLock->nStartTime = 0;
2471 : #endif
2472 70 : return psLock;
2473 : }
2474 33023 : case LOCK_SPIN:
2475 : {
2476 33023 : CPLSpinLock *hSpinLock = CPLCreateSpinLock();
2477 33022 : if (!hSpinLock)
2478 0 : return nullptr;
2479 33022 : CPLLock *psLock = static_cast<CPLLock *>(malloc(sizeof(CPLLock)));
2480 33022 : if (psLock == nullptr)
2481 : {
2482 0 : fprintf(stderr, "CPLCreateLock() failed.\n");
2483 0 : CPLDestroySpinLock(hSpinLock);
2484 0 : return nullptr;
2485 : }
2486 33022 : psLock->eType = eType;
2487 33022 : psLock->u.hSpinLock = hSpinLock;
2488 : #ifdef DEBUG_CONTENTION
2489 33022 : psLock->bDebugPerf = false;
2490 33022 : psLock->bDebugPerfAsked = false;
2491 33022 : psLock->nCurrentHolders = 0;
2492 33022 : psLock->nStartTime = 0;
2493 : #endif
2494 33022 : return psLock;
2495 : }
2496 0 : default:
2497 0 : CPLAssert(false);
2498 : return nullptr;
2499 : }
2500 : }
2501 :
2502 : /************************************************************************/
2503 : /* CPLCreateOrAcquireLock() */
2504 : /************************************************************************/
2505 :
2506 4762 : int CPLCreateOrAcquireLock(CPLLock **ppsLock, CPLLockType eType)
2507 : {
2508 : #ifdef DEBUG_CONTENTION
2509 4762 : GUIntBig nStartTime = 0;
2510 4762 : if ((*ppsLock) && (*ppsLock)->bDebugPerfAsked)
2511 0 : nStartTime = CPLrdtsc();
2512 : #endif
2513 4762 : int ret = 0;
2514 :
2515 4762 : switch (eType)
2516 : {
2517 4760 : case LOCK_RECURSIVE_MUTEX:
2518 : case LOCK_ADAPTIVE_MUTEX:
2519 : {
2520 4760 : ret = CPLCreateOrAcquireMutexInternal(ppsLock, 1000, eType);
2521 4760 : break;
2522 : }
2523 2 : case LOCK_SPIN:
2524 : {
2525 2 : ret = CPLCreateOrAcquireSpinLockInternal(ppsLock);
2526 2 : break;
2527 : }
2528 0 : default:
2529 0 : CPLAssert(false);
2530 : return FALSE;
2531 : }
2532 : #ifdef DEBUG_CONTENTION
2533 4762 : if (ret && (*ppsLock)->bDebugPerfAsked &&
2534 0 : CPLAtomicInc(&((*ppsLock)->nCurrentHolders)) == 1)
2535 : {
2536 0 : (*ppsLock)->bDebugPerf = true;
2537 0 : (*ppsLock)->nStartTime = nStartTime;
2538 : }
2539 : #endif
2540 4762 : return ret;
2541 : }
2542 :
2543 : /************************************************************************/
2544 : /* CPLAcquireLock() */
2545 : /************************************************************************/
2546 :
2547 24048500 : int CPLAcquireLock(CPLLock *psLock)
2548 : {
2549 : #ifdef DEBUG_CONTENTION
2550 24048500 : GUIntBig nStartTime = 0;
2551 24048500 : if (psLock->bDebugPerfAsked)
2552 1952510 : nStartTime = CPLrdtsc();
2553 : #endif
2554 : int ret;
2555 24048200 : if (psLock->eType == LOCK_SPIN)
2556 6505590 : ret = CPLAcquireSpinLock(psLock->u.hSpinLock);
2557 : else
2558 17542600 : ret = CPLAcquireMutex(psLock->u.hMutex, 1000);
2559 : #ifdef DEBUG_CONTENTION
2560 26004700 : if (ret && psLock->bDebugPerfAsked &&
2561 1952510 : CPLAtomicInc(&(psLock->nCurrentHolders)) == 1)
2562 : {
2563 1952510 : psLock->bDebugPerf = true;
2564 1952510 : psLock->nStartTime = nStartTime;
2565 : }
2566 : #endif
2567 24052200 : return ret;
2568 : }
2569 :
2570 : /************************************************************************/
2571 : /* CPLReleaseLock() */
2572 : /************************************************************************/
2573 :
2574 24056900 : void CPLReleaseLock(CPLLock *psLock)
2575 : {
2576 : #ifdef DEBUG_CONTENTION
2577 24056900 : bool bHitMaxDiff = false;
2578 24056900 : GIntBig nMaxDiff = 0;
2579 24056900 : double dfAvgDiff = 0;
2580 24056900 : if (psLock->bDebugPerf && CPLAtomicDec(&(psLock->nCurrentHolders)) == 0)
2581 : {
2582 1952510 : const GUIntBig nStopTime = CPLrdtscp();
2583 : // coverity[missing_lock:FALSE]
2584 1952510 : const GIntBig nDiffTime =
2585 1952510 : static_cast<GIntBig>(nStopTime - psLock->nStartTime);
2586 1952510 : if (nDiffTime > psLock->nMaxDiff)
2587 : {
2588 26 : bHitMaxDiff = true;
2589 26 : psLock->nMaxDiff = nDiffTime;
2590 : }
2591 1952510 : nMaxDiff = psLock->nMaxDiff;
2592 1952510 : psLock->nIters++;
2593 1952510 : psLock->dfAvgDiff += (nDiffTime - psLock->dfAvgDiff) / psLock->nIters;
2594 1952510 : dfAvgDiff = psLock->dfAvgDiff;
2595 : }
2596 : #endif
2597 24056900 : if (psLock->eType == LOCK_SPIN)
2598 6505590 : CPLReleaseSpinLock(psLock->u.hSpinLock);
2599 : else
2600 17551300 : CPLReleaseMutex(psLock->u.hMutex);
2601 : #ifdef DEBUG_CONTENTION
2602 24056900 : if (psLock->bDebugPerf &&
2603 1952490 : (bHitMaxDiff || (psLock->nIters % 1000000) == (1000000 - 1)))
2604 : {
2605 26 : CPLDebug("LOCK", "Lock contention : max = " CPL_FRMT_GIB ", avg = %.0f",
2606 : nMaxDiff, dfAvgDiff);
2607 : }
2608 : #endif
2609 24056900 : }
2610 :
2611 : /************************************************************************/
2612 : /* CPLDestroyLock() */
2613 : /************************************************************************/
2614 :
2615 33507 : void CPLDestroyLock(CPLLock *psLock)
2616 : {
2617 33507 : if (psLock->eType == LOCK_SPIN)
2618 33022 : CPLDestroySpinLock(psLock->u.hSpinLock);
2619 : else
2620 485 : CPLDestroyMutex(psLock->u.hMutex);
2621 33507 : free(psLock);
2622 33507 : }
2623 :
2624 : /************************************************************************/
2625 : /* CPLLockSetDebugPerf() */
2626 : /************************************************************************/
2627 :
2628 : #ifdef DEBUG_CONTENTION
2629 4762 : void CPLLockSetDebugPerf(CPLLock *psLock, int bEnableIn)
2630 : {
2631 4762 : psLock->bDebugPerfAsked = CPL_TO_BOOL(bEnableIn);
2632 4762 : }
2633 : #else
2634 : void CPLLockSetDebugPerf(CPLLock * /* psLock */, int bEnableIn)
2635 : {
2636 : if (!bEnableIn)
2637 : return;
2638 :
2639 : static bool bOnce = false;
2640 : if (!bOnce)
2641 : {
2642 : bOnce = true;
2643 : CPLDebug("LOCK", "DEBUG_CONTENTION not available");
2644 : }
2645 : }
2646 : #endif
2647 :
2648 : /************************************************************************/
2649 : /* CPLLockHolder() */
2650 : /************************************************************************/
2651 :
2652 4762 : CPLLockHolder::CPLLockHolder(CPLLock **phLock, CPLLockType eType,
2653 4762 : const char *pszFileIn, int nLineIn)
2654 :
2655 : {
2656 : #ifndef MUTEX_NONE
2657 4762 : pszFile = pszFileIn;
2658 4762 : nLine = nLineIn;
2659 :
2660 : #ifdef DEBUG_MUTEX
2661 : // XXX: There is no way to use CPLDebug() here because it works with
2662 : // mutexes itself so we will fall in infinite recursion. Good old
2663 : // fprintf() will do the job right.
2664 : fprintf(stderr, "CPLLockHolder: Request %p for pid %ld at %d/%s.\n",
2665 : *phLock, static_cast<long>(CPLGetPID()), nLine, pszFile);
2666 : #endif
2667 :
2668 4762 : if (!CPLCreateOrAcquireLock(phLock, eType))
2669 : {
2670 0 : fprintf(stderr, "CPLLockHolder: Failed to acquire lock!\n");
2671 0 : hLock = nullptr;
2672 : }
2673 : else
2674 : {
2675 : #ifdef DEBUG_MUTEX
2676 : fprintf(stderr, "CPLLockHolder: Acquired %p for pid %ld at %d/%s.\n",
2677 : *phLock, static_cast<long>(CPLGetPID()), nLine, pszFile);
2678 : #endif
2679 :
2680 4762 : hLock = *phLock;
2681 : }
2682 : #endif // ndef MUTEX_NONE
2683 4762 : }
2684 :
2685 : /************************************************************************/
2686 : /* CPLLockHolder() */
2687 : /************************************************************************/
2688 :
2689 24045600 : CPLLockHolder::CPLLockHolder(CPLLock *hLockIn, const char *pszFileIn,
2690 24045600 : int nLineIn)
2691 :
2692 : {
2693 : #ifndef MUTEX_NONE
2694 24045600 : pszFile = pszFileIn;
2695 24045600 : nLine = nLineIn;
2696 24045600 : hLock = hLockIn;
2697 :
2698 24045600 : if (hLock != nullptr)
2699 : {
2700 24044300 : if (!CPLAcquireLock(hLock))
2701 : {
2702 0 : fprintf(stderr, "CPLLockHolder: Failed to acquire lock!\n");
2703 0 : hLock = nullptr;
2704 : }
2705 : }
2706 : #endif // ndef MUTEX_NONE
2707 24048700 : }
2708 :
2709 : /************************************************************************/
2710 : /* ~CPLLockHolder() */
2711 : /************************************************************************/
2712 :
2713 48104100 : CPLLockHolder::~CPLLockHolder()
2714 :
2715 : {
2716 : #ifndef MUTEX_NONE
2717 24052100 : if (hLock != nullptr)
2718 : {
2719 : #ifdef DEBUG_MUTEX
2720 : fprintf(stderr, "~CPLLockHolder: Release %p for pid %ld at %d/%s.\n",
2721 : hLock, static_cast<long>(CPLGetPID()), nLine, pszFile);
2722 : #endif
2723 24052100 : CPLReleaseLock(hLock);
2724 : }
2725 : #endif // ndef MUTEX_NONE
2726 24052100 : }
2727 :
2728 : /************************************************************************/
2729 : /* CPLGetCurrentProcessID() */
2730 : /************************************************************************/
2731 :
2732 : #ifdef CPL_MULTIPROC_WIN32
2733 :
2734 : int CPLGetCurrentProcessID()
2735 : {
2736 : return GetCurrentProcessId();
2737 : }
2738 :
2739 : #else
2740 :
2741 : #include <sys/types.h>
2742 : #include <unistd.h>
2743 :
2744 2326 : int CPLGetCurrentProcessID()
2745 : {
2746 2326 : return getpid();
2747 : }
2748 :
2749 : #endif
|