VirtualBox

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

Last change on this file since 8251 was 8155, checked in by vboxsync, 17 years ago

The Big Sun Rebranding Header Change

  • Property svn:eol-style set to native
  • Property svn:keywords set to Date Revision Author Id
File size: 6.5 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_RTTHREAD;
46
47 mReadLockCount = 0;
48 mWriteLockLevel = 0;
49 mWriteLockPending = 0;
50
51#endif /* VBOX_MAIN_USE_SEMRW */
52}
53
54RWLockHandle::~RWLockHandle()
55{
56#ifdef VBOX_MAIN_USE_SEMRW
57
58 RTSemRWDestroy (mSemRW);
59
60#else /* VBOX_MAIN_USE_SEMRW */
61
62 RTSemEventMultiDestroy (mGoReadSem);
63 RTSemEventDestroy (mGoWriteSem);
64 RTCritSectDelete (&mCritSect);
65
66#endif /* VBOX_MAIN_USE_SEMRW */
67}
68
69bool RWLockHandle::isWriteLockOnCurrentThread() const
70{
71#ifdef VBOX_MAIN_USE_SEMRW
72
73 return RTSemRWIsWriteOwner (mSemRW);
74
75#else /* VBOX_MAIN_USE_SEMRW */
76
77 RTCritSectEnter (&mCritSect);
78 bool locked = mWriteLockThread == RTThreadSelf();
79 RTCritSectLeave (&mCritSect);
80 return locked;
81
82#endif /* VBOX_MAIN_USE_SEMRW */
83}
84
85void RWLockHandle::lockWrite()
86{
87#ifdef VBOX_MAIN_USE_SEMRW
88
89 int vrc = RTSemRWRequestWrite (mSemRW, RT_INDEFINITE_WAIT);
90 AssertRC (vrc);
91
92#else /* VBOX_MAIN_USE_SEMRW */
93
94 RTCritSectEnter (&mCritSect);
95
96 if (mWriteLockThread != RTThreadSelf())
97 {
98 if (mReadLockCount != 0 || mWriteLockThread != NIL_RTTHREAD ||
99 mWriteLockPending != 0 /* respect other pending writers */)
100 {
101 /* wait until all read locks or another write lock is released */
102 ++ mWriteLockPending;
103 Assert (mWriteLockPending != 0 /* pending writer overflow? */);
104 RTCritSectLeave (&mCritSect);
105 RTSemEventWait (mGoWriteSem, RT_INDEFINITE_WAIT);
106 RTCritSectEnter (&mCritSect);
107 -- mWriteLockPending;
108 }
109
110 Assert (mWriteLockLevel == 0);
111 Assert (mWriteLockThread == NIL_RTTHREAD);
112
113 mWriteLockThread = RTThreadSelf();
114 }
115
116 ++ mWriteLockLevel;
117 Assert (mWriteLockLevel != 0 /* overflow */);
118
119 RTCritSectLeave (&mCritSect);
120
121#endif /* VBOX_MAIN_USE_SEMRW */
122}
123
124void RWLockHandle::unlockWrite()
125{
126#ifdef VBOX_MAIN_USE_SEMRW
127
128 int vrc = RTSemRWReleaseWrite (mSemRW);
129 AssertRC (vrc);
130
131#else /* VBOX_MAIN_USE_SEMRW */
132
133 RTCritSectEnter (&mCritSect);
134
135 Assert (mWriteLockLevel != 0 /* unlockWrite() w/o preceding lockWrite()? */);
136 if (mWriteLockLevel != 0)
137 {
138 -- mWriteLockLevel;
139 if (mWriteLockLevel == 0)
140 {
141 mWriteLockThread = NIL_RTTHREAD;
142
143 /* no write locks, let writers go if there are any (top priority),
144 * otherwise let readers go if there are any */
145 if (mWriteLockPending != 0)
146 RTSemEventSignal (mGoWriteSem);
147 else if (mReadLockCount != 0)
148 RTSemEventMultiSignal (mGoReadSem);
149 }
150 }
151
152 RTCritSectLeave (&mCritSect);
153
154#endif /* VBOX_MAIN_USE_SEMRW */
155}
156
157void RWLockHandle::lockRead()
158{
159#ifdef VBOX_MAIN_USE_SEMRW
160
161 int vrc = RTSemRWRequestRead (mSemRW, RT_INDEFINITE_WAIT);
162 AssertRC (vrc);
163
164#else /* VBOX_MAIN_USE_SEMRW */
165
166 RTCritSectEnter (&mCritSect);
167
168 ++ mReadLockCount;
169 Assert (mReadLockCount != 0 /* read lock overflow? */);
170
171 bool isWriteLock = mWriteLockLevel != 0;
172 bool isFirstReadLock = mReadLockCount == 1;
173
174 if (isWriteLock && mWriteLockThread == RTThreadSelf())
175 {
176 /* read lock nested into the write lock, cause return immediately */
177 isWriteLock = false;
178 }
179 else
180 {
181 if (!isWriteLock)
182 {
183 /* write locks are top priority, so let them go if they are
184 * pending */
185 if (mWriteLockPending != 0)
186 {
187 isWriteLock = true;
188 /* the first postponed reader kicks pending writers */
189 if (isFirstReadLock)
190 RTSemEventSignal (mGoWriteSem);
191 }
192 }
193
194 /* the first waiting reader resets the semaphore before letting it be
195 * posted (i.e. before leaving the critical section) */
196 if (isWriteLock && isFirstReadLock)
197 RTSemEventMultiReset (mGoReadSem);
198 }
199
200 RTCritSectLeave (&mCritSect);
201
202 /* wait until the write lock is released */
203 if (isWriteLock)
204 RTSemEventMultiWait (mGoReadSem, RT_INDEFINITE_WAIT);
205
206#endif /* VBOX_MAIN_USE_SEMRW */
207}
208
209void RWLockHandle::unlockRead()
210{
211#ifdef VBOX_MAIN_USE_SEMRW
212
213 int vrc = RTSemRWReleaseRead (mSemRW);
214 AssertRC (vrc);
215
216#else /* VBOX_MAIN_USE_SEMRW */
217
218 RTCritSectEnter (&mCritSect);
219
220 Assert (mReadLockCount != 0 /* unlockRead() w/o preceding lockRead()? */);
221 if (mReadLockCount != 0)
222 {
223 if (mWriteLockLevel != 0)
224 {
225 /* read unlock nested into the write lock, just decrease the
226 * counter */
227 Assert (mWriteLockThread == RTThreadSelf()
228 /* unlockRead() after lockWrite()? */);
229 if (mWriteLockThread == RTThreadSelf())
230 -- mReadLockCount;
231 }
232 else
233 {
234 -- mReadLockCount;
235 if (mReadLockCount == 0)
236 {
237 /* no read locks, let writers go if there are any */
238 if (mWriteLockPending != 0)
239 RTSemEventSignal (mGoWriteSem);
240 }
241 }
242 }
243
244 RTCritSectLeave (&mCritSect);
245
246#endif /* VBOX_MAIN_USE_SEMRW */
247}
248
249uint32_t RWLockHandle::writeLockLevel() const
250{
251#ifdef VBOX_MAIN_USE_SEMRW
252
253 return RTSemRWGetWriteRecursion (mSemRW);
254
255#else /* VBOX_MAIN_USE_SEMRW */
256
257 Assert (mWriteLockLevel != 0);
258
259 return mWriteLockLevel;
260
261#endif /* VBOX_MAIN_USE_SEMRW */
262}
263
264} /* namespace util */
265
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