cannam@3
|
1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
|
cannam@3
|
2
|
cannam@3
|
3 /*
|
cannam@3
|
4 Basic cross-platform mutex abstraction class.
|
cannam@3
|
5 This file copyright 2007 Chris Cannam.
|
cannam@3
|
6 */
|
cannam@3
|
7
|
cannam@3
|
8 #include "Mutex.h"
|
cannam@3
|
9 #include <iostream>
|
cannam@3
|
10
|
cannam@3
|
11 #ifndef _WIN32
|
cannam@3
|
12 #include <sys/time.h>
|
cannam@3
|
13 #include <time.h>
|
cannam@3
|
14 #endif
|
cannam@3
|
15
|
cannam@3
|
16 using std::cerr;
|
cannam@3
|
17 using std::endl;
|
cannam@3
|
18 using std::string;
|
cannam@3
|
19
|
cannam@3
|
20 #ifdef _WIN32
|
cannam@3
|
21
|
cannam@3
|
22 Mutex::Mutex()
|
cannam@3
|
23 #ifndef NO_THREAD_CHECKS
|
cannam@3
|
24 :
|
cannam@3
|
25 m_lockedBy(-1)
|
cannam@3
|
26 #endif
|
cannam@3
|
27 {
|
cannam@3
|
28 m_mutex = CreateMutex(NULL, FALSE, NULL);
|
cannam@3
|
29 #ifdef DEBUG_MUTEX
|
cannam@3
|
30 cerr << "MUTEX DEBUG: " << (void *)GetCurrentThreadId() << ": Initialised mutex " << &m_mutex << endl;
|
cannam@3
|
31 #endif
|
cannam@3
|
32 }
|
cannam@3
|
33
|
cannam@3
|
34 Mutex::~Mutex()
|
cannam@3
|
35 {
|
cannam@3
|
36 #ifdef DEBUG_MUTEX
|
cannam@3
|
37 cerr << "MUTEX DEBUG: " << (void *)GetCurrentThreadId() << ": Destroying mutex " << &m_mutex << endl;
|
cannam@3
|
38 #endif
|
cannam@3
|
39 CloseHandle(m_mutex);
|
cannam@3
|
40 }
|
cannam@3
|
41
|
cannam@3
|
42 void
|
cannam@3
|
43 Mutex::lock()
|
cannam@3
|
44 {
|
cannam@3
|
45 #ifndef NO_THREAD_CHECKS
|
cannam@3
|
46 DWORD tid = GetCurrentThreadId();
|
cannam@3
|
47 if (m_lockedBy == tid) {
|
cannam@3
|
48 cerr << "ERROR: Deadlock on mutex " << &m_mutex << endl;
|
cannam@3
|
49 }
|
cannam@3
|
50 #endif
|
cannam@3
|
51 #ifdef DEBUG_MUTEX
|
cannam@3
|
52 cerr << "MUTEX DEBUG: " << (void *)tid << ": Want to lock mutex " << &m_mutex << endl;
|
cannam@3
|
53 #endif
|
cannam@3
|
54 WaitForSingleObject(m_mutex, INFINITE);
|
cannam@3
|
55 #ifndef NO_THREAD_CHECKS
|
cannam@3
|
56 m_lockedBy = tid;
|
cannam@3
|
57 #endif
|
cannam@3
|
58 #ifdef DEBUG_MUTEX
|
cannam@3
|
59 cerr << "MUTEX DEBUG: " << (void *)tid << ": Locked mutex " << &m_mutex << endl;
|
cannam@3
|
60 #endif
|
cannam@3
|
61 }
|
cannam@3
|
62
|
cannam@3
|
63 void
|
cannam@3
|
64 Mutex::unlock()
|
cannam@3
|
65 {
|
cannam@3
|
66 #ifndef NO_THREAD_CHECKS
|
cannam@3
|
67 DWORD tid = GetCurrentThreadId();
|
cannam@3
|
68 if (m_lockedBy != tid) {
|
cannam@3
|
69 cerr << "ERROR: Mutex " << &m_mutex << " not owned by unlocking thread" << endl;
|
cannam@3
|
70 return;
|
cannam@3
|
71 }
|
cannam@3
|
72 #endif
|
cannam@3
|
73 #ifdef DEBUG_MUTEX
|
cannam@3
|
74 cerr << "MUTEX DEBUG: " << (void *)tid << ": Unlocking mutex " << &m_mutex << endl;
|
cannam@3
|
75 #endif
|
cannam@3
|
76 #ifndef NO_THREAD_CHECKS
|
cannam@3
|
77 m_lockedBy = -1;
|
cannam@3
|
78 #endif
|
cannam@3
|
79 ReleaseMutex(m_mutex);
|
cannam@3
|
80 }
|
cannam@3
|
81
|
cannam@3
|
82 bool
|
cannam@3
|
83 Mutex::trylock()
|
cannam@3
|
84 {
|
cannam@3
|
85 #ifndef NO_THREAD_CHECKS
|
cannam@3
|
86 DWORD tid = GetCurrentThreadId();
|
cannam@3
|
87 #endif
|
cannam@3
|
88 DWORD result = WaitForSingleObject(m_mutex, 0);
|
cannam@3
|
89 if (result == WAIT_TIMEOUT || result == WAIT_FAILED) {
|
cannam@3
|
90 #ifdef DEBUG_MUTEX
|
cannam@3
|
91 cerr << "MUTEX DEBUG: " << (void *)tid << ": Mutex " << &m_mutex << " unavailable" << endl;
|
cannam@3
|
92 #endif
|
cannam@3
|
93 return false;
|
cannam@3
|
94 } else {
|
cannam@3
|
95 #ifndef NO_THREAD_CHECKS
|
cannam@3
|
96 m_lockedBy = tid;
|
cannam@3
|
97 #endif
|
cannam@3
|
98 #ifdef DEBUG_MUTEX
|
cannam@3
|
99 cerr << "MUTEX DEBUG: " << (void *)tid << ": Locked mutex " << &m_mutex << " (from trylock)" << endl;
|
cannam@3
|
100 #endif
|
cannam@3
|
101 return true;
|
cannam@3
|
102 }
|
cannam@3
|
103 }
|
cannam@3
|
104
|
cannam@3
|
105 #else /* !_WIN32 */
|
cannam@3
|
106
|
cannam@3
|
107 Mutex::Mutex()
|
cannam@3
|
108 #ifndef NO_THREAD_CHECKS
|
cannam@3
|
109 :
|
cannam@3
|
110 m_lockedBy(0),
|
cannam@3
|
111 m_locked(false)
|
cannam@3
|
112 #endif
|
cannam@3
|
113 {
|
cannam@3
|
114 pthread_mutex_init(&m_mutex, 0);
|
cannam@3
|
115 #ifdef DEBUG_MUTEX
|
cannam@3
|
116 cerr << "MUTEX DEBUG: " << (void *)pthread_self() << ": Initialised mutex " << &m_mutex << endl;
|
cannam@3
|
117 #endif
|
cannam@3
|
118 }
|
cannam@3
|
119
|
cannam@3
|
120 Mutex::~Mutex()
|
cannam@3
|
121 {
|
cannam@3
|
122 #ifdef DEBUG_MUTEX
|
cannam@3
|
123 cerr << "MUTEX DEBUG: " << (void *)pthread_self() << ": Destroying mutex " << &m_mutex << endl;
|
cannam@3
|
124 #endif
|
cannam@3
|
125 pthread_mutex_destroy(&m_mutex);
|
cannam@3
|
126 }
|
cannam@3
|
127
|
cannam@3
|
128 void
|
cannam@3
|
129 Mutex::lock()
|
cannam@3
|
130 {
|
cannam@3
|
131 #ifndef NO_THREAD_CHECKS
|
cannam@3
|
132 pthread_t tid = pthread_self();
|
cannam@3
|
133 if (m_locked && m_lockedBy == tid) {
|
cannam@3
|
134 cerr << "ERROR: Deadlock on mutex " << &m_mutex << endl;
|
cannam@3
|
135 }
|
cannam@3
|
136 #endif
|
cannam@3
|
137 #ifdef DEBUG_MUTEX
|
cannam@3
|
138 cerr << "MUTEX DEBUG: " << (void *)tid << ": Want to lock mutex " << &m_mutex << endl;
|
cannam@3
|
139 #endif
|
cannam@3
|
140 pthread_mutex_lock(&m_mutex);
|
cannam@3
|
141 #ifndef NO_THREAD_CHECKS
|
cannam@3
|
142 m_lockedBy = tid;
|
cannam@3
|
143 m_locked = true;
|
cannam@3
|
144 #endif
|
cannam@3
|
145 #ifdef DEBUG_MUTEX
|
cannam@3
|
146 cerr << "MUTEX DEBUG: " << (void *)tid << ": Locked mutex " << &m_mutex << endl;
|
cannam@3
|
147 #endif
|
cannam@3
|
148 }
|
cannam@3
|
149
|
cannam@3
|
150 void
|
cannam@3
|
151 Mutex::unlock()
|
cannam@3
|
152 {
|
cannam@3
|
153 #ifndef NO_THREAD_CHECKS
|
cannam@3
|
154 pthread_t tid = pthread_self();
|
cannam@3
|
155 if (!m_locked) {
|
cannam@3
|
156 cerr << "ERROR: Mutex " << &m_mutex << " not locked in unlock" << endl;
|
cannam@3
|
157 return;
|
cannam@3
|
158 } else if (m_lockedBy != tid) {
|
cannam@3
|
159 cerr << "ERROR: Mutex " << &m_mutex << " not owned by unlocking thread" << endl;
|
cannam@3
|
160 return;
|
cannam@3
|
161 }
|
cannam@3
|
162 #endif
|
cannam@3
|
163 #ifdef DEBUG_MUTEX
|
cannam@3
|
164 cerr << "MUTEX DEBUG: " << (void *)tid << ": Unlocking mutex " << &m_mutex << endl;
|
cannam@3
|
165 #endif
|
cannam@3
|
166 #ifndef NO_THREAD_CHECKS
|
cannam@3
|
167 m_locked = false;
|
cannam@3
|
168 #endif
|
cannam@3
|
169 pthread_mutex_unlock(&m_mutex);
|
cannam@3
|
170 }
|
cannam@3
|
171
|
cannam@3
|
172 bool
|
cannam@3
|
173 Mutex::trylock()
|
cannam@3
|
174 {
|
cannam@3
|
175 #ifndef NO_THREAD_CHECKS
|
cannam@3
|
176 pthread_t tid = pthread_self();
|
cannam@3
|
177 #endif
|
cannam@3
|
178 if (pthread_mutex_trylock(&m_mutex)) {
|
cannam@3
|
179 #ifdef DEBUG_MUTEX
|
cannam@3
|
180 cerr << "MUTEX DEBUG: " << (void *)tid << ": Mutex " << &m_mutex << " unavailable" << endl;
|
cannam@3
|
181 #endif
|
cannam@3
|
182 return false;
|
cannam@3
|
183 } else {
|
cannam@3
|
184 #ifndef NO_THREAD_CHECKS
|
cannam@3
|
185 m_lockedBy = tid;
|
cannam@3
|
186 m_locked = true;
|
cannam@3
|
187 #endif
|
cannam@3
|
188 #ifdef DEBUG_MUTEX
|
cannam@3
|
189 cerr << "MUTEX DEBUG: " << (void *)tid << ": Locked mutex " << &m_mutex << " (from trylock)" << endl;
|
cannam@3
|
190 #endif
|
cannam@3
|
191 return true;
|
cannam@3
|
192 }
|
cannam@3
|
193 }
|
cannam@3
|
194
|
cannam@3
|
195 #endif
|
cannam@5
|
196
|
cannam@5
|
197 MutexLocker::MutexLocker(Mutex *mutex) :
|
cannam@5
|
198 m_mutex(mutex)
|
cannam@5
|
199 {
|
cannam@5
|
200 if (m_mutex) {
|
cannam@5
|
201 m_mutex->lock();
|
cannam@5
|
202 }
|
cannam@5
|
203 }
|
cannam@5
|
204
|
cannam@5
|
205 MutexLocker::~MutexLocker()
|
cannam@5
|
206 {
|
cannam@5
|
207 if (m_mutex) {
|
cannam@5
|
208 m_mutex->unlock();
|
cannam@5
|
209 }
|
cannam@5
|
210 }
|
cannam@5
|
211
|