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 /*! \file Inventor/C/threads/common.h */
34
35 /*!
36 \struct cc_recmutex common.h Inventor/C/threads/common.h
37 \ingroup threads
38 \brief The structure for the recursive mutex.
39 */
40
41 /*!
42 \typedef struct cc_recmutex cc_recmutex
43 \ingroup threads
44 \brief The type definition for the recursive mutex structure.
45 */
46
47 /*! \file recmutex.h */
48 #include <Inventor/C/threads/recmutex.h>
49
50 #include <cstdlib>
51 #include <cassert>
52
53 #include <Inventor/C/errors/debugerror.h>
54 #include <Inventor/C/threads/mutex.h>
55 #include <Inventor/C/threads/thread.h>
56 #include <Inventor/C/threads/condvar.h>
57
58 #include "tidbitsp.h"
59 #include "threads/recmutexp.h"
60
61 /* ********************************************************************** */
62
63 /* debugging. for instance useful for checking that there's not
64 excessive mutex construction. */
65
66 /* these are declared in mutex.cpp */
67 extern unsigned int cc_debug_mtxcount;
68 extern const char * COIN_DEBUG_MUTEX_COUNT;
69
70 /* ********************************************************************** */
71
72 /*!
73 \internal
74 */
75 void
cc_recmutex_struct_init(cc_recmutex * recmutex)76 cc_recmutex_struct_init(cc_recmutex * recmutex)
77 {
78 cc_mutex_struct_init(&recmutex->mutex);
79 cc_condvar_struct_init(&recmutex->condvar);
80
81 recmutex->threadid = 0;
82 recmutex->level = 0;
83 recmutex->waiters = 0;
84 }
85
86 /*!
87 \internal
88 */
89 void
cc_recmutex_struct_clean(cc_recmutex * recmutex)90 cc_recmutex_struct_clean(cc_recmutex * recmutex)
91 {
92 cc_mutex_struct_clean(&recmutex->mutex);
93 cc_condvar_struct_clean(&recmutex->condvar);
94 }
95
96 /*! Constructs a recursive mutex. */
97
98 cc_recmutex *
cc_recmutex_construct(void)99 cc_recmutex_construct(void)
100 {
101 cc_recmutex * recmutex;
102 recmutex = (cc_recmutex *) malloc(sizeof(cc_recmutex));
103 assert(recmutex != NULL);
104 cc_recmutex_struct_init(recmutex);
105
106 { /* debugging */
107 const char * env = coin_getenv(COIN_DEBUG_MUTEX_COUNT);
108 if (env && (atoi(env) > 0)) {
109 cc_debug_mtxcount += 1;
110 (void)fprintf(stderr, "DEBUG: live mutexes +1 => %u (recmutex++)\n",
111 cc_debug_mtxcount);
112 }
113 }
114
115 return recmutex;
116 }
117
118
119 /*! Destroys the recursive mutex \a recmutex. */
120
121 void
cc_recmutex_destruct(cc_recmutex * recmutex)122 cc_recmutex_destruct(cc_recmutex * recmutex)
123 {
124 { /* debugging */
125 const char * env = coin_getenv(COIN_DEBUG_MUTEX_COUNT);
126 if (env && (atoi(env) > 0)) {
127 assert((cc_debug_mtxcount > 0) && "skewed mutex construct/destruct pairing");
128 cc_debug_mtxcount -= 1;
129 (void)fprintf(stderr, "DEBUG: live mutexes -1 => %u (recmutex--)\n",
130 cc_debug_mtxcount);
131 }
132 }
133
134 assert(recmutex != NULL);
135 cc_recmutex_struct_clean(recmutex);
136 free(recmutex);
137 }
138
139 /*
140 Internal function used by cc_recmutex_lock() and cc_recmutex_try_lock().
141 */
recmutex_lock_internal(cc_recmutex * recmutex,int wait)142 static int recmutex_lock_internal(cc_recmutex * recmutex, int wait)
143 {
144 int level = -1; /* return -1 for recmutex_try_lock() if we couldn't get the mutex */
145 unsigned long id = cc_thread_id();
146
147 assert(recmutex != NULL);
148 cc_mutex_lock(&recmutex->mutex);
149 if (recmutex->level == 0) {
150 recmutex->level++;
151 recmutex->threadid = id;
152 level = recmutex->level;
153 }
154 else if (id == recmutex->threadid) {
155 recmutex->level++;
156 level = recmutex->level;
157 }
158 else if (wait) {
159 recmutex->waiters++;
160 /* wait in loop, since some thread might snatch the mutex before
161 us when we receive a signal */
162 do {
163 cc_condvar_wait(&recmutex->condvar, &recmutex->mutex);
164 } while (recmutex->level > 0);
165
166 assert(recmutex->level == 0);
167 recmutex->waiters--;
168 recmutex->threadid = id;
169 recmutex->level++;
170 level = recmutex->level;
171 }
172 cc_mutex_unlock(&recmutex->mutex);
173 return level;
174 }
175
176 /*! Locks the recursive mutex \a recmutex. Returns the nesting level. */
177
178 int
cc_recmutex_lock(cc_recmutex * recmutex)179 cc_recmutex_lock(cc_recmutex * recmutex)
180 {
181 return recmutex_lock_internal(recmutex, TRUE);
182 }
183
184 /*! Attempts to lock the recursive mutex \a recmutex. Returns TRUE if
185 thread got the lock or already had the lock. */
186 int
cc_recmutex_try_lock(cc_recmutex * recmutex)187 cc_recmutex_try_lock(cc_recmutex * recmutex)
188 {
189 return recmutex_lock_internal(recmutex, FALSE) >= 0;
190 }
191
192 /*! Unlocks the recursive mutex \a recmutex. Returns the nesting level
193 after unlocking. */
194
195 int
cc_recmutex_unlock(cc_recmutex * recmutex)196 cc_recmutex_unlock(cc_recmutex * recmutex)
197 {
198 int level;
199 assert(recmutex != NULL);
200 assert(recmutex->threadid == cc_thread_id());
201 assert(recmutex->level > 0);
202 cc_mutex_lock(&recmutex->mutex);
203 recmutex->level--;
204 if (recmutex->level == 0 && recmutex->waiters) {
205 cc_condvar_wake_one(&recmutex->condvar);
206 }
207 level = recmutex->level;
208 cc_mutex_unlock(&recmutex->mutex);
209 return level;
210 }
211
212 /*
213 internal functions
214 */
215
216 static cc_recmutex * recmutex_field_lock;
217 static cc_recmutex * recmutex_notify_lock;
218
219 static void
recmutex_cleanup(void)220 recmutex_cleanup(void)
221 {
222 cc_recmutex_destruct(recmutex_field_lock);
223 cc_recmutex_destruct(recmutex_notify_lock);
224 }
225
226 void
cc_recmutex_init(void)227 cc_recmutex_init(void)
228 {
229 recmutex_field_lock = cc_recmutex_construct();
230 recmutex_notify_lock = cc_recmutex_construct();
231 /* atexit priority makes this callback trigger after normal cleanup
232 functions which might still use a recmutex instance */
233 coin_atexit((coin_atexit_f*) recmutex_cleanup, CC_ATEXIT_THREADING_SUBSYSTEM);
234 }
235
236 int
cc_recmutex_internal_field_lock(void)237 cc_recmutex_internal_field_lock(void)
238 {
239 return cc_recmutex_lock(recmutex_field_lock);
240 }
241
242 int
cc_recmutex_internal_field_unlock(void)243 cc_recmutex_internal_field_unlock(void)
244 {
245 return cc_recmutex_unlock(recmutex_field_lock);
246 }
247
248 int
cc_recmutex_internal_notify_lock(void)249 cc_recmutex_internal_notify_lock(void)
250 {
251 return cc_recmutex_lock(recmutex_notify_lock);
252 }
253
254 int
cc_recmutex_internal_notify_unlock(void)255 cc_recmutex_internal_notify_unlock(void)
256 {
257 return cc_recmutex_unlock(recmutex_notify_lock);
258 }
259