1 /**************************************************************************\
2 * Copyright (c) Kongsberg Oil & Gas Technologies AS
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met:
8 *
9 * Redistributions of source code must retain the above copyright notice,
10 * this list of conditions and the following disclaimer.
11 *
12 * Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * Neither the name of the copyright holder nor the names of its
17 * contributors may be used to endorse or promote products derived from
18 * this software without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24 * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 \**************************************************************************/
32
33 /* FIXME: should provide dummy implementations of the (few) internal
34 public cc_mutex_*() calls, so one can include the header files
35 mutex.h and SbMutex.h without #ifdef checks, and also declare
36 e.g. SbMutex instances when thread-support is missing.
37
38 This would clean up source code everywhere we're using mutex'es.
39
40 20050516 mortene.
41 */
42
43 /*! \file Inventor/C/threads/common.h */
44
45 /*!
46 \struct cc_mutex common.h Inventor/C/threads/common.h
47 \ingroup threads
48 \brief The structure for a mutex.
49 */
50
51 /*!
52 \typedef struct cc_mutex cc_mutex
53 \ingroup threads
54 \brief The type definition for the mutex structure.
55 */
56
57 /*! \file mutex.h */
58 #include <Inventor/C/threads/mutex.h>
59
60 #include <cstdlib>
61 #include <cassert>
62 #include <cstddef>
63 #include <cerrno>
64 #include <cfloat>
65
66 #include <Inventor/C/base/time.h>
67 #include <Inventor/C/errors/debugerror.h>
68
69 #include "threads/mutexp.h"
70 #include "tidbitsp.h"
71
72 #ifdef USE_PTHREAD
73 #include "mutex_pthread.icc"
74 #endif /* USE_PTHREAD */
75
76 #ifdef USE_W32THREAD
77 /* we test if Win32 TryEnterCriticalSection exists, and use Win32
78 critical section if it does, and Win32 mutex if it doesn't */
79 typedef BOOL (WINAPI * cc_mutex_TryEnterCriticalSection_func)(LPCRITICAL_SECTION);
80 static cc_mutex_TryEnterCriticalSection_func cc_mutex_TryEnterCriticalSection = NULL;
81 #include "mutex_win32mutex.icc"
82 #include "mutex_win32cs.icc"
83 #endif /* USE_W32THREAD */
84
85 /**************************************************************************/
86
87 static double maxmutexlocktime = DBL_MAX;
88 static double reportmutexlocktiming = DBL_MAX;
89
90 /**************************************************************************/
91
92 /*
93 \internal
94 */
95
96 void
cc_mutex_struct_init(cc_mutex * mutex_struct)97 cc_mutex_struct_init(cc_mutex * mutex_struct)
98 {
99 int ok;
100 #ifdef USE_W32THREAD
101 if (cc_mutex_TryEnterCriticalSection)
102 ok = win32_cs_struct_init(mutex_struct);
103 else
104 ok = win32_mutex_struct_init(mutex_struct);
105 #else /* USE_W32THREAD */
106 ok = internal_mutex_struct_init(mutex_struct);
107 #endif /* ! USE_W32THREAD */
108 assert(ok);
109 }
110
111 /*
112 \internal
113 */
114
115 void
cc_mutex_struct_clean(cc_mutex * mutex_struct)116 cc_mutex_struct_clean(cc_mutex * mutex_struct)
117 {
118 int ok;
119 assert(mutex_struct);
120 #ifdef USE_W32THREAD
121 if (cc_mutex_TryEnterCriticalSection)
122 ok = win32_cs_struct_clean(mutex_struct);
123 else
124 ok = win32_mutex_struct_clean(mutex_struct);
125 #else /* USE_W32THREAD */
126 ok = internal_mutex_struct_clean(mutex_struct);
127 #endif /* ! USE_W32THREAD */
128 assert(ok == CC_OK);
129 }
130
131 /**************************************************************************/
132
133 /* debugging. for instance useful for checking that there's not
134 excessive mutex construction. */
135
136 /* don't hide 'static' these to hide them in file-scope, as they are
137 used from rwmutex.cpp and recmutex.cpp aswell. */
138 unsigned int cc_debug_mtxcount = 0;
139 const char * COIN_DEBUG_MUTEX_COUNT = "COIN_DEBUG_MUTEX_COUNT";
140
141 /**************************************************************************/
142
143 /*! Constructs a mutex. */
144 cc_mutex *
cc_mutex_construct(void)145 cc_mutex_construct(void)
146 {
147 cc_mutex * mutex;
148 mutex = (cc_mutex *) malloc(sizeof(cc_mutex));
149 assert(mutex != NULL);
150 cc_mutex_struct_init(mutex);
151
152 { /* debugging */
153 const char * env = coin_getenv(COIN_DEBUG_MUTEX_COUNT);
154 if (env && (atoi(env) > 0)) {
155 cc_debug_mtxcount += 1;
156 (void)fprintf(stderr, "DEBUG: live mutexes +1 => %u (mutex++)\n",
157 cc_debug_mtxcount);
158 }
159 }
160
161 return mutex;
162 }
163
164 /*! Destroys the \a mutex specified. */
165 void
cc_mutex_destruct(cc_mutex * mutex)166 cc_mutex_destruct(cc_mutex * mutex)
167 {
168 { /* debugging */
169 const char * env = coin_getenv(COIN_DEBUG_MUTEX_COUNT);
170 if (env && (atoi(env) > 0)) {
171 assert((cc_debug_mtxcount > 0) && "skewed mutex construct/destruct pairing");
172 cc_debug_mtxcount -= 1;
173 (void)fprintf(stderr, "DEBUG: live mutexes -1 => %u (mutex--)\n",
174 cc_debug_mtxcount);
175 }
176 }
177
178 assert(mutex != NULL);
179 cc_mutex_struct_clean(mutex);
180 free(mutex);
181 }
182
183 /**************************************************************************/
184
185 /*! Locks the the \a mutex specified. */
186 void
cc_mutex_lock(cc_mutex * mutex)187 cc_mutex_lock(cc_mutex * mutex)
188 {
189 int ok;
190 SbBool timeit;
191 cc_time start = 0.0;
192
193 assert(mutex != NULL);
194
195 timeit = (maxmutexlocktime != DBL_MAX) || (reportmutexlocktiming != DBL_MAX);
196 if (timeit) { start = cc_time_gettimeofday(); }
197
198 #ifdef USE_W32THREAD
199 ok = cc_mutex_TryEnterCriticalSection ? win32_cs_lock(mutex) : win32_mutex_lock(mutex);
200 #else /* USE_W32THREAD */
201 ok = internal_mutex_lock(mutex);
202 #endif /* USE_W32THREAD */
203
204 assert(ok == CC_OK);
205
206 /* This is here as an optional debugging aid, when having problems
207 related to locks that are held too long. (Typically resulting in
208 unresponsive user interaction / lags.) */
209 if (timeit) {
210 const cc_time spent = cc_time_gettimeofday() - start;
211
212 if (spent >= reportmutexlocktiming) {
213 /* Can't use cc_debugerror_postinfo() here, because we get a
214 recursive call to this function, and a non-terminating lock /
215 hang. */
216 (void)fprintf(stdout, "DEBUG cc_mutex_lock(): mutex %p spent %f secs in lock\n",
217 mutex, spent);
218 }
219
220 assert(spent <= maxmutexlocktime);
221 }
222 }
223
224 /*! Tests the specified \a mutex to see it is already locked. */
225
226 int
cc_mutex_try_lock(cc_mutex * mutex)227 cc_mutex_try_lock(cc_mutex * mutex)
228 {
229 int ok;
230 assert(mutex != NULL);
231 #ifdef USE_W32THREAD
232 if (cc_mutex_TryEnterCriticalSection)
233 ok = win32_cs_try_lock(mutex);
234 else
235 ok = win32_mutex_try_lock(mutex);
236 #else /* USE_W32THREAD */
237 ok = internal_mutex_try_lock(mutex);
238 #endif /* ! USE_W32THREAD */
239 assert(ok == CC_OK || ok == CC_BUSY);
240 return ok;
241 }
242
243 /*! Unlocks the specified \a mutex.*/
244
245 void
cc_mutex_unlock(cc_mutex * mutex)246 cc_mutex_unlock(cc_mutex * mutex)
247 {
248 int ok;
249 assert(mutex != NULL);
250 #ifdef USE_W32THREAD
251 if (cc_mutex_TryEnterCriticalSection)
252 ok = win32_cs_unlock(mutex);
253 else
254 ok = win32_mutex_unlock(mutex);
255 #else /* USE_W32THREAD */
256 ok = internal_mutex_unlock(mutex);
257 #endif /* USE_W32THREAD */
258
259 assert(ok == CC_OK);
260 }
261
262 static cc_mutex * cc_global_mutex = NULL;
263
264 static void
cc_mutex_cleanup(void)265 cc_mutex_cleanup(void)
266 {
267 cc_mutex_destruct(cc_global_mutex);
268 cc_global_mutex = NULL;
269 }
270
271 void
cc_mutex_init(void)272 cc_mutex_init(void)
273 {
274 const char * env = coin_getenv("COIN_DEBUG_MUTEXLOCK_MAXTIME");
275
276 #ifdef USE_W32THREAD /* TryEnterCriticalSection test. */
277
278 HINSTANCE h = GetModuleHandle("kernel32.dll");
279 /* If we can't get a handle to kernel32.dll, something is seriously
280 wrong, and we should investigate. <mortene> */
281 assert(h && "GetModuleHandle('kernel32.dll') failed!");
282
283 /* This function is unsupported in Win95/98/Me and NT <=3.51, but we
284 still want to use it if it's available, since it can provide
285 major speed-ups for certain aspects of Win32 mutex handling. */
286 cc_mutex_TryEnterCriticalSection = (cc_mutex_TryEnterCriticalSection_func)
287 GetProcAddress(h, "TryEnterCriticalSection");
288
289 #endif /* USE_W32THREAD */
290
291 if (cc_global_mutex == NULL) {
292 cc_global_mutex = cc_mutex_construct();
293 /* atexit priority makes this callback trigger after other cleanup
294 functions. */
295 /* FIXME: not sure if this really needs the "- 1", but I added it
296 to keep the same order wrt the other thread-related clean-up
297 functions, since before I changed hard-coded numbers for
298 enumerated values for coin_atexit() invocations. 20060301 mortene. */
299 coin_atexit((coin_atexit_f*) cc_mutex_cleanup, CC_ATEXIT_THREADING_SUBSYSTEM_LOWPRIORITY);
300 }
301
302 if (env) { maxmutexlocktime = atof(env); }
303
304 env = coin_getenv("COIN_DEBUG_MUTEXLOCK_TIMING");
305 if (env) { reportmutexlocktiming = atof(env); }
306 }
307
308 void
cc_mutex_global_lock(void)309 cc_mutex_global_lock(void)
310 {
311 /* Do this test in case a mutex is needed before cc_mutex_init() is
312 called (called from SoDB::init()). This is safe, since the
313 application should not be multithreaded before SoDB::init() is
314 called */
315 if (cc_global_mutex == NULL) cc_mutex_init();
316
317 (void) cc_mutex_lock(cc_global_mutex);
318 }
319
320 void
cc_mutex_global_unlock(void)321 cc_mutex_global_unlock(void)
322 {
323 (void) cc_mutex_unlock(cc_global_mutex);
324 }
325