diff options
Diffstat (limited to 'cpukit/posix/src/sempost.c')
-rw-r--r-- | cpukit/posix/src/sempost.c | 60 |
1 files changed, 40 insertions, 20 deletions
diff --git a/cpukit/posix/src/sempost.c b/cpukit/posix/src/sempost.c index da2b1a5495..de0ae71fc7 100644 --- a/cpukit/posix/src/sempost.c +++ b/cpukit/posix/src/sempost.c @@ -18,31 +18,51 @@ #include "config.h" #endif -#include <semaphore.h> -#include <limits.h> - #include <rtems/posix/semaphoreimpl.h> -#include <rtems/posix/posixapi.h> -int sem_post( - sem_t *sem -) +#include <limits.h> + +int sem_post( sem_t *_sem ) { - POSIX_Semaphore_Control *the_semaphore; - Thread_queue_Context queue_context; - Status_Control status; + Sem_Control *sem; + ISR_Level level; + Thread_queue_Context queue_context; + Thread_queue_Heads *heads; + unsigned int count; + + POSIX_SEMAPHORE_VALIDATE_OBJECT( _sem ); + + sem = _Sem_Get( &_sem->_Semaphore ); + _Thread_queue_Context_initialize( &queue_context ); + _Thread_queue_Context_ISR_disable( &queue_context, level ); + _Sem_Queue_acquire_critical( sem, &queue_context ); + + heads = sem->Queue.Queue.heads; + count = sem->count; + + if ( __predict_true( heads == NULL && count < SEM_VALUE_MAX ) ) { + sem->count = count + 1; + _Sem_Queue_release( sem, level, &queue_context ); + return 0; + } + + if ( __predict_true( heads != NULL ) ) { + const Thread_queue_Operations *operations; + Thread_Control *first; - the_semaphore = _POSIX_Semaphore_Get( sem, &queue_context ); + _Thread_queue_Context_set_ISR_level( &queue_context, level ); + operations = SEMAPHORE_TQ_OPERATIONS; + first = ( *operations->first )( heads ); - if ( the_semaphore == NULL ) { - rtems_set_errno_and_return_minus_one( EINVAL ); + _Thread_queue_Extract_critical( + &sem->Queue.Queue, + operations, + first, + &queue_context + ); + return 0; } - status = _CORE_semaphore_Surrender( - &the_semaphore->Semaphore, - POSIX_SEMAPHORE_TQ_OPERATIONS, - SEM_VALUE_MAX, - &queue_context - ); - return _POSIX_Zero_or_minus_one_plus_errno( status ); + _Sem_Queue_release( sem, level, &queue_context ); + rtems_set_errno_and_return_minus_one( EOVERFLOW ); } |