/* * ptimer.c,v 1.1 1996/06/03 16:29:58 joel Exp */ #include #include #include #include #include #include #include #include /************************************/ /* These includes are now necessary */ /************************************/ #include #include #include #include #include #include #include #include #include #include /*****************************/ /* 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; indexit_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, ¤t_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; }