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