source: rtems/cpukit/posix/src/nanosleep.c @ fa9f964f

5
Last change on this file since fa9f964f was d063e7b3, checked in by Sebastian Huber <sebastian.huber@…>, on 01/11/17 at 07:42:04

score: Replace STATES_DELAYING

Replace STATES_DELAYING with STATES_WAITING_FOR_TIME.

There is no need for separate timeout thread states. The
Thread_Control::Timer::header and Watchdog_Control::cpu members can be
used to figure out the kind of timeout.

  • Property mode set to 100644
File size: 5.8 KB
RevLine 
[d527562e]1/**
2 * @file
3 *
[d937d36]4 * @brief Suspends Execution of calling thread until Time elapses
[5cb175bb]5 * @ingroup POSIXAPI
[d527562e]6 */
7
[9f95a19]8/*
[d937d36]9 *  COPYRIGHT (c) 1989-2015.
[412dbff6]10 *  On-Line Applications Research Corporation (OAR).
[6e98ea91]11 *
12 *  Copyright (c) 2016. Gedare Bloom.
[412dbff6]13 *
14 *  The license and distribution terms for this file may be
15 *  found in the file LICENSE in this distribution or at
[c499856]16 *  http://www.rtems.org/license/LICENSE.
[9f95a19]17 */
18
[f42b726]19#if HAVE_CONFIG_H
20#include "config.h"
21#endif
22
[9f95a19]23#include <time.h>
24#include <errno.h>
25
[c6e21ee1]26#include <rtems/seterr.h>
[5618c37a]27#include <rtems/score/threadimpl.h>
[aa05cfbb]28#include <rtems/score/threadqimpl.h>
[c6e21ee1]29#include <rtems/score/timespec.h>
[4b48ece0]30#include <rtems/score/watchdogimpl.h>
[9f95a19]31
[aa05cfbb]32static Thread_queue_Control _Nanosleep_Pseudo_queue =
[1e1a91ed]33  THREAD_QUEUE_INITIALIZER( "Nanosleep" );
[aa05cfbb]34
[6e98ea91]35static inline int nanosleep_helper(
[709594f0]36  clockid_t             clock_id,
[e0f17fc]37  uint64_t              ticks,
[709594f0]38  struct timespec      *timeout,
[e0f17fc]39  struct timespec      *rmtp,
40  Watchdog_Discipline   discipline
[9f95a19]41)
42{
[125f248]43  Thread_queue_Context queue_context;
44  struct timespec      stop;
45  int                  err;
[9f95a19]46
[125f248]47  err = 0;
48
49  _Thread_queue_Context_initialize( &queue_context );
[620b23e]50  _Thread_queue_Context_set_thread_state(
51    &queue_context,
[d063e7b3]52    STATES_WAITING_FOR_TIME | STATES_INTERRUPTIBLE_BY_SIGNAL
[620b23e]53  );
[125f248]54  _Thread_queue_Context_set_enqueue_callout(
55    &queue_context,
56    _Thread_queue_Enqueue_do_nothing
57  );
58
59  if ( discipline == WATCHDOG_ABSOLUTE ) {
60    _Thread_queue_Context_set_absolute_timeout( &queue_context, ticks );
61  } else {
62    _Thread_queue_Context_set_relative_timeout( &queue_context, ticks );
63  }
[aa05cfbb]64
[812da54]65  /*
66   *  Block for the desired amount of time
67   */
[125f248]68  _Thread_queue_Acquire( &_Nanosleep_Pseudo_queue, &queue_context );
[a4217c6]69  _Thread_queue_Enqueue(
[125f248]70    &_Nanosleep_Pseudo_queue.Queue,
[1e1a91ed]71    &_Thread_queue_Operations_FIFO,
[125f248]72    _Thread_Executing,
73    &queue_context
[aa05cfbb]74  );
[9f95a19]75
[709594f0]76  clock_gettime( clock_id, &stop );
[d937d36]77  /*
78   * If the user wants the time remaining, do the conversion.
79   */
[709594f0]80  if ( _Timespec_Less_than( &stop, timeout ) ) {
[9f95a19]81    /*
[d937d36]82     *  If there is time remaining, then we were interrupted by a signal.
[9f95a19]83     */
[709594f0]84    err = EINTR;
85    if ( rmtp != NULL ) {
86      _Timespec_Subtract( &stop, timeout, rmtp );
87    }
88  } else if ( rmtp != NULL ) {
89    /* no time remaining */
90    _Timespec_Set_to_zero( rmtp );
91  }
[9f95a19]92
[709594f0]93  return err;
[9f95a19]94}
[39d97ab]95
96/*
97 * A nanosleep for zero time is implemented as a yield.
98 * This behavior is also beyond the POSIX specification but is
99 * consistent with the RTEMS API and yields desirable behavior.
100 */
101static inline int nanosleep_yield( struct timespec *rmtp )
102{
103  /*
104   * It is critical to obtain the executing thread after thread dispatching is
105   * disabled on SMP configurations.
106   */
107  Thread_Control  *executing;
108  Per_CPU_Control *cpu_self;
109
110  executing = _Thread_Get_executing();
111  cpu_self = _Thread_Dispatch_disable();
112  _Thread_Yield( executing );
[d78d529]113  _Thread_Dispatch_direct( cpu_self );
[39d97ab]114  if ( rmtp ) {
115    rmtp->tv_sec = 0;
116    rmtp->tv_nsec = 0;
117  }
118  return 0;
119}
120
[6e98ea91]121/*
122 *  14.2.5 High Resolution Sleep, P1003.1b-1993, p. 269
123 */
124int nanosleep(
125  const struct timespec  *rqtp,
126  struct timespec        *rmtp
127)
128{
[e0f17fc]129  int err;
[39d97ab]130  struct timespec now;
[e0f17fc]131  uint64_t ticks;
[39d97ab]132  Watchdog_Interval relative_interval;
[e0f17fc]133
134  /*
135   *  Return EINVAL if the delay interval is negative.
136   *
137   *  NOTE:  This behavior is beyond the POSIX specification.
138   *         FSU and GNU/Linux pthreads shares this behavior.
139   */
[dfa2cdb]140  if ( !_Timespec_Is_valid( rqtp ) ) {
141    rtems_set_errno_and_return_minus_one( EINVAL );
142  }
[e0f17fc]143
[39d97ab]144  relative_interval = _Timespec_To_ticks( rqtp );
145  if ( relative_interval == 0 )
146    return nanosleep_yield( rmtp );
147
[e0f17fc]148 /* CLOCK_REALTIME can be adjusted during the timeout,
149  * so convert to an absolute timeout value and put the
150  * thread on the WATCHDOG_ABSOLUTE threadq. */
[39d97ab]151  err = clock_gettime( CLOCK_REALTIME, &now );
[e0f17fc]152  if ( err != 0 )
153    return -1;
[39d97ab]154  _Timespec_Add_to( &now, rqtp );
155  ticks = _Watchdog_Ticks_from_timespec( &now );
[709594f0]156  err = nanosleep_helper( CLOCK_REALTIME,
157      ticks,
158      &now,
159      rmtp,
160      WATCHDOG_ABSOLUTE
161  );
[e0f17fc]162  if ( err != 0 ) {
[6e98ea91]163    rtems_set_errno_and_return_minus_one( err );
164  }
165  return 0;
166}
167
168/*
169 * High Resolution Sleep with Specifiable Clock, IEEE Std 1003.1, 2001
170 */
171int clock_nanosleep(
172  clockid_t               clock_id,
173  int                     flags,
174  const struct timespec  *rqtp,
175  struct timespec        *rmtp
176)
177{
178  int err = 0;
[709594f0]179  struct timespec timeout;
[e0f17fc]180  uint64_t ticks;
[39d97ab]181  Watchdog_Interval relative_interval;
[e0f17fc]182  TOD_Absolute_timeout_conversion_results status;
183
184  if ( !_Timespec_Is_valid( rqtp ) )
185    return EINVAL;
186
[39d97ab]187  /* get relative ticks of the requested timeout */
[e0f17fc]188  if ( flags & TIMER_ABSTIME ) {
189    /* See if absolute time already passed */
[39d97ab]190    status = _TOD_Absolute_timeout_to_ticks(rqtp, clock_id, &relative_interval);
[e0f17fc]191    if ( status == TOD_ABSOLUTE_TIMEOUT_INVALID )
192      return EINVAL;
[39d97ab]193    if ( status == TOD_ABSOLUTE_TIMEOUT_IS_IN_PAST )
[e0f17fc]194      return 0;
[39d97ab]195    if ( status == TOD_ABSOLUTE_TIMEOUT_IS_NOW )
196      return nanosleep_yield( NULL );
[e0f17fc]197    rmtp = NULL; /* Do not touch rmtp when using absolute time */
[709594f0]198    timeout.tv_sec = 0;
199    timeout.tv_nsec = 0;
[e0f17fc]200  } else {
[709594f0]201    /* prepare to convert relative ticks to absolute timeout */
202    err = clock_gettime( clock_id, &timeout );
203    if ( err != 0 )
204      return EINVAL;
[39d97ab]205    relative_interval = _Timespec_To_ticks( rqtp );
[e0f17fc]206  }
[39d97ab]207  if ( relative_interval == 0 )
208    return nanosleep_yield( rmtp );
[e0f17fc]209
[709594f0]210  _Timespec_Add_to( &timeout, rqtp );
[e0f17fc]211  if ( clock_id == CLOCK_REALTIME ) {
[709594f0]212    ticks = _Watchdog_Ticks_from_timespec( &timeout );
213    err = nanosleep_helper(
214        clock_id,
215        ticks,
216        &timeout,
217        rmtp,
218        WATCHDOG_ABSOLUTE
219    );
[e0f17fc]220  } else if ( clock_id == CLOCK_MONOTONIC ) {
221    /* use the WATCHDOG_RELATIVE to ignore changes in wall time */
[39d97ab]222    err = nanosleep_helper(
[709594f0]223        clock_id,
[39d97ab]224        relative_interval,
[709594f0]225        &timeout,
[39d97ab]226        rmtp,
227        WATCHDOG_RELATIVE
228    );
[6e98ea91]229  } else {
230    err = ENOTSUP;
231  }
232  return err;
233}
Note: See TracBrowser for help on using the repository browser.