(file) Return to Semaphore.cpp CVS log (file) (dir) Up to [Pegasus] / pegasus / src / Pegasus / Common

  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

No CVS admin address has been configured
Powered by
ViewCVS 0.9.2