source: rtems/cpukit/posix/src/time.c @ 8959fcc

4.104.114.84.95
Last change on this file since 8959fcc was 52d99d4a, checked in by Joel Sherrill <joel.sherrill@…>, on 01/28/97 at 23:33:22

Switch to using newlib's implementation of time().

  • Property mode set to 100644
File size: 7.9 KB
Line 
1/*
2 *  $Id$
3 */
4
5#include <assert.h>
6#include <time.h>
7#include <errno.h>
8
9#include <rtems/system.h>
10#include <rtems/score/isr.h>
11#include <rtems/score/thread.h>
12#include <rtems/score/tod.h>
13
14#include <rtems/posix/seterr.h>
15#include <rtems/posix/time.h>
16
17/*PAGE
18 *
19 *  _POSIX_Timespec_subtract
20 */
21
22void _POSIX_Timespec_subtract(
23  const struct timespec *the_start,
24  const struct timespec *end,
25  struct timespec *result
26)
27{
28  struct timespec  start_struct = *the_start;
29  struct timespec *start = &start_struct;
30  unsigned int nsecs_per_sec = TOD_NANOSECONDS_PER_SECOND;
31 
32  if (end->tv_nsec < start->tv_nsec) {
33    int seconds = (start->tv_nsec - end->tv_nsec) / nsecs_per_sec + 1;
34    start->tv_nsec -= nsecs_per_sec * seconds;
35    start->tv_sec += seconds;
36  }
37 
38  if (end->tv_nsec - start->tv_nsec > nsecs_per_sec) {
39    int seconds = (start->tv_nsec - end->tv_nsec) / nsecs_per_sec;
40    start->tv_nsec += nsecs_per_sec * seconds;
41    start->tv_sec -= seconds;
42  }
43 
44  result->tv_sec  = end->tv_sec - start->tv_sec;
45  result->tv_nsec = end->tv_nsec - start->tv_nsec;
46}
47
48/*PAGE
49 *
50 *  _POSIX_Timespec_to_interval
51 */
52
53Watchdog_Interval _POSIX_Timespec_to_interval(
54  const struct timespec *time
55)
56{
57  Watchdog_Interval  ticks;
58
59  ticks  = (time->tv_sec * TOD_MICROSECONDS_PER_SECOND) /
60             _TOD_Microseconds_per_tick;
61
62  ticks += (time->tv_nsec / TOD_NANOSECONDS_PER_MICROSECOND) /
63             _TOD_Microseconds_per_tick;
64
65  return ticks;
66}
67
68/*PAGE
69 *
70 *  _POSIX_Interval_to_timespec
71 */
72 
73void _POSIX_Interval_to_timespec(
74  Watchdog_Interval  ticks,
75  struct timespec   *time
76)
77{
78  unsigned32  usecs;
79
80  usecs = ticks * _TOD_Microseconds_per_tick;
81
82  time->tv_sec  = usecs / TOD_MICROSECONDS_PER_SECOND;
83  time->tv_nsec = (usecs % TOD_MICROSECONDS_PER_SECOND) *
84                    TOD_NANOSECONDS_PER_MICROSECOND;
85}
86
87/*PAGE
88 *
89 *  4.5.1 Get System Time, P1003.1b-1993, p. 91
90 */
91
92/* Using the implementation in newlib */
93#if 0
94time_t time(
95  time_t   *tloc
96)
97{
98  time_t  seconds_since_epoch;
99
100  /*
101   *  No error is the time of day is not set.   For RTEMS the system time
102   *  starts out at the rtems epoch.
103   */
104
105  /*
106   *  Internally the RTEMS epoch is 1988.  This must be taken into account.
107   */
108
109  seconds_since_epoch = _TOD_Seconds_since_epoch;
110     
111  seconds_since_epoch += POSIX_TIME_SECONDS_1970_THROUGH_1988;
112
113  if ( tloc )
114    *tloc = seconds_since_epoch;
115
116  return seconds_since_epoch;
117}
118#endif
119
120/*PAGE
121 *
122 *  14.2.1 Clocks, P1003.1b-1993, p. 263
123 */
124
125int clock_settime(
126  clockid_t              clock_id,
127  const struct timespec *tp
128)
129{
130  struct tm         split_time;
131  TOD_Control       tod;
132  Watchdog_Interval seconds;
133
134  assert( tp );
135
136  switch ( clock_id ) {
137 
138    case CLOCK_REALTIME:
139      (void) gmtime_r( &tp->tv_sec, &split_time );
140 
141      /*
142       *  Convert the tm structure format to that used by the TOD Handler
143       *
144       *  NOTE: TOD Handler does not honor leap seconds.
145       */
146
147      tod.year   = split_time.tm_year + 1900;  /* RHS is years since 1900 */
148      tod.month  = split_time.tm_mon + 1;      /* RHS uses 0-11 */
149      tod.day    = split_time.tm_mday;
150      tod.hour   = split_time.tm_hour;
151      tod.minute = split_time.tm_min;
152      tod.second = split_time.tm_sec;  /* RHS allows 0-61 for leap seconds */
153
154      tod.ticks  = (tp->tv_nsec / TOD_NANOSECONDS_PER_MICROSECOND) /
155                      _TOD_Microseconds_per_tick;
156
157      if ( !_TOD_Validate( &tod ) )
158        set_errno_and_return_minus_one( EINVAL );
159 
160      /*
161       *  We can't use the tp->tv_sec field because it is based on
162       *  a different EPOCH.
163       */
164
165      seconds = _TOD_To_seconds( &tod );
166      _Thread_Disable_dispatch();
167        _TOD_Set( &tod, seconds );
168      _Thread_Enable_dispatch();
169      break;
170 
171#ifdef _POSIX_CPUTIME
172    case CLOCK_PROCESS_CPUTIME:
173      return POSIX_NOT_IMPLEMENTED();
174      break;
175#endif
176 
177#ifdef _POSIX_THREAD_CPUTIME
178    case CLOCK_THREAD_CPUTIME:
179      return POSIX_NOT_IMPLEMENTED();
180      break;
181#endif
182    default:
183      set_errno_and_return_minus_one( EINVAL );
184 
185  }
186  return 0;
187}
188
189/*PAGE
190 *
191 *  14.2.1 Clocks, P1003.1b-1993, p. 263
192 */
193
194int clock_gettime(
195  clockid_t        clock_id,
196  struct timespec *tp
197)
198{
199  ISR_Level      level;
200  time_t         seconds;
201  long           ticks;
202
203  if ( !tp )
204    set_errno_and_return_minus_one( EINVAL );
205
206  switch ( clock_id ) {
207
208    case CLOCK_REALTIME:
209 
210      _ISR_Disable( level );
211        seconds = _TOD_Seconds_since_epoch;
212        ticks   = _TOD_Current.ticks;
213      _ISR_Enable( level );
214 
215      tp->tv_sec  = seconds + POSIX_TIME_SECONDS_1970_THROUGH_1988;
216      tp->tv_nsec = ticks * _TOD_Microseconds_per_tick *
217                      TOD_NANOSECONDS_PER_MICROSECOND;
218      break;
219
220#ifdef _POSIX_CPUTIME
221    case CLOCK_PROCESS_CPUTIME:
222      /* don't base this on _Watchdog_Ticks_since_boot--duration is too short*/
223      return POSIX_NOT_IMPLEMENTED();
224      break;
225#endif
226
227#ifdef _POSIX_THREAD_CPUTIME
228    case CLOCK_THREAD_CPUTIME:
229      return POSIX_NOT_IMPLEMENTED();
230      break;
231#endif
232    default:
233      set_errno_and_return_minus_one( EINVAL );
234
235  }
236  return 0;
237}
238
239/*PAGE
240 *
241 *  14.2.1 Clocks, P1003.1b-1993, p. 263
242 */
243
244int clock_getres(
245  clockid_t        clock_id,
246  struct timespec *res
247)
248{
249  if ( !res )
250    set_errno_and_return_minus_one( EINVAL );
251 
252  switch ( clock_id ) {
253 
254    /*
255     *  All time in rtems is based on the same clock tick.
256     */
257
258    case CLOCK_REALTIME:
259    case CLOCK_PROCESS_CPUTIME:
260    case CLOCK_THREAD_CPUTIME:
261      if ( res )
262        _POSIX_Interval_to_timespec( _TOD_Microseconds_per_tick, res );
263      break;
264 
265    default:
266      set_errno_and_return_minus_one( EINVAL );
267 
268  }
269  return 0;
270}
271
272/*PAGE
273 *
274 *  14.2.5 High Resolution Sleep, P1003.1b-1993, p. 269
275 */
276
277int nanosleep(
278  const struct timespec  *rqtp,
279  struct timespec        *rmtp
280)
281{
282  Watchdog_Interval  ticks;
283  struct timespec   *the_rqtp;
284
285  if ( !rqtp )
286    set_errno_and_return_minus_one( EINVAL );
287
288  the_rqtp = (struct timespec *)rqtp;
289
290  /*
291   *  Return EAGAIN if the delay interval is negative. 
292   *
293   *  NOTE:  This behavior is beyond the POSIX specification. 
294   *         FSU pthreads shares this behavior.
295   */
296
297  if ( the_rqtp->tv_sec < 0 )
298    the_rqtp->tv_sec = 0;
299
300  if ( /* the_rqtp->tv_sec < 0 || */ the_rqtp->tv_nsec < 0 )
301    set_errno_and_return_minus_one( EAGAIN );
302
303  if ( the_rqtp->tv_nsec >= TOD_NANOSECONDS_PER_SECOND )
304    set_errno_and_return_minus_one( EINVAL );
305 
306  ticks = _POSIX_Timespec_to_interval( the_rqtp );
307
308  /*
309   *  This behavior is also beyond the POSIX specification but is
310   *  consistent with the RTEMS api and yields desirable behavior.
311   */
312
313  if ( !ticks ) {
314    _Thread_Yield_processor();
315    _Thread_Dispatch();
316    if ( rmtp ) {
317       rmtp->tv_sec = 0;
318       rmtp->tv_nsec = 0;
319    }
320    return 0;
321  }
322 
323  _Thread_Disable_dispatch();
324    _Thread_Set_state(
325      _Thread_Executing,
326      STATES_DELAYING | STATES_INTERRUPTIBLE_BY_SIGNAL
327    );
328    _Watchdog_Initialize(
329      &_Thread_Executing->Timer,
330      _Thread_Delay_ended,
331      _Thread_Executing->Object.id,
332      NULL
333    );
334    _Watchdog_Insert_ticks( &_Thread_Executing->Timer, ticks );
335  _Thread_Enable_dispatch();
336
337  /* calculate time remaining */
338
339  if ( rmtp ) {
340    ticks -=
341      _Thread_Executing->Timer.stop_time - _Thread_Executing->Timer.start_time;
342
343    _POSIX_Interval_to_timespec( ticks, rmtp );
344
345    /*
346     *  If there is time remaining, then we were interrupted by a signal.
347     */
348
349    if ( ticks )
350      set_errno_and_return_minus_one( EINTR );
351  }
352
353  return 0;
354}
355
356/*PAGE
357 *
358 *  20.1.3 Accessing a Process CPU-time CLock, P1003.4b/D8, p. 55
359 */
360
361int clock_getcpuclockid(
362  pid_t      pid,
363  clockid_t *clock_id
364)
365{
366  return POSIX_NOT_IMPLEMENTED();
367}
368
369/*PAGE
370 *
371 *  20.1.5 CPU-time Clock Attribute Access, P1003.4b/D8, p. 58
372 */
373
374int clock_setenable_attr(
375  clockid_t    clock_id,
376  int          attr
377)
378{
379  return POSIX_NOT_IMPLEMENTED();
380}
381
382/*PAGE
383 *
384 *  20.1.5 CPU-time Clock Attribute Access, P1003.4b/D8, p. 58
385 */
386
387int clock_getenable_attr(
388  clockid_t    clock_id,
389  int         *attr
390)
391{
392  return POSIX_NOT_IMPLEMENTED();
393}
Note: See TracBrowser for help on using the repository browser.