source: rtems/cpukit/posix/src/ptimer1.c @ 0243b0d

4.104.114.84.9
Last change on this file since 0243b0d was 0243b0d, checked in by Joel Sherrill <joel.sherrill@…>, on Jun 8, 2006 at 8:47:48 PM

2006-06-08 Joel Sherrill <joel@…>

  • posix/Makefile.am, posix/preinstall.am, posix/include/rtems/posix/timer.h, posix/src/ptimer.c, posix/src/ptimer1.c, sapi/src/posixapi.c, score/include/rtems/score/object.h:
  • Property mode set to 100644
File size: 15.5 KB
RevLine 
[68003979]1/*
2 *  ptimer.c,v 1.1 1996/06/03 16:29:58 joel Exp
3 */
[f42b726]4
5#if HAVE_CONFIG_H
6#include "config.h"
7#endif
[874297f3]8
[68003979]9#include <assert.h>
10#include <time.h>
11#include <errno.h>
12
13#include <rtems/system.h>
14#include <rtems/score/isr.h>
15#include <rtems/score/thread.h>
16#include <rtems/score/tod.h>
17
18#include <rtems/posix/time.h>
19
20/************************************/
21/* These includes are now necessary */
22/************************************/
23
[0ff3df03]24#include <unistd.h>
[68003979]25#include <rtems/rtems/status.h>
26#include <rtems/rtems/types.h>
27#include <rtems/rtems/timer.h>
28#include <rtems/rtems/clock.h>
29#include <rtems/posix/psignal.h>
30#include <pthread.h>
31#include <stdio.h>
32#include <signal.h>
33
[188c82b]34#include <rtems/seterr.h>
[68003979]35#include <rtems/posix/timer.h>
36
[0243b0d]37boolean _Watchdog_Insert_ticks_helper(
38  Watchdog_Control               *timer,
39  Watchdog_Interval               ticks,
40  Objects_Id                      id,
41  Watchdog_Service_routine_entry  TSR,
42  void                           *arg
43)
[68003979]44{
[0243b0d]45  ISR_Level            level;
46
47  (void) _Watchdog_Remove( timer );
48  _ISR_Disable( level );
49
50    /*
51     *  Check to see if the watchdog has just been inserted by a
52     *  higher priority interrupt.  If so, abandon this insert.
53     */
54    if ( timer->state != WATCHDOG_INACTIVE ) {
55      _ISR_Enable( level );
56      return FALSE;
57    }
[68003979]58
[0243b0d]59    /*
60     *  OK.  Now we now the timer was not rescheduled by an interrupt
61     *  so we can atomically initialize it as in use.
62     */
63    _Watchdog_Initialize( timer, TSR, id, arg );
64    _Watchdog_Insert_ticks( timer, ticks );
65  _ISR_Enable( level );
66  return TRUE;
[68003979]67}
68
[0243b0d]69/* #define DEBUG_MESSAGES */
[68003979]70
[0243b0d]71/*
[874297f3]72 * ITIMERSPEC_TO_RTEMS_TIME_OF_DAY_S
[68003979]73 *
[874297f3]74 *  Description: This function converts the data of a structure itimerspec
75 *               into structure rtems_time_of_day
[0243b0d]76  */
[68003979]77
[0243b0d]78void ITIMERSPEC_TO_RTEMS_TIME_OF_DAY_S(
79  const struct itimerspec *itimer,
80  rtems_time_of_day *rtems_time
81)
[68003979]82{
83   unsigned long int seconds;
84
85   /* The leap years and the months with 28, 29 or 31 days have not been
[0243b0d]86    * considered. It will be made in the future */
[68003979]87
88   seconds            = itimer->it_value.tv_sec;
89
90   rtems_time->year   = seconds / SECONDS_PER_YEAR_C;
91   seconds            = seconds % SECONDS_PER_YEAR_C;
92
93   rtems_time->month  = seconds / SECONDS_PER_MONTH_C;
94   seconds            = seconds % SECONDS_PER_MONTH_C;
95
96   rtems_time->day    = seconds / SECONDS_PER_DAY_C;
97   seconds            = seconds % SECONDS_PER_DAY_C;
98
99   rtems_time->hour   = seconds / SECONDS_PER_HOUR_C;
100   seconds            = seconds % SECONDS_PER_HOUR_C;
101
102   rtems_time->minute = seconds / SECONDS_PER_MINUTE_C;
103   seconds            = seconds % SECONDS_PER_MINUTE_C;
104
105   rtems_time->second = seconds;
106
[7210dcb4]107   rtems_time->ticks  = itimer->it_value.tv_nsec/
108                        (NSEC_PER_SEC_C / SEC_TO_TICKS_C);
[68003979]109
110}
111
112
113/* ***************************************************************************
[0243b0d]114 * _POSIX_Timer_TSR
[68003979]115 *
116 *  Description: This is the operation that is ran when a timer expires
117 * ***************************************************************************/
118
119
[0243b0d]120void _POSIX_Timer_TSR(Objects_Id timer, void *data)
[68003979]121{
[0243b0d]122  POSIX_Timer_Control *ptimer;
123  boolean              activated;
124
125  ptimer = (POSIX_Timer_Control *)data;
126
127  /* Increment the number of expirations. */
128  ptimer->overrun = ptimer->overrun + 1;
129  /* The timer must be reprogrammed */
130  if ( ( ptimer->timer_data.it_interval.tv_sec  != 0 ) ||
131       ( ptimer->timer_data.it_interval.tv_nsec != 0 ) ) {
132#if 0
133    status = rtems_timer_fire_after(
134         ptimer->timer_id, ptimer->ticks, _POSIX_Timer_TSR, ptimer );
135#endif
136    activated = _Watchdog_Insert_ticks_helper(
137      &ptimer->Timer,
138      ptimer->ticks,
139      ptimer->Object.id,
140      _POSIX_Timer_TSR,
141      ptimer
142    );
143    if ( !activated )
144      return;
145
146    /* Store the time when the timer was started again */
147    ptimer->time = _TOD_Current;
148
149    /* The state really did not change but just to be safe */
150    ptimer->state = STATE_CREATE_RUN_C;
[68003979]151  } else {
[0243b0d]152   /* Indicates that the timer is stopped */
153   ptimer->state = STATE_CREATE_STOP_C;
[68003979]154  }
155
[874297f3]156  /*
[68003979]157   * The sending of the signal to the process running the handling function
158   * specified for that signal is simulated
159   */
160
[0243b0d]161  if ( pthread_kill ( ptimer->thread_id, ptimer->inf.sigev_signo ) ) {
162    /* XXX error handling */
[874297f3]163  }
[68003979]164
[0243b0d]165  /* After the signal handler returns, the count of expirations of the
[68003979]166   * timer must be set to 0.
167   */
[0243b0d]168  ptimer->overrun = 0;
[68003979]169}
170
[874297f3]171/* *********************************************************************
[68003979]172 *  14.2.2 Create a Per-Process Timer, P1003.1b-1993, p. 264
173 * ********************************************************************/
174
175/* **************
176 * timer_create
177 * **************/
178
179int timer_create(
180  clockid_t        clock_id,
181  struct sigevent *evp,
182  timer_t         *timerid
183)
184{
[0243b0d]185  POSIX_Timer_Control *ptimer;
[68003979]186
[138aa38]187  if ( clock_id != CLOCK_REALTIME )
188    rtems_set_errno_and_return_minus_one( EINVAL );
189
[874297f3]190 /*
[939e29d]191  *  The data of the structure evp are checked in order to verify if they
[874297f3]192  *  are coherent.
[68003979]193  */
194
195  if (evp != NULL) {
[939e29d]196    /* The structure has data */
[874297f3]197    if ( ( evp->sigev_notify != SIGEV_NONE ) &&
[939e29d]198         ( evp->sigev_notify != SIGEV_SIGNAL ) ) {
[68003979]199       /* The value of the field sigev_notify is not valid */
[e180a77e]200       rtems_set_errno_and_return_minus_one( EINVAL );
[68003979]201     }
[138aa38]202
203     if ( !evp->sigev_signo )
204       rtems_set_errno_and_return_minus_one( EINVAL );
205
206     if ( !is_valid_signo(evp->sigev_signo) )
207       rtems_set_errno_and_return_minus_one( EINVAL );
[68003979]208  }
[874297f3]209
[0243b0d]210  _Thread_Disable_dispatch();         /* to prevent deletion */
[68003979]211
[0243b0d]212  /*
213   *  Allocate a timer
214   */
215  ptimer = _POSIX_Timer_Allocate();
216  if ( !ptimer ) {
217    _Thread_Enable_dispatch();
218    rtems_set_errno_and_return_minus_one( EAGAIN );
219  }
[874297f3]220
[0243b0d]221  /* The data of the created timer are stored to use them later */
[68003979]222
[0243b0d]223  ptimer->state     = STATE_CREATE_NEW_C;
224  ptimer->thread_id = _Thread_Executing->Object.id;
[68003979]225
[0243b0d]226  if ( evp != NULL ) {
227    ptimer->inf.sigev_notify = evp->sigev_notify;
228    ptimer->inf.sigev_signo  = evp->sigev_signo;
229    ptimer->inf.sigev_value  = evp->sigev_value;
[68003979]230  }
231
[0243b0d]232  ptimer->overrun  = 0;
233  ptimer->timer_data.it_value.tv_sec     = 0;
234  ptimer->timer_data.it_value.tv_nsec    = 0;
235  ptimer->timer_data.it_interval.tv_sec  = 0;
236  ptimer->timer_data.it_interval.tv_nsec = 0;
237
238  _Watchdog_Initialize( &ptimer->Timer, NULL, 0, NULL );
239  _Objects_Open(&_POSIX_Timer_Information, &ptimer->Object, (Objects_Name) 0);
[68003979]240
[0243b0d]241  *timerid  = ptimer->Object.id;
242  _Thread_Enable_dispatch();
243  return 0;
[68003979]244}
245
246/*
247 *  14.2.3 Delete a Per_process Timer, P1003.1b-1993, p. 266
248 */
249
250int timer_delete(
251  timer_t timerid
252)
253{
254 /*
255  * IDEA: This function must probably stop the timer first and then delete it
256  *
257  *       It will have to do a call to rtems_timer_cancel and then another
258  *       call to rtems_timer_delete.
[874297f3]259  *       The call to rtems_timer_delete will be probably unnecessary,
[68003979]260  *       because rtems_timer_delete stops the timer before deleting it.
261  */
[0243b0d]262  POSIX_Timer_Control *ptimer;
263  Objects_Locations    location;
264
265  ptimer = _POSIX_Timer_Get( timerid, &location );
266  switch ( location ) {
267    case OBJECTS_REMOTE:
268#if defined(RTEMS_MULTIPROCESSING)
269      _Thread_Dispatch();
[e180a77e]270      rtems_set_errno_and_return_minus_one( EINVAL );
[0243b0d]271#endif
[68003979]272
[0243b0d]273    case OBJECTS_ERROR:
274      rtems_set_errno_and_return_minus_one( EINVAL );
[68003979]275
[0243b0d]276    case OBJECTS_LOCAL:
277      _Objects_Close( &_POSIX_Timer_Information, &ptimer->Object );
278      ptimer->state = STATE_FREE_C;
279      (void) _Watchdog_Remove( &ptimer->Timer );
280      _POSIX_Timer_Free( ptimer );
281      _Thread_Enable_dispatch();
282      return 0;
283  }
284  return -1;   /* unreached - only to remove warnings */
[68003979]285}
286
287/*
288 *  14.2.4 Per-Process Timers, P1003.1b-1993, p. 267
289 */
290
291/* **************
292 * timer_settime
293 * **************/
294
295
296int timer_settime(
297  timer_t                  timerid,
298  int                      flags,
299  const struct itimerspec *value,
300  struct itimerspec       *ovalue
301)
302{
[0243b0d]303  POSIX_Timer_Control *ptimer;
304  Objects_Locations    location;
305  boolean              activated;
[68003979]306
[0243b0d]307  if ( value == NULL ) {
308    rtems_set_errno_and_return_minus_one( EINVAL );
309  }
[68003979]310
[0243b0d]311  /* First, it verifies if the structure "value" is correct */
312  if ( ( value->it_value.tv_nsec > MAX_NSEC_C ) ||
313       ( value->it_value.tv_nsec < MIN_NSEC_C ) ) {
314    /* The number of nanoseconds is not correct */
315    rtems_set_errno_and_return_minus_one( EINVAL );
316  }
317 
318  /* XXX check for seconds in the past */
[68003979]319
[0243b0d]320  if ( flags != TIMER_ABSTIME && flags != TIMER_RELATIVE_C ) {
321    rtems_set_errno_and_return_minus_one( EINVAL );
322  }
[68003979]323
[0243b0d]324  /* If the function reaches this point, then it will be necessary to do
325   * something with the structure of times of the timer: to stop, start
326   * or start it again
327   */
[68003979]328
[0243b0d]329  ptimer = _POSIX_Timer_Get( timerid, &location );
330  switch ( location ) {
331    case OBJECTS_REMOTE:
332#if defined(RTEMS_MULTIPROCESSING)
333      _Thread_Dispatch();
334      return -1;
[e180a77e]335     rtems_set_errno_and_return_minus_one( EINVAL );
[0243b0d]336#endif
[68003979]337
[0243b0d]338    case OBJECTS_ERROR:
339      return -1;
340
341    case OBJECTS_LOCAL:
342      /* First, it verifies if the timer must be stopped */
343      if ( value->it_value.tv_sec == 0 && value->it_value.tv_nsec == 0 ) {
344         /* Stop the timer */
345         (void) _Watchdog_Remove( &ptimer->Timer );
346         /* The old data of the timer are returned */
347         if ( ovalue )
348           *ovalue = ptimer->timer_data;
349         /* The new data are set */
350         ptimer->timer_data = *value;
351         /* Indicates that the timer is created and stopped */
352         ptimer->state = STATE_CREATE_STOP_C;
353         /* Returns with success */
354        _Thread_Enable_dispatch();
355        return 0;
356       }
[68003979]357
[0243b0d]358       /* absolute or relative? */
359       switch (flags) {
360         case TIMER_ABSTIME:
[68003979]361
[0243b0d]362           /* The fire time is absolute: use "rtems_time_fire_when" */
363           /* First, it converts from struct itimerspec to rtems_time_of_day */
[68003979]364
[0243b0d]365#if 0
366           ITIMERSPEC_TO_RTEMS_TIME_OF_DAY_S( value, &tod );
367           status = rtems_timer_fire_when(
368             ptimer->timer_id, &tod, _POSIX_Timer_TSR, ptimer);
369#endif
370           _Watchdog_Initialize(
371             &ptimer->Timer, _POSIX_Timer_TSR, ptimer->Object.id, ptimer );
372
373           _Watchdog_Insert_seconds(
374              &ptimer->Timer,
375              value->it_value.tv_sec - _TOD_Seconds_since_epoch
376           );
377
378           /* Returns the old ones in "ovalue" */
379           if ( ovalue )
380             *ovalue = ptimer->timer_data;
381           ptimer->timer_data = *value;
382
383           /* Indicate that the time is running */
384           ptimer->state = STATE_CREATE_RUN_C;
385
386           /* Stores the time in which the timer was started again */
387           ptimer->time = _TOD_Current;
388           _Thread_Enable_dispatch();
389           return 0;
390           break;
391
392         /* The fire time is relative: use "rtems_time_fire_after" */
393         case TIMER_RELATIVE_C:
394           /* First, convert from seconds and nanoseconds to ticks */
395           ptimer->ticks = ( SEC_TO_TICKS_C * value->it_value.tv_sec ) +
396                ( value->it_value.tv_nsec / (NSEC_PER_SEC_C / SEC_TO_TICKS_C));
397
398#if 0
399           status = rtems_timer_fire_after(
400             ptimer->timer_id, ptimer->ticks, _POSIX_Timer_TSR, ptimer );
401#endif
402           activated = _Watchdog_Insert_ticks_helper(
403             &ptimer->Timer,
404             ptimer->ticks,
405             ptimer->Object.id,
406             _POSIX_Timer_TSR,
407             ptimer
408           );
409           if ( !activated )
410             return 0;
411
412           /* The timer has been started and is running */
413           /* return the old ones in "ovalue" */
414           if ( ovalue )
415             *ovalue = ptimer->timer_data;
416           ptimer->timer_data = *value;
417
418           /* Indicate that the time is running */
419           ptimer->state = STATE_CREATE_RUN_C;
420           ptimer->time = _TOD_Current;
421            _Thread_Enable_dispatch();
422           return 0;
423      }
424      _Thread_Enable_dispatch();
425      rtems_set_errno_and_return_minus_one( EINVAL );
426  }
427  return -1;   /* unreached - only to remove warnings */
[68003979]428}
429
430/*
431 *  14.2.4 Per-Process Timers, P1003.1b-1993, p. 267
432 */
433
434/* **************
435 * timer_gettime
436 * **************/
437
438int timer_gettime(
439  timer_t            timerid,
440  struct itimerspec *value
441)
442{
443
[874297f3]444 /*
[68003979]445  * IDEA:  This function does not use functions of RTEMS to the handle
446  *        of timers. It uses some functions for managing the time.
447  *
448  *        A possible form to do this is the following:
449  *
[874297f3]450  *          - When a timer is initialized, the value of the time in
[68003979]451  *            that moment is stored.
452  *          - When this function is called, it returns the difference
453  *            between the current time and the initialization time.
454  */
[874297f3]455
[0243b0d]456  POSIX_Timer_Control *ptimer;
457  Objects_Locations    location;
458  rtems_time_of_day    current_time;
459  uint32_t             hours;
460  uint32_t             minutes;
461  uint32_t             seconds;
462  uint32_t             ticks;
463  uint32_t             nanosec;
[68003979]464
465  /* Reads the current time */
[16ce86f9]466  current_time = _TOD_Current;
[68003979]467
[0243b0d]468  ptimer = _POSIX_Timer_Get( timerid, &location );
469  switch ( location ) {
470    case OBJECTS_REMOTE:
471#if defined(RTEMS_MULTIPROCESSING)
472      _Thread_Dispatch();
473      rtems_set_errno_and_return_minus_one( EINVAL );
474#endif
[874297f3]475
[0243b0d]476    case OBJECTS_ERROR:
477      rtems_set_errno_and_return_minus_one( EINVAL );
[68003979]478
[0243b0d]479    case OBJECTS_LOCAL:
480      /* Calculates the difference between the start time of the timer and
481       * the current one */
[68003979]482
[0243b0d]483      hours    = current_time.hour - ptimer->time.hour;
[68003979]484
[0243b0d]485      if ( current_time.minute < ptimer->time.minute ) {
486        minutes = 60 - ptimer->time.minute + current_time.minute;
487        hours--;
488      } else {
489        minutes = current_time.minute - ptimer->time.minute;
490      }
[68003979]491
[0243b0d]492      if ( current_time.second < ptimer->time.second ) {
493        seconds = 60 - ptimer->time.second + current_time.second;
494        minutes--;
495      } else {
496        seconds = current_time.second - ptimer->time.second;
497      }
[874297f3]498
[0243b0d]499      if ( current_time.ticks < ptimer->time.ticks ) {
500        ticks = 100 - ptimer->time.ticks + current_time.ticks;
501        seconds--;
502      } else {
503        ticks = current_time.ticks - ptimer->time.ticks;
504      }
[874297f3]505
[0243b0d]506      /* The time that the timer is running is calculated */
507      seconds = hours   * 60 * 60 +
508                minutes * 60      +
509                seconds;
[874297f3]510
[0243b0d]511      nanosec  = ticks * 10 *  /* msec     */
512                 1000  *       /* microsec */
513                 1000;         /* nanosec  */
[68003979]514
515
[0243b0d]516      /* Calculates the time left before the timer finishes */
[874297f3]517
[0243b0d]518      value->it_value.tv_sec  = ptimer->timer_data.it_value.tv_sec - seconds;
519      value->it_value.tv_nsec = ptimer->timer_data.it_value.tv_nsec - nanosec;
[68003979]520
[0243b0d]521      value->it_interval.tv_sec  = ptimer->timer_data.it_interval.tv_sec;
522      value->it_interval.tv_nsec = ptimer->timer_data.it_interval.tv_nsec;
[68003979]523
[0243b0d]524      _Thread_Enable_dispatch();
525      return 0;
526  }
527  return -1;   /* unreached - only to remove warnings */
[68003979]528}
529
530/*
531 *  14.2.4 Per-Process Timers, P1003.1b-1993, p. 267
532 */
533
[0243b0d]534/*
[68003979]535 * timer_getoverrun
[0243b0d]536 *
537 * The expiration of a timer must increase by one a counter.
538 * After the signal handler associated to the timer finishes
539 * its execution, _POSIX_Timer_TSR will have to set this counter to 0.
540 */
[68003979]541
542int timer_getoverrun(
543  timer_t   timerid
544)
545{
[0243b0d]546  int                  overrun;
547  POSIX_Timer_Control *ptimer;
548  Objects_Locations    location;
549
550  ptimer = _POSIX_Timer_Get( timerid, &location );
551  switch ( location ) {
552    case OBJECTS_REMOTE:
553#if defined(RTEMS_MULTIPROCESSING)
554      _Thread_Dispatch();
555      rtems_set_errno_and_return_minus_one( EINVAL );
556#endif
[68003979]557
[0243b0d]558    case OBJECTS_ERROR:
559      rtems_set_errno_and_return_minus_one( EINVAL );
[68003979]560
[0243b0d]561    case OBJECTS_LOCAL:
562      overrun = ptimer->overrun;
563      ptimer->overrun = 0;
564      _Thread_Enable_dispatch();
565      return overrun;
[68003979]566  }
[0243b0d]567  return -1;   /* unreached - only to remove warnings */
[68003979]568}
Note: See TracBrowser for help on using the repository browser.