sem_timedwait.c 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  1. /*
  2. * -------------------------------------------------------------
  3. *
  4. * Module: sem_timedwait.c
  5. *
  6. * Purpose:
  7. * Semaphores aren't actually part of the PThreads standard.
  8. * They are defined by the POSIX Standard:
  9. *
  10. * POSIX 1003.1b-1993 (POSIX.1b)
  11. *
  12. * -------------------------------------------------------------
  13. *
  14. * --------------------------------------------------------------------------
  15. *
  16. * Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems
  17. * Copyright(C) 2008 Jason Schmidlapp
  18. *
  19. * Contact Email: [email protected]
  20. *
  21. *
  22. * Based upon Pthreads-win32 - POSIX Threads Library for Win32
  23. * Copyright(C) 1998 John E. Bossom
  24. * Copyright(C) 1999,2005 Pthreads-win32 contributors
  25. *
  26. * Contact Email: [email protected]
  27. *
  28. * The original list of contributors to the Pthreads-win32 project
  29. * is contained in the file CONTRIBUTORS.ptw32 included with the
  30. * source code distribution. The list can also be seen at the
  31. * following World Wide Web location:
  32. * http://sources.redhat.com/pthreads-win32/contributors.html
  33. *
  34. * This library is free software; you can redistribute it and/or
  35. * modify it under the terms of the GNU Lesser General Public
  36. * License as published by the Free Software Foundation; either
  37. * version 2 of the License, or (at your option) any later version.
  38. *
  39. * This library is distributed in the hope that it will be useful,
  40. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  41. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  42. * Lesser General Public License for more details.
  43. *
  44. * You should have received a copy of the GNU Lesser General Public
  45. * License along with this library in the file COPYING.LIB;
  46. * if not, write to the Free Software Foundation, Inc.,
  47. * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
  48. */
  49. #include <stdio.h>
  50. #include <stdlib.h>
  51. #include "pthread.h"
  52. #include "semaphore.h"
  53. #include "implement.h"
  54. typedef struct
  55. {
  56. sem_t sem;
  57. int * resultPtr;
  58. } sem_timedwait_cleanup_args_t;
  59. static void
  60. pte_sem_timedwait_cleanup (void * args)
  61. {
  62. sem_timedwait_cleanup_args_t * a = (sem_timedwait_cleanup_args_t *)args;
  63. sem_t s = a->sem;
  64. if (pthread_mutex_lock (&s->lock) == 0)
  65. {
  66. /*
  67. * We either timed out or were cancelled.
  68. * If someone has posted between then and now we try to take the semaphore.
  69. * Otherwise the semaphore count may be wrong after we
  70. * return. In the case of a cancellation, it is as if we
  71. * were cancelled just before we return (after taking the semaphore)
  72. * which is ok.
  73. */
  74. unsigned int timeout = 0;
  75. if (pte_osSemaphorePend(s->sem, &timeout) == PTE_OS_OK)
  76. {
  77. /* We got the semaphore on the second attempt */
  78. *(a->resultPtr) = 0;
  79. }
  80. else
  81. {
  82. /* Indicate we're no longer waiting */
  83. s->value++;
  84. /*
  85. * Don't release the OS sema, it doesn't need adjustment
  86. * because it doesn't record the number of waiters.
  87. */
  88. }
  89. (void) pthread_mutex_unlock (&s->lock);
  90. }
  91. }
  92. int
  93. sem_timedwait (sem_t * sem, const struct timespec *abstime)
  94. /*
  95. * ------------------------------------------------------
  96. * DOCPUBLIC
  97. * This function waits on a semaphore possibly until
  98. * 'abstime' time.
  99. *
  100. * PARAMETERS
  101. * sem
  102. * pointer to an instance of sem_t
  103. *
  104. * abstime
  105. * pointer to an instance of struct timespec
  106. *
  107. * DESCRIPTION
  108. * This function waits on a semaphore. If the
  109. * semaphore value is greater than zero, it decreases
  110. * its value by one. If the semaphore value is zero, then
  111. * the calling thread (or process) is blocked until it can
  112. * successfully decrease the value or until interrupted by
  113. * a signal.
  114. *
  115. * If 'abstime' is a NULL pointer then this function will
  116. * block until it can successfully decrease the value or
  117. * until interrupted by a signal.
  118. *
  119. * RESULTS
  120. * 0 successfully decreased semaphore,
  121. * -1 failed, error in errno
  122. * ERRNO
  123. * EINVAL 'sem' is not a valid semaphore,
  124. * ENOSYS semaphores are not supported,
  125. * EINTR the function was interrupted by a signal,
  126. * EDEADLK a deadlock condition was detected.
  127. * ETIMEDOUT abstime elapsed before success.
  128. *
  129. * ------------------------------------------------------
  130. */
  131. {
  132. int result = 0;
  133. sem_t s = *sem;
  134. pthread_testcancel();
  135. if (sem == NULL)
  136. {
  137. result = EINVAL;
  138. }
  139. else
  140. {
  141. unsigned int milliseconds;
  142. unsigned int *pTimeout;
  143. if (abstime == NULL)
  144. {
  145. pTimeout = NULL;
  146. }
  147. else
  148. {
  149. /*
  150. * Calculate timeout as milliseconds from current system time.
  151. */
  152. milliseconds = pte_relmillisecs (abstime);
  153. pTimeout = &milliseconds;
  154. }
  155. if ((result = pthread_mutex_lock (&s->lock)) == 0)
  156. {
  157. int v;
  158. /* See sem_destroy.c
  159. */
  160. if (*sem == NULL)
  161. {
  162. (void) pthread_mutex_unlock (&s->lock);
  163. errno = EINVAL;
  164. return -1;
  165. }
  166. v = --s->value;
  167. (void) pthread_mutex_unlock (&s->lock);
  168. if (v < 0)
  169. {
  170. {
  171. sem_timedwait_cleanup_args_t cleanup_args;
  172. cleanup_args.sem = s;
  173. cleanup_args.resultPtr = &result;
  174. /* Must wait */
  175. pthread_cleanup_push(pte_sem_timedwait_cleanup, (void *) &cleanup_args);
  176. result = pte_cancellable_wait(s->sem,pTimeout);
  177. pthread_cleanup_pop(result);
  178. }
  179. }
  180. }
  181. }
  182. if (result != 0)
  183. {
  184. errno = result;
  185. return -1;
  186. }
  187. return 0;
  188. } /* sem_timedwait */