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