1 : /**********************************************************************
2 : * $Id: cpl_multiproc.cpp 22648 2011-07-05 23:14:50Z warmerdam $
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 22648 2011-07-05 23:14:50Z warmerdam $");
44 :
45 : #if defined(CPL_MULTIPROC_STUB) && !defined(DEBUG)
46 : # define MUTEX_NONE
47 : #endif
48 :
49 : /************************************************************************/
50 : /* CPLMutexHolder() */
51 : /************************************************************************/
52 :
53 14314782 : CPLMutexHolder::CPLMutexHolder( void **phMutex, double dfWaitInSeconds,
54 : const char *pszFileIn,
55 : int nLineIn )
56 :
57 : {
58 : #ifndef MUTEX_NONE
59 14314782 : pszFile = pszFileIn;
60 14314782 : 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 14314782 : 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 14314782 : hMutex = *phMutex;
87 : }
88 : #endif /* ndef MUTEX_NONE */
89 14314782 : }
90 :
91 : /************************************************************************/
92 : /* ~CPLMutexHolder() */
93 : /************************************************************************/
94 :
95 14314782 : CPLMutexHolder::~CPLMutexHolder()
96 :
97 : {
98 : #ifndef MUTEX_NONE
99 14314782 : 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 14314782 : CPLReleaseMutex( hMutex );
107 : }
108 : #endif /* ndef MUTEX_NONE */
109 14314782 : }
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 966 : static void CPLCleanupTLSList( void **papTLSList )
170 :
171 : {
172 : int i;
173 :
174 : // printf( "CPLCleanupTLSList(%p)\n", papTLSList );
175 :
176 966 : if( papTLSList == NULL )
177 0 : return;
178 :
179 31878 : for( i = 0; i < CTLS_MAX; i++ )
180 : {
181 30912 : if( papTLSList[i] != NULL && papTLSList[i+CTLS_MAX] != NULL )
182 : {
183 2026 : CPLTLSFreeFunc pfnFree = (CPLTLSFreeFunc) papTLSList[i + CTLS_MAX];
184 2026 : pfnFree( papTLSList[i] );
185 2026 : papTLSList[i] = NULL;
186 : }
187 : }
188 :
189 966 : 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 : /* CPLGetThreadingModel() */
205 : /************************************************************************/
206 :
207 : const char *CPLGetThreadingModel()
208 :
209 : {
210 : return "stub";
211 : }
212 :
213 : /************************************************************************/
214 : /* CPLCreateMutex() */
215 : /************************************************************************/
216 :
217 : void *CPLCreateMutex()
218 :
219 : {
220 : #ifndef MUTEX_NONE
221 : unsigned char *pabyMutex = (unsigned char *) CPLMalloc( 4 );
222 :
223 : pabyMutex[0] = 1;
224 : pabyMutex[1] = 'r';
225 : pabyMutex[2] = 'e';
226 : pabyMutex[3] = 'd';
227 :
228 : return (void *) pabyMutex;
229 : #else
230 : return (void *) 0xdeadbeef;
231 : #endif
232 : }
233 :
234 : /************************************************************************/
235 : /* CPLAcquireMutex() */
236 : /************************************************************************/
237 :
238 : int CPLAcquireMutex( void *hMutex, double dfWaitInSeconds )
239 :
240 : {
241 : #ifndef MUTEX_NONE
242 : unsigned char *pabyMutex = (unsigned char *) hMutex;
243 :
244 : CPLAssert( pabyMutex[1] == 'r' && pabyMutex[2] == 'e'
245 : && pabyMutex[3] == 'd' );
246 :
247 : pabyMutex[0] += 1;
248 :
249 : return TRUE;
250 : #else
251 : return TRUE;
252 : #endif
253 : }
254 :
255 : /************************************************************************/
256 : /* CPLReleaseMutex() */
257 : /************************************************************************/
258 :
259 : void CPLReleaseMutex( void *hMutex )
260 :
261 : {
262 : #ifndef MUTEX_NONE
263 : unsigned char *pabyMutex = (unsigned char *) hMutex;
264 :
265 : CPLAssert( pabyMutex[1] == 'r' && pabyMutex[2] == 'e'
266 : && pabyMutex[3] == 'd' );
267 :
268 : if( pabyMutex[0] < 1 )
269 : CPLDebug( "CPLMultiProc",
270 : "CPLReleaseMutex() called on mutex with %d as ref count!",
271 : pabyMutex[0] );
272 :
273 : pabyMutex[0] -= 1;
274 : #endif
275 : }
276 :
277 : /************************************************************************/
278 : /* CPLDestroyMutex() */
279 : /************************************************************************/
280 :
281 : void CPLDestroyMutex( void *hMutex )
282 :
283 : {
284 : #ifndef MUTEX_NONE
285 : unsigned char *pabyMutex = (unsigned char *) hMutex;
286 :
287 : CPLAssert( pabyMutex[1] == 'r' && pabyMutex[2] == 'e'
288 : && pabyMutex[3] == 'd' );
289 :
290 : CPLFree( pabyMutex );
291 : #endif
292 : }
293 :
294 : /************************************************************************/
295 : /* CPLLockFile() */
296 : /* */
297 : /* Lock a file. This implementation has a terrible race */
298 : /* condition. If we don't succeed in opening the lock file, we */
299 : /* assume we can create one and own the target file, but other */
300 : /* processes might easily try creating the target file at the */
301 : /* same time, overlapping us. Death! Mayhem! The traditional */
302 : /* solution is to use open() with _O_CREAT|_O_EXCL but this */
303 : /* function and these arguments aren't trivially portable. */
304 : /* Also, this still leaves a race condition on NFS drivers */
305 : /* (apparently). */
306 : /************************************************************************/
307 :
308 : void *CPLLockFile( const char *pszPath, double dfWaitInSeconds )
309 :
310 : {
311 : FILE *fpLock;
312 : char *pszLockFilename;
313 :
314 : /* -------------------------------------------------------------------- */
315 : /* We use a lock file with a name derived from the file we want */
316 : /* to lock to represent the file being locked. Note that for */
317 : /* the stub implementation the target file does not even need */
318 : /* to exist to be locked. */
319 : /* -------------------------------------------------------------------- */
320 : pszLockFilename = (char *) CPLMalloc(strlen(pszPath) + 30);
321 : sprintf( pszLockFilename, "%s.lock", pszPath );
322 :
323 : fpLock = fopen( pszLockFilename, "r" );
324 : while( fpLock != NULL && dfWaitInSeconds > 0.0 )
325 : {
326 : fclose( fpLock );
327 : CPLSleep( MIN(dfWaitInSeconds,0.5) );
328 : dfWaitInSeconds -= 0.5;
329 :
330 : fpLock = fopen( pszLockFilename, "r" );
331 : }
332 :
333 : if( fpLock != NULL )
334 : {
335 : fclose( fpLock );
336 : CPLFree( pszLockFilename );
337 : return NULL;
338 : }
339 :
340 : fpLock = fopen( pszLockFilename, "w" );
341 :
342 : if( fpLock == NULL )
343 : {
344 : CPLFree( pszLockFilename );
345 : return NULL;
346 : }
347 :
348 : fwrite( "held\n", 1, 5, fpLock );
349 : fclose( fpLock );
350 :
351 : return pszLockFilename;
352 : }
353 :
354 : /************************************************************************/
355 : /* CPLUnlockFile() */
356 : /************************************************************************/
357 :
358 : void CPLUnlockFile( void *hLock )
359 :
360 : {
361 : char *pszLockFilename = (char *) hLock;
362 :
363 : if( hLock == NULL )
364 : return;
365 :
366 : VSIUnlink( pszLockFilename );
367 :
368 : CPLFree( pszLockFilename );
369 : }
370 :
371 : /************************************************************************/
372 : /* CPLGetPID() */
373 : /************************************************************************/
374 :
375 : GIntBig CPLGetPID()
376 :
377 : {
378 : return 1;
379 : }
380 :
381 : /************************************************************************/
382 : /* CPLCreateThread(); */
383 : /************************************************************************/
384 :
385 : int CPLCreateThread( CPLThreadFunc pfnMain, void *pArg )
386 :
387 : {
388 : CPLDebug( "CPLCreateThread", "Fails to dummy implementation" );
389 :
390 : return -1;
391 : }
392 :
393 : /************************************************************************/
394 : /* CPLSleep() */
395 : /************************************************************************/
396 :
397 : void CPLSleep( double dfWaitInSeconds )
398 :
399 : {
400 : time_t ltime;
401 : time_t ttime;
402 :
403 : time( <ime );
404 : ttime = ltime + (int) (dfWaitInSeconds+0.5);
405 :
406 : for( ; ltime < ttime; time(<ime) )
407 : {
408 : /* currently we just busy wait. Perhaps we could at least block on
409 : io? */
410 : }
411 : }
412 :
413 : /************************************************************************/
414 : /* CPLGetTLSList() */
415 : /************************************************************************/
416 :
417 : static void **papTLSList = NULL;
418 :
419 : static void **CPLGetTLSList()
420 :
421 : {
422 : if( papTLSList == NULL )
423 : papTLSList = (void **) CPLCalloc(sizeof(void*),CTLS_MAX*2);
424 :
425 : return papTLSList;
426 : }
427 :
428 : /************************************************************************/
429 : /* CPLCleanupTLS() */
430 : /************************************************************************/
431 :
432 : void CPLCleanupTLS()
433 :
434 : {
435 : CPLCleanupTLSList( papTLSList );
436 : papTLSList = NULL;
437 : }
438 :
439 : /* endif CPL_MULTIPROC_STUB */
440 :
441 : #elif defined(CPL_MULTIPROC_WIN32)
442 :
443 :
444 : /************************************************************************/
445 : /* ==================================================================== */
446 : /* CPL_MULTIPROC_WIN32 */
447 : /* */
448 : /* WIN32 Implementation of multiprocessing functions. */
449 : /* ==================================================================== */
450 : /************************************************************************/
451 :
452 : /* InitializeCriticalSectionAndSpinCount requires _WIN32_WINNT >= 0x403 */
453 : #define _WIN32_WINNT 0x0500
454 :
455 : #include <windows.h>
456 :
457 : /* windows.h header must be included above following lines. */
458 : #if defined(WIN32CE)
459 : # include "cpl_win32ce_api.h"
460 : # define TLS_OUT_OF_INDEXES ((DWORD)0xFFFFFFFF)
461 : #endif
462 :
463 : /************************************************************************/
464 : /* CPLGetThreadingModel() */
465 : /************************************************************************/
466 :
467 : const char *CPLGetThreadingModel()
468 :
469 : {
470 : return "win32";
471 : }
472 :
473 : /************************************************************************/
474 : /* CPLCreateMutex() */
475 : /************************************************************************/
476 :
477 : void *CPLCreateMutex()
478 :
479 : {
480 : #ifdef USE_WIN32_MUTEX
481 : HANDLE hMutex;
482 :
483 : hMutex = CreateMutex( NULL, TRUE, NULL );
484 :
485 : return (void *) hMutex;
486 : #else
487 : CRITICAL_SECTION *pcs;
488 :
489 : /* Do not use CPLMalloc() since its debugging infrastructure */
490 : /* can call the CPL*Mutex functions... */
491 : pcs = (CRITICAL_SECTION *)malloc(sizeof(*pcs));
492 : if( pcs )
493 : {
494 : InitializeCriticalSectionAndSpinCount(pcs, 4000);
495 : EnterCriticalSection(pcs);
496 : }
497 :
498 : return (void *) pcs;
499 : #endif
500 : }
501 :
502 : /************************************************************************/
503 : /* CPLAcquireMutex() */
504 : /************************************************************************/
505 :
506 : int CPLAcquireMutex( void *hMutexIn, double dfWaitInSeconds )
507 :
508 : {
509 : #ifdef USE_WIN32_MUTEX
510 : HANDLE hMutex = (HANDLE) hMutexIn;
511 : DWORD hr;
512 :
513 : hr = WaitForSingleObject( hMutex, (int) (dfWaitInSeconds * 1000) );
514 :
515 : return hr != WAIT_TIMEOUT;
516 : #else
517 : CRITICAL_SECTION *pcs = (CRITICAL_SECTION *)hMutexIn;
518 : BOOL ret;
519 :
520 : while( (ret = TryEnterCriticalSection(pcs)) == 0 && dfWaitInSeconds > 0.0 )
521 : {
522 : CPLSleep( MIN(dfWaitInSeconds,0.125) );
523 : dfWaitInSeconds -= 0.125;
524 : }
525 :
526 : return ret;
527 : #endif
528 : }
529 :
530 : /************************************************************************/
531 : /* CPLReleaseMutex() */
532 : /************************************************************************/
533 :
534 : void CPLReleaseMutex( void *hMutexIn )
535 :
536 : {
537 : #ifdef USE_WIN32_MUTEX
538 : HANDLE hMutex = (HANDLE) hMutexIn;
539 :
540 : ReleaseMutex( hMutex );
541 : #else
542 : CRITICAL_SECTION *pcs = (CRITICAL_SECTION *)hMutexIn;
543 :
544 : LeaveCriticalSection(pcs);
545 : #endif
546 : }
547 :
548 : /************************************************************************/
549 : /* CPLDestroyMutex() */
550 : /************************************************************************/
551 :
552 : void CPLDestroyMutex( void *hMutexIn )
553 :
554 : {
555 : #ifdef USE_WIN32_MUTEX
556 : HANDLE hMutex = (HANDLE) hMutexIn;
557 :
558 : CloseHandle( hMutex );
559 : #else
560 : CRITICAL_SECTION *pcs = (CRITICAL_SECTION *)hMutexIn;
561 :
562 : DeleteCriticalSection( pcs );
563 : free( pcs );
564 : #endif
565 : }
566 :
567 : /************************************************************************/
568 : /* CPLLockFile() */
569 : /************************************************************************/
570 :
571 : void *CPLLockFile( const char *pszPath, double dfWaitInSeconds )
572 :
573 : {
574 : char *pszLockFilename;
575 : HANDLE hLockFile;
576 :
577 : pszLockFilename = (char *) CPLMalloc(strlen(pszPath) + 30);
578 : sprintf( pszLockFilename, "%s.lock", pszPath );
579 :
580 : hLockFile =
581 : CreateFile( pszLockFilename, GENERIC_WRITE, 0, NULL,CREATE_NEW,
582 : FILE_ATTRIBUTE_NORMAL|FILE_FLAG_DELETE_ON_CLOSE, NULL );
583 :
584 : while( GetLastError() == ERROR_ALREADY_EXISTS
585 : && dfWaitInSeconds > 0.0 )
586 : {
587 : CloseHandle( hLockFile );
588 : CPLSleep( MIN(dfWaitInSeconds,0.125) );
589 : dfWaitInSeconds -= 0.125;
590 :
591 : hLockFile =
592 : CreateFile( pszLockFilename, GENERIC_WRITE, 0, NULL, CREATE_NEW,
593 : FILE_ATTRIBUTE_NORMAL|FILE_FLAG_DELETE_ON_CLOSE,
594 : NULL );
595 : }
596 :
597 : CPLFree( pszLockFilename );
598 :
599 : if( hLockFile == INVALID_HANDLE_VALUE )
600 : return NULL;
601 :
602 : if( GetLastError() == ERROR_ALREADY_EXISTS )
603 : {
604 : CloseHandle( hLockFile );
605 : return NULL;
606 : }
607 :
608 : return (void *) hLockFile;
609 : }
610 :
611 : /************************************************************************/
612 : /* CPLUnlockFile() */
613 : /************************************************************************/
614 :
615 : void CPLUnlockFile( void *hLock )
616 :
617 : {
618 : HANDLE hLockFile = (HANDLE) hLock;
619 :
620 : CloseHandle( hLockFile );
621 : }
622 :
623 : /************************************************************************/
624 : /* CPLGetPID() */
625 : /************************************************************************/
626 :
627 : GIntBig CPLGetPID()
628 :
629 : {
630 : return (GIntBig) GetCurrentThreadId();
631 : }
632 :
633 : /************************************************************************/
634 : /* CPLStdCallThreadJacket() */
635 : /************************************************************************/
636 :
637 : typedef struct {
638 : void *pAppData;
639 : CPLThreadFunc pfnMain;
640 : } CPLStdCallThreadInfo;
641 :
642 : static DWORD WINAPI CPLStdCallThreadJacket( void *pData )
643 :
644 : {
645 : CPLStdCallThreadInfo *psInfo = (CPLStdCallThreadInfo *) pData;
646 :
647 : psInfo->pfnMain( psInfo->pAppData );
648 :
649 : CPLFree( psInfo );
650 :
651 : CPLCleanupTLS();
652 :
653 : return 0;
654 : }
655 :
656 : /************************************************************************/
657 : /* CPLCreateThread() */
658 : /* */
659 : /* The WIN32 CreateThread() call requires an entry point that */
660 : /* has __stdcall conventions, so we provide a jacket function */
661 : /* to supply that. */
662 : /************************************************************************/
663 :
664 : int CPLCreateThread( CPLThreadFunc pfnMain, void *pThreadArg )
665 :
666 : {
667 : HANDLE hThread;
668 : DWORD nThreadId;
669 : CPLStdCallThreadInfo *psInfo;
670 :
671 : psInfo = (CPLStdCallThreadInfo*) CPLCalloc(sizeof(CPLStdCallThreadInfo),1);
672 : psInfo->pAppData = pThreadArg;
673 : psInfo->pfnMain = pfnMain;
674 :
675 : hThread = CreateThread( NULL, 0, CPLStdCallThreadJacket, psInfo,
676 : 0, &nThreadId );
677 :
678 : if( hThread == NULL )
679 : return -1;
680 :
681 : CloseHandle( hThread );
682 :
683 : return nThreadId;
684 : }
685 :
686 : /************************************************************************/
687 : /* CPLSleep() */
688 : /************************************************************************/
689 :
690 : void CPLSleep( double dfWaitInSeconds )
691 :
692 : {
693 : Sleep( (DWORD) (dfWaitInSeconds * 1000.0) );
694 : }
695 :
696 : static int bTLSKeySetup = FALSE;
697 : static DWORD nTLSKey;
698 :
699 : /************************************************************************/
700 : /* CPLGetTLSList() */
701 : /************************************************************************/
702 :
703 : static void **CPLGetTLSList()
704 :
705 : {
706 : void **papTLSList;
707 :
708 : if( !bTLSKeySetup )
709 : {
710 : nTLSKey = TlsAlloc();
711 : if( nTLSKey == TLS_OUT_OF_INDEXES )
712 : {
713 : CPLError( CE_Fatal, CPLE_AppDefined,
714 : "TlsAlloc() failed!" );
715 : }
716 : bTLSKeySetup = TRUE;
717 : }
718 :
719 : papTLSList = (void **) TlsGetValue( nTLSKey );
720 : if( papTLSList == NULL )
721 : {
722 : papTLSList = (void **) CPLCalloc(sizeof(void*),CTLS_MAX*2);
723 : if( TlsSetValue( nTLSKey, papTLSList ) == 0 )
724 : {
725 : CPLError( CE_Fatal, CPLE_AppDefined,
726 : "TlsSetValue() failed!" );
727 : }
728 : }
729 :
730 : return papTLSList;
731 : }
732 :
733 : /************************************************************************/
734 : /* CPLCleanupTLS() */
735 : /************************************************************************/
736 :
737 : void CPLCleanupTLS()
738 :
739 : {
740 : void **papTLSList;
741 :
742 : if( !bTLSKeySetup )
743 : return;
744 :
745 : papTLSList = (void **) TlsGetValue( nTLSKey );
746 : if( papTLSList == NULL )
747 : return;
748 :
749 : TlsSetValue( nTLSKey, NULL );
750 :
751 : CPLCleanupTLSList( papTLSList );
752 : }
753 :
754 : /* endif CPL_MULTIPROC_WIN32 */
755 :
756 : #elif defined(CPL_MULTIPROC_PTHREAD)
757 :
758 : #include <pthread.h>
759 : #include <time.h>
760 :
761 : /************************************************************************/
762 : /* ==================================================================== */
763 : /* CPL_MULTIPROC_PTHREAD */
764 : /* */
765 : /* PTHREAD Implementation of multiprocessing functions. */
766 : /* ==================================================================== */
767 : /************************************************************************/
768 :
769 : /************************************************************************/
770 : /* CPLCreateOrAcquireMutex() */
771 : /************************************************************************/
772 :
773 14314782 : int CPLCreateOrAcquireMutex( void **phMutex, double dfWaitInSeconds )
774 :
775 : {
776 14314782 : int bSuccess = FALSE;
777 : static pthread_mutex_t global_mutex = PTHREAD_MUTEX_INITIALIZER;
778 :
779 14314782 : pthread_mutex_lock(&global_mutex);
780 14314782 : if( *phMutex == NULL )
781 : {
782 6127 : *phMutex = CPLCreateMutex();
783 6127 : bSuccess = *phMutex != NULL;
784 6127 : pthread_mutex_unlock(&global_mutex);
785 : }
786 : else
787 : {
788 14308655 : pthread_mutex_unlock(&global_mutex);
789 :
790 14308655 : bSuccess = CPLAcquireMutex( *phMutex, dfWaitInSeconds );
791 : }
792 :
793 14314782 : return bSuccess;
794 : }
795 :
796 : /************************************************************************/
797 : /* CPLGetThreadingModel() */
798 : /************************************************************************/
799 :
800 0 : const char *CPLGetThreadingModel()
801 :
802 : {
803 0 : return "pthread";
804 : }
805 :
806 : /************************************************************************/
807 : /* CPLCreateMutex() */
808 : /************************************************************************/
809 :
810 6243 : void *CPLCreateMutex()
811 :
812 : {
813 : pthread_mutex_t *hMutex;
814 :
815 6243 : hMutex = (pthread_mutex_t *) malloc(sizeof(pthread_mutex_t));
816 6243 : if (hMutex == NULL)
817 0 : return NULL;
818 :
819 : #if defined(PTHREAD_MUTEX_RECURSIVE) || defined(HAVE_PTHREAD_MUTEX_RECURSIVE)
820 : {
821 : pthread_mutexattr_t attr;
822 6243 : pthread_mutexattr_init( &attr );
823 6243 : pthread_mutexattr_settype( &attr, PTHREAD_MUTEX_RECURSIVE );
824 6243 : pthread_mutex_init( hMutex, &attr );
825 : }
826 : /* BSDs have PTHREAD_MUTEX_RECURSIVE as an enum, not a define. */
827 : /* But they have #define MUTEX_TYPE_COUNTING_FAST PTHREAD_MUTEX_RECURSIVE */
828 : #elif defined(MUTEX_TYPE_COUNTING_FAST)
829 : {
830 : pthread_mutexattr_t attr;
831 : pthread_mutexattr_init( &attr );
832 : pthread_mutexattr_settype( &attr, MUTEX_TYPE_COUNTING_FAST );
833 : pthread_mutex_init( hMutex, &attr );
834 : }
835 : #elif defined(PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP)
836 : pthread_mutex_t tmp_mutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
837 : *hMutex = tmp_mutex;
838 : #else
839 : #error "Recursive mutexes apparently unsupported, configure --without-threads"
840 : #endif
841 :
842 : // mutexes are implicitly acquired when created.
843 6243 : CPLAcquireMutex( hMutex, 0.0 );
844 :
845 6243 : return (void *) hMutex;
846 : }
847 :
848 : /************************************************************************/
849 : /* CPLAcquireMutex() */
850 : /************************************************************************/
851 :
852 14333163 : int CPLAcquireMutex( void *hMutexIn, double dfWaitInSeconds )
853 :
854 : {
855 : int err;
856 :
857 : /* we need to add timeout support */
858 14333163 : err = pthread_mutex_lock( (pthread_mutex_t *) hMutexIn );
859 :
860 14333163 : if( err != 0 )
861 : {
862 0 : if( err == EDEADLK )
863 0 : fprintf(stderr, "CPLAcquireMutex: Error = %d/EDEADLK", err );
864 : else
865 0 : fprintf(stderr, "CPLAcquireMutex: Error = %d", err );
866 :
867 0 : return FALSE;
868 : }
869 :
870 14333163 : return TRUE;
871 : }
872 :
873 : /************************************************************************/
874 : /* CPLReleaseMutex() */
875 : /************************************************************************/
876 :
877 14333163 : void CPLReleaseMutex( void *hMutexIn )
878 :
879 : {
880 14333163 : pthread_mutex_unlock( (pthread_mutex_t *) hMutexIn );
881 14333163 : }
882 :
883 : /************************************************************************/
884 : /* CPLDestroyMutex() */
885 : /************************************************************************/
886 :
887 3637 : void CPLDestroyMutex( void *hMutexIn )
888 :
889 : {
890 3637 : pthread_mutex_destroy( (pthread_mutex_t *) hMutexIn );
891 3637 : free( hMutexIn );
892 3637 : }
893 :
894 : /************************************************************************/
895 : /* CPLLockFile() */
896 : /* */
897 : /* This is really a stub implementation, see first */
898 : /* CPLLockFile() for caveats. */
899 : /************************************************************************/
900 :
901 2 : void *CPLLockFile( const char *pszPath, double dfWaitInSeconds )
902 :
903 : {
904 : FILE *fpLock;
905 : char *pszLockFilename;
906 :
907 : /* -------------------------------------------------------------------- */
908 : /* We use a lock file with a name derived from the file we want */
909 : /* to lock to represent the file being locked. Note that for */
910 : /* the stub implementation the target file does not even need */
911 : /* to exist to be locked. */
912 : /* -------------------------------------------------------------------- */
913 2 : pszLockFilename = (char *) CPLMalloc(strlen(pszPath) + 30);
914 2 : sprintf( pszLockFilename, "%s.lock", pszPath );
915 :
916 2 : fpLock = fopen( pszLockFilename, "r" );
917 4 : while( fpLock != NULL && dfWaitInSeconds > 0.0 )
918 : {
919 0 : fclose( fpLock );
920 0 : CPLSleep( MIN(dfWaitInSeconds,0.5) );
921 0 : dfWaitInSeconds -= 0.5;
922 :
923 0 : fpLock = fopen( pszLockFilename, "r" );
924 : }
925 :
926 2 : if( fpLock != NULL )
927 : {
928 0 : fclose( fpLock );
929 0 : CPLFree( pszLockFilename );
930 0 : return NULL;
931 : }
932 :
933 2 : fpLock = fopen( pszLockFilename, "w" );
934 :
935 2 : if( fpLock == NULL )
936 : {
937 0 : CPLFree( pszLockFilename );
938 0 : return NULL;
939 : }
940 :
941 2 : fwrite( "held\n", 1, 5, fpLock );
942 2 : fclose( fpLock );
943 :
944 2 : return pszLockFilename;
945 : }
946 :
947 : /************************************************************************/
948 : /* CPLUnlockFile() */
949 : /************************************************************************/
950 :
951 2 : void CPLUnlockFile( void *hLock )
952 :
953 : {
954 2 : char *pszLockFilename = (char *) hLock;
955 :
956 2 : if( hLock == NULL )
957 0 : return;
958 :
959 2 : VSIUnlink( pszLockFilename );
960 :
961 2 : CPLFree( pszLockFilename );
962 : }
963 :
964 : /************************************************************************/
965 : /* CPLGetPID() */
966 : /************************************************************************/
967 :
968 24347 : GIntBig CPLGetPID()
969 :
970 : {
971 24347 : return (GIntBig) pthread_self();
972 : }
973 :
974 : /************************************************************************/
975 : /* CPLStdCallThreadJacket() */
976 : /************************************************************************/
977 :
978 : typedef struct {
979 : void *pAppData;
980 : CPLThreadFunc pfnMain;
981 : pthread_t hThread;
982 : } CPLStdCallThreadInfo;
983 :
984 1 : static void *CPLStdCallThreadJacket( void *pData )
985 :
986 : {
987 1 : CPLStdCallThreadInfo *psInfo = (CPLStdCallThreadInfo *) pData;
988 :
989 1 : psInfo->pfnMain( psInfo->pAppData );
990 :
991 1 : CPLFree( psInfo );
992 :
993 1 : return NULL;
994 : }
995 :
996 : /************************************************************************/
997 : /* CPLCreateThread() */
998 : /* */
999 : /* The WIN32 CreateThread() call requires an entry point that */
1000 : /* has __stdcall conventions, so we provide a jacket function */
1001 : /* to supply that. */
1002 : /************************************************************************/
1003 :
1004 1 : int CPLCreateThread( CPLThreadFunc pfnMain, void *pThreadArg )
1005 :
1006 : {
1007 :
1008 : CPLStdCallThreadInfo *psInfo;
1009 : pthread_attr_t hThreadAttr;
1010 :
1011 1 : psInfo = (CPLStdCallThreadInfo*) CPLCalloc(sizeof(CPLStdCallThreadInfo),1);
1012 1 : psInfo->pAppData = pThreadArg;
1013 1 : psInfo->pfnMain = pfnMain;
1014 :
1015 1 : pthread_attr_init( &hThreadAttr );
1016 1 : pthread_attr_setdetachstate( &hThreadAttr, PTHREAD_CREATE_DETACHED );
1017 1 : if( pthread_create( &(psInfo->hThread), &hThreadAttr,
1018 : CPLStdCallThreadJacket, (void *) psInfo ) != 0 )
1019 : {
1020 0 : CPLFree( psInfo );
1021 0 : return -1;
1022 : }
1023 :
1024 1 : return 1; /* can we return the actual thread pid? */
1025 : }
1026 :
1027 : /************************************************************************/
1028 : /* CPLSleep() */
1029 : /************************************************************************/
1030 :
1031 1 : void CPLSleep( double dfWaitInSeconds )
1032 :
1033 : {
1034 : struct timespec sRequest, sRemain;
1035 :
1036 1 : sRequest.tv_sec = (int) floor(dfWaitInSeconds);
1037 1 : sRequest.tv_nsec = (int) ((dfWaitInSeconds - sRequest.tv_sec)*1000000000);
1038 1 : nanosleep( &sRequest, &sRemain );
1039 1 : }
1040 :
1041 : static pthread_key_t oTLSKey;
1042 : static pthread_once_t oTLSKeySetup = PTHREAD_ONCE_INIT;
1043 :
1044 : /************************************************************************/
1045 : /* CPLMake_key() */
1046 : /************************************************************************/
1047 :
1048 649 : static void CPLMake_key()
1049 :
1050 : {
1051 649 : if( pthread_key_create( &oTLSKey, (void (*)(void*)) CPLCleanupTLSList ) != 0 )
1052 : {
1053 0 : CPLError( CE_Fatal, CPLE_AppDefined, "pthread_key_create() failed!" );
1054 : }
1055 649 : }
1056 :
1057 : /************************************************************************/
1058 : /* CPLCleanupTLS() */
1059 : /************************************************************************/
1060 :
1061 982 : void CPLCleanupTLS()
1062 :
1063 : {
1064 : void **papTLSList;
1065 :
1066 982 : papTLSList = (void **) pthread_getspecific( oTLSKey );
1067 982 : if( papTLSList == NULL )
1068 18 : return;
1069 :
1070 964 : pthread_setspecific( oTLSKey, NULL );
1071 :
1072 964 : CPLCleanupTLSList( papTLSList );
1073 : }
1074 :
1075 : /************************************************************************/
1076 : /* CPLGetTLSList() */
1077 : /************************************************************************/
1078 :
1079 31293257 : static void **CPLGetTLSList()
1080 :
1081 : {
1082 : void **papTLSList;
1083 :
1084 31293257 : if ( pthread_once(&oTLSKeySetup, CPLMake_key) != 0 )
1085 : {
1086 : CPLError( CE_Fatal, CPLE_AppDefined,
1087 0 : "pthread_once() failed!" );
1088 : }
1089 :
1090 31293257 : papTLSList = (void **) pthread_getspecific( oTLSKey );
1091 31293257 : if( papTLSList == NULL )
1092 : {
1093 987 : papTLSList = (void **) CPLCalloc(sizeof(void*),CTLS_MAX*2);
1094 987 : if( pthread_setspecific( oTLSKey, papTLSList ) != 0 )
1095 : {
1096 : CPLError( CE_Fatal, CPLE_AppDefined,
1097 0 : "pthread_setspecific() failed!" );
1098 : }
1099 : }
1100 :
1101 31293257 : return papTLSList;
1102 : }
1103 :
1104 : #endif /* def CPL_MULTIPROC_PTHREAD */
1105 :
1106 : /************************************************************************/
1107 : /* CPLGetTLS() */
1108 : /************************************************************************/
1109 :
1110 31287282 : void *CPLGetTLS( int nIndex )
1111 :
1112 : {
1113 31287282 : void** papTLSList = CPLGetTLSList();
1114 :
1115 31287282 : CPLAssert( nIndex >= 0 && nIndex < CTLS_MAX );
1116 :
1117 31287282 : return papTLSList[nIndex];
1118 : }
1119 :
1120 : /************************************************************************/
1121 : /* CPLSetTLS() */
1122 : /************************************************************************/
1123 :
1124 4824 : void CPLSetTLS( int nIndex, void *pData, int bFreeOnExit )
1125 :
1126 : {
1127 4824 : CPLSetTLSWithFreeFunc(nIndex, pData, (bFreeOnExit) ? CPLFree : NULL);
1128 4824 : }
1129 :
1130 : /************************************************************************/
1131 : /* CPLSetTLSWithFreeFunc() */
1132 : /************************************************************************/
1133 :
1134 : /* Warning : the CPLTLSFreeFunc must not in any case directly or indirectly */
1135 : /* use or fetch any TLS data, or a terminating thread will hang ! */
1136 5975 : void CPLSetTLSWithFreeFunc( int nIndex, void *pData, CPLTLSFreeFunc pfnFree )
1137 :
1138 : {
1139 5975 : void **papTLSList = CPLGetTLSList();
1140 :
1141 5975 : CPLAssert( nIndex >= 0 && nIndex < CTLS_MAX );
1142 :
1143 5975 : papTLSList[nIndex] = pData;
1144 5975 : papTLSList[CTLS_MAX + nIndex] = (void*) pfnFree;
1145 5975 : }
|