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 /*!
34   \class SoCacheElement Inventor/elements/SoCacheElement.h
35   \brief The SoCacheElement class stores and manages the open caches.
36 
37   \ingroup elements
38 */
39 
40 // *************************************************************************
41 
42 #include <Inventor/elements/SoCacheElement.h>
43 
44 #include <cassert>
45 #include <cstdlib>
46 
47 #include <Inventor/caches/SoCache.h>
48 #include <Inventor/errors/SoDebugError.h>
49 #include <Inventor/misc/SoState.h>
50 
51 #ifdef HAVE_CONFIG_H
52 #include "config.h"
53 #endif // HAVE_CONFIG_H
54 
55 #ifdef COIN_THREADSAFE
56 #include <Inventor/threads/SbTypedStorage.h>
57 #endif // COIN_THREADSAFE
58 
59 #include "tidbitsp.h"
60 #include "SbBasicP.h"
61 #include "coindefs.h"
62 
63 // *************************************************************************
64 
65 SbBool SoCacheElement::invalidated = FALSE;
66 
67 // *************************************************************************
68 
69 #ifdef COIN_THREADSAFE
70 
71 static SbTypedStorage <SbBool*> * invalidated_storage = NULL;
72 
73 static void
cacheelement_cleanup(void)74 cacheelement_cleanup(void)
75 {
76   delete invalidated_storage;
77 }
78 
79 #endif // COIN_THREADSAFE
80 
81 // *************************************************************************
82 
83 SO_ELEMENT_SOURCE(SoCacheElement);
84 
85 // *************************************************************************
86 
87 // Doc in superclass.
88 void
initClass(void)89 SoCacheElement::initClass(void)
90 {
91   SO_ELEMENT_INIT_CLASS(SoCacheElement, inherited);
92   SoCacheElement::invalidated = FALSE;
93 
94 #ifdef COIN_THREADSAFE
95   invalidated_storage = new SbTypedStorage <SbBool*> (sizeof(SbBool));
96   *(invalidated_storage->get()) = FALSE;
97   coin_atexit((coin_atexit_f*) cacheelement_cleanup, CC_ATEXIT_NORMAL);
98 #endif // COIN_THREADSAFE
99 }
100 
101 /*!
102   The destructor.
103 */
104 
~SoCacheElement(void)105 SoCacheElement::~SoCacheElement(void)
106 {
107 }
108 
109 // Doc in superclass.
110 void
init(SoState * state)111 SoCacheElement::init(SoState * state)
112 {
113   inherited::init(state);
114   this->cache = NULL;
115 }
116 
117 // *************************************************************************
118 
119 // Documented in superclass. Overridden to initialize element.
120 void
push(SoState * state)121 SoCacheElement::push(SoState * state)
122 {
123   inherited::push(state);
124   this->cache = NULL;
125 }
126 
127 // Documented in superclass. Overridden to unref the cache, since the
128 // cache is ref'ed in set().
129 void
pop(SoState * state,const SoElement * prevTopElement)130 SoCacheElement::pop(SoState * state, const SoElement * prevTopElement)
131 {
132   SoCacheElement * prev =
133     const_cast<SoCacheElement *>
134     ( coin_assert_cast<const SoCacheElement *>(
135                                           prevTopElement
136                                          )
137      );
138   if (prev->cache) {
139     prev->cache->unref();
140     prev->cache = NULL;
141   }
142   inherited::pop(state, prevTopElement);
143   if (!this->anyOpen(state)) state->setCacheOpen(FALSE);
144 }
145 
146 
147 /*!
148   Sets the current cache. The cache is ref'ed before returning.
149 */
150 void
set(SoState * const state,SoCache * const cache)151 SoCacheElement::set(SoState * const state, SoCache * const cache)
152 {
153   SoCacheElement * elem = coin_assert_cast<SoCacheElement *>
154     (
155      SoElement::getElement(state, classStackIndex)
156      );
157 
158   if (elem) {
159     if (elem->cache) elem->cache->unref();
160     elem->cache = cache;
161     if (elem->cache) {
162       elem->cache->ref();
163       state->setCacheOpen(TRUE);
164     }
165   }
166 }
167 
168 /*!
169   This method returns the cache, or NULL if there is no cache.
170 */
171 
172 SoCache *
getCache(void) const173 SoCacheElement::getCache(void) const
174 {
175   return this->cache;
176 }
177 
178 /*!
179   This method returns TRUE if a cache is currently open.
180 */
181 
182 SbBool
anyOpen(SoState * const state)183 SoCacheElement::anyOpen(SoState * const state)
184 {
185   const SoCacheElement * elem = coin_assert_cast<const SoCacheElement *>
186      (
187       state->getElementNoPush(classStackIndex)
188       );
189   while (elem) {
190     if (elem->cache) return TRUE;
191     elem = coin_safe_cast<const SoCacheElement*>(elem->getNextInStack());
192   }
193   return FALSE;
194 }
195 
196 /*!
197   This method invalidates open caches. It should be called by
198   uncacheable nodes.
199 */
200 void
invalidate(SoState * const state)201 SoCacheElement::invalidate(SoState * const state)
202 {
203 #if COIN_DEBUG && 0 // debug
204   SoDebugError::postInfo("SoCacheElement::invalidate",
205                          "Invalidate all caches");
206 #endif // debug
207 
208 #ifdef COIN_THREADSAFE
209   *(invalidated_storage->get()) = TRUE;
210 #else // COIN_THREADSAFE
211   SoCacheElement::invalidated = TRUE;
212 #endif // ! COIN_THREADSAFE
213 
214   const SoCacheElement * elem =
215     coin_assert_cast<const SoCacheElement *>
216     (
217      state->getElementNoPush(classStackIndex)
218      );
219 
220   while (elem && elem->cache) {
221     elem->cache->invalidate();
222     elem = coin_safe_cast<const SoCacheElement *>(elem->getNextInStack());
223   }
224 }
225 
226 /*!
227   SoCacheElement objects should not be compared because you obviously don't
228   cache them in the cache.
229 */
230 SbBool
matches(const SoElement * COIN_UNUSED_ARG (element)) const231 SoCacheElement::matches(const SoElement * COIN_UNUSED_ARG(element)) const
232 {
233   assert(FALSE && "this method should not be called for this element");
234   return FALSE;
235 }
236 
237 /*!
238   SoCacheElement objects should not be "copied" because you obviously don't
239   cache them in the cache.
240 
241   \sa SbBool SoCacheElement::matches(const SoElement * element) const
242 */
243 SoElement *
copyMatchInfo(void) const244 SoCacheElement::copyMatchInfo(void) const
245 {
246   assert(FALSE && "this method should not be called for this element");
247   return NULL;
248 }
249 
250 /*!
251   This method returns the next cache element. That is the next cache
252   element pointing towards the bottom of the state.
253 */
254 SoCacheElement *
getNextCacheElement(void) const255 SoCacheElement::getNextCacheElement(void) const
256 {
257   return coin_safe_cast<SoCacheElement *>
258     (
259      this->getNextInStack()
260      );
261 }
262 
263 /*!
264   This method adds \a element to the elements used lists of all the open
265   caches in \a state.
266 */
267 
268 void
addElement(SoState * const state,const SoElement * const element)269 SoCacheElement::addElement(SoState * const state,
270                            const SoElement * const element)
271 {
272   SoCacheElement * elem =
273     coin_assert_cast<SoCacheElement *>
274     (
275      state->getElementNoPush(classStackIndex)
276      );
277 
278   while (elem) {
279     if (elem->cache) elem->cache->addElement(element);
280     elem = coin_safe_cast<SoCacheElement *>(elem->getNextInStack());
281   }
282 }
283 
284 /*!
285   This method creates dependencies on \a cache for all the open caches
286   in \a state.
287 */
288 
289 void
addCacheDependency(SoState * const state,SoCache * const cache)290 SoCacheElement::addCacheDependency(SoState * const state,
291                                    SoCache * const cache)
292 {
293   SoCacheElement * elem = coin_assert_cast<SoCacheElement *>
294     (
295      state->getElementNoPush(classStackIndex)
296      );
297   while (elem && elem->cache) {
298     elem->cache->addCacheDependency(state, cache);
299     elem = coin_assert_cast<SoCacheElement *>(elem->getNextInStack());
300   }
301 }
302 
303 /*!
304   This method returns the old invalidated bit value, and sets it to
305   \a newvalue.
306 */
307 
308 SbBool
setInvalid(const SbBool newvalue)309 SoCacheElement::setInvalid(const SbBool newvalue)
310 {
311 #ifdef COIN_THREADSAFE
312   SbBool * ptr = invalidated_storage->get();
313   SbBool oldval = *ptr;
314   *ptr = newvalue;
315 #else // COIN_THREADSAFE
316   SbBool oldval = SoCacheElement::invalidated;
317   SoCacheElement::invalidated = newvalue;
318 #endif // ! COIN_THREADSAFE
319   return oldval;
320 }
321 
322 /*!
323   This method returns the current cache.  No cache dependencies are honored.
324 */
325 
326 SoCache *
getCurrentCache(SoState * const state)327 SoCacheElement::getCurrentCache(SoState * const state)
328 {
329   return (coin_assert_cast<const SoCacheElement *>(state->getElementNoPush(classStackIndex)))->cache;
330 }
331