1 : /**********************************************************************
2 : * $Id: cpl_multiproc.cpp 18481 2010-01-08 23:09:13Z 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 : #include "cpl_multiproc.h"
31 : #include "cpl_conv.h"
32 :
33 : #if !defined(WIN32CE)
34 : # include <time.h>
35 : #else
36 : # include <wce_time.h>
37 : #endif
38 :
39 : CPL_CVSID("$Id: cpl_multiproc.cpp 18481 2010-01-08 23:09:13Z rouault $");
40 :
41 : #if defined(CPL_MULTIPROC_STUB) && !defined(DEBUG)
42 : # define MUTEX_NONE
43 : #endif
44 :
45 : /************************************************************************/
46 : /* CPLMutexHolder() */
47 : /************************************************************************/
48 :
49 11388451 : CPLMutexHolder::CPLMutexHolder( void **phMutex, double dfWaitInSeconds,
50 : const char *pszFileIn,
51 : int nLineIn )
52 :
53 : {
54 : #ifndef MUTEX_NONE
55 11388451 : pszFile = pszFileIn;
56 11388451 : nLine = nLineIn;
57 :
58 : #ifdef DEBUG_MUTEX
59 : CPLDebug( "MH", "Request %p for pid %ld at %d/%s",
60 : *phMutex, (long) CPLGetPID(), nLine, pszFile );
61 : #endif
62 :
63 11388451 : if( !CPLCreateOrAcquireMutex( phMutex, dfWaitInSeconds ) )
64 : {
65 0 : CPLDebug( "CPLMutexHolder", "failed to acquire mutex!" );
66 0 : hMutex = NULL;
67 : }
68 : else
69 : {
70 : #ifdef DEBUG_MUTEX
71 : CPLDebug( "MH", "Acquired %p for pid %ld at %d/%s",
72 : *phMutex, (long) CPLGetPID(), nLine, pszFile );
73 : #endif
74 :
75 11388451 : hMutex = *phMutex;
76 : }
77 : #endif /* ndef MUTEX_NONE */
78 11388451 : }
79 :
80 : /************************************************************************/
81 : /* ~CPLMutexHolder() */
82 : /************************************************************************/
83 :
84 11388451 : CPLMutexHolder::~CPLMutexHolder()
85 :
86 : {
87 : #ifndef MUTEX_NONE
88 11388451 : if( hMutex != NULL )
89 : {
90 : #ifdef DEBUG_MUTEX
91 : CPLDebug( "MH", "Release %p for pid %ld at %d/%s",
92 : hMutex, (long) CPLGetPID(), nLine, pszFile );
93 : #endif
94 11388451 : CPLReleaseMutex( hMutex );
95 : }
96 : #endif /* ndef MUTEX_NONE */
97 11388451 : }
98 :
99 :
100 : /************************************************************************/
101 : /* CPLCreateOrAcquireMutex() */
102 : /************************************************************************/
103 :
104 11388451 : int CPLCreateOrAcquireMutex( void **phMutex, double dfWaitInSeconds )
105 :
106 : {
107 11388451 : int bSuccess = FALSE;
108 :
109 : #ifndef MUTEX_NONE
110 : static void *hCOAMutex = NULL;
111 :
112 : /*
113 : ** ironically, creation of this initial mutex is not threadsafe
114 : ** even though we use it to ensure that creation of other mutexes
115 : ** is threadsafe.
116 : */
117 11388451 : if( hCOAMutex == NULL )
118 : {
119 379 : hCOAMutex = CPLCreateMutex();
120 : }
121 : else
122 : {
123 11388072 : CPLAcquireMutex( hCOAMutex, dfWaitInSeconds );
124 : }
125 :
126 11388451 : if( *phMutex == NULL )
127 : {
128 2543 : *phMutex = CPLCreateMutex();
129 2543 : CPLReleaseMutex( hCOAMutex );
130 2543 : bSuccess = TRUE;
131 : }
132 : else
133 : {
134 11385908 : CPLReleaseMutex( hCOAMutex );
135 :
136 11385908 : bSuccess = CPLAcquireMutex( *phMutex, dfWaitInSeconds );
137 : }
138 : #endif /* ndef MUTEX_NONE */
139 :
140 11388451 : return bSuccess;
141 : }
142 :
143 : /************************************************************************/
144 : /* CPLCleanupTLSList() */
145 : /* */
146 : /* Free resources associated with a TLS vector (implementation */
147 : /* independent). */
148 : /************************************************************************/
149 :
150 619 : static void CPLCleanupTLSList( void **papTLSList )
151 :
152 : {
153 : int i;
154 :
155 : // printf( "CPLCleanupTLSList(%p)\n", papTLSList );
156 :
157 619 : if( papTLSList == NULL )
158 0 : return;
159 :
160 20427 : for( i = 0; i < CTLS_MAX; i++ )
161 : {
162 19808 : if( papTLSList[i] != NULL && papTLSList[i+CTLS_MAX] != NULL )
163 : {
164 1786 : CPLFree( papTLSList[i] );
165 : }
166 : }
167 :
168 619 : CPLFree( papTLSList );
169 : }
170 :
171 : #ifdef CPL_MULTIPROC_STUB
172 : /************************************************************************/
173 : /* ==================================================================== */
174 : /* CPL_MULTIPROC_STUB */
175 : /* */
176 : /* Stub implementation. Mutexes don't provide exclusion, file */
177 : /* locking is achieved with extra "lock files", and thread */
178 : /* creation doesn't work. The PID is always just one. */
179 : /* ==================================================================== */
180 : /************************************************************************/
181 :
182 : /************************************************************************/
183 : /* CPLGetThreadingModel() */
184 : /************************************************************************/
185 :
186 : const char *CPLGetThreadingModel()
187 :
188 : {
189 : return "stub";
190 : }
191 :
192 : /************************************************************************/
193 : /* CPLCreateMutex() */
194 : /************************************************************************/
195 :
196 : void *CPLCreateMutex()
197 :
198 : {
199 : #ifndef MUTEX_NONE
200 : unsigned char *pabyMutex = (unsigned char *) CPLMalloc( 4 );
201 :
202 : pabyMutex[0] = 1;
203 : pabyMutex[1] = 'r';
204 : pabyMutex[2] = 'e';
205 : pabyMutex[3] = 'd';
206 :
207 : return (void *) pabyMutex;
208 : #else
209 : return (void *) 0xdeadbeef;
210 : #endif
211 : }
212 :
213 : /************************************************************************/
214 : /* CPLAcquireMutex() */
215 : /************************************************************************/
216 :
217 : int CPLAcquireMutex( void *hMutex, double dfWaitInSeconds )
218 :
219 : {
220 : #ifndef MUTEX_NONE
221 : unsigned char *pabyMutex = (unsigned char *) hMutex;
222 :
223 : CPLAssert( pabyMutex[1] == 'r' && pabyMutex[2] == 'e'
224 : && pabyMutex[3] == 'd' );
225 :
226 : pabyMutex[0] += 1;
227 :
228 : return TRUE;
229 : #else
230 : return TRUE;
231 : #endif
232 : }
233 :
234 : /************************************************************************/
235 : /* CPLReleaseMutex() */
236 : /************************************************************************/
237 :
238 : void CPLReleaseMutex( void *hMutex )
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 : if( pabyMutex[0] < 1 )
248 : CPLDebug( "CPLMultiProc",
249 : "CPLReleaseMutex() called on mutex with %d as ref count!",
250 : pabyMutex[0] );
251 :
252 : pabyMutex[0] -= 1;
253 : #endif
254 : }
255 :
256 : /************************************************************************/
257 : /* CPLDestroyMutex() */
258 : /************************************************************************/
259 :
260 : void CPLDestroyMutex( void *hMutex )
261 :
262 : {
263 : #ifndef MUTEX_NONE
264 : unsigned char *pabyMutex = (unsigned char *) hMutex;
265 :
266 : CPLAssert( pabyMutex[1] == 'r' && pabyMutex[2] == 'e'
267 : && pabyMutex[3] == 'd' );
268 :
269 : CPLFree( pabyMutex );
270 : #endif
271 : }
272 :
273 : /************************************************************************/
274 : /* CPLLockFile() */
275 : /* */
276 : /* Lock a file. This implementation has a terrible race */
277 : /* condition. If we don't succeed in opening the lock file, we */
278 : /* assume we can create one and own the target file, but other */
279 : /* processes might easily try creating the target file at the */
280 : /* same time, overlapping us. Death! Mayhem! The traditional */
281 : /* solution is to use open() with _O_CREAT|_O_EXCL but this */
282 : /* function and these arguments aren't trivially portable. */
283 : /* Also, this still leaves a race condition on NFS drivers */
284 : /* (apparently). */
285 : /************************************************************************/
286 :
287 : void *CPLLockFile( const char *pszPath, double dfWaitInSeconds )
288 :
289 : {
290 : FILE *fpLock;
291 : char *pszLockFilename;
292 :
293 : /* -------------------------------------------------------------------- */
294 : /* We use a lock file with a name derived from the file we want */
295 : /* to lock to represent the file being locked. Note that for */
296 : /* the stub implementation the target file does not even need */
297 : /* to exist to be locked. */
298 : /* -------------------------------------------------------------------- */
299 : pszLockFilename = (char *) CPLMalloc(strlen(pszPath) + 30);
300 : sprintf( pszLockFilename, "%s.lock", pszPath );
301 :
302 : fpLock = fopen( pszLockFilename, "r" );
303 : while( fpLock != NULL && dfWaitInSeconds > 0.0 )
304 : {
305 : fclose( fpLock );
306 : CPLSleep( MIN(dfWaitInSeconds,0.5) );
307 : dfWaitInSeconds -= 0.5;
308 :
309 : fpLock = fopen( pszLockFilename, "r" );
310 : }
311 :
312 : if( fpLock != NULL )
313 : {
314 : fclose( fpLock );
315 : CPLFree( pszLockFilename );
316 : return NULL;
317 : }
318 :
319 : fpLock = fopen( pszLockFilename, "w" );
320 :
321 : if( fpLock == NULL )
322 : {
323 : CPLFree( pszLockFilename );
324 : return NULL;
325 : }
326 :
327 : fwrite( "held\n", 1, 5, fpLock );
328 : fclose( fpLock );
329 :
330 : return pszLockFilename;
331 : }
332 :
333 : /************************************************************************/
334 : /* CPLUnlockFile() */
335 : /************************************************************************/
336 :
337 : void CPLUnlockFile( void *hLock )
338 :
339 : {
340 : char *pszLockFilename = (char *) hLock;
341 :
342 : if( hLock == NULL )
343 : return;
344 :
345 : VSIUnlink( pszLockFilename );
346 :
347 : CPLFree( pszLockFilename );
348 : }
349 :
350 : /************************************************************************/
351 : /* CPLGetPID() */
352 : /************************************************************************/
353 :
354 : GIntBig CPLGetPID()
355 :
356 : {
357 : return 1;
358 : }
359 :
360 : /************************************************************************/
361 : /* CPLCreateThread(); */
362 : /************************************************************************/
363 :
364 : int CPLCreateThread( CPLThreadFunc pfnMain, void *pArg )
365 :
366 : {
367 : CPLDebug( "CPLCreateThread", "Fails to dummy implementation" );
368 :
369 : return -1;
370 : }
371 :
372 : /************************************************************************/
373 : /* CPLSleep() */
374 : /************************************************************************/
375 :
376 : void CPLSleep( double dfWaitInSeconds )
377 :
378 : {
379 : time_t ltime;
380 : time_t ttime;
381 :
382 : time( <ime );
383 : ttime = ltime + (int) (dfWaitInSeconds+0.5);
384 :
385 : for( ; ltime < ttime; time(<ime) )
386 : {
387 : /* currently we just busy wait. Perhaps we could at least block on
388 : io? */
389 : }
390 : }
391 :
392 : /************************************************************************/
393 : /* CPLGetTLSList() */
394 : /************************************************************************/
395 :
396 : static void **papTLSList = NULL;
397 :
398 : static void **CPLGetTLSList()
399 :
400 : {
401 : if( papTLSList == NULL )
402 : papTLSList = (void **) CPLCalloc(sizeof(void*),CTLS_MAX*2);
403 :
404 : return papTLSList;
405 : }
406 :
407 : /************************************************************************/
408 : /* CPLCleanupTLS() */
409 : /************************************************************************/
410 :
411 : void CPLCleanupTLS()
412 :
413 : {
414 : CPLCleanupTLSList( papTLSList );
415 : papTLSList = NULL;
416 : }
417 :
418 : #endif /* def CPL_MULTIPROC_STUB */
419 :
420 : #if defined(CPL_MULTIPROC_WIN32)
421 :
422 :
423 : /************************************************************************/
424 : /* ==================================================================== */
425 : /* CPL_MULTIPROC_WIN32 */
426 : /* */
427 : /* WIN32 Implementation of multiprocessing functions. */
428 : /* ==================================================================== */
429 : /************************************************************************/
430 :
431 : #include <windows.h>
432 :
433 : /* windows.h header must be included above following lines. */
434 : #if defined(WIN32CE)
435 : # include "cpl_win32ce_api.h"
436 : # define TLS_OUT_OF_INDEXES ((DWORD)0xFFFFFFFF)
437 : #endif
438 :
439 :
440 : /************************************************************************/
441 : /* CPLGetThreadingModel() */
442 : /************************************************************************/
443 :
444 : const char *CPLGetThreadingModel()
445 :
446 : {
447 : return "win32";
448 : }
449 :
450 : /************************************************************************/
451 : /* CPLCreateMutex() */
452 : /************************************************************************/
453 :
454 : void *CPLCreateMutex()
455 :
456 : {
457 : HANDLE hMutex;
458 :
459 : hMutex = CreateMutex( NULL, TRUE, NULL );
460 :
461 : return (void *) hMutex;
462 : }
463 :
464 : /************************************************************************/
465 : /* CPLAcquireMutex() */
466 : /************************************************************************/
467 :
468 : int CPLAcquireMutex( void *hMutexIn, double dfWaitInSeconds )
469 :
470 : {
471 : HANDLE hMutex = (HANDLE) hMutexIn;
472 : DWORD hr;
473 :
474 : hr = WaitForSingleObject( hMutex, (int) (dfWaitInSeconds * 1000) );
475 :
476 : return hr != WAIT_TIMEOUT;
477 : }
478 :
479 : /************************************************************************/
480 : /* CPLReleaseMutex() */
481 : /************************************************************************/
482 :
483 : void CPLReleaseMutex( void *hMutexIn )
484 :
485 : {
486 : HANDLE hMutex = (HANDLE) hMutexIn;
487 :
488 : ReleaseMutex( hMutex );
489 : }
490 :
491 : /************************************************************************/
492 : /* CPLDestroyMutex() */
493 : /************************************************************************/
494 :
495 : void CPLDestroyMutex( void *hMutexIn )
496 :
497 : {
498 : HANDLE hMutex = (HANDLE) hMutexIn;
499 :
500 : CloseHandle( hMutex );
501 : }
502 :
503 : /************************************************************************/
504 : /* CPLLockFile() */
505 : /************************************************************************/
506 :
507 : void *CPLLockFile( const char *pszPath, double dfWaitInSeconds )
508 :
509 : {
510 : char *pszLockFilename;
511 : HANDLE hLockFile;
512 :
513 : pszLockFilename = (char *) CPLMalloc(strlen(pszPath) + 30);
514 : sprintf( pszLockFilename, "%s.lock", pszPath );
515 :
516 : hLockFile =
517 : CreateFile( pszLockFilename, GENERIC_WRITE, 0, NULL,CREATE_NEW,
518 : FILE_ATTRIBUTE_NORMAL|FILE_FLAG_DELETE_ON_CLOSE, NULL );
519 :
520 : while( GetLastError() == ERROR_ALREADY_EXISTS
521 : && dfWaitInSeconds > 0.0 )
522 : {
523 : CloseHandle( hLockFile );
524 : CPLSleep( MIN(dfWaitInSeconds,0.125) );
525 : dfWaitInSeconds -= 0.125;
526 :
527 : hLockFile =
528 : CreateFile( pszLockFilename, GENERIC_WRITE, 0, NULL, CREATE_NEW,
529 : FILE_ATTRIBUTE_NORMAL|FILE_FLAG_DELETE_ON_CLOSE,
530 : NULL );
531 : }
532 :
533 : CPLFree( pszLockFilename );
534 :
535 : if( hLockFile == INVALID_HANDLE_VALUE )
536 : return NULL;
537 :
538 : if( GetLastError() == ERROR_ALREADY_EXISTS )
539 : {
540 : CloseHandle( hLockFile );
541 : return NULL;
542 : }
543 :
544 : return (void *) hLockFile;
545 : }
546 :
547 : /************************************************************************/
548 : /* CPLUnlockFile() */
549 : /************************************************************************/
550 :
551 : void CPLUnlockFile( void *hLock )
552 :
553 : {
554 : HANDLE hLockFile = (HANDLE) hLock;
555 :
556 : CloseHandle( hLockFile );
557 : }
558 :
559 : /************************************************************************/
560 : /* CPLGetPID() */
561 : /************************************************************************/
562 :
563 : GIntBig CPLGetPID()
564 :
565 : {
566 : return (GIntBig) GetCurrentThreadId();
567 : }
568 :
569 : /************************************************************************/
570 : /* CPLStdCallThreadJacket() */
571 : /************************************************************************/
572 :
573 : typedef struct {
574 : void *pAppData;
575 : CPLThreadFunc pfnMain;
576 : } CPLStdCallThreadInfo;
577 :
578 : static DWORD WINAPI CPLStdCallThreadJacket( void *pData )
579 :
580 : {
581 : CPLStdCallThreadInfo *psInfo = (CPLStdCallThreadInfo *) pData;
582 :
583 : psInfo->pfnMain( psInfo->pAppData );
584 :
585 : CPLFree( psInfo );
586 :
587 : CPLCleanupTLS();
588 :
589 : return 0;
590 : }
591 :
592 : /************************************************************************/
593 : /* CPLCreateThread() */
594 : /* */
595 : /* The WIN32 CreateThread() call requires an entry point that */
596 : /* has __stdcall conventions, so we provide a jacket function */
597 : /* to supply that. */
598 : /************************************************************************/
599 :
600 : int CPLCreateThread( CPLThreadFunc pfnMain, void *pThreadArg )
601 :
602 : {
603 : HANDLE hThread;
604 : DWORD nThreadId;
605 : CPLStdCallThreadInfo *psInfo;
606 :
607 : psInfo = (CPLStdCallThreadInfo*) CPLCalloc(sizeof(CPLStdCallThreadInfo),1);
608 : psInfo->pAppData = pThreadArg;
609 : psInfo->pfnMain = pfnMain;
610 :
611 : hThread = CreateThread( NULL, 0, CPLStdCallThreadJacket, psInfo,
612 : 0, &nThreadId );
613 :
614 : if( hThread == NULL )
615 : return -1;
616 :
617 : CloseHandle( hThread );
618 :
619 : return nThreadId;
620 : }
621 :
622 : /************************************************************************/
623 : /* CPLSleep() */
624 : /************************************************************************/
625 :
626 : void CPLSleep( double dfWaitInSeconds )
627 :
628 : {
629 : Sleep( (DWORD) (dfWaitInSeconds * 1000.0) );
630 : }
631 :
632 : static int bTLSKeySetup = FALSE;
633 : static DWORD nTLSKey;
634 :
635 : /************************************************************************/
636 : /* CPLGetTLSList() */
637 : /************************************************************************/
638 :
639 : static void **CPLGetTLSList()
640 :
641 : {
642 : void **papTLSList;
643 :
644 : if( !bTLSKeySetup )
645 : {
646 : nTLSKey = TlsAlloc();
647 : if( nTLSKey == TLS_OUT_OF_INDEXES )
648 : {
649 : CPLError( CE_Fatal, CPLE_AppDefined,
650 : "TlsAlloc() failed!" );
651 : }
652 : bTLSKeySetup = TRUE;
653 : }
654 :
655 : papTLSList = (void **) TlsGetValue( nTLSKey );
656 : if( papTLSList == NULL )
657 : {
658 : papTLSList = (void **) CPLCalloc(sizeof(void*),CTLS_MAX*2);
659 : if( TlsSetValue( nTLSKey, papTLSList ) == 0 )
660 : {
661 : CPLError( CE_Fatal, CPLE_AppDefined,
662 : "TlsSetValue() failed!" );
663 : }
664 : }
665 :
666 : return papTLSList;
667 : }
668 :
669 : /************************************************************************/
670 : /* CPLCleanupTLS() */
671 : /************************************************************************/
672 :
673 : void CPLCleanupTLS()
674 :
675 : {
676 : void **papTLSList;
677 :
678 : if( !bTLSKeySetup )
679 : return;
680 :
681 : papTLSList = (void **) TlsGetValue( nTLSKey );
682 : if( papTLSList == NULL )
683 : return;
684 :
685 : TlsSetValue( nTLSKey, NULL );
686 :
687 : CPLCleanupTLSList( papTLSList );
688 : }
689 :
690 : #endif /* def CPL_MULTIPROC_WIN32 */
691 :
692 : #ifdef CPL_MULTIPROC_PTHREAD
693 : #include <pthread.h>
694 : #include <time.h>
695 :
696 : /************************************************************************/
697 : /* ==================================================================== */
698 : /* CPL_MULTIPROC_PTHREAD */
699 : /* */
700 : /* PTHREAD Implementation of multiprocessing functions. */
701 : /* ==================================================================== */
702 : /************************************************************************/
703 :
704 :
705 : /************************************************************************/
706 : /* CPLGetThreadingModel() */
707 : /************************************************************************/
708 :
709 0 : const char *CPLGetThreadingModel()
710 :
711 : {
712 0 : return "pthread";
713 : }
714 :
715 : /************************************************************************/
716 : /* CPLCreateMutex() */
717 : /************************************************************************/
718 :
719 3004 : void *CPLCreateMutex()
720 :
721 : {
722 : pthread_mutex_t *hMutex;
723 :
724 3004 : hMutex = (pthread_mutex_t *) malloc(sizeof(pthread_mutex_t));
725 :
726 : #if defined(PTHREAD_MUTEX_RECURSIVE)
727 : {
728 : pthread_mutexattr_t attr;
729 : pthread_mutexattr_init( &attr );
730 : pthread_mutexattr_settype( &attr, PTHREAD_MUTEX_RECURSIVE );
731 : pthread_mutex_init( hMutex, &attr );
732 : }
733 : /* BSDs have PTHREAD_MUTEX_RECURSIVE as an enum, not a define. */
734 : /* But they have #define MUTEX_TYPE_COUNTING_FAST PTHREAD_MUTEX_RECURSIVE */
735 : #elif defined(MUTEX_TYPE_COUNTING_FAST)
736 : {
737 : pthread_mutexattr_t attr;
738 : pthread_mutexattr_init( &attr );
739 : pthread_mutexattr_settype( &attr, MUTEX_TYPE_COUNTING_FAST );
740 : pthread_mutex_init( hMutex, &attr );
741 : }
742 : #elif defined(PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP)
743 3004 : pthread_mutex_t tmp_mutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
744 3004 : *hMutex = tmp_mutex;
745 : #else
746 : #error "Recursive mutexes apparently unsupported, configure --without-threads"
747 : #endif
748 :
749 : // mutexes are implicitly acquired when created.
750 3004 : CPLAcquireMutex( hMutex, 0.0 );
751 :
752 3004 : return (void *) hMutex;
753 : }
754 :
755 : /************************************************************************/
756 : /* CPLAcquireMutex() */
757 : /************************************************************************/
758 :
759 22781853 : int CPLAcquireMutex( void *hMutexIn, double dfWaitInSeconds )
760 :
761 : {
762 : int err;
763 :
764 : /* we need to add timeout support */
765 22781853 : err = pthread_mutex_lock( (pthread_mutex_t *) hMutexIn );
766 :
767 22781853 : if( err != 0 )
768 : {
769 0 : if( err == EDEADLK )
770 0 : CPLDebug( "CPLAcquireMutex", "Error = %d/EDEADLK", err );
771 : else
772 0 : CPLDebug( "CPLAcquireMutex", "Error = %d", err );
773 :
774 0 : return FALSE;
775 : }
776 :
777 22781853 : return TRUE;
778 : }
779 :
780 : /************************************************************************/
781 : /* CPLReleaseMutex() */
782 : /************************************************************************/
783 :
784 22781775 : void CPLReleaseMutex( void *hMutexIn )
785 :
786 : {
787 22781775 : pthread_mutex_unlock( (pthread_mutex_t *) hMutexIn );
788 22781775 : }
789 :
790 : /************************************************************************/
791 : /* CPLDestroyMutex() */
792 : /************************************************************************/
793 :
794 288 : void CPLDestroyMutex( void *hMutexIn )
795 :
796 : {
797 288 : pthread_mutex_destroy( (pthread_mutex_t *) hMutexIn );
798 288 : free( hMutexIn );
799 288 : }
800 :
801 : /************************************************************************/
802 : /* CPLLockFile() */
803 : /* */
804 : /* This is really a stub implementation, see first */
805 : /* CPLLockFile() for caveats. */
806 : /************************************************************************/
807 :
808 0 : void *CPLLockFile( const char *pszPath, double dfWaitInSeconds )
809 :
810 : {
811 : FILE *fpLock;
812 : char *pszLockFilename;
813 :
814 : /* -------------------------------------------------------------------- */
815 : /* We use a lock file with a name derived from the file we want */
816 : /* to lock to represent the file being locked. Note that for */
817 : /* the stub implementation the target file does not even need */
818 : /* to exist to be locked. */
819 : /* -------------------------------------------------------------------- */
820 0 : pszLockFilename = (char *) CPLMalloc(strlen(pszPath) + 30);
821 0 : sprintf( pszLockFilename, "%s.lock", pszPath );
822 :
823 0 : fpLock = fopen( pszLockFilename, "r" );
824 0 : while( fpLock != NULL && dfWaitInSeconds > 0.0 )
825 : {
826 0 : fclose( fpLock );
827 0 : CPLSleep( MIN(dfWaitInSeconds,0.5) );
828 0 : dfWaitInSeconds -= 0.5;
829 :
830 0 : fpLock = fopen( pszLockFilename, "r" );
831 : }
832 :
833 0 : if( fpLock != NULL )
834 : {
835 0 : fclose( fpLock );
836 0 : CPLFree( pszLockFilename );
837 0 : return NULL;
838 : }
839 :
840 0 : fpLock = fopen( pszLockFilename, "w" );
841 :
842 0 : if( fpLock == NULL )
843 : {
844 0 : CPLFree( pszLockFilename );
845 0 : return NULL;
846 : }
847 :
848 0 : fwrite( "held\n", 1, 5, fpLock );
849 0 : fclose( fpLock );
850 :
851 0 : return pszLockFilename;
852 : }
853 :
854 : /************************************************************************/
855 : /* CPLUnlockFile() */
856 : /************************************************************************/
857 :
858 0 : void CPLUnlockFile( void *hLock )
859 :
860 : {
861 0 : char *pszLockFilename = (char *) hLock;
862 :
863 0 : if( hLock == NULL )
864 0 : return;
865 :
866 0 : VSIUnlink( pszLockFilename );
867 :
868 0 : CPLFree( pszLockFilename );
869 : }
870 :
871 : /************************************************************************/
872 : /* CPLGetPID() */
873 : /************************************************************************/
874 :
875 33427 : GIntBig CPLGetPID()
876 :
877 : {
878 33427 : return (GIntBig) pthread_self();
879 : }
880 :
881 : /************************************************************************/
882 : /* CPLStdCallThreadJacket() */
883 : /************************************************************************/
884 :
885 : typedef struct {
886 : void *pAppData;
887 : CPLThreadFunc pfnMain;
888 : pthread_t hThread;
889 : } CPLStdCallThreadInfo;
890 :
891 1 : static void *CPLStdCallThreadJacket( void *pData )
892 :
893 : {
894 1 : CPLStdCallThreadInfo *psInfo = (CPLStdCallThreadInfo *) pData;
895 :
896 1 : psInfo->pfnMain( psInfo->pAppData );
897 :
898 1 : CPLFree( psInfo );
899 :
900 1 : return NULL;
901 : }
902 :
903 : /************************************************************************/
904 : /* CPLCreateThread() */
905 : /* */
906 : /* The WIN32 CreateThread() call requires an entry point that */
907 : /* has __stdcall conventions, so we provide a jacket function */
908 : /* to supply that. */
909 : /************************************************************************/
910 :
911 1 : int CPLCreateThread( CPLThreadFunc pfnMain, void *pThreadArg )
912 :
913 : {
914 :
915 : CPLStdCallThreadInfo *psInfo;
916 : pthread_attr_t hThreadAttr;
917 :
918 1 : psInfo = (CPLStdCallThreadInfo*) CPLCalloc(sizeof(CPLStdCallThreadInfo),1);
919 1 : psInfo->pAppData = pThreadArg;
920 1 : psInfo->pfnMain = pfnMain;
921 :
922 1 : pthread_attr_init( &hThreadAttr );
923 1 : pthread_attr_setdetachstate( &hThreadAttr, PTHREAD_CREATE_DETACHED );
924 1 : if( pthread_create( &(psInfo->hThread), &hThreadAttr,
925 : CPLStdCallThreadJacket, (void *) psInfo ) != 0 )
926 : {
927 0 : CPLFree( psInfo );
928 0 : return -1;
929 : }
930 :
931 1 : return 1; /* can we return the actual thread pid? */
932 : }
933 :
934 : /************************************************************************/
935 : /* CPLSleep() */
936 : /************************************************************************/
937 :
938 1 : void CPLSleep( double dfWaitInSeconds )
939 :
940 : {
941 : struct timespec sRequest, sRemain;
942 :
943 1 : sRequest.tv_sec = (int) floor(dfWaitInSeconds);
944 1 : sRequest.tv_nsec = (int) ((dfWaitInSeconds - sRequest.tv_sec)*1000000000);
945 1 : nanosleep( &sRequest, &sRemain );
946 1 : }
947 :
948 : static int bTLSKeySetup = FALSE;
949 : static pthread_key_t oTLSKey;
950 :
951 : /************************************************************************/
952 : /* CPLCleanupTLS() */
953 : /************************************************************************/
954 :
955 626 : void CPLCleanupTLS()
956 :
957 : {
958 : void **papTLSList;
959 :
960 626 : if( !bTLSKeySetup )
961 0 : return;
962 :
963 626 : papTLSList = (void **) pthread_getspecific( oTLSKey );
964 626 : if( papTLSList == NULL )
965 9 : return;
966 :
967 617 : pthread_setspecific( oTLSKey, NULL );
968 :
969 617 : CPLCleanupTLSList( papTLSList );
970 : }
971 :
972 : /************************************************************************/
973 : /* CPLGetTLSList() */
974 : /************************************************************************/
975 :
976 2595473 : static void **CPLGetTLSList()
977 :
978 : {
979 : void **papTLSList;
980 :
981 2595473 : if( !bTLSKeySetup )
982 : {
983 380 : if( pthread_key_create( &oTLSKey,
984 : (void (*)(void*)) CPLCleanupTLSList ) != 0 )
985 : {
986 : CPLError( CE_Fatal, CPLE_AppDefined,
987 0 : "pthread_key_create() failed!" );
988 : }
989 380 : bTLSKeySetup = TRUE;
990 : }
991 :
992 2595473 : papTLSList = (void **) pthread_getspecific( oTLSKey );
993 2595473 : if( papTLSList == NULL )
994 : {
995 636 : papTLSList = (void **) CPLCalloc(sizeof(void*),CTLS_MAX*2);
996 636 : if( pthread_setspecific( oTLSKey, papTLSList ) != 0 )
997 : {
998 : CPLError( CE_Fatal, CPLE_AppDefined,
999 0 : "pthread_setspecific() failed!" );
1000 : }
1001 : }
1002 :
1003 2595473 : return papTLSList;
1004 : }
1005 :
1006 : #endif /* def CPL_MULTIPROC_PTHREAD */
1007 :
1008 : /************************************************************************/
1009 : /* CPLGetTLS() */
1010 : /************************************************************************/
1011 :
1012 2592709 : void *CPLGetTLS( int nIndex )
1013 :
1014 : {
1015 2592709 : void** papTLSList = CPLGetTLSList();
1016 :
1017 : CPLAssert( nIndex >= 0 && nIndex < CTLS_MAX );
1018 :
1019 2592709 : return papTLSList[nIndex];
1020 : }
1021 :
1022 : /************************************************************************/
1023 : /* CPLSetTLS() */
1024 : /************************************************************************/
1025 :
1026 2764 : void CPLSetTLS( int nIndex, void *pData, int bFreeOnExit )
1027 :
1028 : {
1029 2764 : void **papTLSList = CPLGetTLSList();
1030 :
1031 : CPLAssert( nIndex >= 0 && nIndex < CTLS_MAX );
1032 :
1033 2764 : papTLSList[nIndex] = pData;
1034 2764 : papTLSList[CTLS_MAX + nIndex] = (void *) (long) bFreeOnExit;
1035 2764 : }
1036 :
|