1 mike 1.2 //%2006////////////////////////////////////////////////////////////////////////
2 //
3 // Copyright (c) 2000, 2001, 2002 BMC Software; Hewlett-Packard Development
4 // Company, L.P.; IBM Corp.; The Open Group; Tivoli Systems.
5 // Copyright (c) 2003 BMC Software; Hewlett-Packard Development Company, L.P.;
6 // IBM Corp.; EMC Corporation, The Open Group.
7 // Copyright (c) 2004 BMC Software; Hewlett-Packard Development Company, L.P.;
8 // IBM Corp.; EMC Corporation; VERITAS Software Corporation; The Open Group.
9 // Copyright (c) 2005 Hewlett-Packard Development Company, L.P.; IBM Corp.;
10 // EMC Corporation; VERITAS Software Corporation; The Open Group.
11 // Copyright (c) 2006 Hewlett-Packard Development Company, L.P.; IBM Corp.;
12 // EMC Corporation; Symantec Corporation; The Open Group.
13 //
14 // Permission is hereby granted, free of charge, to any person obtaining a copy
15 // of this software and associated documentation files (the "Software"), to
16 // deal in the Software without restriction, including without limitation the
17 // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
18 // sell copies of the Software, and to permit persons to whom the Software is
19 // furnished to do so, subject to the following conditions:
20 //
21 // THE ABOVE COPYRIGHT NOTICE AND THIS PERMISSION NOTICE SHALL BE INCLUDED IN
22 mike 1.2 // ALL COPIES OR SUBSTANTIAL PORTIONS OF THE SOFTWARE. THE SOFTWARE IS PROVIDED
23 // "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
24 // LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
25 // PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
26 // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
27 // ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29 //
30 //==============================================================================
31 //
32 //%/////////////////////////////////////////////////////////////////////////////
33
34 #include "ReadWriteSem.h"
35 #include "Time.h"
36 #include "PegasusAssert.h"
37 #include "Threads.h"
38
39 PEGASUS_NAMESPACE_BEGIN
40
41 //==============================================================================
42 //
43 mike 1.2 // PEGASUS_USE_POSIX_RWLOCK
44 //
45 //==============================================================================
46
47 #ifdef PEGASUS_USE_POSIX_RWLOCK
48
49 ReadWriteSem::ReadWriteSem():_readers(0), _writers(0)
50 {
51 pthread_rwlock_init(&_rwlock.rwlock, NULL);
52 Threads::clear(_rwlock.owner);
53 }
54
55 ReadWriteSem::~ReadWriteSem()
56 {
|
57 kumpf 1.5 int r = 0;
|
58 mike 1.6 while ((r = pthread_rwlock_destroy(&_rwlock.rwlock)) == EBUSY ||
|
59 kumpf 1.5 (r == -1 && errno == EBUSY))
|
60 mike 1.2 {
61 Threads::yield();
62 }
63 }
64
65 void ReadWriteSem::wait(Uint32 mode, ThreadType caller)
66 {
67 int errorcode;
68 if (mode == PEG_SEM_READ)
69 {
70 if (0 == (errorcode = pthread_rwlock_rdlock(&_rwlock.rwlock)))
71 {
72 _readers++;
73 return;
74 }
75 }
76 else if (mode == PEG_SEM_WRITE)
77 {
78 if (0 == (errorcode = pthread_rwlock_wrlock(&_rwlock.rwlock)))
79 {
80 _rwlock.owner = caller;
81 mike 1.2 _writers++;
82 return;
83 }
84 }
85 else
86 throw(Permission(Threads::self()));
87
88 if (errorcode == EDEADLK)
89 throw(Deadlock(_rwlock.owner));
90 else
91 throw(WaitFailed(Threads::self()));
92 }
93
94 void ReadWriteSem::unlock(Uint32 mode, ThreadType caller)
95 {
96 ThreadType owner;
97
98 if (mode == PEG_SEM_WRITE)
99 {
100 owner = _rwlock.owner;
101 Threads::clear(_rwlock.owner);
102 mike 1.2 }
103 if (0 != pthread_rwlock_unlock(&_rwlock.rwlock))
104 {
105 _rwlock.owner = owner;
106 throw(Permission(Threads::self()));
107 }
108 if (mode == PEG_SEM_READ && _readers.get() != 0)
109 _readers--;
110 else if (_writers.get() != 0)
111 _writers--;
112 }
113
114 int ReadWriteSem::read_count() const
115 {
|
116 kumpf 1.5 return _readers.get();
|
117 mike 1.2 }
118
119 int ReadWriteSem::write_count() const
120 {
|
121 kumpf 1.5 return _writers.get();
|
122 mike 1.2 }
123
124 #endif /* PEGASUS_USE_POSIX_RWLOCK */
125
126 //==============================================================================
127 //
128 // PEGASUS_USE_SEMAPHORE_RWLOCK
129 //
130 //==============================================================================
131
132 #if defined(PEGASUS_USE_SEMAPHORE_RWLOCK)
133
134 // // If i get cancelled, I MUST ensure:
135 // 1) I do not hold the internal mutex
136 // 2) I do not hold the write lock
137 // 3) I am not using a reader slot
138
139 ReadWriteSem::ReadWriteSem():_readers(0), _writers(0), _rwlock()
140 {
141 }
142
143 mike 1.2 ReadWriteSem::~ReadWriteSem()
144 {
145 // lock everyone out of this object
146 try
147 {
148 _rwlock._internal_lock.lock();
149 }
|
150 kumpf 1.5 catch (Deadlock &)
|
151 mike 1.2 {
152 // no problem - we own the lock, which is what we want
153 }
|
154 kumpf 1.5 catch (IPCException &)
|
155 mike 1.2 {
156 PEGASUS_ASSERT(0);
157 }
158 while (_readers.get() > 0 || _writers.get() > 0)
159 {
160 Threads::yield();
161 }
162 _rwlock._internal_lock.unlock();
163 }
164
|
165 marek 1.7 //---------------------------------------------------------------------
166 void ReadWriteSem::wait(Uint32 mode, ThreadType caller)
|
167 mike 1.2 {
168 //-----------------------------------------------------------------
169 // Lock this object to maintain integrity while we decide
170 // exactly what to do next.
171 //-----------------------------------------------------------------
172 // AutoPtr<IPCException> caught;
173 // IPCException caught((ThreadType)0);
174 // WaitFailed caughtWaitFailed((ThreadType)0);
175 // TimeOut caughtTimeOut((ThreadType)0);
176 // TooManyReaders caughtTooManyReaders((ThreadType)0);
177
178 ThreadType zero;
179 IPCException caught(zero);
180 WaitFailed caughtWaitFailed(zero);
181 TimeOut caughtTimeOut(zero);
182 TooManyReaders caughtTooManyReaders(zero);
183
184 // cleanup stack frame
185 {
186 // Threads::cleanup_push(extricate_read_write, this);
187
188 mike 1.2 try
189 {
190 _rwlock._internal_lock.lock();
191 }
|
192 kumpf 1.5 catch (const IPCException & e)
|
193 mike 1.2 {
194 caught = e;
195 goto throw_from_here;
196 }
197
198 if (mode == PEG_SEM_WRITE)
199 {
200 //-----------------------------------------------------------------
201 // Write Lock Step 1: lock the object and allow all the readers to exit
202 //-----------------------------------------------------------------
|
203 marek 1.7 while (_readers.get() > 0)
204 Threads::yield();
|
205 mike 1.2 //-----------------------------------------------------------------
206 // Write Lock Step 2: Obtain the Write Mutex
207 // Although there are no readers, there may be a writer
208 //-----------------------------------------------------------------
|
209 marek 1.7 try
|
210 mike 1.2 {
|
211 marek 1.7 _rwlock._wlock.lock();
|
212 mike 1.2 }
|
213 marek 1.7 catch (const IPCException & e)
|
214 mike 1.2 {
|
215 marek 1.7 _rwlock._internal_lock.unlock();
216 caught = e;
217 goto throw_from_here;
|
218 mike 1.2 }
219 //-----------------------------------------------------------------
220 // Write Lock Step 3: set the writer count to one, unlock the object
221 // There are no readers and we are the only writer !
222 //-----------------------------------------------------------------
223 _writers = 1;
224 // set the owner
225 _rwlock._owner = Threads::self();
226 // unlock the object
227 _rwlock._internal_lock.unlock();
228 } // PEG_SEM_WRITE
229 else
230 {
231 //-----------------------------------------------------------------
232 // Read Lock Step 1: Wait for the existing writer (if any) to clear
233 //-----------------------------------------------------------------
|
234 marek 1.7 while (_writers.get() > 0)
235 Threads::yield();
|
236 mike 1.2 //-----------------------------------------------------------------
237 // Read Lock Step 2: wait for a reader slot to open up, then return
238 // At this point there are no writers, but there may be too many
239 // readers.
240 //-----------------------------------------------------------------
|
241 marek 1.7 try
|
242 mike 1.2 {
|
243 marek 1.7 _rwlock._rlock.wait();
|
244 mike 1.2 }
|
245 marek 1.7 catch (const IPCException & e)
|
246 mike 1.2 {
|
247 marek 1.7 _rwlock._internal_lock.unlock();
248 caught = e;
249 goto throw_from_here;
|
250 mike 1.2 }
251 //-----------------------------------------------------------------
252 // Read Lock Step 3: increment the number of readers, unlock the object,
253 // return
254 //-----------------------------------------------------------------
255 _readers++;
256 _rwlock._internal_lock.unlock();
257 }
258 throw_from_here:
|
259 kumpf 1.5 // ATTN:
|
260 mike 1.2 Threads::cleanup_pop(0);
261 }
|
262 mike 1.4 if (!Threads::null(caught.get_owner()))
|
263 mike 1.2 throw caught;
|
264 mike 1.4 if (!Threads::null(caughtWaitFailed.get_owner()))
|
265 mike 1.2 throw caughtWaitFailed;
|
266 mike 1.4 if (!Threads::null(caughtTimeOut.get_owner()))
|
267 mike 1.2 throw caughtTimeOut;
|
268 mike 1.4 if (!Threads::null(caughtTooManyReaders.get_owner()))
269
|
270 mike 1.2 throw caughtTooManyReaders;
271 return;
272 }
273
274 void ReadWriteSem::unlock(Uint32 mode, ThreadType caller)
275 {
276 if (mode == PEG_SEM_WRITE && _writers.get() != 0)
277 {
278 _writers = 0;
279 _rwlock._wlock.unlock();
280 }
281 else if (_readers.get() != 0)
282 {
283 _readers--;
284 _rwlock._rlock.signal();
285 }
286 }
287
288 int ReadWriteSem::read_count() const
289 {
|
290 kumpf 1.5 return _readers.get();
|
291 mike 1.2 }
292
293 int ReadWriteSem::write_count() const
294 {
|
295 kumpf 1.5 return _writers.get();
|
296 mike 1.2 }
297
298 #endif /* !PEGASUS_USE_SEMAPHORE_RWLOCK */
299
300 PEGASUS_NAMESPACE_END
|