Main Page   Class Hierarchy   Compound List   File List   Compound Members   File Members   Related Pages  

cpl_multiproc.cpp

00001 /**********************************************************************
00002  * $Id: cpl_multiproc_cpp-source.html,v 1.3 2002/12/21 19:13:12 warmerda Exp $
00003  *
00004  * Project:  CPL - Common Portability Library
00005  * Purpose:  CPL Multi-Threading, and process handling portability functions.
00006  * Author:   Frank Warmerdam, warmerdam@pobox.com
00007  *
00008  **********************************************************************
00009  * Copyright (c) 2002, Frank Warmerdam
00010  *
00011  * Permission is hereby granted, free of charge, to any person obtaining a
00012  * copy of this software and associated documentation files (the "Software"),
00013  * to deal in the Software without restriction, including without limitation
00014  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
00015  * and/or sell copies of the Software, and to permit persons to whom the
00016  * Software is furnished to do so, subject to the following conditions:
00017  * 
00018  * The above copyright notice and this permission notice shall be included
00019  * in all copies or substantial portions of the Software.
00020  * 
00021  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
00022  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
00023  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
00024  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
00025  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
00026  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 
00027  * DEALINGS IN THE SOFTWARE.
00028  **********************************************************************
00029  *
00030  * $Log: cpl_multiproc_cpp-source.html,v $
00030  * Revision 1.3  2002/12/21 19:13:12  warmerda
00030  * updated
00030  *
00031  * Revision 1.2  2002/07/11 19:36:34  warmerda
00032  * CPLCreateMutex() should implicitly acquire it, fix stub version
00033  *
00034  * Revision 1.1  2002/05/24 04:01:01  warmerda
00035  * New
00036  *
00037  **********************************************************************/
00038 
00039 #include "cpl_multiproc.h"
00040 #include "cpl_conv.h"
00041 #include <time.h>
00042 
00043 CPL_CVSID("$Id: cpl_multiproc_cpp-source.html,v 1.3 2002/12/21 19:13:12 warmerda Exp $");
00044 
00045 #ifdef CPL_MULTIPROC_STUB
00046 /************************************************************************/
00047 /* ==================================================================== */
00048 /*                        CPL_MULTIPROC_STUB                            */
00049 /*                                                                      */
00050 /*      Stub implementation.  Mutexes don't provide exclusion, file     */
00051 /*      locking is achieved with extra "lock files", and thread         */
00052 /*      creation doesn't work.  The PID is always just one.             */
00053 /* ==================================================================== */
00054 /************************************************************************/
00055 
00056 /************************************************************************/
00057 /*                           CPLCreateMutex()                           */
00058 /************************************************************************/
00059 
00060 void *CPLCreateMutex()
00061 
00062 {
00063     unsigned char *pabyMutex = (unsigned char *) CPLMalloc( 4 );
00064 
00065     pabyMutex[0] = 1;
00066     pabyMutex[1] = 'r';
00067     pabyMutex[2] = 'e';
00068     pabyMutex[3] = 'd';
00069 
00070     return (void *) pabyMutex;
00071 }
00072 
00073 /************************************************************************/
00074 /*                          CPLAcquireMutex()                           */
00075 /************************************************************************/
00076 
00077 int CPLAcquireMutex( void *hMutex, double dfWaitInSeconds )
00078 
00079 {
00080     unsigned char *pabyMutex = (unsigned char *) hMutex;
00081 
00082     CPLAssert( pabyMutex[1] == 'r' && pabyMutex[2] == 'e' 
00083                && pabyMutex[3] == 'd' );
00084 
00085     if( pabyMutex[0] != 0 )
00086         CPLDebug( "CPLMultiProc", 
00087                   "CPLAcquireMutex() called on mutex with %d as ref count!",
00088                   pabyMutex[0] );
00089 
00090     pabyMutex[0] += 1;
00091 
00092     return TRUE;
00093 }
00094 
00095 /************************************************************************/
00096 /*                          CPLReleaseMutex()                           */
00097 /************************************************************************/
00098 
00099 void CPLReleaseMutex( void *hMutex )
00100 
00101 {
00102     unsigned char *pabyMutex = (unsigned char *) hMutex;
00103 
00104     CPLAssert( pabyMutex[1] == 'r' && pabyMutex[2] == 'e' 
00105                && pabyMutex[3] == 'd' );
00106 
00107     if( pabyMutex[0] != 1 )
00108         CPLDebug( "CPLMultiProc", 
00109                   "CPLReleaseMutex() called on mutex with %d as ref count!",
00110                   pabyMutex[0] );
00111 
00112     pabyMutex[0] -= 1;
00113 }
00114 
00115 /************************************************************************/
00116 /*                          CPLDestroyMutex()                           */
00117 /************************************************************************/
00118 
00119 void CPLDestroyMutex( void *hMutex )
00120 
00121 {
00122     unsigned char *pabyMutex = (unsigned char *) hMutex;
00123 
00124     CPLAssert( pabyMutex[1] == 'r' && pabyMutex[2] == 'e' 
00125                && pabyMutex[3] == 'd' );
00126 
00127     CPLFree( pabyMutex );
00128 }
00129 
00130 /************************************************************************/
00131 /*                            CPLLockFile()                             */
00132 /*                                                                      */
00133 /*      Lock a file.  This implementation has a terrible race           */
00134 /*      condition.  If we don't succeed in opening the lock file, we    */
00135 /*      assume we can create one and own the target file, but other     */
00136 /*      processes might easily try creating the target file at the      */
00137 /*      same time, overlapping us.  Death!  Mayhem!  The traditional    */
00138 /*      solution is to use open() with _O_CREAT|_O_EXCL but this        */
00139 /*      function and these arguments aren't trivially portable.         */
00140 /*      Also, this still leaves a race condition on NFS drivers         */
00141 /*      (apparently).                                                   */
00142 /************************************************************************/
00143 
00144 void *CPLLockFile( const char *pszPath, double dfWaitInSeconds )
00145 
00146 {
00147     FILE      *fpLock;
00148     char      *pszLockFilename;
00149     
00150 /* -------------------------------------------------------------------- */
00151 /*      We use a lock file with a name derived from the file we want    */
00152 /*      to lock to represent the file being locked.  Note that for      */
00153 /*      the stub implementation the target file does not even need      */
00154 /*      to exist to be locked.                                          */
00155 /* -------------------------------------------------------------------- */
00156     pszLockFilename = (char *) CPLMalloc(strlen(pszPath) + 30);
00157     sprintf( pszLockFilename, "%s.lock", pszPath );
00158 
00159     fpLock = fopen( pszLockFilename, "r" );
00160     while( fpLock != NULL && dfWaitInSeconds > 0.0 )
00161     {
00162         fclose( fpLock );
00163         CPLSleep( MIN(dfWaitInSeconds,0.5) );
00164         dfWaitInSeconds -= 0.5;
00165 
00166         fpLock = fopen( pszLockFilename, "r" );
00167     }
00168         
00169     if( fpLock != NULL )
00170     {
00171         fclose( fpLock );
00172         CPLFree( pszLockFilename );
00173         return NULL;
00174     }
00175 
00176     fpLock = fopen( pszLockFilename, "w" );
00177 
00178     if( fpLock == NULL )
00179     {
00180         CPLFree( pszLockFilename );
00181         return NULL;
00182     }
00183 
00184     fwrite( "held\n", 1, 5, fpLock );
00185     fclose( fpLock );
00186 
00187     return pszLockFilename;
00188 }
00189 
00190 /************************************************************************/
00191 /*                           CPLUnlockFile()                            */
00192 /************************************************************************/
00193 
00194 void CPLUnlockFile( void *hLock )
00195 
00196 {
00197     char *pszLockFilename = (char *) hLock;
00198 
00199     if( hLock == NULL )
00200         return;
00201     
00202     VSIUnlink( pszLockFilename );
00203     
00204     CPLFree( pszLockFilename );
00205 }
00206 
00207 /************************************************************************/
00208 /*                             CPLGetPID()                              */
00209 /************************************************************************/
00210 
00211 int CPLGetPID()
00212 
00213 {
00214     return 1;
00215 }
00216 
00217 /************************************************************************/
00218 /*                          CPLCreateThread();                          */
00219 /************************************************************************/
00220 
00221 int CPLCreateThread( void (*pfnMain)(void *), void *pArg )
00222 
00223 {
00224     return -1;
00225 }
00226 
00227 /************************************************************************/
00228 /*                              CPLSleep()                              */
00229 /************************************************************************/
00230 
00231 void CPLSleep( double dfWaitInSeconds )
00232 
00233 {
00234     time_t  ltime;
00235     time_t  ttime;
00236 
00237     time( &ltime );
00238     ttime = ltime + (int) (dfWaitInSeconds+0.5);
00239 
00240     for( ; ltime < ttime; time(&ltime) )
00241     {
00242         /* currently we just busy wait.  Perhaps we could at least block on 
00243            io? */
00244     }
00245 }
00246 
00247 #endif /* def CPL_MULTIPROC_STUB */
00248 
00249 #ifdef CPL_MULTIPROC_WIN32
00250 #include <windows.h>
00251 
00252   /************************************************************************/
00253   /* ==================================================================== */
00254   /*                        CPL_MULTIPROC_WIN32                           */
00255   /*                                                                      */
00256   /*    WIN32 Implementation of multiprocessing functions.                */
00257   /* ==================================================================== */
00258   /************************************************************************/
00259 
00260 
00261 /************************************************************************/
00262 /*                           CPLCreateMutex()                           */
00263 /************************************************************************/
00264 
00265 void *CPLCreateMutex()
00266 
00267 {
00268     HANDLE hMutex;
00269 
00270     hMutex = CreateMutex( NULL, TRUE, NULL );
00271 
00272     return (void *) hMutex;
00273 }
00274 
00275 /************************************************************************/
00276 /*                          CPLAcquireMutex()                           */
00277 /************************************************************************/
00278 
00279 int CPLAcquireMutex( void *hMutexIn, double dfWaitInSeconds )
00280 
00281 {
00282     HANDLE hMutex = (HANDLE) hMutexIn;
00283     DWORD  hr;
00284 
00285     hr = WaitForSingleObject( hMutex, (int) (dfWaitInSeconds * 1000) );
00286     
00287     return hr != WAIT_TIMEOUT;
00288 }
00289 
00290 /************************************************************************/
00291 /*                          CPLReleaseMutex()                           */
00292 /************************************************************************/
00293 
00294 void CPLReleaseMutex( void *hMutexIn )
00295 
00296 {
00297     HANDLE hMutex = (HANDLE) hMutexIn;
00298 
00299     ReleaseMutex( hMutex );
00300 }
00301 
00302 /************************************************************************/
00303 /*                          CPLDestroyMutex()                           */
00304 /************************************************************************/
00305 
00306 void CPLDestroyMutex( void *hMutexIn )
00307 
00308 {
00309     HANDLE hMutex = (HANDLE) hMutexIn;
00310 
00311     CloseHandle( hMutex );
00312 }
00313 
00314 /************************************************************************/
00315 /*                            CPLLockFile()                             */
00316 /************************************************************************/
00317 
00318 void *CPLLockFile( const char *pszPath, double dfWaitInSeconds )
00319 
00320 {
00321     char      *pszLockFilename;
00322     HANDLE    hLockFile;
00323     
00324     pszLockFilename = (char *) CPLMalloc(strlen(pszPath) + 30);
00325     sprintf( pszLockFilename, "%s.lock", pszPath );
00326 
00327     hLockFile = 
00328         CreateFile( pszLockFilename, GENERIC_WRITE, 0, NULL,CREATE_NEW, 
00329                     FILE_ATTRIBUTE_NORMAL|FILE_FLAG_DELETE_ON_CLOSE, NULL );
00330 
00331     while( GetLastError() == ERROR_ALREADY_EXISTS
00332            && dfWaitInSeconds > 0.0 )
00333     {
00334         CloseHandle( hLockFile );
00335         CPLSleep( MIN(dfWaitInSeconds,0.125) );
00336         dfWaitInSeconds -= 0.125;
00337 
00338         hLockFile = 
00339             CreateFile( pszLockFilename, GENERIC_WRITE, 0, NULL, CREATE_NEW, 
00340                         FILE_ATTRIBUTE_NORMAL|FILE_FLAG_DELETE_ON_CLOSE, 
00341                         NULL );
00342     }
00343 
00344     CPLFree( pszLockFilename );
00345 
00346     if( hLockFile == INVALID_HANDLE_VALUE )
00347         return NULL;
00348 
00349     if( GetLastError() == ERROR_ALREADY_EXISTS )
00350     {
00351         CloseHandle( hLockFile );
00352         return NULL;
00353     }
00354 
00355     return (void *) hLockFile;
00356 }
00357 
00358 /************************************************************************/
00359 /*                           CPLUnlockFile()                            */
00360 /************************************************************************/
00361 
00362 void CPLUnlockFile( void *hLock )
00363 
00364 {
00365     HANDLE    hLockFile = (HANDLE) hLock;
00366 
00367     CloseHandle( hLockFile );
00368 }
00369 
00370 /************************************************************************/
00371 /*                             CPLGetPID()                              */
00372 /************************************************************************/
00373 
00374 int CPLGetPID()
00375 
00376 {
00377     return GetCurrentThreadId();
00378 }
00379 
00380 /************************************************************************/
00381 /*                       CPLStdCallThreadJacket()                       */
00382 /************************************************************************/
00383 
00384 typedef struct {
00385     void *pAppData;
00386     void (*pfnMain)(void *);
00387 } CPLStdCallThreadInfo;
00388 
00389 static DWORD WINAPI CPLStdCallThreadJacket( void *pData )
00390 
00391 {
00392     CPLStdCallThreadInfo *psInfo = (CPLStdCallThreadInfo *) pData;
00393 
00394     psInfo->pfnMain( psInfo->pAppData );
00395 
00396     CPLFree( psInfo );
00397 
00398     return 0;
00399 }
00400 
00401 /************************************************************************/
00402 /*                          CPLCreateThread()                           */
00403 /*                                                                      */
00404 /*      The WIN32 CreateThread() call requires an entry point that      */
00405 /*      has __stdcall conventions, so we provide a jacket function      */
00406 /*      to supply that.                                                 */
00407 /************************************************************************/
00408 
00409 int CPLCreateThread( void (*pfnMain)(void *), void *pThreadArg )
00410 
00411 {
00412     HANDLE hThread;
00413     DWORD  nThreadId;
00414     CPLStdCallThreadInfo *psInfo;
00415 
00416     psInfo = (CPLStdCallThreadInfo*) CPLCalloc(sizeof(CPLStdCallThreadInfo),1);
00417     psInfo->pAppData = pThreadArg;
00418     psInfo->pfnMain = pfnMain;
00419 
00420     hThread = CreateThread( NULL, 0, CPLStdCallThreadJacket, psInfo, 
00421                             0, &nThreadId );
00422 
00423     if( hThread == NULL )
00424         return -1;
00425 
00426     CloseHandle( hThread );
00427 
00428     return nThreadId;
00429 }
00430 
00431 /************************************************************************/
00432 /*                              CPLSleep()                              */
00433 /************************************************************************/
00434 
00435 void CPLSleep( double dfWaitInSeconds )
00436 
00437 {
00438     Sleep( (DWORD) (dfWaitInSeconds * 1000.0) );
00439 }
00440 
00441 #endif /* def CPL_MULTIPROC_WIN32 */
00442 

Generated at Sat Dec 21 14:01:57 2002 for GDAL by doxygen1.2.3-20001105 written by Dimitri van Heesch, © 1997-2000