summaryrefslogtreecommitdiffstats
path: root/cpukit/posix/src/ptimer1.c
diff options
context:
space:
mode:
Diffstat (limited to 'cpukit/posix/src/ptimer1.c')
-rw-r--r--cpukit/posix/src/ptimer1.c568
1 files changed, 568 insertions, 0 deletions
diff --git a/cpukit/posix/src/ptimer1.c b/cpukit/posix/src/ptimer1.c
new file mode 100644
index 0000000000..87a17f22d2
--- /dev/null
+++ b/cpukit/posix/src/ptimer1.c
@@ -0,0 +1,568 @@
+/*
+ * ptimer.c,v 1.1 1996/06/03 16:29:58 joel Exp
+ */
+
+#if HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#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 <unistd.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 <pthread.h>
+#include <stdio.h>
+#include <signal.h>
+
+#include <rtems/seterr.h>
+#include <rtems/posix/timer.h>
+
+boolean _Watchdog_Insert_ticks_helper(
+ Watchdog_Control *timer,
+ Watchdog_Interval ticks,
+ Objects_Id id,
+ Watchdog_Service_routine_entry TSR,
+ void *arg
+)
+{
+ ISR_Level level;
+
+ (void) _Watchdog_Remove( timer );
+ _ISR_Disable( level );
+
+ /*
+ * Check to see if the watchdog has just been inserted by a
+ * higher priority interrupt. If so, abandon this insert.
+ */
+ if ( timer->state != WATCHDOG_INACTIVE ) {
+ _ISR_Enable( level );
+ return FALSE;
+ }
+
+ /*
+ * OK. Now we now the timer was not rescheduled by an interrupt
+ * so we can atomically initialize it as in use.
+ */
+ _Watchdog_Initialize( timer, TSR, id, arg );
+ _Watchdog_Insert_ticks( timer, ticks );
+ _ISR_Enable( level );
+ return TRUE;
+}
+
+/* #define DEBUG_MESSAGES */
+
+/*
+ * 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
+ * considered. 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/
+ (NSEC_PER_SEC_C / SEC_TO_TICKS_C);
+
+}
+
+
+/* ***************************************************************************
+ * _POSIX_Timer_TSR
+ *
+ * Description: This is the operation that is ran when a timer expires
+ * ***************************************************************************/
+
+
+void _POSIX_Timer_TSR(Objects_Id timer, void *data)
+{
+ POSIX_Timer_Control *ptimer;
+ boolean activated;
+
+ ptimer = (POSIX_Timer_Control *)data;
+
+ /* Increment the number of expirations. */
+ ptimer->overrun = ptimer->overrun + 1;
+ /* The timer must be reprogrammed */
+ if ( ( ptimer->timer_data.it_interval.tv_sec != 0 ) ||
+ ( ptimer->timer_data.it_interval.tv_nsec != 0 ) ) {
+#if 0
+ status = rtems_timer_fire_after(
+ ptimer->timer_id, ptimer->ticks, _POSIX_Timer_TSR, ptimer );
+#endif
+ activated = _Watchdog_Insert_ticks_helper(
+ &ptimer->Timer,
+ ptimer->ticks,
+ ptimer->Object.id,
+ _POSIX_Timer_TSR,
+ ptimer
+ );
+ if ( !activated )
+ return;
+
+ /* Store the time when the timer was started again */
+ ptimer->time = _TOD_Current;
+
+ /* The state really did not change but just to be safe */
+ ptimer->state = STATE_CREATE_RUN_C;
+ } else {
+ /* Indicates that the timer is stopped */
+ ptimer->state = STATE_CREATE_STOP_C;
+ }
+
+ /*
+ * The sending of the signal to the process running the handling function
+ * specified for that signal is simulated
+ */
+
+ if ( pthread_kill ( ptimer->thread_id, ptimer->inf.sigev_signo ) ) {
+ /* XXX error handling */
+ }
+
+ /* After the signal handler returns, the count of expirations of the
+ * timer must be set to 0.
+ */
+ ptimer->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
+)
+{
+ POSIX_Timer_Control *ptimer;
+
+ if ( clock_id != CLOCK_REALTIME )
+ rtems_set_errno_and_return_minus_one( EINVAL );
+
+ /*
+ * 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 */
+ rtems_set_errno_and_return_minus_one( EINVAL );
+ }
+
+ if ( !evp->sigev_signo )
+ rtems_set_errno_and_return_minus_one( EINVAL );
+
+ if ( !is_valid_signo(evp->sigev_signo) )
+ rtems_set_errno_and_return_minus_one( EINVAL );
+ }
+
+ _Thread_Disable_dispatch(); /* to prevent deletion */
+
+ /*
+ * Allocate a timer
+ */
+ ptimer = _POSIX_Timer_Allocate();
+ if ( !ptimer ) {
+ _Thread_Enable_dispatch();
+ rtems_set_errno_and_return_minus_one( EAGAIN );
+ }
+
+ /* The data of the created timer are stored to use them later */
+
+ ptimer->state = STATE_CREATE_NEW_C;
+ ptimer->thread_id = _Thread_Executing->Object.id;
+
+ if ( evp != NULL ) {
+ ptimer->inf.sigev_notify = evp->sigev_notify;
+ ptimer->inf.sigev_signo = evp->sigev_signo;
+ ptimer->inf.sigev_value = evp->sigev_value;
+ }
+
+ ptimer->overrun = 0;
+ ptimer->timer_data.it_value.tv_sec = 0;
+ ptimer->timer_data.it_value.tv_nsec = 0;
+ ptimer->timer_data.it_interval.tv_sec = 0;
+ ptimer->timer_data.it_interval.tv_nsec = 0;
+
+ _Watchdog_Initialize( &ptimer->Timer, NULL, 0, NULL );
+ _Objects_Open(&_POSIX_Timer_Information, &ptimer->Object, (Objects_Name) 0);
+
+ *timerid = ptimer->Object.id;
+ _Thread_Enable_dispatch();
+ return 0;
+}
+
+/*
+ * 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.
+ */
+ POSIX_Timer_Control *ptimer;
+ Objects_Locations location;
+
+ ptimer = _POSIX_Timer_Get( timerid, &location );
+ switch ( location ) {
+ case OBJECTS_REMOTE:
+#if defined(RTEMS_MULTIPROCESSING)
+ _Thread_Dispatch();
+ rtems_set_errno_and_return_minus_one( EINVAL );
+#endif
+
+ case OBJECTS_ERROR:
+ rtems_set_errno_and_return_minus_one( EINVAL );
+
+ case OBJECTS_LOCAL:
+ _Objects_Close( &_POSIX_Timer_Information, &ptimer->Object );
+ ptimer->state = STATE_FREE_C;
+ (void) _Watchdog_Remove( &ptimer->Timer );
+ _POSIX_Timer_Free( ptimer );
+ _Thread_Enable_dispatch();
+ return 0;
+ }
+ return -1; /* unreached - only to remove warnings */
+}
+
+/*
+ * 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
+)
+{
+ POSIX_Timer_Control *ptimer;
+ Objects_Locations location;
+ boolean activated;
+
+ if ( value == NULL ) {
+ rtems_set_errno_and_return_minus_one( EINVAL );
+ }
+
+ /* 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 */
+ rtems_set_errno_and_return_minus_one( EINVAL );
+ }
+
+ /* XXX check for seconds in the past */
+
+ if ( flags != TIMER_ABSTIME && flags != TIMER_RELATIVE_C ) {
+ rtems_set_errno_and_return_minus_one( EINVAL );
+ }
+
+ /* 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
+ */
+
+ ptimer = _POSIX_Timer_Get( timerid, &location );
+ switch ( location ) {
+ case OBJECTS_REMOTE:
+#if defined(RTEMS_MULTIPROCESSING)
+ _Thread_Dispatch();
+ return -1;
+ rtems_set_errno_and_return_minus_one( EINVAL );
+#endif
+
+ case OBJECTS_ERROR:
+ return -1;
+
+ case OBJECTS_LOCAL:
+ /* First, it verifies if the timer must be stopped */
+ if ( value->it_value.tv_sec == 0 && value->it_value.tv_nsec == 0 ) {
+ /* Stop the timer */
+ (void) _Watchdog_Remove( &ptimer->Timer );
+ /* The old data of the timer are returned */
+ if ( ovalue )
+ *ovalue = ptimer->timer_data;
+ /* The new data are set */
+ ptimer->timer_data = *value;
+ /* Indicates that the timer is created and stopped */
+ ptimer->state = STATE_CREATE_STOP_C;
+ /* Returns with success */
+ _Thread_Enable_dispatch();
+ return 0;
+ }
+
+ /* absolute or relative? */
+ switch (flags) {
+ case TIMER_ABSTIME:
+
+ /* The fire time is absolute: use "rtems_time_fire_when" */
+ /* First, it converts from struct itimerspec to rtems_time_of_day */
+
+#if 0
+ ITIMERSPEC_TO_RTEMS_TIME_OF_DAY_S( value, &tod );
+ status = rtems_timer_fire_when(
+ ptimer->timer_id, &tod, _POSIX_Timer_TSR, ptimer);
+#endif
+ _Watchdog_Initialize(
+ &ptimer->Timer, _POSIX_Timer_TSR, ptimer->Object.id, ptimer );
+
+ _Watchdog_Insert_seconds(
+ &ptimer->Timer,
+ value->it_value.tv_sec - _TOD_Seconds_since_epoch
+ );
+
+ /* Returns the old ones in "ovalue" */
+ if ( ovalue )
+ *ovalue = ptimer->timer_data;
+ ptimer->timer_data = *value;
+
+ /* Indicate that the time is running */
+ ptimer->state = STATE_CREATE_RUN_C;
+
+ /* Stores the time in which the timer was started again */
+ ptimer->time = _TOD_Current;
+ _Thread_Enable_dispatch();
+ return 0;
+ break;
+
+ /* The fire time is relative: use "rtems_time_fire_after" */
+ case TIMER_RELATIVE_C:
+ /* First, convert from seconds and nanoseconds to ticks */
+ ptimer->ticks = ( SEC_TO_TICKS_C * value->it_value.tv_sec ) +
+ ( value->it_value.tv_nsec / (NSEC_PER_SEC_C / SEC_TO_TICKS_C));
+
+#if 0
+ status = rtems_timer_fire_after(
+ ptimer->timer_id, ptimer->ticks, _POSIX_Timer_TSR, ptimer );
+#endif
+ activated = _Watchdog_Insert_ticks_helper(
+ &ptimer->Timer,
+ ptimer->ticks,
+ ptimer->Object.id,
+ _POSIX_Timer_TSR,
+ ptimer
+ );
+ if ( !activated )
+ return 0;
+
+ /* The timer has been started and is running */
+ /* return the old ones in "ovalue" */
+ if ( ovalue )
+ *ovalue = ptimer->timer_data;
+ ptimer->timer_data = *value;
+
+ /* Indicate that the time is running */
+ ptimer->state = STATE_CREATE_RUN_C;
+ ptimer->time = _TOD_Current;
+ _Thread_Enable_dispatch();
+ return 0;
+ }
+ _Thread_Enable_dispatch();
+ rtems_set_errno_and_return_minus_one( EINVAL );
+ }
+ return -1; /* unreached - only to remove warnings */
+}
+
+/*
+ * 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.
+ */
+
+ POSIX_Timer_Control *ptimer;
+ Objects_Locations location;
+ rtems_time_of_day current_time;
+ uint32_t hours;
+ uint32_t minutes;
+ uint32_t seconds;
+ uint32_t ticks;
+ uint32_t nanosec;
+
+ /* Reads the current time */
+ current_time = _TOD_Current;
+
+ ptimer = _POSIX_Timer_Get( timerid, &location );
+ switch ( location ) {
+ case OBJECTS_REMOTE:
+#if defined(RTEMS_MULTIPROCESSING)
+ _Thread_Dispatch();
+ rtems_set_errno_and_return_minus_one( EINVAL );
+#endif
+
+ case OBJECTS_ERROR:
+ rtems_set_errno_and_return_minus_one( EINVAL );
+
+ case OBJECTS_LOCAL:
+ /* Calculates the difference between the start time of the timer and
+ * the current one */
+
+ hours = current_time.hour - ptimer->time.hour;
+
+ if ( current_time.minute < ptimer->time.minute ) {
+ minutes = 60 - ptimer->time.minute + current_time.minute;
+ hours--;
+ } else {
+ minutes = current_time.minute - ptimer->time.minute;
+ }
+
+ if ( current_time.second < ptimer->time.second ) {
+ seconds = 60 - ptimer->time.second + current_time.second;
+ minutes--;
+ } else {
+ seconds = current_time.second - ptimer->time.second;
+ }
+
+ if ( current_time.ticks < ptimer->time.ticks ) {
+ ticks = 100 - ptimer->time.ticks + current_time.ticks;
+ seconds--;
+ } else {
+ ticks = current_time.ticks - ptimer->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 = ptimer->timer_data.it_value.tv_sec - seconds;
+ value->it_value.tv_nsec = ptimer->timer_data.it_value.tv_nsec - nanosec;
+
+ value->it_interval.tv_sec = ptimer->timer_data.it_interval.tv_sec;
+ value->it_interval.tv_nsec = ptimer->timer_data.it_interval.tv_nsec;
+
+ _Thread_Enable_dispatch();
+ return 0;
+ }
+ return -1; /* unreached - only to remove warnings */
+}
+
+/*
+ * 14.2.4 Per-Process Timers, P1003.1b-1993, p. 267
+ */
+
+/*
+ * timer_getoverrun
+ *
+ * The expiration of a timer must increase by one a counter.
+ * After the signal handler associated to the timer finishes
+ * its execution, _POSIX_Timer_TSR will have to set this counter to 0.
+ */
+
+int timer_getoverrun(
+ timer_t timerid
+)
+{
+ int overrun;
+ POSIX_Timer_Control *ptimer;
+ Objects_Locations location;
+
+ ptimer = _POSIX_Timer_Get( timerid, &location );
+ switch ( location ) {
+ case OBJECTS_REMOTE:
+#if defined(RTEMS_MULTIPROCESSING)
+ _Thread_Dispatch();
+ rtems_set_errno_and_return_minus_one( EINVAL );
+#endif
+
+ case OBJECTS_ERROR:
+ rtems_set_errno_and_return_minus_one( EINVAL );
+
+ case OBJECTS_LOCAL:
+ overrun = ptimer->overrun;
+ ptimer->overrun = 0;
+ _Thread_Enable_dispatch();
+ return overrun;
+ }
+ return -1; /* unreached - only to remove warnings */
+}