Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:24:21

0001 /* SPDX-License-Identifier: BSD-2-Clause */
0002 
0003 /**
0004  * @file
0005  *
0006  * @ingroup POSIXAPI
0007  *
0008  * @brief Suspends Execution of calling thread until Time elapses
0009  */
0010 
0011 /*
0012  *  COPYRIGHT (c) 1989-2015.
0013  *  On-Line Applications Research Corporation (OAR).
0014  * 
0015  *  Copyright (c) 2016. Gedare Bloom.
0016  *
0017  * Redistribution and use in source and binary forms, with or without
0018  * modification, are permitted provided that the following conditions
0019  * are met:
0020  * 1. Redistributions of source code must retain the above copyright
0021  *    notice, this list of conditions and the following disclaimer.
0022  * 2. Redistributions in binary form must reproduce the above copyright
0023  *    notice, this list of conditions and the following disclaimer in the
0024  *    documentation and/or other materials provided with the distribution.
0025  *
0026  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0027  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0028  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0029  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
0030  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
0031  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
0032  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0033  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
0034  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
0035  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
0036  * POSSIBILITY OF SUCH DAMAGE.
0037  */
0038 
0039 #ifdef HAVE_CONFIG_H
0040 #include "config.h"
0041 #endif
0042 
0043 #include <time.h>
0044 
0045 #include <rtems/score/threadimpl.h>
0046 #include <rtems/score/threadqimpl.h>
0047 #include <rtems/score/timespec.h>
0048 #include <rtems/score/timecounter.h>
0049 #include <rtems/score/watchdogimpl.h>
0050 #include <rtems/posix/posixapi.h>
0051 
0052 static Thread_queue_Control _Nanosleep_Pseudo_queue =
0053   THREAD_QUEUE_INITIALIZER( "Nanosleep" );
0054 
0055 /*
0056  * High Resolution Sleep with Specifiable Clock, IEEE Std 1003.1, 2001
0057  */
0058 int clock_nanosleep(
0059   clockid_t               clock_id,
0060   int                     flags,
0061   const struct timespec  *rqtp,
0062   struct timespec        *rmtp
0063 )
0064 {
0065   Thread_queue_Context queue_context;
0066   bool                 absolute;
0067   Thread_Control      *executing;
0068   int                  eno;
0069 
0070   if ( clock_id != CLOCK_REALTIME && clock_id != CLOCK_MONOTONIC ) {
0071     return ENOTSUP;
0072   }
0073 
0074   _Thread_queue_Context_initialize( &queue_context );
0075   _Thread_queue_Context_set_thread_state(
0076     &queue_context,
0077     STATES_WAITING_FOR_TIME | STATES_INTERRUPTIBLE_BY_SIGNAL
0078   );
0079 
0080   if ( ( flags & TIMER_ABSTIME ) != 0 ) {
0081     absolute = true;
0082     rmtp = NULL;
0083   } else {
0084     absolute = false;
0085 
0086     /*
0087      * A relative CLOCK_REALTIME time out shall not be affected by
0088      * CLOCK_REALTIME changes through clock_settime().  Since our
0089      * CLOCK_REALTIME is basically just CLOCK_MONOTONIC plus an offset, we can
0090      * simply use the CLOCK_MONOTONIC watchdog for relative CLOCK_REALTIME time
0091      * outs.
0092      */
0093     clock_id = CLOCK_MONOTONIC;
0094   }
0095 
0096   if ( clock_id == CLOCK_REALTIME ) {
0097     _Thread_queue_Context_set_enqueue_timeout_realtime_timespec(
0098       &queue_context,
0099       rqtp,
0100       absolute
0101     );
0102   } else {
0103     _Thread_queue_Context_set_enqueue_timeout_monotonic_timespec(
0104       &queue_context,
0105       rqtp,
0106       absolute
0107     );
0108   }
0109 
0110   _Thread_queue_Acquire( &_Nanosleep_Pseudo_queue, &queue_context );
0111   executing = _Thread_Executing;
0112   _Thread_queue_Enqueue(
0113     &_Nanosleep_Pseudo_queue.Queue,
0114     &_Thread_queue_Operations_FIFO,
0115     executing,
0116     &queue_context
0117   );
0118   eno = _POSIX_Get_error_after_wait( executing );
0119 
0120   if ( eno == ETIMEDOUT ) {
0121     eno = 0;
0122   }
0123 
0124   if ( rmtp != NULL ) {
0125 #if defined( RTEMS_POSIX_API )
0126     if ( eno == EINTR ) {
0127       struct timespec actual_end;
0128       struct timespec planned_end;
0129 
0130       _Assert( clock_id == CLOCK_MONOTONIC );
0131       _Timecounter_Nanouptime( &actual_end );
0132 
0133       _Watchdog_Ticks_to_timespec(
0134         executing->Timer.Watchdog.expire,
0135         &planned_end
0136       );
0137 
0138       if ( _Timespec_Less_than( &actual_end, &planned_end ) ) {
0139         _Timespec_Subtract( &actual_end, &planned_end, rmtp );
0140       } else {
0141         _Timespec_Set_to_zero( rmtp );
0142       }
0143     } else {
0144       _Timespec_Set_to_zero( rmtp );
0145     }
0146 #else
0147     _Assert( eno != EINTR );
0148     _Timespec_Set_to_zero( rmtp );
0149 #endif
0150   }
0151 
0152   return eno;
0153 }