summaryrefslogtreecommitdiffstats
path: root/cpukit/posix/src/timersettime.c
blob: 3c37e7bea34212560c774fdf5ce2b5f32b5b9989 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
/**
 * @file
 *
 * @brief Function Arms or Disarms the Timer Identified by timerid 
 * @ingroup POSIXAPI
 */

/*
 *  14.2.4 Per-Process Timers, P1003.1b-1993, p. 267
 *
 *  COPYRIGHT (c) 1989-2008.
 *  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.
 */

#if HAVE_CONFIG_H
#include "config.h"
#endif

#include <time.h>
#include <errno.h>

#include <rtems/posix/time.h>
#include <rtems/posix/ptimer.h>
#include <rtems/posix/timerimpl.h>
#include <rtems/score/todimpl.h>
#include <rtems/score/watchdogimpl.h>
#include <rtems/seterr.h>

int timer_settime(
  timer_t                  timerid,
  int                      flags,
  const struct itimerspec *__restrict value,
  struct itimerspec       *__restrict ovalue
)
{
  POSIX_Timer_Control *ptimer;
  Objects_Locations    location;
  bool                 activated;
  uint32_t             initial_period;
  struct itimerspec    normalize;

  if ( !value )
    rtems_set_errno_and_return_minus_one( EINVAL );

  /* 
   * First, it verifies if the structure "value" is correct   
   * if the number of nanoseconds is not correct return EINVAL
   */
  if ( !_Timespec_Is_valid( &(value->it_value) ) ) {
    rtems_set_errno_and_return_minus_one( EINVAL );
  }
  if ( !_Timespec_Is_valid( &(value->it_interval) ) ) {
    rtems_set_errno_and_return_minus_one( EINVAL );
  }

  if ( flags != TIMER_ABSTIME && flags != POSIX_TIMER_RELATIVE ) {
    rtems_set_errno_and_return_minus_one( EINVAL );
  }

  normalize = *value;

  /* Convert absolute to relative time */
  if (flags == TIMER_ABSTIME) {
    struct timespec now;
    _TOD_Get( &now );
    /* Check for seconds in the past */
    if ( _Timespec_Greater_than( &now, &normalize.it_value ) )
      rtems_set_errno_and_return_minus_one( EINVAL );
    _Timespec_Subtract( &now, &normalize.it_value, &normalize.it_value );
  }

  /* If the function reaches this point, then it will be necessary to do
   * something with the structure of times of the timer: to stop, start
   * or start it again
   */

  ptimer = _POSIX_Timer_Get( timerid, &location );
  switch ( location ) {

    case OBJECTS_LOCAL:
      /* First, it verifies if the timer must be stopped */
      if ( normalize.it_value.tv_sec == 0 && normalize.it_value.tv_nsec == 0 ) {
         /* Stop the timer */
         (void) _Watchdog_Remove( &ptimer->Timer );
         /* The old data of the timer are returned */
         if ( ovalue )
           *ovalue = ptimer->timer_data;
         /* The new data are set */
         ptimer->timer_data = normalize;
         /* Indicates that the timer is created and stopped */
         ptimer->state = POSIX_TIMER_STATE_CREATE_STOP;
         /* Returns with success */
        _Objects_Put( &ptimer->Object );
        return 0;
       }

       /* Convert from seconds and nanoseconds to ticks */
       ptimer->ticks  = _Timespec_To_ticks( &value->it_interval );
       initial_period = _Timespec_To_ticks( &normalize.it_value );


       activated = _POSIX_Timer_Insert_helper(
         &ptimer->Timer,
         initial_period,
         ptimer->Object.id,
         _POSIX_Timer_TSR,
         ptimer
       );
       if ( !activated ) {
         _Objects_Put( &ptimer->Object );
         return 0;
       }

       /*
        * The timer has been started and is running.  So we return the
        * old ones in "ovalue"
        */
       if ( ovalue )
         *ovalue = ptimer->timer_data;
       ptimer->timer_data = normalize;

       /* Indicate that the time is running */
       ptimer->state = POSIX_TIMER_STATE_CREATE_RUN;
       _TOD_Get( &ptimer->time );
      _Objects_Put( &ptimer->Object );
       return 0;

#if defined(RTEMS_MULTIPROCESSING)
    case OBJECTS_REMOTE:
#endif
    case OBJECTS_ERROR:
      break;
  }

  rtems_set_errno_and_return_minus_one( EINVAL );
}