Open Dynamics Engine
util.h
1 /*************************************************************************
2  * *
3  * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. *
4  * All rights reserved. Email: russ@q12.org Web: www.q12.org *
5  * *
6  * This library is free software; you can redistribute it and/or *
7  * modify it under the terms of EITHER: *
8  * (1) The GNU Lesser General Public License as published by the Free *
9  * Software Foundation; either version 2.1 of the License, or (at *
10  * your option) any later version. The text of the GNU Lesser *
11  * General Public License is included with this library in the *
12  * file LICENSE.TXT. *
13  * (2) The BSD-style license that is included with this library in *
14  * the file LICENSE-BSD.TXT. *
15  * *
16  * This library is distributed in the hope that it will be useful, *
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files *
19  * LICENSE.TXT and LICENSE-BSD.TXT for more details. *
20  * *
21  *************************************************************************/
22 
23 #ifndef _ODE_UTIL_H_
24 #define _ODE_UTIL_H_
25 
26 #include "objects.h"
27 
28 
29 /* the efficient alignment. most platforms align data structures to some
30  * number of bytes, but this is not always the most efficient alignment.
31  * for example, many x86 compilers align to 4 bytes, but on a pentium it
32  * is important to align doubles to 8 byte boundaries (for speed), and
33  * the 4 floats in a SIMD register to 16 byte boundaries. many other
34  * platforms have similar behavior. setting a larger alignment can waste
35  * a (very) small amount of memory. NOTE: this number must be a power of
36  * two. this is set to 16 by default.
37  */
38 #ifndef EFFICIENT_ALIGNMENT
39 #define EFFICIENT_ALIGNMENT 16
40 #endif
41 
42 
43 /* utility */
44 
45 
46 /* round something up to be a multiple of the EFFICIENT_ALIGNMENT */
47 
48 #define dEFFICIENT_SIZE(x) (((x)+(EFFICIENT_ALIGNMENT-1)) & ~((size_t)(EFFICIENT_ALIGNMENT-1)))
49 #define dEFFICIENT_PTR(p) ((void *)dEFFICIENT_SIZE((size_t)(p)))
50 #define dOFFSET_EFFICIENTLY(p, b) ((void *)((size_t)(p) + dEFFICIENT_SIZE(b)))
51 
52 /* alloca aligned to the EFFICIENT_ALIGNMENT. note that this can waste
53  * up to 15 bytes per allocation, depending on what alloca() returns.
54  */
55 #define dALLOCA16(n) \
56  dEFFICIENT_PTR(alloca((n)+(EFFICIENT_ALIGNMENT)))
57 
58 
59 #ifndef SIZE_MAX
60 #define SIZE_MAX ((size_t)(-1))
61 #endif
62 
63 void dInternalHandleAutoDisabling (dxWorld *world, dReal stepsize);
64 void dxStepBody (dxBody *b, dReal h);
65 
66 
68  public dBase
69 {
70  typedef void *(*alloc_block_fn_t)(size_t block_size);
71  typedef void *(*shrink_block_fn_t)(void *block_pointer, size_t block_current_size, size_t block_smaller_size);
72  typedef void (*free_block_fn_t)(void *block_pointer, size_t block_current_size);
73 
74  dxWorldProcessMemoryManager(alloc_block_fn_t fnAlloc, shrink_block_fn_t fnShrink, free_block_fn_t fnFree)
75  {
76  Assign(fnAlloc, fnShrink, fnFree);
77  }
78 
79  void Assign(alloc_block_fn_t fnAlloc, shrink_block_fn_t fnShrink, free_block_fn_t fnFree)
80  {
81  m_fnAlloc = fnAlloc;
82  m_fnShrink = fnShrink;
83  m_fnFree = fnFree;
84  }
85 
86  alloc_block_fn_t m_fnAlloc;
87  shrink_block_fn_t m_fnShrink;
88  free_block_fn_t m_fnFree;
89 };
90 
91 extern dxWorldProcessMemoryManager g_WorldProcessMallocMemoryManager;
92 
94  public dBase
95 {
96  dxWorldProcessMemoryReserveInfo(float fReserveFactor, unsigned uiReserveMinimum)
97  {
98  Assign(fReserveFactor, uiReserveMinimum);
99  }
100 
101  void Assign(float fReserveFactor, unsigned uiReserveMinimum)
102  {
103  m_fReserveFactor = fReserveFactor;
104  m_uiReserveMinimum = uiReserveMinimum;
105  }
106 
107  float m_fReserveFactor; // Use float as precision does not matter here
108  unsigned m_uiReserveMinimum;
109 };
110 
111 extern dxWorldProcessMemoryReserveInfo g_WorldProcessDefaultReserveInfo;
112 
113 
115  private dBase // new/delete must not be called for this class
116 {
117 public:
118 #define BUFFER_TO_ARENA_EXTRA (EFFICIENT_ALIGNMENT + dEFFICIENT_SIZE(sizeof(dxWorldProcessMemArena)))
119  static bool IsArenaPossible(size_t nBufferSize)
120  {
121  return SIZE_MAX - BUFFER_TO_ARENA_EXTRA >= nBufferSize; // This ensures there will be no overflow
122  }
123 
124  static size_t MakeBufferSize(size_t nArenaSize)
125  {
126  return nArenaSize - BUFFER_TO_ARENA_EXTRA;
127  }
128 
129  static size_t MakeArenaSize(size_t nBufferSize)
130  {
131  return BUFFER_TO_ARENA_EXTRA + nBufferSize;
132  }
133 #undef BUFFER_TO_ARENA_EXTRA
134 
135  bool IsStructureValid() const
136  {
137  return m_pAllocBegin != NULL && m_pAllocEnd != NULL && m_pAllocBegin <= m_pAllocEnd
138  && (m_pAllocCurrentOrNextArena == NULL || m_pAllocCurrentOrNextArena == m_pAllocBegin)
139  && m_pArenaBegin != NULL && m_pArenaBegin <= m_pAllocBegin;
140  }
141 
142  size_t GetMemorySize() const
143  {
144  return (size_t)m_pAllocEnd - (size_t)m_pAllocBegin;
145  }
146 
147  void *SaveState() const
148  {
149  return m_pAllocCurrentOrNextArena;
150  }
151 
152  void RestoreState(void *state)
153  {
154  m_pAllocCurrentOrNextArena = state;
155  }
156 
157  void ResetState()
158  {
159  m_pAllocCurrentOrNextArena = m_pAllocBegin;
160  }
161 
162  void *PeekBufferRemainder() const
163  {
164  return m_pAllocCurrentOrNextArena;
165  }
166 
167  void *AllocateBlock(size_t size)
168  {
169  void *block = m_pAllocCurrentOrNextArena;
170  m_pAllocCurrentOrNextArena = dOFFSET_EFFICIENTLY(block, size);
171  dIASSERT(m_pAllocCurrentOrNextArena <= m_pAllocEnd);
172  return block;
173  }
174 
175  template<typename ElementType>
176  ElementType *AllocateArray(size_t count)
177  {
178  return (ElementType *)AllocateBlock(count * sizeof(ElementType));
179  }
180 
181  template<typename ElementType>
182  void ShrinkArray(ElementType *arr, size_t oldcount, size_t newcount)
183  {
184  dIASSERT(newcount <= oldcount);
185  dIASSERT(dOFFSET_EFFICIENTLY(arr, oldcount * sizeof(ElementType)) == m_pAllocCurrentOrNextArena);
186  m_pAllocCurrentOrNextArena = dOFFSET_EFFICIENTLY(arr, newcount * sizeof(ElementType));
187  }
188 
189 public:
190  static dxWorldProcessMemArena *ReallocateMemArena (
191  dxWorldProcessMemArena *oldarena, size_t memreq,
192  const dxWorldProcessMemoryManager *memmgr, float rsrvfactor, unsigned rsrvminimum);
193  static void FreeMemArena (dxWorldProcessMemArena *arena);
194 
195  dxWorldProcessMemArena *GetNextMemArena() const { return (dxWorldProcessMemArena *)m_pAllocCurrentOrNextArena; }
196  void SetNextMemArena(dxWorldProcessMemArena *pArenaInstance) { m_pAllocCurrentOrNextArena = pArenaInstance; }
197 
198 private:
199  static size_t AdjustArenaSizeForReserveRequirements(size_t arenareq, float rsrvfactor, unsigned rsrvminimum);
200 
201 private:
202  void *m_pAllocCurrentOrNextArena;
203  void *m_pAllocBegin;
204  void *m_pAllocEnd;
205  void *m_pArenaBegin;
206 
207  const dxWorldProcessMemoryManager *m_pArenaMemMgr;
208 };
209 
211  public dBase
212 {
213 public:
216 
217  void CleanupWorldReferences(dxWorld *pswWorldInstance);
218 
219 public:
220  bool EnsureStepperSyncObjectsAreAllocated(dxWorld *pswWorldInstance);
221  dCallWaitID GetIslandsSteppingWait() const { return m_pcwIslandsSteppingWait; }
222 
223 public:
224  dxWorldProcessMemArena *ObtainStepperMemArena();
225  void ReturnStepperMemArena(dxWorldProcessMemArena *pmaArenaInstance);
226 
227  dxWorldProcessMemArena *ReallocateIslandsMemArena(size_t nMemoryRequirement,
228  const dxWorldProcessMemoryManager *pmmMemortManager, float fReserveFactor, unsigned uiReserveMinimum);
229  bool ReallocateStepperMemArenas(dxWorld *world, unsigned nIslandThreadsCount, size_t nMemoryRequirement,
230  const dxWorldProcessMemoryManager *pmmMemortManager, float fReserveFactor, unsigned uiReserveMinimum);
231 
232 private:
233  static void FreeArenasList(dxWorldProcessMemArena *pmaExistingArenas);
234 
235 private:
236  void SetIslandsMemArena(dxWorldProcessMemArena *pmaInstance) { m_pmaIslandsArena = pmaInstance; }
237  dxWorldProcessMemArena *GetIslandsMemArena() const { return m_pmaIslandsArena; }
238 
239  void SetStepperArenasList(dxWorldProcessMemArena *pmaInstance) { m_pmaStepperArenas = pmaInstance; }
240  dxWorldProcessMemArena *GetStepperArenasList() const { return m_pmaStepperArenas; }
241 
242  inline dxWorldProcessMemArena *GetStepperArenasHead() const;
243  inline bool TryExtractingStepperArenasHead(dxWorldProcessMemArena *pmaHeadInstance);
244  inline bool TryInsertingStepperArenasHead(dxWorldProcessMemArena *pmaArenaInstance, dxWorldProcessMemArena *pmaExistingHead);
245 
246 public:
247  void LockForAddLimotSerialization();
248  void UnlockForAddLimotSerialization();
249  void LockForStepbodySerialization();
250  void UnlockForStepbodySerialization();
251 
252 private:
253  enum dxProcessContextMutex
254  {
255  dxPCM_STEPPER_ARENA_OBTAIN,
256  dxPCM_STEPPER_ADDLIMOT_SERIALIZE,
257  dxPCM_STEPPER_STEPBODY_SERIALIZE,
258 
259  dxPCM__MAX
260  };
261 
262  static const char *const m_aszContextMutexNames[dxPCM__MAX];
263 
264 private:
265  dxWorldProcessMemArena *m_pmaIslandsArena;
266  dxWorldProcessMemArena *volatile m_pmaStepperArenas;
267  dxWorld *m_pswObjectsAllocWorld;
268  dMutexGroupID m_pmgStepperMutexGroup;
269  dCallWaitID m_pcwIslandsSteppingWait;
270 };
271 
273 {
274  void AssignInfo(size_t islandcount, unsigned int const *islandsizes, dxBody *const *bodies, dxJoint *const *joints)
275  {
276  m_IslandCount = islandcount;
277  m_pIslandSizes = islandsizes;
278  m_pBodies = bodies;
279  m_pJoints = joints;
280  }
281 
282  size_t GetIslandsCount() const { return m_IslandCount; }
283  unsigned int const *GetIslandSizes() const { return m_pIslandSizes; }
284  dxBody *const *GetBodiesArray() const { return m_pBodies; }
285  dxJoint *const *GetJointsArray() const { return m_pJoints; }
286 
287 private:
288  size_t m_IslandCount;
289  unsigned int const *m_pIslandSizes;
290  dxBody *const *m_pBodies;
291  dxJoint *const *m_pJoints;
292 };
293 
295 {
296  dxStepperProcessingCallContext(dxWorld *world, dReal stepSize, unsigned stepperAllowedThreads,
297  dxWorldProcessMemArena *stepperArena, dxBody *const *islandBodiesStart, dxJoint *const *islandJointsStart):
298  m_world(world), m_stepSize(stepSize), m_stepperArena(stepperArena), m_finalReleasee(NULL),
299  m_islandBodiesStart(islandBodiesStart), m_islandJointsStart(islandJointsStart), m_islandBodiesCount(0), m_islandJointsCount(0),
300  m_stepperAllowedThreads(stepperAllowedThreads)
301  {
302  }
303 
304  void AssignIslandSelection(dxBody *const *islandBodiesStart, dxJoint *const *islandJointsStart,
305  unsigned islandBodiesCount, unsigned islandJointsCount)
306  {
307  m_islandBodiesStart = islandBodiesStart;
308  m_islandJointsStart = islandJointsStart;
309  m_islandBodiesCount = islandBodiesCount;
310  m_islandJointsCount = islandJointsCount;
311  }
312 
313  dxBody *const *GetSelectedIslandBodiesEnd() const { return m_islandBodiesStart + m_islandBodiesCount; }
314  dxJoint *const *GetSelectedIslandJointsEnd() const { return m_islandJointsStart + m_islandJointsCount; }
315 
316  void AssignStepperCallFinalReleasee(dCallReleaseeID finalReleasee)
317  {
318  m_finalReleasee = finalReleasee;
319  }
320 
321  dxWorld *const m_world;
322  dReal const m_stepSize;
323  dxWorldProcessMemArena *m_stepperArena;
324  dCallReleaseeID m_finalReleasee;
325  dxBody *const *m_islandBodiesStart;
326  dxJoint *const *m_islandJointsStart;
327  unsigned m_islandBodiesCount;
328  unsigned m_islandJointsCount;
329  unsigned m_stepperAllowedThreads;
330 };
331 
332 #define BEGIN_STATE_SAVE(memarena, state) void *state = memarena->SaveState();
333 #define END_STATE_SAVE(memarena, state) memarena->RestoreState(state)
334 
335 typedef void (*dstepper_fn_t) (const dxStepperProcessingCallContext *callContext);
336 typedef unsigned (*dmaxcallcountestimate_fn_t) (unsigned activeThreadCount, unsigned allowedThreadCount);
337 
338 bool dxProcessIslands (dxWorld *world, const dxWorldProcessIslandsInfo &islandsInfo,
339  dReal stepSize, dstepper_fn_t stepper, dmaxcallcountestimate_fn_t maxCallCountEstimator);
340 
341 
342 typedef size_t (*dmemestimate_fn_t) (dxBody * const *body, unsigned int nb,
343  dxJoint * const *_joint, unsigned int _nj);
344 
345 bool dxReallocateWorldProcessContext (dxWorld *world, dxWorldProcessIslandsInfo &islandsinfo,
346  dReal stepsize, dmemestimate_fn_t stepperestimate);
347 
348 dxWorldProcessMemArena *dxAllocateTemporaryWorldProcessMemArena(
349  size_t memreq, const dxWorldProcessMemoryManager *memmgr/*=NULL*/, const dxWorldProcessMemoryReserveInfo *reserveinfo/*=NULL*/);
350 void dxFreeTemporaryWorldProcessMemArena(dxWorldProcessMemArena *arena);
351 
352 
353 template<class ClassType>
354 inline ClassType *AllocateOnDemand(ClassType *&pctStorage)
355 {
356  ClassType *pctCurrentInstance = pctStorage;
357 
358  if (!pctCurrentInstance)
359  {
360  pctCurrentInstance = new ClassType();
361  pctStorage = pctCurrentInstance;
362  }
363 
364  return pctCurrentInstance;
365 }
366 
367 
368 // World stepping working memory object
370  public dBase
371 {
372 public:
373  dxStepWorkingMemory(): m_uiRefCount(1), m_ppcProcessingContext(NULL), m_priReserveInfo(NULL), m_pmmMemoryManager(NULL) {}
374 
375 private:
376  friend struct dBase; // To avoid GCC warning regarding private destructor
377  ~dxStepWorkingMemory() // Use Release() instead
378  {
379  delete m_ppcProcessingContext;
380  delete m_priReserveInfo;
381  delete m_pmmMemoryManager;
382  }
383 
384 public:
385  void Addref()
386  {
387  dIASSERT(~m_uiRefCount != 0);
388  ++m_uiRefCount;
389  }
390 
391  void Release()
392  {
393  dIASSERT(m_uiRefCount != 0);
394  if (--m_uiRefCount == 0)
395  {
396  delete this;
397  }
398  }
399 
400 public:
401  void CleanupMemory()
402  {
403  delete m_ppcProcessingContext;
404  m_ppcProcessingContext = NULL;
405  }
406 
407  void CleanupWorldReferences(dxWorld *world)
408  {
409  if (m_ppcProcessingContext != NULL)
410  {
411  m_ppcProcessingContext->CleanupWorldReferences(world);
412  }
413  }
414 
415 public:
416  dxWorldProcessContext *SureGetWorldProcessingContext() { return AllocateOnDemand(m_ppcProcessingContext); }
417  dxWorldProcessContext *GetWorldProcessingContext() const { return m_ppcProcessingContext; }
418 
419  const dxWorldProcessMemoryReserveInfo *GetMemoryReserveInfo() const { return m_priReserveInfo; }
420  const dxWorldProcessMemoryReserveInfo *SureGetMemoryReserveInfo() const { return m_priReserveInfo ? m_priReserveInfo : &g_WorldProcessDefaultReserveInfo; }
421  void SetMemoryReserveInfo(float fReserveFactor, unsigned uiReserveMinimum)
422  {
423  if (m_priReserveInfo) { m_priReserveInfo->Assign(fReserveFactor, uiReserveMinimum); }
424  else { m_priReserveInfo = new dxWorldProcessMemoryReserveInfo(fReserveFactor, uiReserveMinimum); }
425  }
426  void ResetMemoryReserveInfoToDefault()
427  {
428  if (m_priReserveInfo) { delete m_priReserveInfo; m_priReserveInfo = NULL; }
429  }
430 
431  const dxWorldProcessMemoryManager *GetMemoryManager() const { return m_pmmMemoryManager; }
432  const dxWorldProcessMemoryManager *SureGetMemoryManager() const { return m_pmmMemoryManager ? m_pmmMemoryManager : &g_WorldProcessMallocMemoryManager; }
433  void SetMemoryManager(dxWorldProcessMemoryManager::alloc_block_fn_t fnAlloc,
434  dxWorldProcessMemoryManager::shrink_block_fn_t fnShrink,
435  dxWorldProcessMemoryManager::free_block_fn_t fnFree)
436  {
437  if (m_pmmMemoryManager) { m_pmmMemoryManager->Assign(fnAlloc, fnShrink, fnFree); }
438  else { m_pmmMemoryManager = new dxWorldProcessMemoryManager(fnAlloc, fnShrink, fnFree); }
439  }
440  void ResetMemoryManagerToDefault()
441  {
442  if (m_pmmMemoryManager) { delete m_pmmMemoryManager; m_pmmMemoryManager = NULL; }
443  }
444 
445 private:
446  unsigned m_uiRefCount;
447  dxWorldProcessContext *m_ppcProcessingContext;
448  dxWorldProcessMemoryReserveInfo *m_priReserveInfo;
449  dxWorldProcessMemoryManager *m_pmmMemoryManager;
450 };
451 
452 
453 #endif
Definition: util.h:369
Definition: util.h:210
Definition: util.h:67
Definition: ode/src/objects.h:57
Definition: util.h:294
Definition: ode/src/objects.h:161
Definition: util.h:93
Definition: ode/src/objects.h:131
Definition: util.h:114
Definition: util.h:272