diff options
Diffstat (limited to 'cpukit')
27 files changed, 465 insertions, 164 deletions
diff --git a/cpukit/ChangeLog b/cpukit/ChangeLog index 29814c16b8..e32283e8cc 100644 --- a/cpukit/ChangeLog +++ b/cpukit/ChangeLog @@ -1,3 +1,40 @@ +2008-07-24 Joel Sherrill <joel.sherrill@OARcorp.com> + + PR 1291/cpukit + * posix/src/posixtimespecabsolutetimeout.c: New file. + * itron/inline/rtems/itron/semaphore.inl, itron/src/twai_sem.c, + posix/Makefile.am, posix/include/mqueue.h, + posix/include/rtems/posix/mqueue.h, + posix/include/rtems/posix/semaphore.h, + posix/include/rtems/posix/time.h, posix/src/condtimedwait.c, + posix/src/mqueuereceive.c, posix/src/mqueuerecvsupp.c, + posix/src/mqueuesend.c, posix/src/mqueuesendsupp.c, + posix/src/mqueuetimedreceive.c, posix/src/mqueuetimedsend.c, + posix/src/mutexfromcorestatus.c, posix/src/mutextimedlock.c, + posix/src/semaphorewaitsupp.c, posix/src/semtimedwait.c, + posix/src/semtrywait.c, posix/src/semwait.c, rtems/src/semobtain.c, + rtems/src/semtranslatereturncode.c, + score/include/rtems/score/coresem.h, score/src/coremsgseize.c, + score/src/coresemseize.c: + This patch addresses issues on implementation of the timeout on the + following POSIX services. Some of these services incorrectly took a + timeout as a relative time. Others would compute a 0 delta to timeout + if the absolute time and the current time were equal and thus + incorrectly block the caller forever. The root of the confusion is + that POSIX specifies that if the timeout is incorrect (e.g. in the + past, is now, or is numerically invalid), that it does not matter if + the call would succeed without blocking. This is in contrast to RTEMS + programming style where all errors are checked before any critical + sections are entered. This fix implemented a more uniform way of + handling POSIX absolute time timeouts. + + pthread_cond_timedwait - could block forever + + mq_timedreceive - used relative not absolute time + + mq_timedsend - used relative not absolute time + + pthread_mutex_timedlock - used relative not absolute time + + pthread_rwlock_timedrdlock- used relative not absolute time + + pthread_rwlock_timedwrlock- used relative not absolute time + + sem_timedwait - could block forever + 2008-04-25 Joel Sherrill <joel.sherrill@OARcorp.com> * score/include/rtems/system.h: Fix typo in comment. diff --git a/cpukit/itron/inline/rtems/itron/semaphore.inl b/cpukit/itron/inline/rtems/itron/semaphore.inl index 1822fb8884..c57347f319 100644 --- a/cpukit/itron/inline/rtems/itron/semaphore.inl +++ b/cpukit/itron/inline/rtems/itron/semaphore.inl @@ -172,8 +172,6 @@ RTEMS_INLINE_ROUTINE ER _ITRON_Semaphore_Translate_core_semaphore_return_code ( return E_TMOUT; case CORE_SEMAPHORE_MAXIMUM_COUNT_EXCEEDED: return E_QOVR; - case CORE_SEMAPHORE_BAD_TIMEOUT_VALUE: - return E_PAR; case THREAD_STATUS_PROXY_BLOCKING: return THREAD_STATUS_PROXY_BLOCKING; } diff --git a/cpukit/itron/src/twai_sem.c b/cpukit/itron/src/twai_sem.c index 90b3121051..0f7510a949 100644 --- a/cpukit/itron/src/twai_sem.c +++ b/cpukit/itron/src/twai_sem.c @@ -30,16 +30,16 @@ ER twai_sem( TMO tmout ) { - ITRON_Semaphore_Control *the_semaphore; - Objects_Locations location; - Watchdog_Interval interval; - Core_semaphore_Blocking_option blocking; + ITRON_Semaphore_Control *the_semaphore; + Objects_Locations location; + Watchdog_Interval interval; + boolean blocking; interval = 0; if ( tmout == TMO_POL ) { - blocking = CORE_SEMAPHORE_NO_WAIT; + blocking = FALSE; } else { - blocking = CORE_SEMAPHORE_BLOCK_FOREVER; + blocking = TRUE; if ( tmout != TMO_FEVR ) interval = TOD_MILLISECONDS_TO_TICKS(tmout); diff --git a/cpukit/posix/Makefile.am b/cpukit/posix/Makefile.am index 65e3dae375..dce2dcb1b3 100644 --- a/cpukit/posix/Makefile.am +++ b/cpukit/posix/Makefile.am @@ -132,10 +132,11 @@ libposix_a_SOURCES += src/semaphore.c src/semaphorecreatesupp.c \ ## TIME_C_FILES libposix_a_SOURCES += src/adjtime.c src/time.c src/posixtimespecsubtract.c \ - src/posixtimespectointerval.c src/posixintervaltotimespec.c \ - src/clockgetcpuclockid.c src/clockgetenableattr.c src/clockgetres.c \ - src/clockgettime.c src/clocksetenableattr.c src/clocksettime.c \ - src/nanosleep.c src/sleep.c src/usleep.c + src/posixtimespecabsolutetimeout.c src/posixtimespectointerval.c \ + src/posixintervaltotimespec.c src/clockgetcpuclockid.c \ + src/clockgetenableattr.c src/clockgetres.c src/clockgettime.c \ + src/clocksetenableattr.c src/clocksettime.c src/nanosleep.c src/sleep.c \ + src/usleep.c # the timer manager needs to be split further but only after its # dependence on the Classic API Timer Manager is removed. diff --git a/cpukit/posix/include/mqueue.h b/cpukit/posix/include/mqueue.h index 0c2a513345..0e1ad8370a 100644 --- a/cpukit/posix/include/mqueue.h +++ b/cpukit/posix/include/mqueue.h @@ -26,47 +26,53 @@ extern "C" { * 15.1.1 Data Structures, P1003.1b-1993, p. 271 */ +/** + * Message queue id type + */ typedef Objects_Id mqd_t; +/** + * This is the message queue attributes structure. + */ struct mq_attr { - long mq_flags; /* Message queue flags */ - long mq_maxmsg; /* Maximum number of messages */ - long mq_msgsize; /* Maximum message size */ - long mq_curmsgs; /* Number of messages currently queued */ + /** This is the message queue flags */ + long mq_flags; + /** This is the maximum number of messages */ + long mq_maxmsg; + /** This is the maximum message size */ + long mq_msgsize; + /** This is the mumber of messages currently queued */ + long mq_curmsgs; }; -/* +/** * 15.2.2 Open a Message Queue, P1003.1b-1993, p. 272 */ - mqd_t mq_open( const char *name, int oflag, ... ); -/* +/** * 15.2.2 Close a Message Queue, P1003.1b-1993, p. 275 */ - int mq_close( mqd_t mqdes ); -/* +/** * 15.2.2 Remove a Message Queue, P1003.1b-1993, p. 276 */ - int mq_unlink( const char *name ); -/* +/** * 15.2.4 Send a Message to a Message Queue, P1003.1b-1993, p. 277 * - * NOTE: P1003.4b/D8, p. 45 adds mq_timedsend(). + * @note P1003.4b/D8, p. 45 adds mq_timedsend(). */ - int mq_send( mqd_t mqdes, const char *msg_ptr, @@ -83,7 +89,7 @@ int mq_timedsend( const char *msg_ptr, size_t msg_len, unsigned int msg_prio, - const struct timespec *timeout + const struct timespec *abstime ); #endif /* _POSIX_TIMEOUTS */ @@ -108,7 +114,7 @@ ssize_t mq_timedreceive( char *msg_ptr, size_t msg_len, unsigned int *msg_prio, - const struct timespec *timeout + const struct timespec *abstime ); #endif /* _POSIX_TIMEOUTS */ diff --git a/cpukit/posix/include/rtems/posix/mqueue.h b/cpukit/posix/include/rtems/posix/mqueue.h index 7b831ac141..cddcfdba72 100644 --- a/cpukit/posix/include/rtems/posix/mqueue.h +++ b/cpukit/posix/include/rtems/posix/mqueue.h @@ -112,6 +112,7 @@ ssize_t _POSIX_Message_queue_Receive_support( char *msg_ptr, size_t msg_len, unsigned int *msg_prio, + boolean wait, Watchdog_Interval timeout ); @@ -128,6 +129,7 @@ int _POSIX_Message_queue_Send_support( const char *msg_ptr, size_t msg_len, uint32_t msg_prio, + boolean wait, Watchdog_Interval timeout ); diff --git a/cpukit/posix/include/rtems/posix/semaphore.h b/cpukit/posix/include/rtems/posix/semaphore.h index 26e0a6b804..78b8e022d8 100644 --- a/cpukit/posix/include/rtems/posix/semaphore.h +++ b/cpukit/posix/include/rtems/posix/semaphore.h @@ -153,9 +153,9 @@ void _POSIX_Semaphore_Delete( */ int _POSIX_Semaphore_Wait_support( - sem_t *sem, - Core_semaphore_Blocking_option blocking, - Watchdog_Interval timeout + sem_t *sem, + boolean blocking, + Watchdog_Interval timeout ); /* diff --git a/cpukit/posix/include/rtems/posix/time.h b/cpukit/posix/include/rtems/posix/time.h index 13418cf473..eb3376cc60 100644 --- a/cpukit/posix/include/rtems/posix/time.h +++ b/cpukit/posix/include/rtems/posix/time.h @@ -13,6 +13,23 @@ #include <rtems/score/tod.h> +/* Absolute Timeout Conversion Results + * + * This enumeration defines the possible results of converting + * an absolute time used for timeouts to POSIX blocking calls to + * a number of ticks. + */ +typedef enum { + /* The timeout is invalid. */ + POSIX_ABSOLUTE_TIMEOUT_INVALID, + /* The timeout represents a time that is in the past. */ + POSIX_ABSOLUTE_TIMEOUT_IS_IN_PAST, + /* The timeout represents a time that is equal to the current time. */ + POSIX_ABSOLUTE_TIMEOUT_IS_NOW, + /* The timeout represents a time that is in the future. */ + POSIX_ABSOLUTE_TIMEOUT_IS_IN_FUTURE, +} POSIX_Absolute_timeout_conversion_results_t; + /* * Seconds from January 1, 1970 to January 1, 1988. Used to account for * differences between POSIX API and RTEMS core. @@ -51,4 +68,24 @@ void _POSIX_Interval_to_timespec( struct timespec *time ); +/* + * Convert Absolute Timeout to Ticks + * + * This method takes an absolute time being used as a timeout + * to a blocking directive, validates it and returns the number + * of corresponding clock ticks for use by the SuperCore. + * + * abstime - is the timeout + * ticks_out - will contain the number of ticks + * + * This method returns the number of ticks in @a ticks_out + * and a status value indicating whether the absolute time + * is valid, in the past, equal to the current time or in + * the future as it should be. + */ +POSIX_Absolute_timeout_conversion_results_t _POSIX_Absolute_timeout_to_ticks( + const struct timespec *abstime, + Watchdog_Interval *ticks_out +); + #endif diff --git a/cpukit/posix/src/condtimedwait.c b/cpukit/posix/src/condtimedwait.c index 32ce1d4a05..204dae858c 100644 --- a/cpukit/posix/src/condtimedwait.c +++ b/cpukit/posix/src/condtimedwait.c @@ -28,34 +28,34 @@ int pthread_cond_timedwait( const struct timespec *abstime ) { - Watchdog_Interval timeout; - struct timespec current_time; - struct timespec difference; - boolean already_timedout = FALSE; - - if ( !abstime ) - return EINVAL; + Watchdog_Interval ticks; + boolean already_timedout; /* - * The abstime is a walltime. We turn it into an interval. + * 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. */ - - (void) clock_gettime( CLOCK_REALTIME, ¤t_time ); - - /* XXX probably some error checking should go here */ - - _POSIX_Timespec_subtract( ¤t_time, abstime, &difference ); - - if ( ( difference.tv_sec < 0 ) || ( ( difference.tv_sec == 0 ) && - ( difference.tv_nsec < 0 ) ) ) - already_timedout = TRUE; - - timeout = _POSIX_Timespec_to_interval( &difference ); + switch ( _POSIX_Absolute_timeout_to_ticks(abstime, &ticks) ) { + case POSIX_ABSOLUTE_TIMEOUT_INVALID: + return EINVAL; + case POSIX_ABSOLUTE_TIMEOUT_IS_IN_PAST: + case POSIX_ABSOLUTE_TIMEOUT_IS_NOW: + already_timedout = TRUE; + break; + case POSIX_ABSOLUTE_TIMEOUT_IS_IN_FUTURE: + already_timedout = FALSE; + break; + } return _POSIX_Condition_variables_Wait_support( cond, mutex, - timeout, + ticks, already_timedout ); } diff --git a/cpukit/posix/src/mqueuereceive.c b/cpukit/posix/src/mqueuereceive.c index e87d5fa8e9..1ba213e58a 100644 --- a/cpukit/posix/src/mqueuereceive.c +++ b/cpukit/posix/src/mqueuereceive.c @@ -51,6 +51,7 @@ ssize_t mq_receive( msg_ptr, msg_len, msg_prio, + TRUE, THREAD_QUEUE_WAIT_FOREVER ); } diff --git a/cpukit/posix/src/mqueuerecvsupp.c b/cpukit/posix/src/mqueuerecvsupp.c index d97db51642..9badfb65d4 100644 --- a/cpukit/posix/src/mqueuerecvsupp.c +++ b/cpukit/posix/src/mqueuerecvsupp.c @@ -32,8 +32,7 @@ #include <rtems/posix/mqueue.h> #include <rtems/posix/time.h> -/*PAGE - * +/* * _POSIX_Message_queue_Receive_support * * NOTE: XXX Document how size, priority, length, and the buffer go @@ -45,6 +44,7 @@ ssize_t _POSIX_Message_queue_Receive_support( char *msg_ptr, size_t msg_len, unsigned int *msg_prio, + boolean wait, Watchdog_Interval timeout ) { @@ -52,6 +52,7 @@ ssize_t _POSIX_Message_queue_Receive_support( POSIX_Message_queue_Control_fd *the_mq_fd; Objects_Locations location; size_t length_out; + boolean do_wait; the_mq_fd = _POSIX_Message_queue_Get_fd( mqdes, &location ); switch ( location ) { @@ -81,12 +82,23 @@ ssize_t _POSIX_Message_queue_Receive_support( length_out = -1; + /* + * A timed receive with a bad time will do a poll regardless. + */ + if ( wait ) + do_wait = (the_mq_fd->oflag & O_NONBLOCK) ? FALSE : TRUE; + else + do_wait = wait; + + /* + * Now perform the actual message receive + */ _CORE_message_queue_Seize( &the_mq->Message_queue, mqdes, msg_ptr, &length_out, - (the_mq_fd->oflag & O_NONBLOCK) ? FALSE : TRUE, + do_wait, timeout ); diff --git a/cpukit/posix/src/mqueuesend.c b/cpukit/posix/src/mqueuesend.c index 484fe72183..3bb11c3ab4 100644 --- a/cpukit/posix/src/mqueuesend.c +++ b/cpukit/posix/src/mqueuesend.c @@ -51,6 +51,7 @@ int mq_send( msg_ptr, msg_len, msg_prio, + TRUE, THREAD_QUEUE_WAIT_FOREVER ); } diff --git a/cpukit/posix/src/mqueuesendsupp.c b/cpukit/posix/src/mqueuesendsupp.c index 60f48fcdba..006c1ba4a2 100644 --- a/cpukit/posix/src/mqueuesendsupp.c +++ b/cpukit/posix/src/mqueuesendsupp.c @@ -43,6 +43,7 @@ int _POSIX_Message_queue_Send_support( const char *msg_ptr, size_t msg_len, uint32_t msg_prio, + boolean wait, Watchdog_Interval timeout ) { @@ -50,6 +51,7 @@ int _POSIX_Message_queue_Send_support( POSIX_Message_queue_Control_fd *the_mq_fd; Objects_Locations location; CORE_message_queue_Status msg_status; + boolean do_wait; /* * Validate the priority. @@ -77,6 +79,17 @@ int _POSIX_Message_queue_Send_support( the_mq = the_mq_fd->Queue; + /* + * A timed receive with a bad time will do a poll regardless. + */ + if ( wait ) + do_wait = (the_mq_fd->oflag & O_NONBLOCK) ? FALSE : TRUE; + else + do_wait = wait; + + /* + * Now perform the actual message receive + */ msg_status = _CORE_message_queue_Submit( &the_mq->Message_queue, (void *) msg_ptr, @@ -88,7 +101,7 @@ int _POSIX_Message_queue_Send_support( NULL, #endif _POSIX_Message_queue_Priority_to_core( msg_prio ), - (the_mq_fd->oflag & O_NONBLOCK) ? FALSE : TRUE, + do_wait, timeout /* no timeout */ ); diff --git a/cpukit/posix/src/mqueuetimedreceive.c b/cpukit/posix/src/mqueuetimedreceive.c index 2ad5f4c6d6..436fddebcf 100644 --- a/cpukit/posix/src/mqueuetimedreceive.c +++ b/cpukit/posix/src/mqueuetimedreceive.c @@ -44,14 +44,38 @@ ssize_t mq_timedreceive( char *msg_ptr, size_t msg_len, unsigned int *msg_prio, - const struct timespec *timeout + const struct timespec *abstime ) { + Watchdog_Interval ticks; + boolean do_wait; + + /* + * 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. + */ + switch ( _POSIX_Absolute_timeout_to_ticks( abstime, &ticks ) ) { + case POSIX_ABSOLUTE_TIMEOUT_INVALID: + case POSIX_ABSOLUTE_TIMEOUT_IS_IN_PAST: + case POSIX_ABSOLUTE_TIMEOUT_IS_NOW: + do_wait = FALSE; + break; + case POSIX_ABSOLUTE_TIMEOUT_IS_IN_FUTURE: + do_wait = TRUE; + break; + } + return _POSIX_Message_queue_Receive_support( mqdes, msg_ptr, msg_len, msg_prio, - _POSIX_Timespec_to_interval( timeout ) + do_wait, + ticks ); } diff --git a/cpukit/posix/src/mqueuetimedsend.c b/cpukit/posix/src/mqueuetimedsend.c index 89569368be..87458b7f02 100644 --- a/cpukit/posix/src/mqueuetimedsend.c +++ b/cpukit/posix/src/mqueuetimedsend.c @@ -44,14 +44,38 @@ int mq_timedsend( const char *msg_ptr, size_t msg_len, unsigned int msg_prio, - const struct timespec *timeout + const struct timespec *abstime ) { + Watchdog_Interval ticks; + boolean do_wait; + + /* + * 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. + */ + switch ( _POSIX_Absolute_timeout_to_ticks( abstime, &ticks ) ) { + case POSIX_ABSOLUTE_TIMEOUT_INVALID: + case POSIX_ABSOLUTE_TIMEOUT_IS_IN_PAST: + case POSIX_ABSOLUTE_TIMEOUT_IS_NOW: + do_wait = FALSE; + break; + case POSIX_ABSOLUTE_TIMEOUT_IS_IN_FUTURE: + do_wait = TRUE; + break; + } + return _POSIX_Message_queue_Send_support( mqdes, msg_ptr, msg_len, msg_prio, - _POSIX_Timespec_to_interval( timeout ) + do_wait, + ticks ); } diff --git a/cpukit/posix/src/mutexfromcorestatus.c b/cpukit/posix/src/mutexfromcorestatus.c index 3c6f617861..dddc3cea4b 100644 --- a/cpukit/posix/src/mutexfromcorestatus.c +++ b/cpukit/posix/src/mutexfromcorestatus.c @@ -41,7 +41,7 @@ int _POSIX_Mutex_From_core_mutex_status( case CORE_MUTEX_WAS_DELETED: return EINVAL; case CORE_MUTEX_TIMEOUT: - return EAGAIN; + return ETIMEDOUT; case CORE_MUTEX_STATUS_CEILING_VIOLATED: return EINVAL; default: diff --git a/cpukit/posix/src/mutextimedlock.c b/cpukit/posix/src/mutextimedlock.c index e86c3040dd..f1963c2efe 100644 --- a/cpukit/posix/src/mutextimedlock.c +++ b/cpukit/posix/src/mutextimedlock.c @@ -28,12 +28,58 @@ int pthread_mutex_timedlock( pthread_mutex_t *mutex, - const struct timespec *timeout + const struct timespec *abstime ) { - return _POSIX_Mutex_Lock_support( + Watchdog_Interval ticks; + boolean do_wait; + POSIX_Absolute_timeout_conversion_results_t status; + int lock_status; + + /* + * 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. + */ + status = _POSIX_Absolute_timeout_to_ticks( abstime, &ticks ); + switch ( status ) { + case POSIX_ABSOLUTE_TIMEOUT_INVALID: + case POSIX_ABSOLUTE_TIMEOUT_IS_IN_PAST: + case POSIX_ABSOLUTE_TIMEOUT_IS_NOW: + do_wait = FALSE; + break; + case POSIX_ABSOLUTE_TIMEOUT_IS_IN_FUTURE: + do_wait = TRUE; + break; + } + + lock_status = _POSIX_Mutex_Lock_support( mutex, - TRUE, - _POSIX_Timespec_to_interval( timeout ) + do_wait, + ticks ); + + /* + * This service only gives us the option to block. We used a polling + * attempt to lock if the abstime was not in the future. If we did + * not obtain the mutex, then not look at the status immediately, + * make sure the right reason is returned. + */ + if ( !do_wait && (lock_status == EBUSY) ) { + switch (lock_status) { + case POSIX_ABSOLUTE_TIMEOUT_INVALID: + return EINVAL; + case POSIX_ABSOLUTE_TIMEOUT_IS_IN_PAST: + case POSIX_ABSOLUTE_TIMEOUT_IS_NOW: + return ETIMEDOUT; + case POSIX_ABSOLUTE_TIMEOUT_IS_IN_FUTURE: + break; + } + } + + return lock_status; } diff --git a/cpukit/posix/src/posixtimespecabsolutetimeout.c b/cpukit/posix/src/posixtimespecabsolutetimeout.c new file mode 100644 index 0000000000..4c6a84e1e9 --- /dev/null +++ b/cpukit/posix/src/posixtimespecabsolutetimeout.c @@ -0,0 +1,126 @@ +/* + * Convert abstime timeout to ticks + */ + +/* + * COPYRIGHT (c) 1989-2007. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#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/object.h> +#include <rtems/posix/semaphore.h> +#include <rtems/posix/time.h> +#include <rtems/seterr.h> + +static boolean _Timespec_Is_valid( + const struct timespec *time +) +{ + if ( !time ) + return FALSE; + + if ( time->tv_sec < 0 ) + return FALSE; + + if ( time->tv_nsec < 0 ) + return FALSE; + + if ( time->tv_nsec >= TOD_NANOSECONDS_PER_SECOND ) + return FALSE; + + return TRUE; +} + +static boolean _Timespec_Less_than( + const struct timespec *lhs, + const struct timespec *rhs +) +{ + if ( lhs->tv_sec < rhs->tv_sec ) + return TRUE; + + if ( lhs->tv_sec > rhs->tv_sec ) + return FALSE; + + /* ASSERT: lhs->tv_sec == rhs->tv_sec */ + if ( lhs->tv_nsec < rhs->tv_nsec ) + return TRUE; + + return FALSE; +} + + +/* + * The abstime is a walltime. We turn it into an interval. + */ +POSIX_Absolute_timeout_conversion_results_t _POSIX_Absolute_timeout_to_ticks( + const struct timespec *abstime, + Watchdog_Interval *ticks_out +) +{ + struct timespec current_time; + struct timespec difference; + + + /* + * Make sure there is always a value returned. + */ + *ticks_out = 0; + + /* + * Is the absolute time even valid? + */ + if ( !_Timespec_Is_valid(abstime) ) + return POSIX_ABSOLUTE_TIMEOUT_INVALID; + + /* + * Is the absolute time in the past? + */ + clock_gettime( CLOCK_REALTIME, ¤t_time ); + + if ( _Timespec_Less_than( abstime, ¤t_time ) ) + return POSIX_ABSOLUTE_TIMEOUT_IS_IN_PAST; + + /* + * How long until the requested absolute time? + */ + _POSIX_Timespec_subtract( ¤t_time, abstime, &difference ); + + /* + * Internally the SuperCore uses ticks, so convert to them. + */ + *ticks_out = _POSIX_Timespec_to_interval( &difference ); + + /* + * If the difference was 0, then the future is now. It is so bright + * we better wear shades. + */ + if ( !*ticks_out ) + return POSIX_ABSOLUTE_TIMEOUT_IS_NOW; + + /* + * This is the case we were expecting and it took this long to + * get here. + */ + return POSIX_ABSOLUTE_TIMEOUT_IS_IN_FUTURE; +} + diff --git a/cpukit/posix/src/semaphorewaitsupp.c b/cpukit/posix/src/semaphorewaitsupp.c index 1c5f815b25..f460331612 100644 --- a/cpukit/posix/src/semaphorewaitsupp.c +++ b/cpukit/posix/src/semaphorewaitsupp.c @@ -26,9 +26,9 @@ */ int _POSIX_Semaphore_Wait_support( - sem_t *sem, - Core_semaphore_Blocking_option blocking, - Watchdog_Interval timeout + sem_t *sem, + boolean blocking, + Watchdog_Interval timeout ) { POSIX_Semaphore_Control *the_semaphore; @@ -65,9 +65,6 @@ int _POSIX_Semaphore_Wait_support( * count to the largest value the count can hold. */ break; - case CORE_SEMAPHORE_BAD_TIMEOUT_VALUE: - rtems_set_errno_and_return_minus_one( EINVAL ); - break; } } return 0; diff --git a/cpukit/posix/src/semtimedwait.c b/cpukit/posix/src/semtimedwait.c index 662845ecd9..6a78c742d0 100644 --- a/cpukit/posix/src/semtimedwait.c +++ b/cpukit/posix/src/semtimedwait.c @@ -32,40 +32,51 @@ int sem_timedwait( const struct timespec *abstime ) { + Watchdog_Interval ticks; + boolean do_wait = TRUE; + POSIX_Absolute_timeout_conversion_results_t status; + int lock_status; + /* - * The abstime is a walltime. We turn it into an interval. + * 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. */ - Watchdog_Interval ticks = 0; - struct timespec current_time; - struct timespec difference; - Core_semaphore_Blocking_option blocking = CORE_SEMAPHORE_BLOCK_WITH_TIMEOUT; + status = _POSIX_Absolute_timeout_to_ticks( abstime, &ticks ); + switch ( status ) { + case POSIX_ABSOLUTE_TIMEOUT_INVALID: + case POSIX_ABSOLUTE_TIMEOUT_IS_IN_PAST: + case POSIX_ABSOLUTE_TIMEOUT_IS_NOW: + do_wait = FALSE; + break; + case POSIX_ABSOLUTE_TIMEOUT_IS_IN_FUTURE: + do_wait = TRUE; + break; + } + + lock_status = _POSIX_Semaphore_Wait_support( sem, do_wait, ticks ); /* - * Error check the absolute time to timeout + * 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 0 - if ( /* abstime->tv_sec < 0 || */ abstime->tv_nsec ) /* tv_sec is unsigned */ - blocking = CORE_SEMAPHORE_BAD_TIMEOUT_VALUE; - else -#endif - if ( abstime->tv_nsec >= TOD_NANOSECONDS_PER_SECOND ) { - blocking = CORE_SEMAPHORE_BAD_TIMEOUT; - } else { - clock_gettime( CLOCK_REALTIME, ¤t_time ); - /* - * Make sure the abstime is in the future - */ - if ( abstime->tv_sec < current_time.tv_sec ) - blocking = CORE_SEMAPHORE_BAD_TIMEOUT; - else if ( (abstime->tv_sec == current_time.tv_sec) && - (abstime->tv_nsec <= current_time.tv_nsec) ) - blocking = CORE_SEMAPHORE_BAD_TIMEOUT; - else { - _POSIX_Timespec_subtract( ¤t_time, abstime, &difference ); - ticks = _POSIX_Timespec_to_interval( &difference ); - blocking = CORE_SEMAPHORE_BLOCK_WITH_TIMEOUT; + if ( !do_wait && (lock_status == EBUSY) ) { + switch (lock_status) { + case POSIX_ABSOLUTE_TIMEOUT_INVALID: + return EINVAL; + case POSIX_ABSOLUTE_TIMEOUT_IS_IN_PAST: + case POSIX_ABSOLUTE_TIMEOUT_IS_NOW: + return ETIMEDOUT; + case POSIX_ABSOLUTE_TIMEOUT_IS_IN_FUTURE: + break; } - } + } - return _POSIX_Semaphore_Wait_support( sem, blocking, ticks ); + return lock_status; } diff --git a/cpukit/posix/src/semtrywait.c b/cpukit/posix/src/semtrywait.c index 2aecde9425..17a7dd41ca 100644 --- a/cpukit/posix/src/semtrywait.c +++ b/cpukit/posix/src/semtrywait.c @@ -31,5 +31,5 @@ int sem_trywait( sem_t *sem ) { - return _POSIX_Semaphore_Wait_support( sem, FALSE, THREAD_QUEUE_WAIT_FOREVER ); + return _POSIX_Semaphore_Wait_support(sem, FALSE, THREAD_QUEUE_WAIT_FOREVER); } diff --git a/cpukit/posix/src/semwait.c b/cpukit/posix/src/semwait.c index b43a1e47b4..9ef787c727 100644 --- a/cpukit/posix/src/semwait.c +++ b/cpukit/posix/src/semwait.c @@ -31,9 +31,5 @@ int sem_wait( sem_t *sem ) { - return _POSIX_Semaphore_Wait_support( - sem, - CORE_SEMAPHORE_BLOCK_FOREVER, - THREAD_QUEUE_WAIT_FOREVER - ); + return _POSIX_Semaphore_Wait_support( sem, TRUE, THREAD_QUEUE_WAIT_FOREVER ); } diff --git a/cpukit/rtems/src/semobtain.c b/cpukit/rtems/src/semobtain.c index bfa8831f6a..db99b85073 100644 --- a/cpukit/rtems/src/semobtain.c +++ b/cpukit/rtems/src/semobtain.c @@ -107,8 +107,7 @@ rtems_status_code rtems_semaphore_obtain( _CORE_semaphore_Seize_isr_disable( &the_semaphore->Core_control.semaphore, id, - ((_Options_Is_no_wait( option_set )) ? - CORE_SEMAPHORE_NO_WAIT : CORE_SEMAPHORE_BLOCK_FOREVER), + ((_Options_Is_no_wait( option_set )) ? FALSE : TRUE), timeout, &level ); diff --git a/cpukit/rtems/src/semtranslatereturncode.c b/cpukit/rtems/src/semtranslatereturncode.c index d7d2d306ac..87999d3cc9 100644 --- a/cpukit/rtems/src/semtranslatereturncode.c +++ b/cpukit/rtems/src/semtranslatereturncode.c @@ -103,7 +103,6 @@ rtems_status_code _Semaphore_Translate_core_semaphore_return_code_[] = { RTEMS_OBJECT_WAS_DELETED, /* CORE_SEMAPHORE_WAS_DELETED */ RTEMS_TIMEOUT, /* CORE_SEMAPHORE_TIMEOUT */ RTEMS_INTERNAL_ERROR, /* CORE_SEMAPHORE_MAXIMUM_COUNT_EXCEEDED */ - RTEMS_INTERNAL_ERROR /* CORE_SEMAPHORE_BAD_TIMEOUT_VALUE */ }; rtems_status_code _Semaphore_Translate_core_semaphore_return_code ( @@ -114,7 +113,7 @@ rtems_status_code _Semaphore_Translate_core_semaphore_return_code ( if ( status == THREAD_STATUS_PROXY_BLOCKING ) return RTEMS_PROXY_BLOCKING; #endif - if ( status > CORE_MUTEX_STATUS_CEILING_VIOLATED ) + if ( status > CORE_SEMAPHORE_MAXIMUM_COUNT_EXCEEDED ) return RTEMS_INTERNAL_ERROR; return _Semaphore_Translate_core_semaphore_return_code_[status]; } diff --git a/cpukit/score/include/rtems/score/coresem.h b/cpukit/score/include/rtems/score/coresem.h index f508d9f00c..6db409ebe4 100644 --- a/cpukit/score/include/rtems/score/coresem.h +++ b/cpukit/score/include/rtems/score/coresem.h @@ -82,14 +82,7 @@ typedef enum { /** This status indicates that an attempt was made to unlock the semaphore * and this would have made its count greater than that allowed. */ - CORE_SEMAPHORE_MAXIMUM_COUNT_EXCEEDED, - /** This status indicates that the semaphore was not immediately - * available and the caller passed a bad timeout value to the API - * routine. In this case, the API required that the validity check - * for the timeout occur after the check that the semaphore was immediately - * available. - */ - CORE_SEMAPHORE_BAD_TIMEOUT_VALUE + CORE_SEMAPHORE_MAXIMUM_COUNT_EXCEEDED } CORE_semaphore_Status; /** @@ -123,25 +116,6 @@ typedef struct { } CORE_semaphore_Control; /** - * The following enumerated type is the set of blocking options - * available to seize operation. - */ -typedef enum { - /** This value indicates that the caller does not wish to block. */ - CORE_SEMAPHORE_NO_WAIT, - /** This value indicates that the caller is willing to block forever. */ - CORE_SEMAPHORE_BLOCK_FOREVER, - /** This value indicates that the caller is blocking with a timeout. */ - CORE_SEMAPHORE_BLOCK_WITH_TIMEOUT, - /** This value indicates that the caller wanted to block but passed in - * a bad timeout value to the API. Unfortunately, this is a weird case - * where the timeout bad error is required to be generated only if - * the semaphore is not available. - */ - CORE_SEMAPHORE_BAD_TIMEOUT -} Core_semaphore_Blocking_option; - -/** * This routine initializes the semaphore based on the parameters passed. * * @param[in] the_semaphore is the semaphore to initialize @@ -163,15 +137,15 @@ void _CORE_semaphore_Initialize( * @param[in] the_semaphore is the semaphore to seize * @param[in] id is the Id of the API level Semaphore object associated * with this instance of a SuperCore Semaphore - * @param[in] wait is the blocking mode + * @param[in] wait indicates if the caller is willing to block * @param[in] timeout is the number of ticks the calling thread is willing * to wait if @a wait is TRUE. */ void _CORE_semaphore_Seize( - CORE_semaphore_Control *the_semaphore, - Objects_Id id, - Core_semaphore_Blocking_option wait, - Watchdog_Interval timeout + CORE_semaphore_Control *the_semaphore, + Objects_Id id, + boolean wait, + Watchdog_Interval timeout ); /** diff --git a/cpukit/score/src/coremsgseize.c b/cpukit/score/src/coremsgseize.c index a71f1de794..e049b6e114 100644 --- a/cpukit/score/src/coremsgseize.c +++ b/cpukit/score/src/coremsgseize.c @@ -84,7 +84,7 @@ void _CORE_message_queue_Seize( *size = the_message->Contents.size; _Thread_Executing->Wait.count = the_message->priority; - _CORE_message_queue_Copy_buffer(the_message->Contents.buffer,buffer,*size); + _CORE_message_queue_Copy_buffer(the_message->Contents.buffer, buffer,*size); /* * There could be a thread waiting to send a message. If there @@ -107,7 +107,7 @@ void _CORE_message_queue_Seize( */ the_message->priority = the_thread->Wait.count; - the_message->Contents.size = (uint32_t )the_thread->Wait.return_argument_1; + the_message->Contents.size = (uint32_t)the_thread->Wait.option; _CORE_message_queue_Copy_buffer( the_thread->Wait.return_argument, the_message->Contents.buffer, diff --git a/cpukit/score/src/coresemseize.c b/cpukit/score/src/coresemseize.c index 693a19a713..779b24ca6a 100644 --- a/cpukit/score/src/coresemseize.c +++ b/cpukit/score/src/coresemseize.c @@ -51,10 +51,10 @@ */ void _CORE_semaphore_Seize( - CORE_semaphore_Control *the_semaphore, - Objects_Id id, - Core_semaphore_Blocking_option wait, - Watchdog_Interval timeout + CORE_semaphore_Control *the_semaphore, + Objects_Id id, + boolean wait, + Watchdog_Interval timeout ) { Thread_Control *executing; @@ -69,23 +69,20 @@ void _CORE_semaphore_Seize( return; } - switch ( wait ) { - case CORE_SEMAPHORE_NO_WAIT: - _ISR_Enable( level ); - executing->Wait.return_code = CORE_SEMAPHORE_STATUS_UNSATISFIED_NOWAIT; - return; - case CORE_SEMAPHORE_BAD_TIMEOUT: - _ISR_Enable( level ); - executing->Wait.return_code = CORE_SEMAPHORE_BAD_TIMEOUT_VALUE; - return; - case CORE_SEMAPHORE_BLOCK_FOREVER: - case CORE_SEMAPHORE_BLOCK_WITH_TIMEOUT: - _Thread_queue_Enter_critical_section( &the_semaphore->Wait_queue ); - executing->Wait.queue = &the_semaphore->Wait_queue; - executing->Wait.id = id; - _ISR_Enable( level ); - _Thread_queue_Enqueue( &the_semaphore->Wait_queue, timeout ); - break; + if ( !wait ) { + _ISR_Enable( level ); + executing->Wait.return_code = CORE_SEMAPHORE_STATUS_UNSATISFIED_NOWAIT; + return; } + /* + * If the semaphore is not available and the caller is willing to + * block, then we now block the caller with optional timeout. + */ + _Thread_queue_Enter_critical_section( &the_semaphore->Wait_queue ); + executing->Wait.queue = &the_semaphore->Wait_queue; + executing->Wait.id = id; + _ISR_Enable( level ); + _Thread_queue_Enqueue( &the_semaphore->Wait_queue, timeout ); + } |