source: rtems/cpukit/posix/src/ptimer1.c @ b602c298

4.104.114.84.95
Last change on this file since b602c298 was b602c298, checked in by Joel Sherrill <joel.sherrill@…>, on 08/25/00 at 17:15:44

2000-08-25 Joel Sherrill <joel.sherrill@…>

  • inline/rtems/posix/timer.inl, include/rtems/posix/timer.h, inline/rtems/posix/Makefile.am, src/ptimer1.c: Redid the style of src/ptimer1.c. Continued effort to make the POSIX Timer implementation match that of other managers. Added data structures required to use SuperCore? Object Handler.
  • Property mode set to 100644
File size: 21.3 KB
Line 
1/*
2 *  ptimer.c,v 1.1 1996/06/03 16:29:58 joel Exp
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/time.h>
15
16/************************************/
17/* These includes are now necessary */
18/************************************/
19
20#include <sys/features.h>
21#include <rtems/rtems/status.h>
22#include <rtems/rtems/types.h>
23#include <rtems/rtems/timer.h>
24#include <rtems/rtems/clock.h>
25#include <rtems/posix/psignal.h>
26#include <rtems/score/wkspace.h>
27#include <pthread.h>
28#include <stdio.h>
29#include <signal.h>
30
31#include <rtems/posix/seterr.h>
32#include <rtems/posix/timer.h>
33
34/*****************************/
35/* End of necessary includes */
36/*****************************/
37
38/* ************
39 * Constants
40 * ************/
41
42/*
43#define DEBUG_MESSAGES
44 */
45
46/*
47 * Data for the signals
48 */
49
50/***********************************
51 * Definition of Internal Functions
52 ***********************************/
53
54/* ***************************************************************************
55 * TIMER_INITIALIZE_S
56 *
57 *  Description: Initialize the data of a timer
58 * ***************************************************************************/
59
60extern void TIMER_INITIALIZE_S ( int timer_pos );
61
62/* ***************************************************************************
63 * _POSIX_Timer_Manager_initialization
64 *
65 *  Description: Initialize the internal structure in which the data of all
66 *               the timers are stored
67 * ***************************************************************************/
68
69/* split to reduce minimum size */
70
71/* ***************************************************************************
72 * FIRST_FREE_POSITION_F
73 *
74 *  Description: Returns the first free position in the table of timers.
75 *               If there is not a free position, it returns NO_MORE_TIMERS_C
76 * ***************************************************************************/
77
78int FIRST_FREE_POSITION_F ()
79{
80   int index;
81
82   for (index=0; index<timer_max; index++) {
83      if ( timer_struct[index].state == STATE_FREE_C ) {
84         return index;
85      }
86   }
87   
88   /* The function reaches this point only if all the position are occupied */
89
90   return NO_MORE_TIMERS_C;
91}
92
93/* ***************************************************************************
94 * TIMER_POSITION_F
95 *
96 *  Description: Returns the position in the table of timers in which the
97 *               data of the timer are stored.
98 *               If the timer identifier does not exist, it returns
99 *               BAD_TIMER_C
100 * ***************************************************************************/
101
102int TIMER_POSITION_F ( timer_t timer_id )
103{
104  int index;
105
106  for (index=0; index<timer_max; index++ ) {
107
108     /* Looks for the position of the timer. The timer must exist and the
109      * position can not be free */
110     if ( ( timer_struct[index].timer_id == timer_id ) &&
111          ( timer_struct[index].state != STATE_FREE_C ) ) {
112        return index;
113     }
114  }
115
116  /* If the function reaches this point is because the timer identifier
117   * is not correct */
118
119   return BAD_TIMER_C;
120
121}
122
123/* ***************************************************************************
124 * COPY_ITIMERSPEC_S
125 *
126 *  Description: Does a copy of a variable of type struct itimerspec 
127 * ***************************************************************************/
128
129void COPY_ITIMERSPEC_S ( const struct itimerspec *source,
130                         struct itimerspec *target )
131{
132
133   target->it_value.tv_sec     = source->it_value.tv_sec;
134   target->it_value.tv_nsec    = source->it_value.tv_nsec;
135   target->it_interval.tv_sec  = source->it_interval.tv_sec;
136   target->it_interval.tv_nsec = source->it_interval.tv_nsec;
137
138}
139
140/* ***************************************************************************
141 * ITIMERSPEC_TO_RTEMS_TIME_OF_DAY_S
142 *
143 *  Description: This function converts the data of a structure itimerspec
144 *               into structure rtems_time_of_day
145 * ***************************************************************************/
146
147void ITIMERSPEC_TO_RTEMS_TIME_OF_DAY_S
148   ( const struct itimerspec *itimer, rtems_time_of_day *rtems_time )
149{
150   unsigned long int seconds;
151
152   /* The leap years and the months with 28, 29 or 31 days have not been
153    * considerated. It will be made in the future */
154
155   seconds            = itimer->it_value.tv_sec;
156
157   rtems_time->year   = seconds / SECONDS_PER_YEAR_C;
158   seconds            = seconds % SECONDS_PER_YEAR_C;
159
160   rtems_time->month  = seconds / SECONDS_PER_MONTH_C;
161   seconds            = seconds % SECONDS_PER_MONTH_C;
162
163   rtems_time->day    = seconds / SECONDS_PER_DAY_C;
164   seconds            = seconds % SECONDS_PER_DAY_C;
165
166   rtems_time->hour   = seconds / SECONDS_PER_HOUR_C;
167   seconds            = seconds % SECONDS_PER_HOUR_C;
168
169   rtems_time->minute = seconds / SECONDS_PER_MINUTE_C;
170   seconds            = seconds % SECONDS_PER_MINUTE_C;
171
172   rtems_time->second = seconds;
173
174   rtems_time->ticks  = ( itimer->it_value.tv_nsec * SEC_TO_TICKS_C ) /
175                        NSEC_PER_SEC_C;
176
177}
178
179
180/* ***************************************************************************
181 * FIRE_TIMER_S
182 *
183 *  Description: This is the operation that is ran when a timer expires
184 * ***************************************************************************/
185
186
187rtems_timer_service_routine FIRE_TIMER_S (rtems_id timer, void *data)
188{
189  int               timer_pos;  /* Position in the table of the timer that   
190                                 *  has expirated                            */
191  rtems_status_code return_v;   /* Return value of rtems_timer_fire_after    */
192  int               sig_number; /* Number of the signal to send              */
193
194 
195  /* The position of the table of timers that contains the data of the
196   * expired timer will be stored in "timer_pos". In theory a timer can not
197   * expire if it has not been created or has been deleted */
198
199  timer_pos = TIMER_POSITION_F(timer);
200
201  /* Increases the number of expiration of the timer in one unit. */
202  timer_struct[timer_pos].overrun = timer_struct[timer_pos].overrun + 1;
203
204
205  if ( ( timer_struct[timer_pos].timer_data.it_interval.tv_sec  != 0 ) ||
206       ( timer_struct[timer_pos].timer_data.it_interval.tv_nsec != 0 ) ) {
207
208     /* The timer must be reprogrammed */
209
210     return_v = rtems_timer_fire_after ( timer,
211                                        timer_struct[timer_pos].ticks,
212                                        FIRE_TIMER_S,
213                                        NULL );
214
215     /* Stores the time when the timer was started again */
216
217     timer_struct[timer_pos].time = _TOD_Current;
218     
219     /* The state has not to be actualized, because nothing modifies it */
220
221     timer_struct[timer_pos].state = STATE_CREATE_RUN_C;
222
223  } else {
224     /* Indicates that the timer is stopped */
225 
226     timer_struct[timer_pos].state = STATE_CREATE_STOP_C;
227
228  }
229
230  /*
231   * The sending of the signal to the process running the handling function
232   * specified for that signal is simulated
233   */
234
235  sig_number = timer_struct[timer_pos].inf.sigev_signo;
236
237  if( pthread_kill ( timer_struct[timer_pos].thread_id ,
238                     timer_struct[timer_pos].inf.sigev_signo ) ) {
239     /* XXX error handling */
240  }
241
242  /*
243   * After the signal handler returns, the count of expirations of the
244   * timer must be set to 0.
245   */
246
247  timer_struct[timer_pos].overrun = 0;
248
249}
250
251/* *********************************************************************
252 *  14.2.2 Create a Per-Process Timer, P1003.1b-1993, p. 264
253 * ********************************************************************/
254
255/* **************
256 * timer_create
257 * **************/
258
259int timer_create(
260  clockid_t        clock_id,
261  struct sigevent *evp,
262  timer_t         *timerid
263)
264{
265
266  rtems_status_code return_v;  /* return value of the operation    */
267  rtems_id          timer_id;  /* created timer identifier         */
268  int               timer_pos; /* Position in the table of timers  */
269
270 /*
271  *  The data of the structure evp are checked in order to verify if they
272  *  are coherent.
273  */
274
275  if (evp != NULL) {
276    /* The structure has data */
277    if ( ( evp->sigev_notify != SIGEV_NONE ) &&
278         ( evp->sigev_notify != SIGEV_SIGNAL ) ) {
279       /* The value of the field sigev_notify is not valid */
280       set_errno_and_return_minus_one( EINVAL );
281     }
282  }
283 
284 /*
285  *  A timer is created using the primitive rtems_timer_create
286  */
287
288  return_v = rtems_timer_create ( clock_id, &timer_id );
289
290  switch (return_v) {
291     case RTEMS_SUCCESSFUL :
292
293       /*
294        * The timer has been created properly
295        */
296 
297        /* Obtains the first free position in the table of timers */
298
299        timer_pos = FIRST_FREE_POSITION_F();
300
301        if ( timer_pos == NO_MORE_TIMERS_C ) {
302           /* There is not position for another timers in spite of RTEMS
303            * supports it. It will necessaty to increase the structure used */
304
305           set_errno_and_return_minus_one( EAGAIN );
306        }
307
308        /* Exit parameter */
309
310        *timerid  = timer_id;
311
312        /* The data of the created timer are stored to use them later */
313
314        timer_struct[timer_pos].state     = STATE_CREATE_NEW_C;
315
316        /* NEW VERSION*/
317        timer_struct[timer_pos].thread_id = pthread_self ();
318       
319        if ( evp != NULL ) {
320           timer_struct[timer_pos].inf.sigev_notify = evp->sigev_notify;
321           timer_struct[timer_pos].inf.sigev_signo  = evp->sigev_signo;
322           timer_struct[timer_pos].inf.sigev_value  = evp->sigev_value;
323        }
324
325        timer_struct[timer_pos].timer_id = timer_id;
326        timer_struct[timer_pos].overrun  = 0;
327
328        timer_struct[timer_pos].timer_data.it_value.tv_sec     = 0;
329        timer_struct[timer_pos].timer_data.it_value.tv_nsec    = 0;
330        timer_struct[timer_pos].timer_data.it_interval.tv_sec  = 0;
331        timer_struct[timer_pos].timer_data.it_interval.tv_nsec = 0;
332
333        return 0;
334
335     case RTEMS_INVALID_NAME : /* The assigned name is not valid */
336
337       set_errno_and_return_minus_one( EINVAL );
338
339     case RTEMS_TOO_MANY :
340
341       /* There has been created too much timers for the same process */
342       set_errno_and_return_minus_one( EAGAIN );
343     
344     default :
345
346       /*
347        * Does nothing. It only returns the error without assigning a value
348        * to errno. In theory, it can not happen because the call to
349        * rtems_timer_create can not return other different value.
350        */
351
352       set_errno_and_return_minus_one( EINVAL );
353  }
354
355  /*
356   * The next sentence is used to avoid singular situations
357   */
358
359  set_errno_and_return_minus_one( EINVAL );
360}
361
362/*
363 *  14.2.3 Delete a Per_process Timer, P1003.1b-1993, p. 266
364 */
365
366int timer_delete(
367  timer_t timerid
368)
369{
370 
371 /*
372  * IDEA: This function must probably stop the timer first and then delete it
373  *
374  *       It will have to do a call to rtems_timer_cancel and then another
375  *       call to rtems_timer_delete.
376  *       The call to rtems_timer_delete will be probably unnecessary,
377  *       because rtems_timer_delete stops the timer before deleting it.
378  */
379
380  int               timer_pos;
381  rtems_status_code status;
382
383
384   /* First the position in the table of timers is obtained */
385
386   timer_pos = TIMER_POSITION_F ( timerid );
387
388   if ( timer_pos == BAD_TIMER_C ) {
389      /* The timer identifier is erroneus */
390      set_errno_and_return_minus_one( EINVAL );
391   }
392
393   /* The timer is deleted */
394
395   status = rtems_timer_delete ( timerid );
396
397   if ( status == RTEMS_INVALID_ID ) {
398     /* The timer identifier is erroneus */
399     set_errno_and_return_minus_one( EINVAL );
400   }
401
402   /* Initializes the data of the timer */
403
404   TIMER_INITIALIZE_S ( timer_pos );
405   return 0;
406}
407
408/*
409 *  14.2.4 Per-Process Timers, P1003.1b-1993, p. 267
410 */
411
412/* **************
413 * timer_settime
414 * **************/
415
416
417int timer_settime(
418  timer_t                  timerid,
419  int                      flags,
420  const struct itimerspec *value,
421  struct itimerspec       *ovalue
422)
423{
424
425   rtems_status_code return_v;   /* Return of the calls to RTEMS        */
426   int               timer_pos;  /* Position of the timer in the table  */
427   rtems_time_of_day rtems_time; /* Time in RTEMS                       */
428   
429
430   /* First the position in the table of timers is obtained */
431
432   timer_pos = TIMER_POSITION_F ( timerid );
433
434   if ( timer_pos == BAD_TIMER_C ) {
435     /* The timer identifier is erroneus */
436     set_errno_and_return_minus_one( EINVAL );
437   }
438
439   if ( value == NULL ) {
440     /* The stucture of times of the timer is free, and then returns an
441        error but the variable errno is not actualized */
442
443     set_errno_and_return_minus_one( EINVAL );
444   }
445
446   /* If the function reaches this point, then it will be necessary to do
447    * something with the structure of times of the timer: to stop, start
448    * or start it again */
449
450   /* First, it verifies if the timer must be stopped */
451
452   if ( value->it_value.tv_sec == 0 && value->it_value.tv_nsec == 0 ) {
453      /* The timer is stopped */
454
455      return_v = rtems_timer_cancel ( timerid );
456
457      /* The old data of the timer are returned */
458
459      if ( ovalue )
460        *ovalue = timer_struct[timer_pos].timer_data;
461
462      /* The new data are set */
463
464      timer_struct[timer_pos].timer_data = *value;
465
466      /* Indicates that the timer is created and stopped */
467 
468      timer_struct[timer_pos].state = STATE_CREATE_STOP_C;
469
470      /* Returns with success */
471
472      return 0;
473   }
474
475   /*
476    * If the function reaches this point, then the timer will have to be
477    * initialized with new values: to start it or start it again
478    */
479 
480   /* First, it verifies if the structure "value" is correct */
481
482    if ( ( value->it_value.tv_nsec > MAX_NSEC_C ) ||
483         ( value->it_value.tv_nsec < MIN_NSEC_C ) ) {
484       /* The number of nanoseconds is not correct */
485
486       set_errno_and_return_minus_one( EINVAL );
487    }
488
489   /* Then, "value" must be converted from seconds and nanoseconds to clock
490    * ticks, to use it in the calls to RTEMS */
491
492   /* It is also necessary to take in account if the time is absolute
493    * or relative */
494
495   switch (flags) {
496      case TIMER_ABSTIME:
497
498        /* The fire time is absolute:
499         * It has to use "rtems_time_fire_when" */
500
501        /* First, it converts from struct itimerspec to rtems_time_of_day */
502
503        ITIMERSPEC_TO_RTEMS_TIME_OF_DAY_S ( value, &rtems_time );
504
505        return_v = rtems_timer_fire_when ( timerid, &rtems_time, FIRE_TIMER_S, NULL);
506
507        switch ( return_v ) {
508           case RTEMS_SUCCESSFUL:
509
510              /* The timer has been started and is running */
511
512              /* Actualizes the data of the structure and
513               * returns the old ones in "ovalue" */
514
515              if ( ovalue )
516                *ovalue = timer_struct[timer_pos].timer_data;
517
518              timer_struct[timer_pos].timer_data = *value;
519 
520              /* It indicates that the time is running */
521
522              timer_struct[timer_pos].state = STATE_CREATE_RUN_C;
523
524              /* Stores the time in which the timer was started again */
525
526              timer_struct[timer_pos].time = _TOD_Current;
527              return 0;
528
529              break;
530
531           case RTEMS_INVALID_ID:
532
533              /* XXX error handling */
534              break;
535
536           case RTEMS_NOT_DEFINED:
537
538              /* XXX error handling */
539              break;
540
541           case RTEMS_INVALID_CLOCK:
542
543              /* XXX error handling */
544              break;
545
546           default:
547
548       
549        }
550     
551        break;
552
553      case TIMER_RELATIVE_C:
554
555        /* The fire time is relative:
556         * It has to use "rtems_time_fire_after" */
557
558        /* First, it converts from seconds and nanoseconds to ticks */
559
560        /* The form in which this operation is done can produce a lost
561         * of precision of 1 second */
562 
563/*      This is the process to convert from nanoseconds to ticks
564 *
565 *      There is a tick every 10 miliseconds, then the nanoseconds are
566 *      divided between 10**7. The result of this operation will be the
567 *      number of ticks
568 */
569
570        timer_struct[timer_pos].ticks =
571             ( SEC_TO_TICKS_C * value->it_value.tv_sec ) +
572             ( value->it_value.tv_nsec / ( 1000 * 1000 * 10 ) );
573
574        return_v = rtems_timer_fire_after ( timerid,
575                                           timer_struct[timer_pos].ticks,
576                                           FIRE_TIMER_S,
577                                           NULL );
578
579        switch (return_v) {
580           case RTEMS_SUCCESSFUL:
581
582              /* The timer has been started and is running */
583
584              /* Actualizes the data of the structure and
585               * returns the old ones in "ovalue" */
586
587              if ( ovalue )
588                *ovalue = timer_struct[timer_pos].timer_data;
589
590              timer_struct[timer_pos].timer_data = *value;
591 
592              /* It indicates that the time is running */
593
594              timer_struct[timer_pos].state = STATE_CREATE_RUN_C;
595
596              /* Stores the time in which the timer was started again */
597
598              timer_struct[timer_pos].time = _TOD_Current;
599 
600              return 0;
601
602              break;
603
604           case RTEMS_INVALID_ID:
605
606              /* The timer identifier is not correct. In theory, this
607               * situation can not occur, but the solution is easy */
608
609              set_errno_and_return_minus_one( EINVAL );
610
611              break;
612
613           case RTEMS_INVALID_NUMBER:
614
615              /* In this case, RTEMS fails because the values of timing
616               * are incorrect */
617
618              /*
619               * I do not know if errno must be actualized
620               *
621               * errno = EINVAL;
622               */
623
624              set_errno_and_return_minus_one( EINVAL );
625              break;
626           
627           default:
628        }
629
630        break;
631
632      default:
633
634        /* It does nothing, although it will be probably necessary to
635         * return an error */
636   }
637
638   /* To avoid problems */
639   return 0;
640}
641
642
643/*
644 *  14.2.4 Per-Process Timers, P1003.1b-1993, p. 267
645 */
646
647/* **************
648 * timer_gettime
649 * **************/
650
651int timer_gettime(
652  timer_t            timerid,
653  struct itimerspec *value
654)
655{
656
657 /*
658  * IDEA:  This function does not use functions of RTEMS to the handle
659  *        of timers. It uses some functions for managing the time.
660  *
661  *        A possible form to do this is the following:
662  *
663  *          - When a timer is initialized, the value of the time in
664  *            that moment is stored.
665  *          - When this function is called, it returns the difference
666  *            between the current time and the initialization time.
667  */
668 
669  rtems_time_of_day current_time;
670  int               timer_pos;
671  unsigned32        hours;
672  unsigned32        minutes;
673  unsigned32        seconds;
674  unsigned32        ticks;
675  unsigned32        nanosec;
676 
677
678  /* Reads the current time */
679
680  current_time = _TOD_Current;
681
682  timer_pos = TIMER_POSITION_F ( timerid );
683
684  if ( timer_pos == BAD_TIMER_C ) {
685    /* The timer identifier is erroneus */ 
686    set_errno_and_return_minus_one( EINVAL );
687  }
688
689  /* Calculates the difference between the start time of the timer and
690   * the current one */
691
692  hours    = current_time.hour - timer_struct[timer_pos].time.hour;
693
694  if ( current_time.minute < timer_struct[timer_pos].time.minute ) {
695     minutes = 60 - timer_struct[timer_pos].time.minute + current_time.minute;
696     hours--;
697  } else {
698     minutes = current_time.minute - timer_struct[timer_pos].time.minute;
699  }
700   
701  if ( current_time.second < timer_struct[timer_pos].time.second ) {
702     seconds = 60 - timer_struct[timer_pos].time.second + current_time.second;
703     minutes--;
704  } else {
705     seconds = current_time.second - timer_struct[timer_pos].time.second;
706  }
707
708  if ( current_time.ticks < timer_struct[timer_pos].time.ticks ) {
709     ticks = 100 - timer_struct[timer_pos].time.ticks + current_time.ticks;
710     seconds--;
711  } else {
712     ticks = current_time.ticks - timer_struct[timer_pos].time.ticks;
713  }
714
715  /* The time that the timer is running is calculated */
716  seconds = hours   * 60 * 60 +
717            minutes * 60      +
718            seconds;
719
720  nanosec  = ticks * 10 *  /* msec     */
721             1000  *       /* microsec */
722             1000;         /* nanosec  */
723
724 
725  /* Calculates the time left before the timer finishes */
726 
727  value->it_value.tv_sec =
728    timer_struct[timer_pos].timer_data.it_value.tv_sec - seconds;
729 
730  value->it_value.tv_nsec =
731    timer_struct[timer_pos].timer_data.it_value.tv_nsec - nanosec;
732
733
734  value->it_interval.tv_sec  =
735    timer_struct[timer_pos].timer_data.it_interval.tv_sec;
736  value->it_interval.tv_nsec =
737    timer_struct[timer_pos].timer_data.it_interval.tv_nsec;
738 
739
740  return 0;
741
742}
743
744/*
745 *  14.2.4 Per-Process Timers, P1003.1b-1993, p. 267
746 */
747
748/* *****************
749 * timer_getoverrun
750 * *****************/
751
752int timer_getoverrun(
753  timer_t   timerid
754)
755{
756
757 /*
758  * IDEA: This function must count the times the timer expires.
759  *   
760  *       The expiration of a timer must increase by one a counter.
761  *       After the signal handler associated to the timer finishs
762  *       its execution, FIRE_TIMER_S will have to set this counter to 0.
763  */
764
765  int timer_pos; /* Position of the timer in the structure     */
766  int overrun;   /* Overflow count                             */
767
768
769  timer_pos = TIMER_POSITION_F ( timerid );
770
771  if ( timer_pos == BAD_TIMER_C ) {
772    /* The timer identifier is erroneus */
773    set_errno_and_return_minus_one( EINVAL );
774  }
775
776  /* The overflow count of the timer is stored in "overrun" */
777
778  overrun = timer_struct[timer_pos].overrun;
779
780  /* It is set to 0 */
781
782  timer_struct[timer_pos].overrun = 0;
783
784  return overrun;
785
786}
Note: See TracBrowser for help on using the repository browser.