1 //
2 // Copyright (c) ZeroC, Inc. All rights reserved.
3 //
4 
5 #include <IceUtil/RecMutex.h>
6 #include <IceUtil/Exception.h>
7 
8 using namespace std;
9 
RecMutex()10 IceUtil::RecMutex::RecMutex() :
11     _count(0)
12 {
13 #ifdef _WIN32
14     init(PrioNone);
15 #else
16     init(getDefaultMutexProtocol());
17 #endif
18 }
19 
RecMutex(const IceUtil::MutexProtocol protocol)20 IceUtil::RecMutex::RecMutex(const IceUtil::MutexProtocol protocol) :
21     _count(0)
22 {
23     init(protocol);
24 }
25 
26 #ifdef _WIN32
27 
28 void
init(const MutexProtocol)29 IceUtil::RecMutex::init(const MutexProtocol)
30 {
31 #   ifdef ICE_OS_UWP
32     InitializeCriticalSectionEx(&_mutex, 0, 0);
33 #   else
34     InitializeCriticalSection(&_mutex);
35 #   endif
36 }
37 
~RecMutex()38 IceUtil::RecMutex::~RecMutex()
39 {
40     assert(_count == 0);
41     DeleteCriticalSection(&_mutex);
42 }
43 
44 void
lock() const45 IceUtil::RecMutex::lock() const
46 {
47     EnterCriticalSection(&_mutex);
48     if(++_count > 1)
49     {
50         LeaveCriticalSection(&_mutex);
51     }
52 }
53 
54 bool
tryLock() const55 IceUtil::RecMutex::tryLock() const
56 {
57     if(!TryEnterCriticalSection(&_mutex))
58     {
59         return false;
60     }
61     if(++_count > 1)
62     {
63         LeaveCriticalSection(&_mutex);
64     }
65     return true;
66 }
67 
68 void
unlock() const69 IceUtil::RecMutex::unlock() const
70 {
71     if(--_count == 0)
72     {
73         LeaveCriticalSection(&_mutex);
74     }
75 }
76 
77 #   ifdef ICE_HAS_WIN32_CONDVAR
78 void
unlock(LockState & state) const79 IceUtil::RecMutex::unlock(LockState& state) const
80 {
81     state.mutex = &_mutex;
82     state.count = _count;
83     _count = 0;
84 }
85 
86 void
lock(LockState & state) const87 IceUtil::RecMutex::lock(LockState& state) const
88 {
89     _count = state.count;
90 }
91 #   else
92 void
unlock(LockState & state) const93 IceUtil::RecMutex::unlock(LockState& state) const
94 {
95     state.count = _count;
96     _count = 0;
97     LeaveCriticalSection(&_mutex);
98 }
99 
100 void
lock(LockState & state) const101 IceUtil::RecMutex::lock(LockState& state) const
102 {
103     EnterCriticalSection(&_mutex);
104     _count = state.count;
105 }
106 #   endif
107 
108 #else
109 
110 void
init(ICE_MAYBE_UNUSED const MutexProtocol protocol)111 IceUtil::RecMutex::init(ICE_MAYBE_UNUSED const MutexProtocol protocol)
112 {
113     int rc;
114     pthread_mutexattr_t attr;
115     rc = pthread_mutexattr_init(&attr);
116     assert(rc == 0);
117     if(rc != 0)
118     {
119         pthread_mutexattr_destroy(&attr);
120         throw ThreadSyscallException(__FILE__, __LINE__, rc);
121     }
122 
123     rc = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
124     assert(rc == 0);
125     if(rc != 0)
126     {
127         pthread_mutexattr_destroy(&attr);
128         throw ThreadSyscallException(__FILE__, __LINE__, rc);
129     }
130 
131 #if defined(_POSIX_THREAD_PRIO_INHERIT) && _POSIX_THREAD_PRIO_INHERIT > 0
132     if(PrioInherit == protocol)
133     {
134         rc = pthread_mutexattr_setprotocol(&attr, PTHREAD_PRIO_INHERIT);
135         assert(rc == 0);
136         if(rc != 0)
137         {
138             throw ThreadSyscallException(__FILE__, __LINE__, rc);
139         }
140     }
141 #endif
142 
143     rc = pthread_mutex_init(&_mutex, &attr);
144     assert(rc == 0);
145     if(rc != 0)
146     {
147         pthread_mutexattr_destroy(&attr);
148         throw ThreadSyscallException(__FILE__, __LINE__, rc);
149     }
150 
151     rc = pthread_mutexattr_destroy(&attr);
152     assert(rc == 0);
153     if(rc != 0)
154     {
155         throw ThreadSyscallException(__FILE__, __LINE__, rc);
156     }
157 }
158 
~RecMutex()159 IceUtil::RecMutex::~RecMutex()
160 {
161     assert(_count == 0);
162 #ifndef NDEBUG
163     int rc = pthread_mutex_destroy(&_mutex);
164     assert(rc == 0);
165 #else
166     pthread_mutex_destroy(&_mutex);
167 #endif
168 }
169 
170 void
lock() const171 IceUtil::RecMutex::lock() const
172 {
173     int rc = pthread_mutex_lock(&_mutex);
174     if(rc != 0)
175     {
176         throw ThreadSyscallException(__FILE__, __LINE__, rc);
177     }
178     if(++_count > 1)
179     {
180         rc = pthread_mutex_unlock(&_mutex);
181         assert(rc == 0);
182     }
183 }
184 
185 bool
tryLock() const186 IceUtil::RecMutex::tryLock() const
187 {
188     int rc = pthread_mutex_trylock(&_mutex);
189     bool result = (rc == 0);
190     if(!result)
191     {
192         if(rc != EBUSY)
193         {
194             throw ThreadSyscallException(__FILE__, __LINE__, rc);
195         }
196     }
197     else if(++_count > 1)
198     {
199         rc = pthread_mutex_unlock(&_mutex);
200         if(rc != 0)
201         {
202             throw ThreadSyscallException(__FILE__, __LINE__, rc);
203         }
204     }
205     return result;
206 }
207 
208 void
unlock() const209 IceUtil::RecMutex::unlock() const
210 {
211     if(--_count == 0)
212     {
213 #ifndef NDEBUG
214         int rc = pthread_mutex_unlock(&_mutex);
215         assert(rc == 0);
216 #else
217         pthread_mutex_unlock(&_mutex);
218 #endif
219     }
220 }
221 
222 void
unlock(LockState & state) const223 IceUtil::RecMutex::unlock(LockState& state) const
224 {
225     state.mutex = &_mutex;
226     state.count = _count;
227     _count = 0;
228 }
229 
230 void
lock(LockState & state) const231 IceUtil::RecMutex::lock(LockState& state) const
232 {
233     _count = state.count;
234 }
235 
236 #endif
237 
238 bool
willUnlock() const239 IceUtil::RecMutex::willUnlock() const
240 {
241     return _count == 1;
242 }
243