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