1 /**********************************************************************
2  * $Id: cpl_multiproc.h 5bf28e3bebd1032c4c8f50564d077f95cdf897d3 2020-09-30 14:07:46 +0200 Even Rouault $
3  *
4  * Project:  CPL - Common Portability Library
5  * Purpose:  CPL Multi-Threading, and process handling portability functions.
6  * Author:   Frank Warmerdam, warmerdam@pobox.com
7  *
8  **********************************************************************
9  * Copyright (c) 2002, Frank Warmerdam
10  * Copyright (c) 2008-2013, Even Rouault <even dot rouault at spatialys.com>
11  *
12  * Permission is hereby granted, free of charge, to any person obtaining a
13  * copy of this software and associated documentation files (the "Software"),
14  * to deal in the Software without restriction, including without limitation
15  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
16  * and/or sell copies of the Software, and to permit persons to whom the
17  * Software is furnished to do so, subject to the following conditions:
18  *
19  * The above copyright notice and this permission notice shall be included
20  * in all copies or substantial portions of the Software.
21  *
22  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
25  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
27  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
28  * DEALINGS IN THE SOFTWARE.
29  ****************************************************************************/
30 
31 #ifndef CPL_MULTIPROC_H_INCLUDED_
32 #define CPL_MULTIPROC_H_INCLUDED_
33 
34 #include "cpl_port.h"
35 
36 /*
37 ** There are three primary implementations of the multi-process support
38 ** controlled by one of CPL_MULTIPROC_WIN32, CPL_MULTIPROC_PTHREAD or
39 ** CPL_MULTIPROC_STUB being defined.  If none are defined, the stub
40 ** implementation will be used.
41 */
42 
43 #if defined(WIN32) && !defined(CPL_MULTIPROC_STUB)
44 #  define CPL_MULTIPROC_WIN32
45 /* MinGW can have pthread support, so disable it to avoid issues */
46 /* in cpl_multiproc.cpp */
47 #  undef  CPL_MULTIPROC_PTHREAD
48 #endif
49 
50 #if !defined(CPL_MULTIPROC_WIN32) && !defined(CPL_MULTIPROC_PTHREAD) \
51  && !defined(CPL_MULTIPROC_STUB) && !defined(CPL_MULTIPROC_NONE)
52 #  define CPL_MULTIPROC_STUB
53 #endif
54 
55 CPL_C_START
56 
57 typedef void (*CPLThreadFunc)(void *);
58 
59 void CPL_DLL *CPLLockFile( const char *pszPath, double dfWaitInSeconds );
60 void  CPL_DLL CPLUnlockFile( void *hLock );
61 
62 #ifdef DEBUG
63 typedef struct _CPLMutex  CPLMutex;
64 typedef struct _CPLCond   CPLCond;
65 typedef struct _CPLJoinableThread CPLJoinableThread;
66 #else
67 #define CPLMutex void
68 #define CPLCond void
69 #define CPLJoinableThread void
70 #endif
71 
72 /* Options for CPLCreateMutexEx() and CPLCreateOrAcquireMutexEx() */
73 #define CPL_MUTEX_RECURSIVE         0
74 #define CPL_MUTEX_ADAPTIVE          1
75 #define CPL_MUTEX_REGULAR           2
76 
77 CPLMutex CPL_DLL *CPLCreateMutex( void ); /* returned acquired */
78 CPLMutex CPL_DLL *CPLCreateMutexEx( int nOptions ); /* returned acquired */
79 int   CPL_DLL CPLCreateOrAcquireMutex( CPLMutex **, double dfWaitInSeconds );
80 int   CPL_DLL CPLCreateOrAcquireMutexEx( CPLMutex **, double dfWaitInSeconds, int nOptions  );
81 int   CPL_DLL CPLAcquireMutex( CPLMutex *hMutex, double dfWaitInSeconds );
82 void  CPL_DLL CPLReleaseMutex( CPLMutex *hMutex );
83 void  CPL_DLL CPLDestroyMutex( CPLMutex *hMutex );
84 void  CPL_DLL CPLCleanupMasterMutex( void );
85 
86 CPLCond  CPL_DLL *CPLCreateCond( void );
87 void  CPL_DLL  CPLCondWait( CPLCond *hCond, CPLMutex* hMutex );
88 typedef enum
89 {
90     COND_TIMED_WAIT_COND,
91     COND_TIMED_WAIT_TIME_OUT,
92     COND_TIMED_WAIT_OTHER
93 } CPLCondTimedWaitReason;
94 CPLCondTimedWaitReason CPL_DLL CPLCondTimedWait( CPLCond *hCond, CPLMutex* hMutex, double dfWaitInSeconds );
95 void  CPL_DLL  CPLCondSignal( CPLCond *hCond );
96 void  CPL_DLL  CPLCondBroadcast( CPLCond *hCond );
97 void  CPL_DLL  CPLDestroyCond( CPLCond *hCond );
98 
99 /** Contrary to what its name suggests, CPLGetPID() actually returns the thread id */
100 GIntBig CPL_DLL CPLGetPID( void );
101 int CPL_DLL CPLGetCurrentProcessID( void );
102 int   CPL_DLL CPLCreateThread( CPLThreadFunc pfnMain, void *pArg );
103 CPLJoinableThread  CPL_DLL* CPLCreateJoinableThread( CPLThreadFunc pfnMain, void *pArg );
104 void  CPL_DLL CPLJoinThread(CPLJoinableThread* hJoinableThread);
105 void  CPL_DLL CPLSleep( double dfWaitInSeconds );
106 
107 const char CPL_DLL *CPLGetThreadingModel( void );
108 
109 int CPL_DLL CPLGetNumCPUs( void );
110 
111 typedef struct _CPLLock CPLLock;
112 
113 /* Currently LOCK_ADAPTIVE_MUTEX is Linux-only and LOCK_SPIN only available */
114 /* on systems with pthread_spinlock API (so not MacOsX). If a requested type */
115 /* isn't available, it fallbacks to LOCK_RECURSIVE_MUTEX */
116 typedef enum
117 {
118     LOCK_RECURSIVE_MUTEX,
119     LOCK_ADAPTIVE_MUTEX,
120     LOCK_SPIN
121 } CPLLockType;
122 
123 CPLLock  CPL_DLL *CPLCreateLock( CPLLockType eType ); /* returned NON acquired */
124 int   CPL_DLL  CPLCreateOrAcquireLock( CPLLock**, CPLLockType eType );
125 int   CPL_DLL  CPLAcquireLock( CPLLock* );
126 void  CPL_DLL  CPLReleaseLock( CPLLock* );
127 void  CPL_DLL  CPLDestroyLock( CPLLock* );
128 void  CPL_DLL  CPLLockSetDebugPerf( CPLLock*, int bEnableIn ); /* only available on x86/x86_64 with GCC for now */
129 
130 CPL_C_END
131 
132 #if defined(__cplusplus) && !defined(CPL_SUPRESS_CPLUSPLUS)
133 
134 /* Instantiates the mutex if not already done. The parameter x should be a (void**). */
135 #define CPLMutexHolderD(x)  CPLMutexHolder oHolder(x,1000.0,__FILE__,__LINE__);
136 
137 /* Instantiates the mutex with options if not already done. */
138 /* The parameter x should be a (void**). */
139 #define CPLMutexHolderExD(x, nOptions)  CPLMutexHolder oHolder(x,1000.0,__FILE__,__LINE__,nOptions);
140 
141 /* This variant assumes the mutex has already been created. If not, it will */
142 /* be a no-op. The parameter x should be a (void*) */
143 #define CPLMutexHolderOptionalLockD(x)  CPLMutexHolder oHolder(x,1000.0,__FILE__,__LINE__);
144 
145 /** Object to hold a mutex */
146 class CPL_DLL CPLMutexHolder
147 {
148   private:
149     CPLMutex   *hMutex = nullptr;
150     // Only used for debugging.
151     const char *pszFile = nullptr;
152     int         nLine = 0;
153 
154     CPL_DISALLOW_COPY_ASSIGN(CPLMutexHolder)
155 
156   public:
157 
158     /** Instantiates the mutex if not already done. */
159     explicit CPLMutexHolder( CPLMutex **phMutex, double dfWaitInSeconds = 1000.0,
160                     const char *pszFile = __FILE__,
161                     int nLine = __LINE__,
162                     int nOptions = CPL_MUTEX_RECURSIVE);
163 
164     /** This variant assumes the mutex has already been created. If not, it will
165      * be a no-op */
166     explicit CPLMutexHolder( CPLMutex* hMutex, double dfWaitInSeconds = 1000.0,
167                     const char *pszFile = __FILE__,
168                     int nLine = __LINE__ );
169 
170     ~CPLMutexHolder();
171 };
172 
173 /* Instantiates the lock if not already done. The parameter x should be a (CPLLock**). */
174 #define CPLLockHolderD(x, eType)  CPLLockHolder oHolder(x,eType,__FILE__,__LINE__);
175 
176 /* This variant assumes the lock has already been created. If not, it will */
177 /* be a no-op. The parameter should be (CPLLock*) */
178 #define CPLLockHolderOptionalLockD(x)  CPLLockHolder oHolder(x,__FILE__,__LINE__);
179 
180 /** Object to hold a lock */
181 class CPL_DLL CPLLockHolder
182 {
183   private:
184     CPLLock    *hLock = nullptr;
185     const char *pszFile = nullptr;
186     int         nLine = 0;
187 
188     CPL_DISALLOW_COPY_ASSIGN(CPLLockHolder)
189 
190   public:
191 
192     /** Instantiates the lock if not already done. */
193     CPLLockHolder( CPLLock **phSpin, CPLLockType eType,
194                     const char *pszFile = __FILE__,
195                     int nLine = __LINE__);
196 
197     /** This variant assumes the lock has already been created. If not, it will
198      * be a no-op */
199     explicit CPLLockHolder( CPLLock* hSpin,
200                     const char *pszFile = __FILE__,
201                     int nLine = __LINE__ );
202 
203     ~CPLLockHolder();
204 };
205 
206 #endif /* def __cplusplus */
207 
208 /* -------------------------------------------------------------------- */
209 /*      Thread local storage.                                           */
210 /* -------------------------------------------------------------------- */
211 
212 #define CTLS_RLBUFFERINFO                1         /* cpl_conv.cpp */
213 #define CTLS_WIN32_COND                  2         /* cpl_multiproc.cpp */
214 #define CTLS_CSVTABLEPTR                 3         /* cpl_csv.cpp */
215 #define CTLS_CSVDEFAULTFILENAME          4         /* cpl_csv.cpp */
216 #define CTLS_ERRORCONTEXT                5         /* cpl_error.cpp */
217 #define CTLS_VSICURL_CACHEDCONNECTION    6         /* cpl_vsil_curl.cpp */
218 #define CTLS_PATHBUF                     7         /* cpl_path.cpp */
219 #define CTLS_ABSTRACTARCHIVE_SPLIT       8         /* cpl_vsil_abstract_archive.cpp */
220 #define CTLS_GDALOPEN_ANTIRECURSION      9         /* gdaldataset.cpp */
221 #define CTLS_CPLSPRINTF                 10         /* cpl_string.h */
222 #define CTLS_RESPONSIBLEPID             11         /* gdaldataset.cpp */
223 #define CTLS_VERSIONINFO                12         /* gdal_misc.cpp */
224 #define CTLS_VERSIONINFO_LICENCE        13         /* gdal_misc.cpp */
225 #define CTLS_CONFIGOPTIONS              14         /* cpl_conv.cpp */
226 #define CTLS_FINDFILE                   15         /* cpl_findfile.cpp */
227 #define CTLS_VSIERRORCONTEXT            16         /* cpl_vsi_error.cpp */
228 #define CTLS_ERRORHANDLERACTIVEDATA     17         /* cpl_error.cpp */
229 #define CTLS_PROJCONTEXTHOLDER          18         /* ogr_proj_p.cpp */
230 #define CTLS_GDALDEFAULTOVR_ANTIREC     19         /* gdaldefaultoverviews.cpp */
231 #define CTLS_HTTPFETCHCALLBACK          20         /* cpl_http.cpp */
232 
233 #define CTLS_MAX                        32
234 
235 CPL_C_START
236 void CPL_DLL * CPLGetTLS( int nIndex );
237 void CPL_DLL * CPLGetTLSEx( int nIndex, int* pbMemoryErrorOccurred );
238 void CPL_DLL CPLSetTLS( int nIndex, void *pData, int bFreeOnExit );
239 
240 /* Warning : the CPLTLSFreeFunc must not in any case directly or indirectly */
241 /* use or fetch any TLS data, or a terminating thread will hang ! */
242 typedef void (*CPLTLSFreeFunc)( void* pData );
243 void CPL_DLL CPLSetTLSWithFreeFunc( int nIndex, void *pData, CPLTLSFreeFunc pfnFree );
244 void CPL_DLL CPLSetTLSWithFreeFuncEx( int nIndex, void *pData, CPLTLSFreeFunc pfnFree, int* pbMemoryErrorOccurred );
245 
246 void CPL_DLL CPLCleanupTLS( void );
247 CPL_C_END
248 
249 #endif /* CPL_MULTIPROC_H_INCLUDED_ */
250