ExternalMutex.h
1 #pragma once
2 #ifndef EXTERNAL_MUTEX_H
3 #define EXTERNAL_MUTEX_H
4 
5 #include <stdlib.h>
6 
7 // some helpful macros
8 #define DECLARE_NOCOPY(ClassName) private: ClassName(const ClassName &); ClassName &operator=(const ClassName &)
9 #define CHECKSTATIC(expr,msg) typedef char ERROR_##msg[(expr) ? 1 : -1]
10 
11 // some constant definitions
12 #define DEFAULT_SPIN_COUNT 4000
13 
14 namespace ExternalMutex
15 {
16 
17  class Mutex
18  {
19  DECLARE_NOCOPY(Mutex);
20 
21  public:
22  Mutex(int spinCount = DEFAULT_SPIN_COUNT); // 0 = don't ever spin (some platforms may not implement spin feature)
23  Mutex(const char* name);
24  ~Mutex();
25 
26  void Lock() const;
27  void Unlock() const;
28  bool TryLock() const; // same as Lock(), except returns false instead of blocking if not available
29 
30  protected:
31  // work-space for implementation pre-allocated to avoid allocations
32  // temporary work-space needed by windows to hold its CRITICAL_SECTION object
33  // normally we would just allocate this on the heap, but we needed to be able to use
34  // the critical section object inside of a custom memory manager, which meant that we
35  // had to have the critical section before doing any dynamic allocations (chicken and
36  // egg thing). This will also have better performance since it avoids an allocation.
37 
38  // note: we make the workspace an array of 6 unsigned 64s's instead of 48 char's, because that will
39  // ensure that the start of our m_workSpaceBuffer is at least 8-byte aligned. It turns out
40  // the PS3 required this for the data it was attempting to stick in there
41  mutable unsigned long long m_workSpaceBuffer[15];
42  };
43 
44 // this helper-class is used to enter/leave a mutex based on stack scoping
45 // use this instead of the manual locks and unlocks for higher maintainability
46  class MutexGuard
47  {
48  DECLARE_NOCOPY(MutexGuard);
49 
50  public:
51  MutexGuard(const Mutex *mutex); // Lock the mutex on construction
52  ~MutexGuard(); // Unlock the mutex on destruction
53  void UnlockEarly(); // Unlock the mutex earlier than destruction (leave will then not occur during destructor)
54 
55  private:
56  const Mutex *m_mutex;
57  };
58 
59  inline MutexGuard::MutexGuard(const Mutex *mutex)
60  {
61  // assert that mutex != null?
62  if (mutex != NULL)
63  {
64  m_mutex = mutex;
65  m_mutex->Lock();
66  }
67  }
68 
69  inline MutexGuard::~MutexGuard()
70  {
71  if (m_mutex != NULL)
72  {
73  m_mutex->Unlock();
74  m_mutex = NULL;
75  }
76  }
77 
78  inline void MutexGuard::UnlockEarly()
79  {
80  if (m_mutex != NULL)
81  {
82  m_mutex->Unlock();
83  m_mutex = NULL;
84  }
85  }
86 
87 } // end of ExternalMutex namespace
88 
89 #endif // EXTERNAL_MUTEX_H