summaryrefslogtreecommitdiffstats
path: root/cpukit/posix/src/semtimedwait.c
diff options
context:
space:
mode:
authorSebastian Huber <sebastian.huber@embedded-brains.de>2017-09-12 08:09:16 +0200
committerSebastian Huber <sebastian.huber@embedded-brains.de>2017-10-05 14:29:01 +0200
commitc090db7405b72ce6d0b726c0a39fb1c1aebab7ea (patch)
tree099a887f445115e9b40d25cd6a2b2b11908d347d /cpukit/posix/src/semtimedwait.c
parentposix: Optimize pthread_once_t (diff)
downloadrtems-c090db7405b72ce6d0b726c0a39fb1c1aebab7ea.tar.bz2
posix: Implement self-contained POSIX semaphores
For semaphore object pointer and object validation see POSIX_SEMAPHORE_VALIDATE_OBJECT(). Destruction or close of a busy semaphore returns an error status. The object is not flushed. POSIX semaphores are now available in all configurations and no longer depend on --enable-posix. Update #2514. Update #3116.
Diffstat (limited to 'cpukit/posix/src/semtimedwait.c')
-rw-r--r--cpukit/posix/src/semtimedwait.c97
1 files changed, 50 insertions, 47 deletions
diff --git a/cpukit/posix/src/semtimedwait.c b/cpukit/posix/src/semtimedwait.c
index 09028f4d08..f00557c38d 100644
--- a/cpukit/posix/src/semtimedwait.c
+++ b/cpukit/posix/src/semtimedwait.c
@@ -18,18 +18,8 @@
#include "config.h"
#endif
-#include <stdarg.h>
-
-#include <errno.h>
-#include <fcntl.h>
-#include <pthread.h>
-#include <semaphore.h>
-#include <limits.h>
-
-#include <rtems/system.h>
-#include <rtems/score/todimpl.h>
#include <rtems/posix/semaphoreimpl.h>
-#include <rtems/seterr.h>
+#include <rtems/score/todimpl.h>
/*
* 11.2.6 Lock a Semaphore, P1003.1b-1993, p.226
@@ -38,47 +28,60 @@
*/
int sem_timedwait(
- sem_t *__restrict sem,
+ sem_t *__restrict _sem,
const struct timespec *__restrict abstime
)
{
- Watchdog_Interval ticks;
- bool do_wait = true;
- TOD_Absolute_timeout_conversion_results status;
- int lock_status;
+ Sem_Control *sem;
+ Thread_queue_Context queue_context;
+ ISR_Level level;
+ Thread_Control *executing;
+ unsigned int count;
- /*
- * POSIX requires that blocking calls with timeouts that take
- * an absolute timeout must ignore issues with the absolute
- * time provided if the operation would otherwise succeed.
- * So we check the abstime provided, and hold on to whether it
- * is valid or not. If it isn't correct and in the future,
- * then we do a polling operation and convert the UNSATISFIED
- * status into the appropriate error.
- *
- * If the status is TOD_ABSOLUTE_TIMEOUT_INVALID,
- * TOD_ABSOLUTE_TIMEOUT_IS_IN_PAST, or TOD_ABSOLUTE_TIMEOUT_IS_NOW,
- * then we should not wait.
- */
- status = _TOD_Absolute_timeout_to_ticks( abstime, CLOCK_REALTIME, &ticks );
- if ( status != TOD_ABSOLUTE_TIMEOUT_IS_IN_FUTURE )
- do_wait = false;
+ POSIX_SEMAPHORE_VALIDATE_OBJECT( _sem );
- lock_status = _POSIX_Semaphore_Wait_support( sem, do_wait, ticks );
+ sem = _Sem_Get( &_sem->_Semaphore );
+ _Thread_queue_Context_initialize( &queue_context );
+ _Thread_queue_Context_ISR_disable( &queue_context, level );
+ executing = _Sem_Queue_acquire_critical( sem, &queue_context );
- /*
- * This service only gives us the option to block. We used a polling
- * attempt to obtain if the abstime was not in the future. If we did
- * not obtain the semaphore, then not look at the status immediately,
- * make sure the right reason is returned.
- */
- if ( !do_wait && (lock_status == EBUSY) ) {
- if ( lock_status == TOD_ABSOLUTE_TIMEOUT_INVALID )
- rtems_set_errno_and_return_minus_one( EINVAL );
- if ( lock_status == TOD_ABSOLUTE_TIMEOUT_IS_IN_PAST ||
- lock_status == TOD_ABSOLUTE_TIMEOUT_IS_NOW )
- rtems_set_errno_and_return_minus_one( ETIMEDOUT );
- }
+ count = sem->count;
+ if ( __predict_true( count > 0 ) ) {
+ sem->count = count - 1;
+ _Sem_Queue_release( sem, level, &queue_context );
+ return 0;
+ } else {
+ Watchdog_Interval ticks;
+ Status_Control status;
+
+ switch ( _TOD_Absolute_timeout_to_ticks( abstime, CLOCK_REALTIME, &ticks ) ) {
+ case TOD_ABSOLUTE_TIMEOUT_INVALID:
+ _Sem_Queue_release( sem, level, &queue_context );
+ rtems_set_errno_and_return_minus_one( EINVAL );
+ break;
+ case TOD_ABSOLUTE_TIMEOUT_IS_IN_PAST:
+ case TOD_ABSOLUTE_TIMEOUT_IS_NOW:
+ _Sem_Queue_release( sem, level, &queue_context );
+ rtems_set_errno_and_return_minus_one( ETIMEDOUT );
+ break;
+ default:
+ break;
+ }
- return lock_status;
+ _Thread_queue_Context_set_thread_state(
+ &queue_context,
+ STATES_WAITING_FOR_SEMAPHORE
+ );
+ _Thread_queue_Context_set_do_nothing_enqueue_callout( &queue_context );
+ _Thread_queue_Context_set_relative_timeout( &queue_context, ticks );
+ _Thread_queue_Context_set_ISR_level( &queue_context, level );
+ _Thread_queue_Enqueue(
+ &sem->Queue.Queue,
+ SEMAPHORE_TQ_OPERATIONS,
+ executing,
+ &queue_context
+ );
+ status = _Thread_Wait_get_status( executing );
+ return _POSIX_Zero_or_minus_one_plus_errno( status );
+ }
}