summaryrefslogblamecommitdiffstats
path: root/c/src/exec/posix/src/ptimer.c
blob: ff65297f96b7df80460e544be60df2961ba9472d (plain) (tree)
1
2
3
4
  
                                               
   
 










                               










































                                                                              
  
                      

   





































































































































































































































































































































                                                                               





                            























































































































                                                                              









                                                            








































                                                                             





                                                    




                  






                                   










































































































































































































































                                                                                     

 
 



                                                    



                  




                             



























































































                                                                              





                                                    



                     



                     
































                                                                         
 
/*
 *  ptimer.c,v 1.1 1996/06/03 16:29:58 joel Exp
 */
 
#include <assert.h>
#include <time.h>
#include <errno.h>

#include <rtems/system.h>
#include <rtems/score/isr.h>
#include <rtems/score/thread.h>
#include <rtems/score/tod.h>

#include <rtems/posix/time.h>

/************************************/
/* These includes are now necessary */
/************************************/

#include <sys/features.h>
#include <rtems/rtems/status.h>
#include <rtems/rtems/types.h>
#include <rtems/rtems/timer.h>
#include <rtems/rtems/clock.h>
#include <rtems/posix/psignal.h>
#include <rtems/score/wkspace.h>
#include <pthread.h>
#include <stdio.h>
#include <signal.h>

/*****************************/
/* End of necessary includes */
/*****************************/

/* ************ 
 * Constants
 * ************/ 

#define STATE_FREE_C        0x01 /* Free position of the table of timers   */
#define STATE_CREATE_NEW_C  0x02 /* Created timer but not running          */
#define STATE_CREATE_RUN_C  0x03 /* Created timer and running              */
#define STATE_CREATE_STOP_C 0x04 /* Created, ran and stopped timer         */
#define MAX_NSEC_C    1000000000 /* Maximum number of nsec allowed         */
#define MIN_NSEC_C             0 /* Minimum number of nsec allowew         */
#define TIMER_RELATIVE_C       0 /* Indicates that the fire time is       
                                  * relative to the current one            */ 
#define SEC_TO_TICKS_C _TOD_Ticks_per_second /* Number of ticks in a second*/
#define NSEC_PER_SEC_C 1000000000 /* Nanoseconds in a second               */

#define NO_MORE_TIMERS_C      11 /* There is not available timers          */
#define BAD_TIMER_C           11 /* The timer does not exist in the table  */

#define SECONDS_PER_YEAR_C    ( 360 * 24 * 60 * 60 )
#define SECONDS_PER_MONTH_C    ( 30 * 24 * 60 * 60 )
#define SECONDS_PER_DAY_C           ( 24 * 60 * 60 )
#define SECONDS_PER_HOUR_C               ( 60 * 60 )
#define SECONDS_PER_MINUTE_C                  ( 60 )

/*
#define DEBUG_MESSAGES
 */

/* *********************************************************
 * Types that will store the created timers and their data 
 * *********************************************************/

/*
 * Data for a timer
 */

typedef struct {
  pthread_t         thread_id;  /* Thread identifier                     */
  char              state;      /* State of the timer                    */
  struct sigevent   inf;        /* Information associated to the timer   */
  timer_t           timer_id;   /* Created timer identifier              */
  struct itimerspec timer_data; /* Timing data of the timer              */
  unsigned32        ticks;      /* Number of ticks of the initialization */
  unsigned32        overrun;    /* Number of expirations of the timer    */
  rtems_time_of_day time;       /* Time in which the timer was started   */
} timer_alive_t;

/*
 * Array of Timers
 */

int timer_max;
timer_alive_t *timer_struct;

/*
 * Data for the signals 
 */

struct sigaction signal_inf[SIGRTMAX];

/***********************************
 * Definition of Internal Functions
 ***********************************/

/* ***************************************************************************
 * PRINT_MSG_S 
 * 
 *  Description: This function write a message in the display.
 *               It is used for debugging and all the calls must be deleted
 *               when the tests finish 
 * ***************************************************************************/

static void PRINT_MSG_S ( char *msg )
{

#ifdef DEBUG_MESSAGES
   printf("%s\n", msg);
#endif

}

/* *************************************************************************** 
 * PRINT_ERRNO_S
 * 
 *  Description: Print the value of the global variable errno in the display
 * ***************************************************************************/

static void PRINT_ERRNO_S ()
{
#ifdef DEBUG_MESSAGES
  switch (errno)
  {
     case EINVAL:
       PRINT_MSG_S ( "errno EINVAL"); break; 
     case EPERM:
       PRINT_MSG_S ( "errno EPERM"); break; 
     case ESRCH:
       PRINT_MSG_S ( "errno ESRCH"); break; 
     case EAGAIN:
       PRINT_MSG_S ( "errno EAGAIN"); break; 
     default :
       printf ("errno: %d\n", errno);
       break;
  }
#endif
}
 
/* ***************************************************************************
 * TIMER_INITIALIZE_S
 *
 *  Description: Initialize the data of a timer 
 * ***************************************************************************/

void TIMER_INITIALIZE_S ( int timer_pos )
{

   /*
    * Indicates that the position in the table is free 
    */

    timer_struct[timer_pos].state = STATE_FREE_C;

   /*
    * The initial data of timing are set with null value 
    */

    timer_struct[timer_pos].timer_data.it_value.tv_sec     = 0;
    timer_struct[timer_pos].timer_data.it_value.tv_nsec    = 0;
    timer_struct[timer_pos].timer_data.it_interval.tv_sec  = 0;
    timer_struct[timer_pos].timer_data.it_interval.tv_nsec = 0;

   /* 
    * The count of expirations is 0 
    */

    timer_struct[timer_pos].overrun = 0;

}

/* ***************************************************************************
 * _POSIX_Timer_Manager_initialization
 *
 *  Description: Initialize the internal structure in which the data of all 
 *               the timers are stored
 * ***************************************************************************/

void _POSIX_Timer_Manager_initialization ( int max_timers )
{
   int index;

   timer_struct = _Workspace_Allocate_or_fatal_error(
      max_timers * sizeof(timer_alive_t) );

   /* 
    *  Initialize all the timers
    */

   for (index=0; index<max_timers; index++)
     TIMER_INITIALIZE_S( index );
}

/* ***************************************************************************
 * FIRST_FREE_POSITION_F 
 *
 *  Description: Returns the first free position in the table of timers.
 *               If there is not a free position, it returns NO_MORE_TIMERS_C 
 * ***************************************************************************/

int FIRST_FREE_POSITION_F ()
{
   int index;

   for (index=0; index<timer_max; index++) {
      if ( timer_struct[index].state == STATE_FREE_C ) {
         return index;
      }
   }
   
   /* The function reaches this point only if all the position are occupied */

   return NO_MORE_TIMERS_C;
}

/* ***************************************************************************
 * TIMER_POSITION_F 
 *
 *  Description: Returns the position in the table of timers in which the
 *               data of the timer are stored.
 *               If the timer identifier does not exist, it returns
 *               BAD_TIMER_C
 * ***************************************************************************/

int TIMER_POSITION_F ( timer_t timer_id )
{
  int index;

  for (index=0; index<timer_max; index++ ) {

     /* Looks for the position of the timer. The timer must exist and the
      * position can not be free */
     if ( ( timer_struct[index].timer_id == timer_id ) &&
          ( timer_struct[index].state != STATE_FREE_C ) ) {
        return index;
     }
  }

  /* If the function reaches this point is because the timer identifier
   * is not correct */

   return BAD_TIMER_C;

}

/* ***************************************************************************
 * COPY_ITIMERSPEC_S 
 *
 *  Description: Does a copy of a variable of type struct itimerspec  
 * ***************************************************************************/

void COPY_ITIMERSPEC_S ( const struct itimerspec *source, 
                         struct itimerspec *target )
{

   target->it_value.tv_sec     = source->it_value.tv_sec;
   target->it_value.tv_nsec    = source->it_value.tv_nsec;
   target->it_interval.tv_sec  = source->it_interval.tv_sec;
   target->it_interval.tv_nsec = source->it_interval.tv_nsec;

}

/* ***************************************************************************
 * ITIMERSPEC_TO_RTEMS_TIME_OF_DAY_S 
 *
 *  Description: This function converts the data of a structure itimerspec 
 *               into structure rtems_time_of_day 
 * ***************************************************************************/

void ITIMERSPEC_TO_RTEMS_TIME_OF_DAY_S 
   ( const struct itimerspec *itimer, rtems_time_of_day *rtems_time )
{
   unsigned long int seconds;

   /* The leap years and the months with 28, 29 or 31 days have not been
    * considerated. It will be made in the future */ 

   seconds            = itimer->it_value.tv_sec;

   rtems_time->year   = seconds / SECONDS_PER_YEAR_C;
   seconds            = seconds % SECONDS_PER_YEAR_C;

   rtems_time->month  = seconds / SECONDS_PER_MONTH_C;
   seconds            = seconds % SECONDS_PER_MONTH_C;

   rtems_time->day    = seconds / SECONDS_PER_DAY_C;
   seconds            = seconds % SECONDS_PER_DAY_C;

   rtems_time->hour   = seconds / SECONDS_PER_HOUR_C;
   seconds            = seconds % SECONDS_PER_HOUR_C;

   rtems_time->minute = seconds / SECONDS_PER_MINUTE_C;
   seconds            = seconds % SECONDS_PER_MINUTE_C;

   rtems_time->second = seconds;

   rtems_time->ticks  = ( itimer->it_value.tv_nsec * SEC_TO_TICKS_C ) /
                        NSEC_PER_SEC_C;

}


/* ***************************************************************************
 * FIRE_TIMER_S 
 *
 *  Description: This is the operation that is ran when a timer expires
 * ***************************************************************************/


rtems_timer_service_routine FIRE_TIMER_S (rtems_id timer, void *data) 
{
  int               timer_pos;  /* Position in the table of the timer that    
			         *  has expirated 			     */
  rtems_status_code return_v;   /* Return value of rtems_timer_fire_after    */
  int               sig_number; /* Number of the signal to send              */

 
  /* The position of the table of timers that contains the data of the 
   * expired timer will be stored in "timer_pos". In theory a timer can not
   * expire if it has not been created or has been deleted */ 

  PRINT_MSG_S ("FIRE_TIMER_S");

  timer_pos = TIMER_POSITION_F(timer);

  /* Increases the number of expiration of the timer in one unit. */
  timer_struct[timer_pos].overrun = timer_struct[timer_pos].overrun + 1;


  if ( ( timer_struct[timer_pos].timer_data.it_interval.tv_sec  != 0 ) ||
       ( timer_struct[timer_pos].timer_data.it_interval.tv_nsec != 0 ) ) {

     /* The timer must be reprogrammed */

     return_v = rtems_timer_fire_after ( timer, 
                                        timer_struct[timer_pos].ticks, 
                                        FIRE_TIMER_S, 
                                        NULL );

     /* Stores the time when the timer was started again */ 

     return_v = rtems_clock_get ( RTEMS_CLOCK_GET_TOD, 
                                 &timer_struct[timer_pos].time );
     
     /* The state has not to be actualized, because nothing modifies it */

     timer_struct[timer_pos].state = STATE_CREATE_RUN_C;

  } else {
     /* Indicates that the timer is stopped */
 
     timer_struct[timer_pos].state = STATE_CREATE_STOP_C;

  }

  /* 
   * The sending of the signal to the process running the handling function
   * specified for that signal is simulated
   */

  sig_number = timer_struct[timer_pos].inf.sigev_signo;

  if( pthread_kill ( timer_struct[timer_pos].thread_id ,
                     timer_struct[timer_pos].inf.sigev_signo ) ) {
     PRINT_MSG_S ("ERROR_PTHREAD_KILL");
  } else {
     PRINT_MSG_S ("SUCCESS_PTHREAD_KILL");
  }

  /*
   * After the signal handler returns, the count of expirations of the
   * timer must be set to 0.
   */

  timer_struct[timer_pos].overrun = 0;

}

/* ********************************************************************* 
 *  14.2.2 Create a Per-Process Timer, P1003.1b-1993, p. 264
 * ********************************************************************/

/* **************
 * timer_create
 * **************/

int timer_create(
  clockid_t        clock_id,
  struct sigevent *evp,
  timer_t         *timerid
)
{

  rtems_status_code return_v;  /* return value of the operation    */
  rtems_id          timer_id;  /* created timer identifier         */
  int               timer_pos; /* Position in the table of timers  */

 /* 
  * The data of the structure evp are checked in order to verify if they
  * are coherent. 
  */

  if (evp != NULL) {
     /* The structure has data */

     if ( ( evp->sigev_notify != SIGEV_NONE ) && 
          ( evp->sigev_notify != SIGEV_SIGNAL ) ) {
       /* The value of the field sigev_notify is not valid */

       return (-1);

     }
  }
 
 /*
  * A timer is created using the primitive rtems_timer_create
  */

  return_v = rtems_timer_create ( clock_id, &timer_id );

  switch (return_v) {
     case RTEMS_SUCCESSFUL : 

       PRINT_MSG_S("SUCCESS: rtems create timer RTEMS_SUCCESSFUL");
      
       /*
        * The timer has been created properly
        */
 
        /* Obtains the first free position in the table of timers */

        timer_pos = FIRST_FREE_POSITION_F();

        if ( timer_pos == NO_MORE_TIMERS_C ) {
           /* There is not position for another timers in spite of RTEMS 
	    * supports it. It will necessaty to increase the structure used */

           errno = EAGAIN;

           return -1;
        }

        /* Exit parameter */

        *timerid  = timer_id;

        /* The data of the created timer are stored to use them later */

        timer_struct[timer_pos].state     = STATE_CREATE_NEW_C;

        /* NEW VERSION*/
        timer_struct[timer_pos].thread_id = pthread_self ();
        

        if ( evp != NULL ) {

           timer_struct[timer_pos].inf.sigev_notify = evp->sigev_notify;
           timer_struct[timer_pos].inf.sigev_signo  = evp->sigev_signo;
           timer_struct[timer_pos].inf.sigev_value  = evp->sigev_value;

        }


        timer_struct[timer_pos].timer_id = timer_id;

        timer_struct[timer_pos].overrun  = 0;

        timer_struct[timer_pos].timer_data.it_value.tv_sec     = 0;
        timer_struct[timer_pos].timer_data.it_value.tv_nsec    = 0;
        timer_struct[timer_pos].timer_data.it_interval.tv_sec  = 0;
        timer_struct[timer_pos].timer_data.it_interval.tv_nsec = 0;

        return 0;
    

     case RTEMS_INVALID_NAME : /* The assigned name is not valid*/

       PRINT_MSG_S ("ERROR: rtems create timer RTEMS_INVALID_NAME");

       errno = EINVAL;

       return (-1);


     case RTEMS_TOO_MANY :

       PRINT_MSG_S ("ERROR: rtems create timer RTEMS_TOO_MANY ");
 
       /* There has been created too much timers for the same process */

       errno = EAGAIN;

       return (-1);
     
     default :

       /*
        * Does nothing. It only returns the error without assigning a value
        * to errno. In theory, it can not happen because the call to
        * rtems_timer_create can not return other different value. 
        */

       return (-1);

  }

  /* 
   * The next sentence is used to avoid singular situations 
   */

  return (-1);

}

/*
 *  14.2.3 Delete a Per_process Timer, P1003.1b-1993, p. 266
 */

int timer_delete(
  timer_t timerid
)
{
 
 /*
  * IDEA: This function must probably stop the timer first and then delete it
  *
  *       It will have to do a call to rtems_timer_cancel and then another
  *       call to rtems_timer_delete.
  *       The call to rtems_timer_delete will be probably unnecessary, 
  *       because rtems_timer_delete stops the timer before deleting it.
  */

  int               timer_pos;
  rtems_status_code status;


   /* First the position in the table of timers is obtained */

   timer_pos = TIMER_POSITION_F ( timerid );

   if ( timer_pos == BAD_TIMER_C ) {
      /* The timer identifier is erroneus */

      errno = EINVAL;
      return -1;
   }

   /* The timer is deleted */

   status = rtems_timer_delete ( timerid );

   if ( status == RTEMS_INVALID_ID ) {
      /* The timer identifier is erroneus */

      errno = EINVAL;
      return -1;
   }

   /* Initializes the data of the timer */

   TIMER_INITIALIZE_S ( timer_pos );

   return 0;
}

/*
 *  14.2.4 Per-Process Timers, P1003.1b-1993, p. 267
 */

/* **************
 * timer_settime
 * **************/


int timer_settime(
  timer_t                  timerid,
  int                      flags,
  const struct itimerspec *value,
  struct itimerspec       *ovalue
)
{

   rtems_status_code return_v;   /* Return of the calls to RTEMS        */
   int               timer_pos;  /* Position of the timer in the table  */
   rtems_time_of_day rtems_time; /* Time in RTEMS                       */

   /* First the position in the table of timers is obtained */

   timer_pos = TIMER_POSITION_F ( timerid );

   if ( timer_pos == BAD_TIMER_C ) {
      /* The timer identifier is erroneus */

      errno = EINVAL;
      return -1;
   }

   if ( value == NULL ) {
     /* The stucture of times of the timer is free, and then returns an
	error but the variable errno is not actualized */

     /* errno = ?????? */

     return -1;
   }

   /* 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 */

   /* First, it verifies if the timer must be stopped */

   if ( value->it_value.tv_sec == 0 && value->it_value.tv_nsec == 0 ) {
      /* The timer is stopped */

      return_v = rtems_timer_cancel ( timerid );

      /* The old data of the timer are returned */

      COPY_ITIMERSPEC_S ( &timer_struct[timer_pos].timer_data, ovalue );

      /* The new data are set */

      COPY_ITIMERSPEC_S ( value, &timer_struct[timer_pos].timer_data );

      /* Indicates that the timer is created and stopped */
 
      timer_struct[timer_pos].state = STATE_CREATE_STOP_C;

      /* Returns with success */

      return 0;
   }

   /* 
    * If the function reaches this point, then the timer will have to be
    * initialized with new values: to start it or start it again 
    */
  
   /* First, it verifies if the structure "value" is correct */

    if ( ( value->it_value.tv_nsec > MAX_NSEC_C ) ||
         ( value->it_value.tv_nsec < MIN_NSEC_C ) ) {
       /* The number of nanoseconds is not correct */

       errno = EINVAL;

       return -1;
    }

   /* Then, "value" must be converted from seconds and nanoseconds to clock
    * ticks, to use it in the calls to RTEMS */

   /* It is also necessary to take in account if the time is absolute 
    * or relative */

   switch (flags) {
      case TIMER_ABSTIME:

        /* The fire time is absolute:
         * It has to use "rtems_time_fire_when" */

        /* First, it converts from struct itimerspec to rtems_time_of_day */

        ITIMERSPEC_TO_RTEMS_TIME_OF_DAY_S ( value, &rtems_time );

        return_v = rtems_timer_fire_when ( timerid, &rtems_time, FIRE_TIMER_S, NULL);

        switch ( return_v ) {
           case RTEMS_SUCCESSFUL:

              PRINT_MSG_S ("SUCCESS: timer_settime RTEMS_SUCCESSFUL");

              /* The timer has been started and is running */

              /* Actualizes the data of the structure and 
               * returns the old ones in "ovalue" */

              COPY_ITIMERSPEC_S ( &timer_struct[timer_pos].timer_data, ovalue );

              COPY_ITIMERSPEC_S ( value, &timer_struct[timer_pos].timer_data );
 
              /* It indicates that the time is running */

              timer_struct[timer_pos].state = STATE_CREATE_RUN_C;

              /* Stores the time in which the timer was started again */

              return_v = rtems_clock_get ( RTEMS_CLOCK_GET_TOD,
                                          &timer_struct[timer_pos].time );

              return 0;

              break;

           case RTEMS_INVALID_ID:

              PRINT_MSG_S ("ERROR: timer_settime RTEMS_INVALID_ID");
              break;

           case RTEMS_NOT_DEFINED:

              PRINT_MSG_S ("ERROR: timer_settime RTEMS_NOT_DEFINED");
              break;

           case RTEMS_INVALID_CLOCK:

              PRINT_MSG_S ("ERROR: timer_settime RTEMS_INVALID_CLOCK");
              break;

           default:

        
        }
     
        break;

      case TIMER_RELATIVE_C:

        /* The fire time is relative:
         * It has to use "rtems_time_fire_after" */

        /* First, it converts from seconds and nanoseconds to ticks */

        /* The form in which this operation is done can produce a lost 
         * of precision of 1 second */
 
/*      This is the process to convert from nanoseconds to ticks
 *
 *      There is a tick every 10 miliseconds, then the nanoseconds are 
 *      divided between 10**7. The result of this operation will be the
 *      number of ticks 
 */

        timer_struct[timer_pos].ticks = 
             ( SEC_TO_TICKS_C * value->it_value.tv_sec ) +
             ( value->it_value.tv_nsec / ( 1000 * 1000 * 10 ) );

        return_v = rtems_timer_fire_after ( timerid, 
                                           timer_struct[timer_pos].ticks, 
                                           FIRE_TIMER_S, 
                                           NULL );

        switch (return_v) {
           case RTEMS_SUCCESSFUL:

              PRINT_MSG_S ( "SUCCESS: timer_settime RTEMS_SUCCESSFUL");
              
              /* The timer has been started and is running */

              /* Actualizes the data of the structure and 
               * returns the old ones in "ovalue" */

              COPY_ITIMERSPEC_S ( &timer_struct[timer_pos].timer_data, ovalue );

              COPY_ITIMERSPEC_S ( value, &timer_struct[timer_pos].timer_data );
 
              /* It indicates that the time is running */

              timer_struct[timer_pos].state = STATE_CREATE_RUN_C;

              /* Stores the time in which the timer was started again */

              return_v = rtems_clock_get ( RTEMS_CLOCK_GET_TOD,
                                          &timer_struct[timer_pos].time );
 
              return 0;

              break;

           case RTEMS_INVALID_ID:

              PRINT_MSG_S ( "ERROR: timer_settime RTEMS_INVALID_ID");

              /* The timer identifier is not correct. In theory, this 
               * situation can not occur, but the solution is easy */ 

              errno = EINVAL;

              return -1;

              break;

           case RTEMS_INVALID_NUMBER:

              PRINT_MSG_S ( "ERROR: timer_settime RTEMS_INVALID_NUMBER");

              /* In this case, RTEMS fails because the values of timing
               * are incorrect */

              /*
               * I do not know if errno must be actualized 
               *
               * errno = EINVAL;
               */

              return -1;

              break;
           
           default:
        }

        break;

      default:

        /* It does nothing, although it will be probably necessary to 
         * return an error */

   }

   /* To avoid problems */

   return 0;

}


/*
 *  14.2.4 Per-Process Timers, P1003.1b-1993, p. 267
 */

/* **************
 * timer_gettime
 * **************/

int timer_gettime(
  timer_t            timerid,
  struct itimerspec *value
)
{

 /* 
  * IDEA:  This function does not use functions of RTEMS to the handle
  *        of timers. It uses some functions for managing the time.
  *
  *        A possible form to do this is the following:
  *
  *          - When a timer is initialized, the value of the time in 
  *            that moment is stored.
  *          - When this function is called, it returns the difference
  *            between the current time and the initialization time.
  */
 
  rtems_time_of_day current_time;
  rtems_status_code return_v;
  int               timer_pos;
  unsigned32        hours;
  unsigned32        minutes;
  unsigned32        seconds;
  unsigned32        ticks;
  unsigned32        nanosec;
 

  /* Reads the current time */

  return_v = rtems_clock_get ( RTEMS_CLOCK_GET_TOD, &current_time );

  timer_pos = TIMER_POSITION_F ( timerid );

  if ( timer_pos == BAD_TIMER_C ) {

     /* The timer identifier is erroneus */  

     errno = EINVAL;

     return (-1);

  }

  /* Calculates the difference between the start time of the timer and
   * the current one */

  hours    = current_time.hour - timer_struct[timer_pos].time.hour;

  if ( current_time.minute < timer_struct[timer_pos].time.minute ) {
     minutes = 60 - timer_struct[timer_pos].time.minute + current_time.minute;
     hours--;
  } else {
     minutes = current_time.minute - timer_struct[timer_pos].time.minute;
  }
    
  if ( current_time.second < timer_struct[timer_pos].time.second ) {
     seconds = 60 - timer_struct[timer_pos].time.second + current_time.second;
     minutes--;
  } else {
     seconds = current_time.second - timer_struct[timer_pos].time.second; 
  }

  if ( current_time.ticks < timer_struct[timer_pos].time.ticks ) {
     ticks = 100 - timer_struct[timer_pos].time.ticks + current_time.ticks;
     seconds--;
  } else {
     ticks = current_time.ticks - timer_struct[timer_pos].time.ticks; 
  }

  /* The time that the timer is running is calculated */
  seconds = hours   * 60 * 60 +
            minutes * 60      +
            seconds; 

  nanosec  = ticks * 10 *  /* msec     */
             1000  *       /* microsec */
             1000;         /* nanosec  */

  
  /* Calculates the time left before the timer finishes */
  
  value->it_value.tv_sec = 
    timer_struct[timer_pos].timer_data.it_value.tv_sec - seconds;
  
  value->it_value.tv_nsec = 
    timer_struct[timer_pos].timer_data.it_value.tv_nsec - nanosec;


  value->it_interval.tv_sec  = 
    timer_struct[timer_pos].timer_data.it_interval.tv_sec;
  value->it_interval.tv_nsec = 
    timer_struct[timer_pos].timer_data.it_interval.tv_nsec;
 

  return 0;

}

/*
 *  14.2.4 Per-Process Timers, P1003.1b-1993, p. 267
 */

/* *****************
 * timer_getoverrun
 * *****************/

int timer_getoverrun(
  timer_t   timerid
)
{

 /*
  * IDEA: This function must count the times the timer expires.
  *   
  *       The expiration of a timer must increase by one a counter.
  *       After the signal handler associated to the timer finishs 
  *       its execution, FIRE_TIMER_S will have to set this counter to 0.
  */

  int timer_pos; /* Position of the timer in the structure     */
  int overrun;   /* Overflow count                             */


  timer_pos = TIMER_POSITION_F ( timerid );

  if ( timer_pos == BAD_TIMER_C ) {
     /* The timer identifier is erroneus */

     errno = EINVAL;

     return -1;
  }

  /* The overflow count of the timer is stored in "overrun" */

  overrun = timer_struct[timer_pos].overrun;

  /* It is set to 0 */

  timer_struct[timer_pos].overrun = 0;

  return overrun;

}