summaryrefslogtreecommitdiffstats
path: root/cpukit/posix/src/nanosleep.c
diff options
context:
space:
mode:
authorGedare Bloom <gedare@rtems.org>2016-07-15 12:52:05 -0400
committerGedare Bloom <gedare@rtems.org>2016-07-25 12:44:48 -0400
commite0f17fcf6f06d3383cd389d809ee4e3d6e0fb14d (patch)
treef361e40fd965fa80d63330b0c50ca7549a87ee93 /cpukit/posix/src/nanosleep.c
parentposix: cond_timedwait remember and use clock from condattr (diff)
downloadrtems-e0f17fcf6f06d3383cd389d809ee4e3d6e0fb14d.tar.bz2
posix: fix clock_nanosleep and nanosleep clock use
Sleeping with CLOCK_REALTIME should use the WATCHDOG_ABSOLUTE clock discipline for the threadq so that the timeout interval may change in case the clock source changes. Similarly, CLOCK_MONOTONIC uses the WATCHDOG_RELATIVE threadq that will only wakeup the thread after the requested count of ticks elapse. updates #2732
Diffstat (limited to 'cpukit/posix/src/nanosleep.c')
-rw-r--r--cpukit/posix/src/nanosleep.c93
1 files changed, 68 insertions, 25 deletions
diff --git a/cpukit/posix/src/nanosleep.c b/cpukit/posix/src/nanosleep.c
index e60dd53ebc..5a3db2a220 100644
--- a/cpukit/posix/src/nanosleep.c
+++ b/cpukit/posix/src/nanosleep.c
@@ -33,9 +33,9 @@ static Thread_queue_Control _Nanosleep_Pseudo_queue =
THREAD_QUEUE_INITIALIZER( "Nanosleep" );
static inline int nanosleep_helper(
- const struct timespec *rqtp,
- struct timespec *rmtp,
- Watchdog_Discipline discipline
+ uint64_t ticks,
+ struct timespec *rmtp,
+ Watchdog_Discipline discipline
)
{
/*
@@ -45,25 +45,9 @@ static inline int nanosleep_helper(
Thread_Control *executing;
Per_CPU_Control *cpu_self;
- Watchdog_Interval ticks;
Watchdog_Interval start;
Watchdog_Interval elapsed;
-
- /*
- * Return EINVAL if the delay interval is negative.
- *
- * NOTE: This behavior is beyond the POSIX specification.
- * FSU and GNU/Linux pthreads shares this behavior.
- */
- if ( !_Timespec_Is_valid( rqtp ) )
- return EINVAL;
-
- /*
- * Convert the timespec delay into the appropriate number of clock ticks.
- */
- ticks = _Timespec_To_ticks( rqtp );
-
executing = _Thread_Get_executing();
/*
@@ -110,7 +94,7 @@ static inline int nanosleep_helper(
/*
* If the user wants the time remaining, do the conversion.
*/
- if ( rmtp && discipline == WATCHDOG_RELATIVE ) {
+ if ( rmtp ) {
_Timespec_From_ticks( ticks, rmtp );
}
@@ -135,8 +119,30 @@ int nanosleep(
struct timespec *rmtp
)
{
- int err = nanosleep_helper(rqtp, rmtp, WATCHDOG_RELATIVE);
- if (err) {
+ int err;
+ struct timespec timeout;
+ uint64_t ticks;
+
+ /*
+ * Return EINVAL if the delay interval is negative.
+ *
+ * NOTE: This behavior is beyond the POSIX specification.
+ * FSU and GNU/Linux pthreads shares this behavior.
+ */
+ if ( !_Timespec_Is_valid( rqtp ) )
+ return EINVAL;
+
+ /* CLOCK_REALTIME can be adjusted during the timeout,
+ * so convert to an absolute timeout value and put the
+ * thread on the WATCHDOG_ABSOLUTE threadq. */
+ err = clock_gettime( CLOCK_REALTIME, &timeout );
+ if ( err != 0 )
+ return -1;
+
+ _Timespec_Add_to( &timeout, rqtp );
+ ticks = _Watchdog_Ticks_from_timespec( &timeout );
+ err = nanosleep_helper(ticks, rmtp, WATCHDOG_ABSOLUTE );
+ if ( err != 0 ) {
rtems_set_errno_and_return_minus_one( err );
}
return 0;
@@ -153,12 +159,49 @@ int clock_nanosleep(
)
{
int err = 0;
- if ( clock_id == CLOCK_REALTIME || clock_id == CLOCK_MONOTONIC ) {
+ struct timespec absolute_timeout;
+ uint64_t ticks;
+ Watchdog_Interval relative_ticks;
+ TOD_Absolute_timeout_conversion_results status;
+
+ /*
+ * Return EINVAL if the delay interval is negative.
+ *
+ * NOTE: This behavior is beyond the POSIX specification.
+ * FSU and GNU/Linux pthreads shares this behavior.
+ */
+ if ( !_Timespec_Is_valid( rqtp ) )
+ return EINVAL;
+
+ if ( flags & TIMER_ABSTIME ) {
+ /* See if absolute time already passed */
+ status = _TOD_Absolute_timeout_to_ticks(rqtp, clock_id, &relative_ticks);
+ if ( status == TOD_ABSOLUTE_TIMEOUT_INVALID )
+ return EINVAL;
+ if ( status == TOD_ABSOLUTE_TIMEOUT_IS_IN_PAST ||
+ status == TOD_ABSOLUTE_TIMEOUT_IS_NOW ) {
+ return 0;
+ }
+ rmtp = NULL; /* Do not touch rmtp when using absolute time */
+ } else {
+ relative_ticks = _Timespec_To_ticks(rqtp);
+ }
+
+ if ( clock_id == CLOCK_REALTIME ) {
if ( flags & TIMER_ABSTIME ) {
- err = nanosleep_helper(rqtp, rmtp, WATCHDOG_ABSOLUTE);
+ ticks = _Watchdog_Ticks_from_timespec(rqtp);
} else {
- err = nanosleep_helper(rqtp, rmtp, WATCHDOG_RELATIVE);
+ err = clock_gettime( CLOCK_REALTIME, &absolute_timeout );
+ if ( err != 0 ) {
+ return EINVAL;
+ }
+ _Timespec_Add_to( &absolute_timeout, rqtp );
+ ticks = _Watchdog_Ticks_from_timespec( &absolute_timeout );
}
+ err = nanosleep_helper( ticks, rmtp, WATCHDOG_ABSOLUTE );
+ } else if ( clock_id == CLOCK_MONOTONIC ) {
+ /* use the WATCHDOG_RELATIVE to ignore changes in wall time */
+ err = nanosleep_helper( relative_ticks, rmtp, WATCHDOG_RELATIVE );
} else {
err = ENOTSUP;
}