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