VirtualBox

source: vbox/trunk/src/VBox/Main/AutoLock.cpp@ 8505

Last change on this file since 8505 was 8424, checked in by vboxsync, 17 years ago

Main/AutoLock: Fixed regression after r30268.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Date Revision Author Id
File size: 7.2 KB
Line 
1/** @file
2 *
3 * AutoWriteLock/AutoReadLock: smart R/W semaphore wrappers
4 */
5
6/*
7 * Copyright (C) 2006-2008 Sun Microsystems, Inc.
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
18 * Clara, CA 95054 USA or visit http://www.sun.com if you need
19 * additional information or have any questions.
20 */
21
22#include "AutoLock.h"
23
24#include "Logging.h"
25
26namespace util
27{
28
29RWLockHandle::RWLockHandle()
30{
31#ifdef VBOX_MAIN_USE_SEMRW
32
33 int vrc = RTSemRWCreate (&mSemRW);
34 AssertRC (vrc);
35
36#else /* VBOX_MAIN_USE_SEMRW */
37
38 int vrc = RTCritSectInit (&mCritSect);
39 AssertRC (vrc);
40 vrc = RTSemEventCreate (&mGoWriteSem);
41 AssertRC (vrc);
42 vrc = RTSemEventMultiCreate (&mGoReadSem);
43 AssertRC (vrc);
44
45 mWriteLockThread = NIL_RTNATIVETHREAD;
46
47 mReadLockCount = 0;
48 mSelfReadLockCount = 0;
49
50 mWriteLockLevel = 0;
51 mWriteLockPending = 0;
52
53#endif /* VBOX_MAIN_USE_SEMRW */
54}
55
56RWLockHandle::~RWLockHandle()
57{
58#ifdef VBOX_MAIN_USE_SEMRW
59
60 RTSemRWDestroy (mSemRW);
61
62#else /* VBOX_MAIN_USE_SEMRW */
63
64 RTSemEventMultiDestroy (mGoReadSem);
65 RTSemEventDestroy (mGoWriteSem);
66 RTCritSectDelete (&mCritSect);
67
68#endif /* VBOX_MAIN_USE_SEMRW */
69}
70
71bool RWLockHandle::isWriteLockOnCurrentThread() const
72{
73#ifdef VBOX_MAIN_USE_SEMRW
74
75 return RTSemRWIsWriteOwner (mSemRW);
76
77#else /* VBOX_MAIN_USE_SEMRW */
78
79 RTCritSectEnter (&mCritSect);
80 bool locked = mWriteLockThread == RTThreadNativeSelf();
81 RTCritSectLeave (&mCritSect);
82 return locked;
83
84#endif /* VBOX_MAIN_USE_SEMRW */
85}
86
87void RWLockHandle::lockWrite()
88{
89#ifdef VBOX_MAIN_USE_SEMRW
90
91 int vrc = RTSemRWRequestWrite (mSemRW, RT_INDEFINITE_WAIT);
92 AssertRC (vrc);
93
94#else /* VBOX_MAIN_USE_SEMRW */
95
96 RTCritSectEnter (&mCritSect);
97
98 RTNATIVETHREAD threadSelf = RTThreadNativeSelf();
99
100 if (mWriteLockThread != threadSelf)
101 {
102 if (mReadLockCount != 0 || mWriteLockThread != NIL_RTNATIVETHREAD ||
103 mWriteLockPending != 0 /* respect other pending writers */)
104 {
105 /* wait until all read locks or another write lock is released */
106 ++ mWriteLockPending;
107 Assert (mWriteLockPending != 0 /* pending writer overflow? */);
108 RTCritSectLeave (&mCritSect);
109 RTSemEventWait (mGoWriteSem, RT_INDEFINITE_WAIT);
110 RTCritSectEnter (&mCritSect);
111 -- mWriteLockPending;
112 }
113
114 Assert (mWriteLockLevel == 0);
115 Assert (mWriteLockThread == NIL_RTNATIVETHREAD);
116 Assert (mSelfReadLockCount == 0 /* missing unlockRead()? */);
117
118 mWriteLockThread = threadSelf;
119 }
120
121 ++ mWriteLockLevel;
122 Assert (mWriteLockLevel != 0 /* overflow */);
123
124 RTCritSectLeave (&mCritSect);
125
126#endif /* VBOX_MAIN_USE_SEMRW */
127}
128
129void RWLockHandle::unlockWrite()
130{
131#ifdef VBOX_MAIN_USE_SEMRW
132
133 int vrc = RTSemRWReleaseWrite (mSemRW);
134 AssertRC (vrc);
135
136#else /* VBOX_MAIN_USE_SEMRW */
137
138 RTCritSectEnter (&mCritSect);
139
140 Assert (mWriteLockLevel != 0 /* unlockWrite() w/o preceding lockWrite()? */);
141 if (mWriteLockLevel != 0)
142 {
143 -- mWriteLockLevel;
144 if (mWriteLockLevel == 0)
145 {
146 Assert (mSelfReadLockCount == 0
147 /* mixed unlockWrite()/unlockRead() order? */);
148
149 mWriteLockThread = NIL_RTNATIVETHREAD;
150
151 /* no write locks, let writers go if there are any (top priority),
152 * otherwise let readers go if there are any */
153 if (mWriteLockPending != 0)
154 RTSemEventSignal (mGoWriteSem);
155 else if (mReadLockCount != 0)
156 RTSemEventMultiSignal (mGoReadSem);
157 }
158 }
159
160 RTCritSectLeave (&mCritSect);
161
162#endif /* VBOX_MAIN_USE_SEMRW */
163}
164
165void RWLockHandle::lockRead()
166{
167#ifdef VBOX_MAIN_USE_SEMRW
168
169 int vrc = RTSemRWRequestRead (mSemRW, RT_INDEFINITE_WAIT);
170 AssertRC (vrc);
171
172#else /* VBOX_MAIN_USE_SEMRW */
173
174 RTCritSectEnter (&mCritSect);
175
176 RTNATIVETHREAD threadSelf = RTThreadNativeSelf();
177
178 bool isWriteLock = mWriteLockLevel != 0;
179 bool isFirstReadLock = mReadLockCount == 0;
180
181 if (isWriteLock && mWriteLockThread == threadSelf)
182 {
183 /* read lock nested into the write lock */
184 ++ mSelfReadLockCount;
185 Assert (mSelfReadLockCount != 0 /* self read lock overflow? */);
186
187 /* cause to return immediately */
188 isWriteLock = false;
189 }
190 else
191 {
192 ++ mReadLockCount;
193 Assert (mReadLockCount != 0 /* read lock overflow? */);
194
195 if (!isWriteLock)
196 {
197 Assert (mSelfReadLockCount == 0 /* missing unlockRead()? */);
198
199 /* write locks are top priority, so let them go if they are
200 * pending */
201 if (mWriteLockPending != 0)
202 {
203 isWriteLock = true;
204 /* the first postponed reader kicks pending writers */
205 if (isFirstReadLock)
206 RTSemEventSignal (mGoWriteSem);
207 }
208 }
209
210 /* the first waiting reader resets the semaphore before letting it be
211 * posted (i.e. before leaving the critical section) */
212 if (isWriteLock && isFirstReadLock)
213 RTSemEventMultiReset (mGoReadSem);
214 }
215
216 RTCritSectLeave (&mCritSect);
217
218 /* wait until the write lock is released */
219 if (isWriteLock)
220 RTSemEventMultiWait (mGoReadSem, RT_INDEFINITE_WAIT);
221
222#endif /* VBOX_MAIN_USE_SEMRW */
223}
224
225void RWLockHandle::unlockRead()
226{
227#ifdef VBOX_MAIN_USE_SEMRW
228
229 int vrc = RTSemRWReleaseRead (mSemRW);
230 AssertRC (vrc);
231
232#else /* VBOX_MAIN_USE_SEMRW */
233
234 RTCritSectEnter (&mCritSect);
235
236 RTNATIVETHREAD threadSelf = RTThreadNativeSelf();
237
238 if (mWriteLockLevel != 0)
239 {
240 /* read unlock nested into the write lock */
241 Assert (mWriteLockThread == threadSelf
242 /* unlockRead() after lockWrite()? */);
243 if (mWriteLockThread == threadSelf)
244 {
245 Assert (mSelfReadLockCount != 0
246 /* unlockRead() w/o preceding lockRead()? */);
247 if (mSelfReadLockCount != 0)
248 {
249 -- mSelfReadLockCount;
250 }
251 }
252 }
253 else
254 {
255 Assert (mReadLockCount != 0
256 /* unlockRead() w/o preceding lockRead()? */);
257 if (mReadLockCount != 0)
258 {
259 -- mReadLockCount;
260 if (mReadLockCount == 0)
261 {
262 /* no read locks, let writers go if there are any */
263 if (mWriteLockPending != 0)
264 RTSemEventSignal (mGoWriteSem);
265 }
266 }
267 }
268
269 RTCritSectLeave (&mCritSect);
270
271#endif /* VBOX_MAIN_USE_SEMRW */
272}
273
274uint32_t RWLockHandle::writeLockLevel() const
275{
276#ifdef VBOX_MAIN_USE_SEMRW
277
278 return RTSemRWGetWriteRecursion (mSemRW);
279
280#else /* VBOX_MAIN_USE_SEMRW */
281
282 Assert (mWriteLockLevel != 0);
283
284 return mWriteLockLevel;
285
286#endif /* VBOX_MAIN_USE_SEMRW */
287}
288
289} /* namespace util */
290
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette