1 martin 1.17 //%LICENSE////////////////////////////////////////////////////////////////
2 //
3 // Licensed to The Open Group (TOG) under one or more contributor license
4 // agreements. Refer to the OpenPegasusNOTICE.txt file distributed with
5 // this work for additional information regarding copyright ownership.
6 // Each contributor licenses this file to you under the OpenPegasus Open
7 // Source License; you may not use this file except in compliance with the
8 // License.
9 //
10 // Permission is hereby granted, free of charge, to any person obtaining a
11 // copy of this software and associated documentation files (the "Software"),
12 // to deal in the Software without restriction, including without limitation
13 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
14 // and/or sell copies of the Software, and to permit persons to whom the
15 // Software is furnished to do so, subject to the following conditions:
16 //
17 // The above copyright notice and this permission notice shall be included
18 // in all copies or substantial portions of the Software.
19 //
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
21 // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 martin 1.17 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
23 // IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
24 // CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
25 // TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
26 // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
27 mike 1.2 //
|
28 martin 1.17 //////////////////////////////////////////////////////////////////////////
|
29 mike 1.2 //
30 //%/////////////////////////////////////////////////////////////////////////////
31
32 #include <Pegasus/Common/Time.h>
|
33 kumpf 1.16 #include <Pegasus/Common/Exception.h>
34 #include <Pegasus/Common/System.h>
|
35 mike 1.2 #include "Semaphore.h"
36
|
37 kumpf 1.7 PEGASUS_NAMESPACE_BEGIN
|
38 mike 1.6
39 static const Uint32 PEGASUS_SEM_VALUE_MAX = 0x0000ffff;
|
40 mike 1.2
41 //==============================================================================
42 //
43 // PEGASUS_USE_PTHREAD_SEMAPHORE
44 //
45 //==============================================================================
46
47 #if defined(PEGASUS_USE_PTHREAD_SEMAPHORE)
48
49 Semaphore::Semaphore(Uint32 initial)
50 {
|
51 mike 1.5 pthread_mutex_init(&_rep.mutex, NULL);
52 pthread_cond_init(&_rep.cond, NULL);
|
53 mike 1.2
54 if (initial > PEGASUS_SEM_VALUE_MAX)
|
55 dmitry.mikulin 1.11 {
|
56 kumpf 1.16 _rep.count = PEGASUS_SEM_VALUE_MAX - 1;
|
57 dmitry.mikulin 1.11 }
|
58 mike 1.2 else
|
59 dmitry.mikulin 1.11 {
|
60 kumpf 1.16 _rep.count = initial;
|
61 dmitry.mikulin 1.11 }
|
62 mike 1.2
63 _rep.owner = Threads::self();
64 _rep.waiters = 0;
65 }
66
67 Semaphore::~Semaphore()
68 {
|
69 ouyang.jian 1.9 #if !defined(PEGASUS_PLATFORM_AIX_RS_IBMCXX) \
70 && !defined(PEGASUS_PLATFORM_PASE_ISERIES_IBMCXX)
|
71 mike 1.5 pthread_mutex_lock(&_rep.mutex);
72 int r = 0;
73 while ((r = pthread_cond_destroy(&_rep.cond) == EBUSY) ||
74 (r == -1 && errno == EBUSY))
75 {
76 pthread_mutex_unlock(&_rep.mutex);
77 Threads::yield();
78 pthread_mutex_lock(&_rep.mutex);
79 }
80 pthread_mutex_unlock(&_rep.mutex);
81 pthread_mutex_destroy(&_rep.mutex);
|
82 mike 1.2 #else
|
83 mike 1.5 int val;
84 val = pthread_mutex_destroy(&_rep.mutex);
85
86 if (val != 0)
|
87 dmitry.mikulin 1.11 {
|
88 mike 1.5 pthread_cond_destroy(&_rep.cond);
|
89 dmitry.mikulin 1.11 }
|
90 mike 1.5 else
|
91 dmitry.mikulin 1.11 {
|
92 mike 1.5 val = pthread_cond_destroy(&_rep.cond);
|
93 dmitry.mikulin 1.11 }
|
94 mike 1.5
95 while (EBUSY == val)
96 {
97 Threads::yield();
98 val = pthread_mutex_destroy(&_rep.mutex);
99 if (val != 0)
|
100 dmitry.mikulin 1.11 {
|
101 mike 1.5 pthread_cond_destroy(&_rep.cond);
|
102 dmitry.mikulin 1.11 }
|
103 mike 1.5 else
|
104 dmitry.mikulin 1.11 {
|
105 mike 1.5 val = pthread_cond_destroy(&_rep.cond);
|
106 dmitry.mikulin 1.11 }
|
107 mike 1.5 }
|
108 mike 1.2 #endif
109 }
110
|
111 ouyang.jian 1.9 #if defined(PEGASUS_PLATFORM_AIX_RS_IBMCXX) \
112 || defined(PEGASUS_PLATFORM_PASE_ISERIES_IBMCXX)
|
113 mike 1.2 // cleanup function
114 static void semaphore_cleanup(void *arg)
115 {
|
116 mike 1.5 // cast back to proper type and unlock mutex
|
117 dave.sudlik 1.8 SemaphoreRep *s = (SemaphoreRep *) arg;
|
118 mike 1.5 pthread_mutex_unlock(&s->mutex);
|
119 mike 1.2 }
120 #endif
121
122 // block until this semaphore is in a signalled state or
123 // throw an exception if the wait fails
|
124 kumpf 1.13 void Semaphore::wait()
|
125 mike 1.2 {
|
126 mike 1.5 // Acquire mutex to enter critical section.
127 pthread_mutex_lock(&_rep.mutex);
|
128 mike 1.2
|
129 mike 1.5 // Push cleanup function onto cleanup stack
130 // The mutex will unlock if the thread is killed early
|
131 ouyang.jian 1.9 #if defined(PEGASUS_PLATFORM_AIX_RS_IBMCXX) \
132 || defined(PEGASUS_PLATFORM_PASE_ISERIES_IBMCXX)
|
133 mike 1.2 Threads::cleanup_push(&semaphore_cleanup, &_rep);
134 #endif
135
|
136 mike 1.5 // Keep track of the number of waiters so that <sema_post> works correctly.
137 _rep.waiters++;
|
138 mike 1.2
|
139 mike 1.5 // Wait until the semaphore count is > 0, then atomically release
140 // <lock_> and wait for <count_nonzero_> to be signaled.
|
141 kumpf 1.16 while (_rep.count == 0)
|
142 dmitry.mikulin 1.11 {
|
143 mike 1.5 pthread_cond_wait(&_rep.cond, &_rep.mutex);
|
144 dmitry.mikulin 1.11 }
|
145 mike 1.2
|
146 mike 1.5 // <_rep.mutex> is now held.
|
147 mike 1.2
|
148 mike 1.5 // Decrement the waiters count.
149 _rep.waiters--;
|
150 mike 1.2
|
151 mike 1.5 // Decrement the semaphore's count.
|
152 kumpf 1.16 _rep.count--;
|
153 mike 1.2
154 // Since we push an unlock onto the cleanup stack
|
155 mike 1.5 // We will pop it off to release the mutex when leaving the critical
156 // section.
|
157 ouyang.jian 1.9 #if defined(PEGASUS_PLATFORM_AIX_RS_IBMCXX) \
158 || defined(PEGASUS_PLATFORM_PASE_ISERIES_IBMCXX)
|
159 mike 1.5 Threads::cleanup_pop(1);
|
160 mike 1.2 #endif
|
161 mike 1.5 // Release mutex to leave critical section.
162 pthread_mutex_unlock(&_rep.mutex);
|
163 mike 1.2 }
164
|
165 kumpf 1.14 Boolean Semaphore::time_wait(Uint32 milliseconds)
|
166 mike 1.2 {
|
167 mike 1.5 // Acquire mutex to enter critical section.
168 pthread_mutex_lock(&_rep.mutex);
169 Boolean timedOut = false;
|
170 mike 1.2
|
171 ouyang.jian 1.9 #if defined(PEGASUS_PLATFORM_AIX_RS_IBMCXX) \
172 || defined(PEGASUS_PLATFORM_PASE_ISERIES_IBMCXX)
|
173 mike 1.5 // Push cleanup function onto cleanup stack
174 // The mutex will unlock if the thread is killed early
|
175 dave.sudlik 1.8 Threads::cleanup_push(&semaphore_cleanup, &_rep);
|
176 mike 1.2 #endif
177
|
178 mike 1.5 // Keep track of the number of waiters so that <sema_post> works correctly.
179 _rep.waiters++;
180
181 struct timeval now = { 0, 0 };
182 struct timespec waittime = { 0, 0 };
183 gettimeofday(&now, NULL);
184 waittime.tv_sec = now.tv_sec;
185 waittime.tv_nsec = now.tv_usec + (milliseconds * 1000); // microseconds
186 waittime.tv_sec += (waittime.tv_nsec / 1000000); // roll overflow into
187 waittime.tv_nsec = (waittime.tv_nsec % 1000000); // the "seconds" part
188 waittime.tv_nsec = waittime.tv_nsec * 1000; // convert to nanoseconds
|
189 mike 1.2
|
190 kumpf 1.16 while ((_rep.count == 0) && !timedOut)
|
191 mike 1.5 {
192 int r = pthread_cond_timedwait(&_rep.cond, &_rep.mutex, &waittime);
193
194 if (((r == -1 && errno == ETIMEDOUT) || (r == ETIMEDOUT)) &&
|
195 kumpf 1.16 _rep.count == 0)
|
196 mike 1.5 {
197 timedOut = true;
198 }
199 }
|
200 mike 1.2
|
201 mike 1.5 if (!timedOut)
202 {
203 // Decrement the semaphore's count.
|
204 kumpf 1.16 _rep.count--;
|
205 mike 1.5 }
206
207 // Decrement the waiters count.
208 _rep.waiters--;
|
209 mike 1.2
|
210 ouyang.jian 1.9 #if defined(PEGASUS_PLATFORM_AIX_RS_IBMCXX) \
211 || defined(PEGASUS_PLATFORM_PASE_ISERIES_IBMCXX)
|
212 mike 1.5 // Since we push an unlock onto the cleanup stack
213 // We will pop it off to release the mutex when leaving the critical
214 // section.
215 Threads::cleanup_pop(1);
|
216 mike 1.2 #endif
217
|
218 mike 1.5 // Release mutex to leave critical section.
219 pthread_mutex_unlock(&_rep.mutex);
|
220 mike 1.2
|
221 kumpf 1.14 return !timedOut;
|
222 mike 1.2 }
223
224 // increment the count of the semaphore
225 void Semaphore::signal()
226 {
|
227 mike 1.5 pthread_mutex_lock(&_rep.mutex);
|
228 mike 1.2
|
229 mike 1.5 // Always allow one thread to continue if it is waiting.
230 if (_rep.waiters > 0)
|
231 dmitry.mikulin 1.11 {
|
232 mike 1.5 pthread_cond_signal(&_rep.cond);
|
233 dmitry.mikulin 1.11 }
|
234 mike 1.2
|
235 mike 1.5 // Increment the semaphore's count.
|
236 kumpf 1.16 _rep.count++;
|
237 mike 1.2
|
238 mike 1.5 pthread_mutex_unlock(&_rep.mutex);
|
239 mike 1.2 }
240
241 #endif /* PEGASUS_USE_PTHREAD_SEMAPHORE */
242
243 //==============================================================================
244 //
245 // PEGASUS_USE_POSIX_SEMAPHORE
246 //
247 //==============================================================================
248
249 #if defined(PEGASUS_USE_POSIX_SEMAPHORE)
250
251 Semaphore::Semaphore(Uint32 initial)
252 {
|
253 mike 1.5 if (initial > PEGASUS_SEM_VALUE_MAX)
|
254 dmitry.mikulin 1.11 {
|
255 mike 1.5 initial = PEGASUS_SEM_VALUE_MAX - 1;
|
256 dmitry.mikulin 1.11 }
257
|
258 mike 1.5 _rep.owner = Threads::self();
|
259 dmitry.mikulin 1.11 if (sem_init(&_rep.sem, 0, initial) == -1)
260 {
|
261 kumpf 1.16 throw Exception(MessageLoaderParms(
262 "Common.InternalException.SEMAPHORE_INIT_FAILED",
263 "Semaphore initialization failed: $0",
264 PEGASUS_SYSTEM_ERRORMSG_NLS));
|
265 dmitry.mikulin 1.11 }
|
266 mike 1.2 }
267
268 Semaphore::~Semaphore()
269 {
|
270 dmitry.mikulin 1.11 while (sem_destroy(&_rep.sem) == -1 && errno == EBUSY)
|
271 mike 1.5 {
272 Threads::yield();
273 }
|
274 mike 1.2 }
275
276 // block until this semaphore is in a signalled state, or
277 // throw an exception if the wait fails
|
278 kumpf 1.13 void Semaphore::wait()
|
279 mike 1.2 {
280 do
281 {
282 int rc = sem_wait(&_rep.sem);
283 if (rc == 0)
284 break;
285
|
286 kumpf 1.13 if (errno != EINTR)
|
287 mike 1.2 {
|
288 kumpf 1.16 throw Exception(MessageLoaderParms(
289 "Common.InternalException.SEMAPHORE_WAIT_FAILED",
290 "Semaphore wait failed: $0",
291 PEGASUS_SYSTEM_ERRORMSG_NLS));
|
292 dmitry.mikulin 1.11 }
|
293 mike 1.2
294 // keep going if above conditions fail
|
295 mike 1.5 }
296 while (true);
|
297 mike 1.2
298 }
299
300 // wait for milliseconds and throw an exception
301 // if wait times out without gaining the semaphore
|
302 kumpf 1.14 Boolean Semaphore::time_wait(Uint32 milliseconds)
|
303 mike 1.2 {
|
304 kumpf 1.12 int retcode;
|
305 mike 1.5
306 struct timeval now, finish, remaining;
307 Uint32 usec;
|
308 mike 1.2
|
309 mike 1.5 gettimeofday(&finish, NULL);
310 finish.tv_sec += (milliseconds / 1000);
311 milliseconds %= 1000;
312 usec = finish.tv_usec + (milliseconds * 1000);
313 finish.tv_sec += (usec / 1000000);
314 finish.tv_usec = usec % 1000000;
|
315 mike 1.2
|
316 mike 1.5 while (1)
317 {
318 do
319 {
320 retcode = sem_trywait(&_rep.sem);
321 }
322 while (retcode == -1 && errno == EINTR);
323
324 if (retcode == 0)
|
325 dmitry.mikulin 1.11 {
|
326 kumpf 1.14 break;
|
327 dmitry.mikulin 1.11 }
|
328 mike 1.5
329 if (retcode == -1 && errno != EAGAIN)
|
330 dmitry.mikulin 1.11 {
|
331 kumpf 1.16 throw Exception(MessageLoaderParms(
332 "Common.InternalException.SEMAPHORE_WAIT_FAILED",
333 "Semaphore wait failed: $0",
334 PEGASUS_SYSTEM_ERRORMSG_NLS));
|
335 dmitry.mikulin 1.11 }
336
|
337 mike 1.5 gettimeofday(&now, NULL);
338 if (Time::subtract(&remaining, &finish, &now))
|
339 dmitry.mikulin 1.11 {
|
340 kumpf 1.14 return false;
|
341 dmitry.mikulin 1.11 }
|
342 mike 1.5 Threads::yield();
343 }
|
344 kumpf 1.14
345 return true;
|
346 mike 1.2 }
347
348 // increment the count of the semaphore
349 void Semaphore::signal()
350 {
|
351 dmitry.mikulin 1.11 if (sem_post(&_rep.sem) == -1)
352 {
|
353 kumpf 1.16 throw Exception(MessageLoaderParms(
354 "Common.InternalException.SEMAPHORE_SIGNAL_FAILED",
355 "Failed to signal semaphore: $0",
356 PEGASUS_SYSTEM_ERRORMSG_NLS));
|
357 dmitry.mikulin 1.11 }
|
358 mike 1.2 }
359
360 #endif /* PEGASUS_USE_POSIX_SEMAPHORE */
361
362 //==============================================================================
363 //
364 // PEGASUS_USE_WINDOWS_SEMAPHORE
365 //
366 //==============================================================================
367
368 #if defined(PEGASUS_USE_WINDOWS_SEMAPHORE)
369
|
370 mike 1.5 Semaphore::Semaphore(Uint32 initial)
|
371 mike 1.2 {
|
372 mike 1.5 if (initial > PEGASUS_SEM_VALUE_MAX)
|
373 dmitry.mikulin 1.11 {
|
374 mike 1.5 initial = PEGASUS_SEM_VALUE_MAX - 1;
|
375 dmitry.mikulin 1.11 }
|
376 mike 1.5 _rep.owner = Threads::self();
377 _rep.sem = CreateSemaphore(NULL, initial, PEGASUS_SEM_VALUE_MAX, NULL);
|
378 mike 1.2 }
379
380 Semaphore::~Semaphore()
381 {
|
382 mike 1.5 CloseHandle(_rep.sem);
|
383 mike 1.2 }
384
385 // block until this semaphore is in a signalled state
|
386 kumpf 1.13 void Semaphore::wait()
|
387 mike 1.2 {
388 DWORD errorcode = WaitForSingleObject(_rep.sem, INFINITE);
|
389 kumpf 1.16 if (errorcode == WAIT_FAILED)
|
390 dmitry.mikulin 1.11 {
|
391 kumpf 1.16 throw Exception(MessageLoaderParms(
392 "Common.InternalException.SEMAPHORE_WAIT_FAILED",
393 "Semaphore wait failed: $0",
394 PEGASUS_SYSTEM_ERRORMSG_NLS));
|
395 dmitry.mikulin 1.11 }
|
396 mike 1.2 }
397
|
398 kumpf 1.15 Boolean Semaphore::time_wait(Uint32 milliseconds)
|
399 mike 1.2 {
400 DWORD errorcode = WaitForSingleObject(_rep.sem, milliseconds);
|
401 kumpf 1.14
402 if (errorcode == WAIT_TIMEOUT)
|
403 dmitry.mikulin 1.11 {
|
404 kumpf 1.14 return false;
|
405 dmitry.mikulin 1.11 }
|
406 kumpf 1.14
407 if (errorcode == WAIT_FAILED)
408 {
|
409 kumpf 1.16 throw Exception(MessageLoaderParms(
410 "Common.InternalException.SEMAPHORE_WAIT_FAILED",
411 "Semaphore wait failed: $0",
412 PEGASUS_SYSTEM_ERRORMSG_NLS));
|
413 kumpf 1.14 }
414
415 return true;
|
416 mike 1.2 }
417
418 // increment the count of the semaphore
419 void Semaphore::signal()
420 {
421 ReleaseSemaphore(_rep.sem, 1, NULL);
422 }
423
424 #endif /* PEGASUS_USE_WINDOWS_SEMAPHORE */
425
426 PEGASUS_NAMESPACE_END
|