1 : /**********************************************************************
2 : * $Id: cpl_multiproc.cpp 25226 2012-11-11 20:23:39Z rouault $
3 : *
4 : * Project: CPL - Common Portability Library
5 : * Purpose: CPL Multi-Threading, and process handling portability functions.
6 : * Author: Frank Warmerdam, warmerdam@pobox.com
7 : *
8 : **********************************************************************
9 : * Copyright (c) 2002, Frank Warmerdam
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_multiproc.h"
35 : #include "cpl_conv.h"
36 :
37 : #if !defined(WIN32CE)
38 : # include <time.h>
39 : #else
40 : # include <wce_time.h>
41 : #endif
42 :
43 : CPL_CVSID("$Id: cpl_multiproc.cpp 25226 2012-11-11 20:23:39Z rouault $");
44 :
45 : #if defined(CPL_MULTIPROC_STUB) && !defined(DEBUG)
46 : # define MUTEX_NONE
47 : #endif
48 :
49 : /************************************************************************/
50 : /* CPLMutexHolder() */
51 : /************************************************************************/
52 :
53 15794988 : CPLMutexHolder::CPLMutexHolder( void **phMutex, double dfWaitInSeconds,
54 : const char *pszFileIn,
55 : int nLineIn )
56 :
57 : {
58 : #ifndef MUTEX_NONE
59 15794988 : pszFile = pszFileIn;
60 15794988 : nLine = nLineIn;
61 :
62 : #ifdef DEBUG_MUTEX
63 : /*
64 : * XXX: There is no way to use CPLDebug() here because it works with
65 : * mutexes itself so we will fall in infinite recursion. Good old
66 : * fprintf() will do the job right.
67 : */
68 : fprintf( stderr,
69 : "CPLMutexHolder: Request %p for pid %ld at %d/%s.\n",
70 : *phMutex, (long) CPLGetPID(), nLine, pszFile );
71 : #endif
72 :
73 15794988 : if( !CPLCreateOrAcquireMutex( phMutex, dfWaitInSeconds ) )
74 : {
75 0 : fprintf( stderr, "CPLMutexHolder: Failed to acquire mutex!\n" );
76 0 : hMutex = NULL;
77 : }
78 : else
79 : {
80 : #ifdef DEBUG_MUTEX
81 : fprintf( stderr,
82 : "CPLMutexHolder: Acquired %p for pid %ld at %d/%s.\n",
83 : *phMutex, (long) CPLGetPID(), nLine, pszFile );
84 : #endif
85 :
86 15794988 : hMutex = *phMutex;
87 : }
88 : #endif /* ndef MUTEX_NONE */
89 15794988 : }
90 :
91 : /************************************************************************/
92 : /* ~CPLMutexHolder() */
93 : /************************************************************************/
94 :
95 15794988 : CPLMutexHolder::~CPLMutexHolder()
96 :
97 : {
98 : #ifndef MUTEX_NONE
99 15794988 : if( hMutex != NULL )
100 : {
101 : #ifdef DEBUG_MUTEX
102 : fprintf( stderr,
103 : "~CPLMutexHolder: Release %p for pid %ld at %d/%s.\n",
104 : hMutex, (long) CPLGetPID(), nLine, pszFile );
105 : #endif
106 15794988 : CPLReleaseMutex( hMutex );
107 : }
108 : #endif /* ndef MUTEX_NONE */
109 15794988 : }
110 :
111 :
112 : /************************************************************************/
113 : /* CPLCreateOrAcquireMutex() */
114 : /************************************************************************/
115 :
116 : #ifndef CPL_MULTIPROC_PTHREAD
117 : int CPLCreateOrAcquireMutex( void **phMutex, double dfWaitInSeconds )
118 :
119 : {
120 : int bSuccess = FALSE;
121 :
122 : #ifndef MUTEX_NONE
123 : static void *hCOAMutex = NULL;
124 :
125 : /*
126 : ** ironically, creation of this initial mutex is not threadsafe
127 : ** even though we use it to ensure that creation of other mutexes
128 : ** is threadsafe.
129 : */
130 : if( hCOAMutex == NULL )
131 : {
132 : hCOAMutex = CPLCreateMutex();
133 : if (hCOAMutex == NULL)
134 : {
135 : *phMutex = NULL;
136 : return FALSE;
137 : }
138 : }
139 : else
140 : {
141 : CPLAcquireMutex( hCOAMutex, dfWaitInSeconds );
142 : }
143 :
144 : if( *phMutex == NULL )
145 : {
146 : *phMutex = CPLCreateMutex();
147 : bSuccess = *phMutex != NULL;
148 : CPLReleaseMutex( hCOAMutex );
149 : }
150 : else
151 : {
152 : CPLReleaseMutex( hCOAMutex );
153 :
154 : bSuccess = CPLAcquireMutex( *phMutex, dfWaitInSeconds );
155 : }
156 : #endif /* ndef MUTEX_NONE */
157 :
158 : return bSuccess;
159 : }
160 : #endif
161 :
162 : /************************************************************************/
163 : /* CPLCleanupTLSList() */
164 : /* */
165 : /* Free resources associated with a TLS vector (implementation */
166 : /* independent). */
167 : /************************************************************************/
168 :
169 1102 : static void CPLCleanupTLSList( void **papTLSList )
170 :
171 : {
172 : int i;
173 :
174 : // printf( "CPLCleanupTLSList(%p)\n", papTLSList );
175 :
176 1102 : if( papTLSList == NULL )
177 0 : return;
178 :
179 36366 : for( i = 0; i < CTLS_MAX; i++ )
180 : {
181 35264 : if( papTLSList[i] != NULL && papTLSList[i+CTLS_MAX] != NULL )
182 : {
183 2572 : CPLTLSFreeFunc pfnFree = (CPLTLSFreeFunc) papTLSList[i + CTLS_MAX];
184 2572 : pfnFree( papTLSList[i] );
185 2572 : papTLSList[i] = NULL;
186 : }
187 : }
188 :
189 1102 : CPLFree( papTLSList );
190 : }
191 :
192 : #if defined(CPL_MULTIPROC_STUB)
193 : /************************************************************************/
194 : /* ==================================================================== */
195 : /* CPL_MULTIPROC_STUB */
196 : /* */
197 : /* Stub implementation. Mutexes don't provide exclusion, file */
198 : /* locking is achieved with extra "lock files", and thread */
199 : /* creation doesn't work. The PID is always just one. */
200 : /* ==================================================================== */
201 : /************************************************************************/
202 :
203 : /************************************************************************/
204 : /* CPLGetNumCPUs() */
205 : /************************************************************************/
206 :
207 : int CPLGetNumCPUs()
208 : {
209 : return 1;
210 : }
211 :
212 : /************************************************************************/
213 : /* CPLGetThreadingModel() */
214 : /************************************************************************/
215 :
216 : const char *CPLGetThreadingModel()
217 :
218 : {
219 : return "stub";
220 : }
221 :
222 : /************************************************************************/
223 : /* CPLCreateMutex() */
224 : /************************************************************************/
225 :
226 : void *CPLCreateMutex()
227 :
228 : {
229 : #ifndef MUTEX_NONE
230 : unsigned char *pabyMutex = (unsigned char *) malloc( 4 );
231 :
232 : pabyMutex[0] = 1;
233 : pabyMutex[1] = 'r';
234 : pabyMutex[2] = 'e';
235 : pabyMutex[3] = 'd';
236 :
237 : return (void *) pabyMutex;
238 : #else
239 : return (void *) 0xdeadbeef;
240 : #endif
241 : }
242 :
243 : /************************************************************************/
244 : /* CPLAcquireMutex() */
245 : /************************************************************************/
246 :
247 : int CPLAcquireMutex( void *hMutex, double dfWaitInSeconds )
248 :
249 : {
250 : #ifndef MUTEX_NONE
251 : unsigned char *pabyMutex = (unsigned char *) hMutex;
252 :
253 : CPLAssert( pabyMutex[1] == 'r' && pabyMutex[2] == 'e'
254 : && pabyMutex[3] == 'd' );
255 :
256 : pabyMutex[0] += 1;
257 :
258 : return TRUE;
259 : #else
260 : return TRUE;
261 : #endif
262 : }
263 :
264 : /************************************************************************/
265 : /* CPLReleaseMutex() */
266 : /************************************************************************/
267 :
268 : void CPLReleaseMutex( void *hMutex )
269 :
270 : {
271 : #ifndef MUTEX_NONE
272 : unsigned char *pabyMutex = (unsigned char *) hMutex;
273 :
274 : CPLAssert( pabyMutex[1] == 'r' && pabyMutex[2] == 'e'
275 : && pabyMutex[3] == 'd' );
276 :
277 : if( pabyMutex[0] < 1 )
278 : CPLDebug( "CPLMultiProc",
279 : "CPLReleaseMutex() called on mutex with %d as ref count!",
280 : pabyMutex[0] );
281 :
282 : pabyMutex[0] -= 1;
283 : #endif
284 : }
285 :
286 : /************************************************************************/
287 : /* CPLDestroyMutex() */
288 : /************************************************************************/
289 :
290 : void CPLDestroyMutex( void *hMutex )
291 :
292 : {
293 : #ifndef MUTEX_NONE
294 : unsigned char *pabyMutex = (unsigned char *) hMutex;
295 :
296 : CPLAssert( pabyMutex[1] == 'r' && pabyMutex[2] == 'e'
297 : && pabyMutex[3] == 'd' );
298 :
299 : free( pabyMutex );
300 : #endif
301 : }
302 :
303 : /************************************************************************/
304 : /* CPLCreateCond() */
305 : /************************************************************************/
306 :
307 : void *CPLCreateCond()
308 : {
309 : return NULL;
310 : }
311 :
312 : /************************************************************************/
313 : /* CPLCondWait() */
314 : /************************************************************************/
315 :
316 : void CPLCondWait( void *hCond, void* hMutex )
317 : {
318 : }
319 :
320 : /************************************************************************/
321 : /* CPLCondSignal() */
322 : /************************************************************************/
323 :
324 : void CPLCondSignal( void *hCond )
325 : {
326 : }
327 :
328 : /************************************************************************/
329 : /* CPLCondBroadcast() */
330 : /************************************************************************/
331 :
332 : void CPLCondBroadcast( void *hCond )
333 : {
334 : }
335 :
336 : /************************************************************************/
337 : /* CPLDestroyCond() */
338 : /************************************************************************/
339 :
340 : void CPLDestroyCond( void *hCond )
341 : {
342 : }
343 :
344 : /************************************************************************/
345 : /* CPLLockFile() */
346 : /* */
347 : /* Lock a file. This implementation has a terrible race */
348 : /* condition. If we don't succeed in opening the lock file, we */
349 : /* assume we can create one and own the target file, but other */
350 : /* processes might easily try creating the target file at the */
351 : /* same time, overlapping us. Death! Mayhem! The traditional */
352 : /* solution is to use open() with _O_CREAT|_O_EXCL but this */
353 : /* function and these arguments aren't trivially portable. */
354 : /* Also, this still leaves a race condition on NFS drivers */
355 : /* (apparently). */
356 : /************************************************************************/
357 :
358 : void *CPLLockFile( const char *pszPath, double dfWaitInSeconds )
359 :
360 : {
361 : FILE *fpLock;
362 : char *pszLockFilename;
363 :
364 : /* -------------------------------------------------------------------- */
365 : /* We use a lock file with a name derived from the file we want */
366 : /* to lock to represent the file being locked. Note that for */
367 : /* the stub implementation the target file does not even need */
368 : /* to exist to be locked. */
369 : /* -------------------------------------------------------------------- */
370 : pszLockFilename = (char *) CPLMalloc(strlen(pszPath) + 30);
371 : sprintf( pszLockFilename, "%s.lock", pszPath );
372 :
373 : fpLock = fopen( pszLockFilename, "r" );
374 : while( fpLock != NULL && dfWaitInSeconds > 0.0 )
375 : {
376 : fclose( fpLock );
377 : CPLSleep( MIN(dfWaitInSeconds,0.5) );
378 : dfWaitInSeconds -= 0.5;
379 :
380 : fpLock = fopen( pszLockFilename, "r" );
381 : }
382 :
383 : if( fpLock != NULL )
384 : {
385 : fclose( fpLock );
386 : CPLFree( pszLockFilename );
387 : return NULL;
388 : }
389 :
390 : fpLock = fopen( pszLockFilename, "w" );
391 :
392 : if( fpLock == NULL )
393 : {
394 : CPLFree( pszLockFilename );
395 : return NULL;
396 : }
397 :
398 : fwrite( "held\n", 1, 5, fpLock );
399 : fclose( fpLock );
400 :
401 : return pszLockFilename;
402 : }
403 :
404 : /************************************************************************/
405 : /* CPLUnlockFile() */
406 : /************************************************************************/
407 :
408 : void CPLUnlockFile( void *hLock )
409 :
410 : {
411 : char *pszLockFilename = (char *) hLock;
412 :
413 : if( hLock == NULL )
414 : return;
415 :
416 : VSIUnlink( pszLockFilename );
417 :
418 : CPLFree( pszLockFilename );
419 : }
420 :
421 : /************************************************************************/
422 : /* CPLGetPID() */
423 : /************************************************************************/
424 :
425 : GIntBig CPLGetPID()
426 :
427 : {
428 : return 1;
429 : }
430 :
431 : /************************************************************************/
432 : /* CPLCreateThread(); */
433 : /************************************************************************/
434 :
435 : int CPLCreateThread( CPLThreadFunc pfnMain, void *pArg )
436 :
437 : {
438 : CPLDebug( "CPLCreateThread", "Fails to dummy implementation" );
439 :
440 : return -1;
441 : }
442 :
443 : /************************************************************************/
444 : /* CPLCreateJoinableThread() */
445 : /************************************************************************/
446 :
447 : void* CPLCreateJoinableThread( CPLThreadFunc pfnMain, void *pThreadArg )
448 :
449 : {
450 : CPLDebug( "CPLCreateJoinableThread", "Fails to dummy implementation" );
451 :
452 : return NULL;
453 : }
454 :
455 : /************************************************************************/
456 : /* CPLJoinThread() */
457 : /************************************************************************/
458 :
459 : void CPLJoinThread(void* hJoinableThread)
460 : {
461 : }
462 :
463 : /************************************************************************/
464 : /* CPLSleep() */
465 : /************************************************************************/
466 :
467 : void CPLSleep( double dfWaitInSeconds )
468 :
469 : {
470 : time_t ltime;
471 : time_t ttime;
472 :
473 : time( <ime );
474 : ttime = ltime + (int) (dfWaitInSeconds+0.5);
475 :
476 : for( ; ltime < ttime; time(<ime) )
477 : {
478 : /* currently we just busy wait. Perhaps we could at least block on
479 : io? */
480 : }
481 : }
482 :
483 : /************************************************************************/
484 : /* CPLGetTLSList() */
485 : /************************************************************************/
486 :
487 : static void **papTLSList = NULL;
488 :
489 : static void **CPLGetTLSList()
490 :
491 : {
492 : if( papTLSList == NULL )
493 : papTLSList = (void **) CPLCalloc(sizeof(void*),CTLS_MAX*2);
494 :
495 : return papTLSList;
496 : }
497 :
498 : /************************************************************************/
499 : /* CPLCleanupTLS() */
500 : /************************************************************************/
501 :
502 : void CPLCleanupTLS()
503 :
504 : {
505 : CPLCleanupTLSList( papTLSList );
506 : papTLSList = NULL;
507 : }
508 :
509 : /* endif CPL_MULTIPROC_STUB */
510 :
511 : #elif defined(CPL_MULTIPROC_WIN32)
512 :
513 :
514 : /************************************************************************/
515 : /* ==================================================================== */
516 : /* CPL_MULTIPROC_WIN32 */
517 : /* */
518 : /* WIN32 Implementation of multiprocessing functions. */
519 : /* ==================================================================== */
520 : /************************************************************************/
521 :
522 : /* InitializeCriticalSectionAndSpinCount requires _WIN32_WINNT >= 0x403 */
523 : #define _WIN32_WINNT 0x0500
524 :
525 : #include <windows.h>
526 :
527 : /* windows.h header must be included above following lines. */
528 : #if defined(WIN32CE)
529 : # include "cpl_win32ce_api.h"
530 : # define TLS_OUT_OF_INDEXES ((DWORD)0xFFFFFFFF)
531 : #endif
532 :
533 : /************************************************************************/
534 : /* CPLGetNumCPUs() */
535 : /************************************************************************/
536 :
537 : int CPLGetNumCPUs()
538 : {
539 : SYSTEM_INFO info;
540 : GetSystemInfo(&info);
541 : DWORD dwNum = info.dwNumberOfProcessors;
542 : if( dwNum < 1 )
543 : return 1;
544 : return (int)dwNum;
545 : }
546 :
547 : /************************************************************************/
548 : /* CPLGetThreadingModel() */
549 : /************************************************************************/
550 :
551 : const char *CPLGetThreadingModel()
552 :
553 : {
554 : return "win32";
555 : }
556 :
557 : /************************************************************************/
558 : /* CPLCreateMutex() */
559 : /************************************************************************/
560 :
561 : void *CPLCreateMutex()
562 :
563 : {
564 : #ifdef USE_WIN32_MUTEX
565 : HANDLE hMutex;
566 :
567 : hMutex = CreateMutex( NULL, TRUE, NULL );
568 :
569 : return (void *) hMutex;
570 : #else
571 : CRITICAL_SECTION *pcs;
572 :
573 : /* Do not use CPLMalloc() since its debugging infrastructure */
574 : /* can call the CPL*Mutex functions... */
575 : pcs = (CRITICAL_SECTION *)malloc(sizeof(*pcs));
576 : if( pcs )
577 : {
578 : InitializeCriticalSectionAndSpinCount(pcs, 4000);
579 : EnterCriticalSection(pcs);
580 : }
581 :
582 : return (void *) pcs;
583 : #endif
584 : }
585 :
586 : /************************************************************************/
587 : /* CPLAcquireMutex() */
588 : /************************************************************************/
589 :
590 : int CPLAcquireMutex( void *hMutexIn, double dfWaitInSeconds )
591 :
592 : {
593 : #ifdef USE_WIN32_MUTEX
594 : HANDLE hMutex = (HANDLE) hMutexIn;
595 : DWORD hr;
596 :
597 : hr = WaitForSingleObject( hMutex, (int) (dfWaitInSeconds * 1000) );
598 :
599 : return hr != WAIT_TIMEOUT;
600 : #else
601 : CRITICAL_SECTION *pcs = (CRITICAL_SECTION *)hMutexIn;
602 : BOOL ret;
603 :
604 : while( (ret = TryEnterCriticalSection(pcs)) == 0 && dfWaitInSeconds > 0.0 )
605 : {
606 : CPLSleep( MIN(dfWaitInSeconds,0.125) );
607 : dfWaitInSeconds -= 0.125;
608 : }
609 :
610 : return ret;
611 : #endif
612 : }
613 :
614 : /************************************************************************/
615 : /* CPLReleaseMutex() */
616 : /************************************************************************/
617 :
618 : void CPLReleaseMutex( void *hMutexIn )
619 :
620 : {
621 : #ifdef USE_WIN32_MUTEX
622 : HANDLE hMutex = (HANDLE) hMutexIn;
623 :
624 : ReleaseMutex( hMutex );
625 : #else
626 : CRITICAL_SECTION *pcs = (CRITICAL_SECTION *)hMutexIn;
627 :
628 : LeaveCriticalSection(pcs);
629 : #endif
630 : }
631 :
632 : /************************************************************************/
633 : /* CPLDestroyMutex() */
634 : /************************************************************************/
635 :
636 : void CPLDestroyMutex( void *hMutexIn )
637 :
638 : {
639 : #ifdef USE_WIN32_MUTEX
640 : HANDLE hMutex = (HANDLE) hMutexIn;
641 :
642 : CloseHandle( hMutex );
643 : #else
644 : CRITICAL_SECTION *pcs = (CRITICAL_SECTION *)hMutexIn;
645 :
646 : DeleteCriticalSection( pcs );
647 : free( pcs );
648 : #endif
649 : }
650 :
651 : /************************************************************************/
652 : /* CPLCreateCond() */
653 : /************************************************************************/
654 :
655 : struct _WaiterItem
656 : {
657 : HANDLE hEvent;
658 : struct _WaiterItem* psNext;
659 : };
660 : typedef struct _WaiterItem WaiterItem;
661 :
662 : typedef struct
663 : {
664 : void *hInternalMutex;
665 : WaiterItem *psWaiterList;
666 : } Win32Cond;
667 :
668 : void *CPLCreateCond()
669 : {
670 : Win32Cond* psCond = (Win32Cond*) malloc(sizeof(Win32Cond));
671 : if (psCond == NULL)
672 : return NULL;
673 : psCond->hInternalMutex = CPLCreateMutex();
674 : if (psCond->hInternalMutex == NULL)
675 : {
676 : free(psCond);
677 : return NULL;
678 : }
679 : CPLReleaseMutex(psCond->hInternalMutex);
680 : psCond->psWaiterList = NULL;
681 : return psCond;
682 : }
683 :
684 : /************************************************************************/
685 : /* CPLCondWait() */
686 : /************************************************************************/
687 :
688 : static void CPLTLSFreeEvent(void* pData)
689 : {
690 : CloseHandle((HANDLE)pData);
691 : }
692 :
693 : void CPLCondWait( void *hCond, void* hClientMutex )
694 : {
695 : Win32Cond* psCond = (Win32Cond*) hCond;
696 :
697 : HANDLE hEvent = (HANDLE) CPLGetTLS(CTLS_WIN32_COND);
698 : if (hEvent == NULL)
699 : {
700 : hEvent = CreateEvent(NULL, /* security attributes */
701 : 0, /* manual reset = no */
702 : 0, /* initial state = unsignaled */
703 : NULL /* no name */);
704 : CPLAssert(hEvent != NULL);
705 :
706 : CPLSetTLSWithFreeFunc(CTLS_WIN32_COND, hEvent, CPLTLSFreeEvent);
707 : }
708 :
709 : /* Insert the waiter into the waiter list of the condition */
710 : CPLAcquireMutex(psCond->hInternalMutex, 1000.0);
711 :
712 : WaiterItem* psItem = (WaiterItem*)malloc(sizeof(WaiterItem));
713 : CPLAssert(psItem != NULL);
714 :
715 : psItem->hEvent = hEvent;
716 : psItem->psNext = psCond->psWaiterList;
717 :
718 : psCond->psWaiterList = psItem;
719 :
720 : CPLReleaseMutex(psCond->hInternalMutex);
721 :
722 : /* Release the client mutex before waiting for the event being signaled */
723 : CPLReleaseMutex(hClientMutex);
724 :
725 : DWORD nRet = WaitForSingleObject(hEvent, INFINITE);
726 : CPLAssert (nRet != WAIT_FAILED);
727 :
728 : /* Reacquire the client mutex */
729 : CPLAcquireMutex(hClientMutex, 1000.0);
730 : }
731 :
732 : /************************************************************************/
733 : /* CPLCondSignal() */
734 : /************************************************************************/
735 :
736 : void CPLCondSignal( void *hCond )
737 : {
738 : Win32Cond* psCond = (Win32Cond*) hCond;
739 :
740 : /* Signal the first registered event, and remove it from the list */
741 : CPLAcquireMutex(psCond->hInternalMutex, 1000.0);
742 :
743 : WaiterItem* psIter = psCond->psWaiterList;
744 : if (psIter != NULL)
745 : {
746 : SetEvent(psIter->hEvent);
747 : psCond->psWaiterList = psIter->psNext;
748 : free(psIter);
749 : }
750 :
751 : CPLReleaseMutex(psCond->hInternalMutex);
752 : }
753 :
754 : /************************************************************************/
755 : /* CPLCondBroadcast() */
756 : /************************************************************************/
757 :
758 : void CPLCondBroadcast( void *hCond )
759 : {
760 : Win32Cond* psCond = (Win32Cond*) hCond;
761 :
762 : /* Signal all the registered events, and remove them from the list */
763 : CPLAcquireMutex(psCond->hInternalMutex, 1000.0);
764 :
765 : WaiterItem* psIter = psCond->psWaiterList;
766 : while (psIter != NULL)
767 : {
768 : WaiterItem* psNext = psIter->psNext;
769 : SetEvent(psIter->hEvent);
770 : free(psIter);
771 : psIter = psNext;
772 : }
773 : psCond->psWaiterList = NULL;
774 :
775 : CPLReleaseMutex(psCond->hInternalMutex);
776 : }
777 :
778 : /************************************************************************/
779 : /* CPLDestroyCond() */
780 : /************************************************************************/
781 :
782 : void CPLDestroyCond( void *hCond )
783 : {
784 : Win32Cond* psCond = (Win32Cond*) hCond;
785 : CPLDestroyMutex(psCond->hInternalMutex);
786 : psCond->hInternalMutex = NULL;
787 : CPLAssert(psCond->psWaiterList == NULL);
788 : free(psCond);
789 : }
790 :
791 : /************************************************************************/
792 : /* CPLLockFile() */
793 : /************************************************************************/
794 :
795 : void *CPLLockFile( const char *pszPath, double dfWaitInSeconds )
796 :
797 : {
798 : char *pszLockFilename;
799 : HANDLE hLockFile;
800 :
801 : pszLockFilename = (char *) CPLMalloc(strlen(pszPath) + 30);
802 : sprintf( pszLockFilename, "%s.lock", pszPath );
803 :
804 : hLockFile =
805 : CreateFile( pszLockFilename, GENERIC_WRITE, 0, NULL,CREATE_NEW,
806 : FILE_ATTRIBUTE_NORMAL|FILE_FLAG_DELETE_ON_CLOSE, NULL );
807 :
808 : while( GetLastError() == ERROR_ALREADY_EXISTS
809 : && dfWaitInSeconds > 0.0 )
810 : {
811 : CloseHandle( hLockFile );
812 : CPLSleep( MIN(dfWaitInSeconds,0.125) );
813 : dfWaitInSeconds -= 0.125;
814 :
815 : hLockFile =
816 : CreateFile( pszLockFilename, GENERIC_WRITE, 0, NULL, CREATE_NEW,
817 : FILE_ATTRIBUTE_NORMAL|FILE_FLAG_DELETE_ON_CLOSE,
818 : NULL );
819 : }
820 :
821 : CPLFree( pszLockFilename );
822 :
823 : if( hLockFile == INVALID_HANDLE_VALUE )
824 : return NULL;
825 :
826 : if( GetLastError() == ERROR_ALREADY_EXISTS )
827 : {
828 : CloseHandle( hLockFile );
829 : return NULL;
830 : }
831 :
832 : return (void *) hLockFile;
833 : }
834 :
835 : /************************************************************************/
836 : /* CPLUnlockFile() */
837 : /************************************************************************/
838 :
839 : void CPLUnlockFile( void *hLock )
840 :
841 : {
842 : HANDLE hLockFile = (HANDLE) hLock;
843 :
844 : CloseHandle( hLockFile );
845 : }
846 :
847 : /************************************************************************/
848 : /* CPLGetPID() */
849 : /************************************************************************/
850 :
851 : GIntBig CPLGetPID()
852 :
853 : {
854 : return (GIntBig) GetCurrentThreadId();
855 : }
856 :
857 : /************************************************************************/
858 : /* CPLStdCallThreadJacket() */
859 : /************************************************************************/
860 :
861 : typedef struct {
862 : void *pAppData;
863 : CPLThreadFunc pfnMain;
864 : HANDLE hThread;
865 : } CPLStdCallThreadInfo;
866 :
867 : static DWORD WINAPI CPLStdCallThreadJacket( void *pData )
868 :
869 : {
870 : CPLStdCallThreadInfo *psInfo = (CPLStdCallThreadInfo *) pData;
871 :
872 : psInfo->pfnMain( psInfo->pAppData );
873 :
874 : if (psInfo->hThread == NULL)
875 : CPLFree( psInfo ); /* Only for detached threads */
876 :
877 : CPLCleanupTLS();
878 :
879 : return 0;
880 : }
881 :
882 : /************************************************************************/
883 : /* CPLCreateThread() */
884 : /* */
885 : /* The WIN32 CreateThread() call requires an entry point that */
886 : /* has __stdcall conventions, so we provide a jacket function */
887 : /* to supply that. */
888 : /************************************************************************/
889 :
890 : int CPLCreateThread( CPLThreadFunc pfnMain, void *pThreadArg )
891 :
892 : {
893 : HANDLE hThread;
894 : DWORD nThreadId;
895 : CPLStdCallThreadInfo *psInfo;
896 :
897 : psInfo = (CPLStdCallThreadInfo*) CPLCalloc(sizeof(CPLStdCallThreadInfo),1);
898 : psInfo->pAppData = pThreadArg;
899 : psInfo->pfnMain = pfnMain;
900 : psInfo->hThread = NULL;
901 :
902 : hThread = CreateThread( NULL, 0, CPLStdCallThreadJacket, psInfo,
903 : 0, &nThreadId );
904 :
905 : if( hThread == NULL )
906 : return -1;
907 :
908 : CloseHandle( hThread );
909 :
910 : return nThreadId;
911 : }
912 :
913 : /************************************************************************/
914 : /* CPLCreateJoinableThread() */
915 : /************************************************************************/
916 :
917 : void* CPLCreateJoinableThread( CPLThreadFunc pfnMain, void *pThreadArg )
918 :
919 : {
920 : HANDLE hThread;
921 : DWORD nThreadId;
922 : CPLStdCallThreadInfo *psInfo;
923 :
924 : psInfo = (CPLStdCallThreadInfo*) CPLCalloc(sizeof(CPLStdCallThreadInfo),1);
925 : psInfo->pAppData = pThreadArg;
926 : psInfo->pfnMain = pfnMain;
927 :
928 : hThread = CreateThread( NULL, 0, CPLStdCallThreadJacket, psInfo,
929 : 0, &nThreadId );
930 :
931 : if( hThread == NULL )
932 : return NULL;
933 :
934 : psInfo->hThread = hThread;
935 : return psInfo;
936 : }
937 :
938 : /************************************************************************/
939 : /* CPLJoinThread() */
940 : /************************************************************************/
941 :
942 : void CPLJoinThread(void* hJoinableThread)
943 : {
944 : CPLStdCallThreadInfo *psInfo = (CPLStdCallThreadInfo *) hJoinableThread;
945 :
946 : WaitForSingleObject(psInfo->hThread, INFINITE);
947 : CloseHandle( psInfo->hThread );
948 : CPLFree( psInfo );
949 : }
950 :
951 : /************************************************************************/
952 : /* CPLSleep() */
953 : /************************************************************************/
954 :
955 : void CPLSleep( double dfWaitInSeconds )
956 :
957 : {
958 : Sleep( (DWORD) (dfWaitInSeconds * 1000.0) );
959 : }
960 :
961 : static int bTLSKeySetup = FALSE;
962 : static DWORD nTLSKey;
963 :
964 : /************************************************************************/
965 : /* CPLGetTLSList() */
966 : /************************************************************************/
967 :
968 : static void **CPLGetTLSList()
969 :
970 : {
971 : void **papTLSList;
972 :
973 : if( !bTLSKeySetup )
974 : {
975 : nTLSKey = TlsAlloc();
976 : if( nTLSKey == TLS_OUT_OF_INDEXES )
977 : {
978 : CPLError( CE_Fatal, CPLE_AppDefined,
979 : "TlsAlloc() failed!" );
980 : }
981 : bTLSKeySetup = TRUE;
982 : }
983 :
984 : papTLSList = (void **) TlsGetValue( nTLSKey );
985 : if( papTLSList == NULL )
986 : {
987 : papTLSList = (void **) CPLCalloc(sizeof(void*),CTLS_MAX*2);
988 : if( TlsSetValue( nTLSKey, papTLSList ) == 0 )
989 : {
990 : CPLError( CE_Fatal, CPLE_AppDefined,
991 : "TlsSetValue() failed!" );
992 : }
993 : }
994 :
995 : return papTLSList;
996 : }
997 :
998 : /************************************************************************/
999 : /* CPLCleanupTLS() */
1000 : /************************************************************************/
1001 :
1002 : void CPLCleanupTLS()
1003 :
1004 : {
1005 : void **papTLSList;
1006 :
1007 : if( !bTLSKeySetup )
1008 : return;
1009 :
1010 : papTLSList = (void **) TlsGetValue( nTLSKey );
1011 : if( papTLSList == NULL )
1012 : return;
1013 :
1014 : TlsSetValue( nTLSKey, NULL );
1015 :
1016 : CPLCleanupTLSList( papTLSList );
1017 : }
1018 :
1019 : /* endif CPL_MULTIPROC_WIN32 */
1020 :
1021 : #elif defined(CPL_MULTIPROC_PTHREAD)
1022 :
1023 : #include <pthread.h>
1024 : #include <time.h>
1025 : #include <unistd.h>
1026 :
1027 : /************************************************************************/
1028 : /* ==================================================================== */
1029 : /* CPL_MULTIPROC_PTHREAD */
1030 : /* */
1031 : /* PTHREAD Implementation of multiprocessing functions. */
1032 : /* ==================================================================== */
1033 : /************************************************************************/
1034 :
1035 : /************************************************************************/
1036 : /* CPLGetNumCPUs() */
1037 : /************************************************************************/
1038 :
1039 47 : int CPLGetNumCPUs()
1040 : {
1041 : #ifdef _SC_NPROCESSORS_ONLN
1042 47 : return (int)sysconf(_SC_NPROCESSORS_ONLN);
1043 : #else
1044 : return 1;
1045 : #endif
1046 : }
1047 :
1048 : /************************************************************************/
1049 : /* CPLCreateOrAcquireMutex() */
1050 : /************************************************************************/
1051 :
1052 15794988 : int CPLCreateOrAcquireMutex( void **phMutex, double dfWaitInSeconds )
1053 :
1054 : {
1055 15794988 : int bSuccess = FALSE;
1056 : static pthread_mutex_t global_mutex = PTHREAD_MUTEX_INITIALIZER;
1057 :
1058 15794988 : pthread_mutex_lock(&global_mutex);
1059 15794988 : if( *phMutex == NULL )
1060 : {
1061 8390 : *phMutex = CPLCreateMutex();
1062 8390 : bSuccess = *phMutex != NULL;
1063 8390 : pthread_mutex_unlock(&global_mutex);
1064 : }
1065 : else
1066 : {
1067 15786598 : pthread_mutex_unlock(&global_mutex);
1068 :
1069 15786598 : bSuccess = CPLAcquireMutex( *phMutex, dfWaitInSeconds );
1070 : }
1071 :
1072 15794988 : return bSuccess;
1073 : }
1074 :
1075 : /************************************************************************/
1076 : /* CPLGetThreadingModel() */
1077 : /************************************************************************/
1078 :
1079 0 : const char *CPLGetThreadingModel()
1080 :
1081 : {
1082 0 : return "pthread";
1083 : }
1084 :
1085 : /************************************************************************/
1086 : /* CPLCreateMutex() */
1087 : /************************************************************************/
1088 :
1089 9287 : void *CPLCreateMutex()
1090 :
1091 : {
1092 : pthread_mutex_t *hMutex;
1093 :
1094 9287 : hMutex = (pthread_mutex_t *) malloc(sizeof(pthread_mutex_t));
1095 9287 : if (hMutex == NULL)
1096 0 : return NULL;
1097 :
1098 : #if defined(PTHREAD_MUTEX_RECURSIVE) || defined(HAVE_PTHREAD_MUTEX_RECURSIVE)
1099 : {
1100 : pthread_mutexattr_t attr;
1101 9287 : pthread_mutexattr_init( &attr );
1102 9287 : pthread_mutexattr_settype( &attr, PTHREAD_MUTEX_RECURSIVE );
1103 9287 : pthread_mutex_init( hMutex, &attr );
1104 : }
1105 : /* BSDs have PTHREAD_MUTEX_RECURSIVE as an enum, not a define. */
1106 : /* But they have #define MUTEX_TYPE_COUNTING_FAST PTHREAD_MUTEX_RECURSIVE */
1107 : #elif defined(MUTEX_TYPE_COUNTING_FAST)
1108 : {
1109 : pthread_mutexattr_t attr;
1110 : pthread_mutexattr_init( &attr );
1111 : pthread_mutexattr_settype( &attr, MUTEX_TYPE_COUNTING_FAST );
1112 : pthread_mutex_init( hMutex, &attr );
1113 : }
1114 : #elif defined(PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP)
1115 : pthread_mutex_t tmp_mutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
1116 : *hMutex = tmp_mutex;
1117 : #else
1118 : #error "Recursive mutexes apparently unsupported, configure --without-threads"
1119 : #endif
1120 :
1121 : // mutexes are implicitly acquired when created.
1122 9287 : CPLAcquireMutex( hMutex, 0.0 );
1123 :
1124 9287 : return (void *) hMutex;
1125 : }
1126 :
1127 : /************************************************************************/
1128 : /* CPLAcquireMutex() */
1129 : /************************************************************************/
1130 :
1131 15841325 : int CPLAcquireMutex( void *hMutexIn, double dfWaitInSeconds )
1132 :
1133 : {
1134 : int err;
1135 :
1136 : /* we need to add timeout support */
1137 15841325 : err = pthread_mutex_lock( (pthread_mutex_t *) hMutexIn );
1138 :
1139 15841326 : if( err != 0 )
1140 : {
1141 0 : if( err == EDEADLK )
1142 0 : fprintf(stderr, "CPLAcquireMutex: Error = %d/EDEADLK", err );
1143 : else
1144 0 : fprintf(stderr, "CPLAcquireMutex: Error = %d", err );
1145 :
1146 0 : return FALSE;
1147 : }
1148 :
1149 15841326 : return TRUE;
1150 : }
1151 :
1152 : /************************************************************************/
1153 : /* CPLReleaseMutex() */
1154 : /************************************************************************/
1155 :
1156 15841326 : void CPLReleaseMutex( void *hMutexIn )
1157 :
1158 : {
1159 15841326 : pthread_mutex_unlock( (pthread_mutex_t *) hMutexIn );
1160 15841324 : }
1161 :
1162 : /************************************************************************/
1163 : /* CPLDestroyMutex() */
1164 : /************************************************************************/
1165 :
1166 5592 : void CPLDestroyMutex( void *hMutexIn )
1167 :
1168 : {
1169 5592 : pthread_mutex_destroy( (pthread_mutex_t *) hMutexIn );
1170 5592 : free( hMutexIn );
1171 5592 : }
1172 :
1173 : /************************************************************************/
1174 : /* CPLCreateCond() */
1175 : /************************************************************************/
1176 :
1177 112 : void *CPLCreateCond()
1178 : {
1179 112 : pthread_cond_t* pCond = (pthread_cond_t* )malloc(sizeof(pthread_cond_t));
1180 112 : if (pCond)
1181 112 : pthread_cond_init(pCond, NULL);
1182 112 : return pCond;
1183 : }
1184 :
1185 : /************************************************************************/
1186 : /* CPLCondWait() */
1187 : /************************************************************************/
1188 :
1189 4259 : void CPLCondWait( void *hCond, void* hMutex )
1190 : {
1191 4259 : pthread_cond_t* pCond = (pthread_cond_t* )hCond;
1192 4259 : pthread_mutex_t * pMutex = (pthread_mutex_t *)hMutex;
1193 4259 : pthread_cond_wait(pCond, pMutex);
1194 4259 : }
1195 :
1196 : /************************************************************************/
1197 : /* CPLCondSignal() */
1198 : /************************************************************************/
1199 :
1200 12826 : void CPLCondSignal( void *hCond )
1201 : {
1202 12826 : pthread_cond_t* pCond = (pthread_cond_t* )hCond;
1203 12826 : pthread_cond_signal(pCond);
1204 12826 : }
1205 :
1206 : /************************************************************************/
1207 : /* CPLCondBroadcast() */
1208 : /************************************************************************/
1209 :
1210 0 : void CPLCondBroadcast( void *hCond )
1211 : {
1212 0 : pthread_cond_t* pCond = (pthread_cond_t* )hCond;
1213 0 : pthread_cond_broadcast(pCond);
1214 0 : }
1215 :
1216 : /************************************************************************/
1217 : /* CPLDestroyCond() */
1218 : /************************************************************************/
1219 :
1220 112 : void CPLDestroyCond( void *hCond )
1221 : {
1222 112 : pthread_cond_t* pCond = (pthread_cond_t* )hCond;
1223 112 : pthread_cond_destroy(pCond);
1224 112 : free(hCond);
1225 112 : }
1226 :
1227 : /************************************************************************/
1228 : /* CPLLockFile() */
1229 : /* */
1230 : /* This is really a stub implementation, see first */
1231 : /* CPLLockFile() for caveats. */
1232 : /************************************************************************/
1233 :
1234 2 : void *CPLLockFile( const char *pszPath, double dfWaitInSeconds )
1235 :
1236 : {
1237 : FILE *fpLock;
1238 : char *pszLockFilename;
1239 :
1240 : /* -------------------------------------------------------------------- */
1241 : /* We use a lock file with a name derived from the file we want */
1242 : /* to lock to represent the file being locked. Note that for */
1243 : /* the stub implementation the target file does not even need */
1244 : /* to exist to be locked. */
1245 : /* -------------------------------------------------------------------- */
1246 2 : pszLockFilename = (char *) CPLMalloc(strlen(pszPath) + 30);
1247 2 : sprintf( pszLockFilename, "%s.lock", pszPath );
1248 :
1249 2 : fpLock = fopen( pszLockFilename, "r" );
1250 4 : while( fpLock != NULL && dfWaitInSeconds > 0.0 )
1251 : {
1252 0 : fclose( fpLock );
1253 0 : CPLSleep( MIN(dfWaitInSeconds,0.5) );
1254 0 : dfWaitInSeconds -= 0.5;
1255 :
1256 0 : fpLock = fopen( pszLockFilename, "r" );
1257 : }
1258 :
1259 2 : if( fpLock != NULL )
1260 : {
1261 0 : fclose( fpLock );
1262 0 : CPLFree( pszLockFilename );
1263 0 : return NULL;
1264 : }
1265 :
1266 2 : fpLock = fopen( pszLockFilename, "w" );
1267 :
1268 2 : if( fpLock == NULL )
1269 : {
1270 0 : CPLFree( pszLockFilename );
1271 0 : return NULL;
1272 : }
1273 :
1274 2 : fwrite( "held\n", 1, 5, fpLock );
1275 2 : fclose( fpLock );
1276 :
1277 2 : return pszLockFilename;
1278 : }
1279 :
1280 : /************************************************************************/
1281 : /* CPLUnlockFile() */
1282 : /************************************************************************/
1283 :
1284 2 : void CPLUnlockFile( void *hLock )
1285 :
1286 : {
1287 2 : char *pszLockFilename = (char *) hLock;
1288 :
1289 2 : if( hLock == NULL )
1290 0 : return;
1291 :
1292 2 : VSIUnlink( pszLockFilename );
1293 :
1294 2 : CPLFree( pszLockFilename );
1295 : }
1296 :
1297 : /************************************************************************/
1298 : /* CPLGetPID() */
1299 : /************************************************************************/
1300 :
1301 44921 : GIntBig CPLGetPID()
1302 :
1303 : {
1304 44921 : return (GIntBig) pthread_self();
1305 : }
1306 :
1307 : /************************************************************************/
1308 : /* CPLStdCallThreadJacket() */
1309 : /************************************************************************/
1310 :
1311 : typedef struct {
1312 : void *pAppData;
1313 : CPLThreadFunc pfnMain;
1314 : pthread_t hThread;
1315 : int bJoinable;
1316 : } CPLStdCallThreadInfo;
1317 :
1318 178 : static void *CPLStdCallThreadJacket( void *pData )
1319 :
1320 : {
1321 178 : CPLStdCallThreadInfo *psInfo = (CPLStdCallThreadInfo *) pData;
1322 :
1323 178 : psInfo->pfnMain( psInfo->pAppData );
1324 :
1325 178 : if (!psInfo->bJoinable)
1326 0 : CPLFree( psInfo );
1327 :
1328 178 : return NULL;
1329 : }
1330 :
1331 : /************************************************************************/
1332 : /* CPLCreateThread() */
1333 : /* */
1334 : /* The WIN32 CreateThread() call requires an entry point that */
1335 : /* has __stdcall conventions, so we provide a jacket function */
1336 : /* to supply that. */
1337 : /************************************************************************/
1338 :
1339 0 : int CPLCreateThread( CPLThreadFunc pfnMain, void *pThreadArg )
1340 :
1341 : {
1342 :
1343 : CPLStdCallThreadInfo *psInfo;
1344 : pthread_attr_t hThreadAttr;
1345 :
1346 0 : psInfo = (CPLStdCallThreadInfo*) CPLCalloc(sizeof(CPLStdCallThreadInfo),1);
1347 0 : psInfo->pAppData = pThreadArg;
1348 0 : psInfo->pfnMain = pfnMain;
1349 0 : psInfo->bJoinable = FALSE;
1350 :
1351 0 : pthread_attr_init( &hThreadAttr );
1352 0 : pthread_attr_setdetachstate( &hThreadAttr, PTHREAD_CREATE_DETACHED );
1353 0 : if( pthread_create( &(psInfo->hThread), &hThreadAttr,
1354 : CPLStdCallThreadJacket, (void *) psInfo ) != 0 )
1355 : {
1356 0 : CPLFree( psInfo );
1357 0 : return -1;
1358 : }
1359 :
1360 0 : return 1; /* can we return the actual thread pid? */
1361 : }
1362 :
1363 : /************************************************************************/
1364 : /* CPLCreateJoinableThread() */
1365 : /************************************************************************/
1366 :
1367 178 : void* CPLCreateJoinableThread( CPLThreadFunc pfnMain, void *pThreadArg )
1368 :
1369 : {
1370 : CPLStdCallThreadInfo *psInfo;
1371 : pthread_attr_t hThreadAttr;
1372 :
1373 178 : psInfo = (CPLStdCallThreadInfo*) CPLCalloc(sizeof(CPLStdCallThreadInfo),1);
1374 178 : psInfo->pAppData = pThreadArg;
1375 178 : psInfo->pfnMain = pfnMain;
1376 178 : psInfo->bJoinable = TRUE;
1377 :
1378 178 : pthread_attr_init( &hThreadAttr );
1379 178 : pthread_attr_setdetachstate( &hThreadAttr, PTHREAD_CREATE_JOINABLE );
1380 178 : if( pthread_create( &(psInfo->hThread), &hThreadAttr,
1381 : CPLStdCallThreadJacket, (void *) psInfo ) != 0 )
1382 : {
1383 0 : CPLFree( psInfo );
1384 0 : return NULL;
1385 : }
1386 :
1387 178 : return psInfo;
1388 : }
1389 :
1390 : /************************************************************************/
1391 : /* CPLJoinThread() */
1392 : /************************************************************************/
1393 :
1394 178 : void CPLJoinThread(void* hJoinableThread)
1395 : {
1396 178 : CPLStdCallThreadInfo *psInfo = (CPLStdCallThreadInfo*) hJoinableThread;
1397 :
1398 : void* status;
1399 178 : pthread_join( psInfo->hThread, &status);
1400 :
1401 178 : CPLFree(psInfo);
1402 178 : }
1403 :
1404 : /************************************************************************/
1405 : /* CPLSleep() */
1406 : /************************************************************************/
1407 :
1408 0 : void CPLSleep( double dfWaitInSeconds )
1409 :
1410 : {
1411 : struct timespec sRequest, sRemain;
1412 :
1413 0 : sRequest.tv_sec = (int) floor(dfWaitInSeconds);
1414 0 : sRequest.tv_nsec = (int) ((dfWaitInSeconds - sRequest.tv_sec)*1000000000);
1415 0 : nanosleep( &sRequest, &sRemain );
1416 0 : }
1417 :
1418 : static pthread_key_t oTLSKey;
1419 : static pthread_once_t oTLSKeySetup = PTHREAD_ONCE_INIT;
1420 :
1421 : /************************************************************************/
1422 : /* CPLMake_key() */
1423 : /************************************************************************/
1424 :
1425 713 : static void CPLMake_key()
1426 :
1427 : {
1428 713 : if( pthread_key_create( &oTLSKey, (void (*)(void*)) CPLCleanupTLSList ) != 0 )
1429 : {
1430 0 : CPLError( CE_Fatal, CPLE_AppDefined, "pthread_key_create() failed!" );
1431 : }
1432 713 : }
1433 :
1434 : /************************************************************************/
1435 : /* CPLCleanupTLS() */
1436 : /************************************************************************/
1437 :
1438 1052 : void CPLCleanupTLS()
1439 :
1440 : {
1441 : void **papTLSList;
1442 :
1443 1052 : papTLSList = (void **) pthread_getspecific( oTLSKey );
1444 1052 : if( papTLSList == NULL )
1445 19 : return;
1446 :
1447 1033 : pthread_setspecific( oTLSKey, NULL );
1448 :
1449 1033 : CPLCleanupTLSList( papTLSList );
1450 : }
1451 :
1452 : /************************************************************************/
1453 : /* CPLGetTLSList() */
1454 : /************************************************************************/
1455 :
1456 38470958 : static void **CPLGetTLSList()
1457 :
1458 : {
1459 : void **papTLSList;
1460 :
1461 38470958 : if ( pthread_once(&oTLSKeySetup, CPLMake_key) != 0 )
1462 : {
1463 : CPLError( CE_Fatal, CPLE_AppDefined,
1464 0 : "pthread_once() failed!" );
1465 : }
1466 :
1467 38470957 : papTLSList = (void **) pthread_getspecific( oTLSKey );
1468 38470958 : if( papTLSList == NULL )
1469 : {
1470 1128 : papTLSList = (void **) CPLCalloc(sizeof(void*),CTLS_MAX*2);
1471 1128 : if( pthread_setspecific( oTLSKey, papTLSList ) != 0 )
1472 : {
1473 : CPLError( CE_Fatal, CPLE_AppDefined,
1474 0 : "pthread_setspecific() failed!" );
1475 : }
1476 : }
1477 :
1478 38470958 : return papTLSList;
1479 : }
1480 :
1481 : #endif /* def CPL_MULTIPROC_PTHREAD */
1482 :
1483 : /************************************************************************/
1484 : /* CPLGetTLS() */
1485 : /************************************************************************/
1486 :
1487 38461458 : void *CPLGetTLS( int nIndex )
1488 :
1489 : {
1490 38461458 : void** papTLSList = CPLGetTLSList();
1491 :
1492 38461459 : CPLAssert( nIndex >= 0 && nIndex < CTLS_MAX );
1493 :
1494 38461459 : return papTLSList[nIndex];
1495 : }
1496 :
1497 : /************************************************************************/
1498 : /* CPLSetTLS() */
1499 : /************************************************************************/
1500 :
1501 8170 : void CPLSetTLS( int nIndex, void *pData, int bFreeOnExit )
1502 :
1503 : {
1504 8170 : CPLSetTLSWithFreeFunc(nIndex, pData, (bFreeOnExit) ? CPLFree : NULL);
1505 8170 : }
1506 :
1507 : /************************************************************************/
1508 : /* CPLSetTLSWithFreeFunc() */
1509 : /************************************************************************/
1510 :
1511 : /* Warning : the CPLTLSFreeFunc must not in any case directly or indirectly */
1512 : /* use or fetch any TLS data, or a terminating thread will hang ! */
1513 9499 : void CPLSetTLSWithFreeFunc( int nIndex, void *pData, CPLTLSFreeFunc pfnFree )
1514 :
1515 : {
1516 9499 : void **papTLSList = CPLGetTLSList();
1517 :
1518 9499 : CPLAssert( nIndex >= 0 && nIndex < CTLS_MAX );
1519 :
1520 9499 : papTLSList[nIndex] = pData;
1521 9499 : papTLSList[CTLS_MAX + nIndex] = (void*) pfnFree;
1522 9499 : }
|