/*! Cancel sleep * - handle return values and errno; * - thread must be handled elsewhere - with source of interrupt (signal?) */ static void kclock_interrupt_sleep ( kthread_t *kthread, void *param ) { ktimer_t *ktimer; timespec_t *remain; itimerspec_t irem; ASSERT ( kthread && param ); ASSERT ( kthread_check_kthread ( kthread ) ); /* is this valid thread */ ASSERT ( kthread_is_suspended ( kthread, NULL, NULL ) ); ktimer = param; remain = ktimer->param; if ( remain ) { /* save remaining time */ timespec_t now; kclock_gettime ( CLOCK_REALTIME, &now ); ktimer_gettime ( ktimer, &irem ); *remain = irem.it_value; time_sub ( remain, &now ); } ktimer_delete (ktimer); kthread_set_syscall_retval ( kthread, EXIT_FAILURE ); kthread_set_errno ( kthread, EINTR ); }
/*! * Get timer expiration time * \param ktimer Timer * \param value Where to store time to next timer expiration (+period) * \return status 0 for success */ int ktimer_gettime ( ktimer_t *ktimer, itimerspec_t *value ) { ASSERT( ktimer && value ); timespec_t now; kclock_gettime ( ktimer->clockid, &now ); *value = ktimer->itimer; /* return relative time to timer expiration */ if ( TIME_IS_SET ( &value->it_value ) ) time_sub ( &value->it_value, &now ); return EXIT_SUCCESS; }
/*! * Get current time * \param clockid Clock to use * \param time Pointer where to store time * \return status (0 if successful, -1 otherwise) */ int sys__clock_gettime ( clockid_t clockid, timespec_t *time ) { int retval; SYS_ENTRY(); ASSERT_ERRNO_AND_EXIT ( time && (clockid==CLOCK_REALTIME || clockid==CLOCK_MONOTONIC), EINVAL ); retval = kclock_gettime ( clockid, time ); SYS_EXIT ( retval, retval ); }
/*! Check if task hasn't overrun its deadline */ static int edf_check_deadline ( kthread_t *kthread ) { /* Check if "now" is greater than "active_deadline" */ timespec_t now; kthread_sched2_t *tsched = kthread_get_sched2_param ( kthread ); kclock_gettime ( CLOCK_REALTIME, &now ); if ( time_cmp ( &now, &tsched->params.edf.active_deadline ) > 0 ) { EDF_LOG ( "%x [DEADLINE OVERRUN]", kthread ); return EXIT_FAILURE; } return 0; }
/*! * Get current time * \param clockid Clock to use * \param time Pointer where to store time * \return status (0 if successful, -1 otherwise) */ int sys__clock_gettime ( void *p ) { clockid_t clockid; timespec_t *time; int retval; clockid = *( (clockid_t *) p ); p += sizeof (clockid_t); time = *( (void **) p ); ASSERT_ERRNO_AND_EXIT ( time && (clockid==CLOCK_REALTIME || clockid==CLOCK_MONOTONIC), EINVAL ); retval = kclock_gettime ( clockid, time ); EXIT ( retval ); }
/*! * Arm/disarm timer * \param ktimer Timer * \param flags Various flags * \param value Set timer values (it_value+it_period) * \param ovalue Where to store time to next timer expiration (+period) * \return status 0 for success */ int ktimer_settime ( ktimer_t *ktimer, int flags, itimerspec_t *value, itimerspec_t *ovalue ) { timespec_t now; ASSERT ( ktimer ); kclock_gettime ( ktimer->clockid, &now ); if ( ovalue ) { *ovalue = ktimer->itimer; /* return relative time to timer expiration */ if ( TIME_IS_SET ( &ovalue->it_value ) ) time_sub ( &ovalue->it_value, &now ); } /* first disarm timer, if it was armed */ if ( TIMER_IS_ARMED ( ktimer ) ) { TIMER_DISARM ( ktimer ); list_remove ( &ktimers, 0, &ktimer->list ); } if ( value && TIME_IS_SET ( &value->it_value ) ) { /* arm timer */ ktimer->itimer = *value; if ( !(flags & TIMER_ABSTIME) ) /* convert to absolute time */ time_add ( &ktimer->itimer.it_value, &now ); list_sort_add ( &ktimers, ktimer, &ktimer->list, ktimer_cmp ); } ktimer_schedule (); return EXIT_SUCCESS; }
/*! Activate timers and reschedule threads if required */ static void ktimer_schedule () { ktimer_t *first; timespec_t time, ref_time; int resched = 0; kclock_gettime ( CLOCK_REALTIME, &time ); /* should have separate "scheduler" for each clock */ ref_time = time; time_add ( &ref_time, &threshold ); /* use "ref_time" instead of "time" when looking timers to activate */ /* should any timer be activated? */ first = list_get ( &ktimers, FIRST ); while ( first != NULL ) { /* timers have absolute values in 'it_value' */ if ( time_cmp ( &first->itimer.it_value, &ref_time ) <= 0 ) { /* 'activate' timer */ /* but first remove timer from list */ first = list_remove ( &ktimers, FIRST, NULL ); /* and add to list if period is given */ if ( TIME_IS_SET ( &first->itimer.it_interval) ) { /* calculate next activation time */ time_add ( &first->itimer.it_value, &first->itimer.it_interval ); /* put back into list */ list_sort_add ( &ktimers, first, &first->list, ktimer_cmp ); } else { TIMER_DISARM ( first ); } if ( first->owner == NULL ) { /* timer set by kernel - call now, directly */ if ( first->evp.sigev_notify_function ) first->evp.sigev_notify_function ( first->evp.sigev_value ); } else { /* timer set by thread */ if ( !ksignal_process_event ( &first->evp, first->owner, SI_TIMER ) ) { resched++; } } first = list_get ( &ktimers, FIRST ); } else { break; } } first = list_get ( &ktimers, FIRST ); if ( first ) { ref_time = first->itimer.it_value; time_sub ( &ref_time, &time ); arch_timer_set ( &ref_time, ktimer_schedule ); } if ( resched ) kthreads_schedule (); }
static int edf_set_thread_sched_parameters ( ksched_t *ksched, kthread_t *kthread, sched_supp_t *params ) { timespec_t now; itimerspec_t alarm; kthread_sched2_t *tsched = kthread_get_sched2_param ( kthread ); if ( ksched->params.edf.active == kthread ) ksched->params.edf.active = NULL; kclock_gettime ( CLOCK_REALTIME, &now ); if ( params->edf.flags & EDF_SET ) { tsched->params.edf.period = params->edf.period; tsched->params.edf.relative_deadline = params->edf.deadline; tsched->params.edf.flags = params->edf.flags ^ EDF_SET; /* create and set periodic alarm */ edf_create_alarm ( kthread, edf_period_alarm, &tsched->params.edf.period_alarm ); tsched->params.edf.next_run = now; time_add ( &tsched->params.edf.next_run, ¶ms->edf.period ); alarm.it_interval = tsched->params.edf.period; alarm.it_value = tsched->params.edf.next_run; ktimer_settime ( tsched->params.edf.period_alarm, TIMER_ABSTIME, &alarm, NULL ); /* adjust "next_run" and "deadline" for "0" period * first "edf_wait" will set correct values for first period */ tsched->params.edf.next_run = now; time_sub ( &tsched->params.edf.next_run, ¶ms->edf.period ); /* create and set deadline alarm */ edf_create_alarm ( kthread, edf_deadline_alarm, &tsched->params.edf.deadline_alarm ); tsched->params.edf.active_deadline = now; time_add ( &tsched->params.edf.active_deadline, ¶ms->edf.deadline ); TIME_RESET ( &alarm.it_interval ); alarm.it_value = tsched->params.edf.active_deadline; ktimer_settime ( tsched->params.edf.deadline_alarm, TIMER_ABSTIME, &alarm, NULL ); /* move thread to edf scheduler */ kthread_enqueue ( kthread, &ksched->params.edf.ready ); edf_schedule (ksched); } else if ( params->edf.flags & EDF_WAIT ) { if ( edf_check_deadline ( kthread ) ) return EXIT_FAILURE; /* set times for next period */ if ( time_cmp ( &now, &tsched->params.edf.next_run ) > 0 ) { time_add ( &tsched->params.edf.next_run, &tsched->params.edf.period ); tsched->params.edf.active_deadline = tsched->params.edf.next_run; time_add ( &tsched->params.edf.active_deadline, &tsched->params.edf.relative_deadline ); if ( kthread == ksched->params.edf.active ) ksched->params.edf.active = NULL; /* set (separate) alarm for deadline * (periodic alarm is set only once as periodic) */ TIME_RESET ( &alarm.it_interval ); alarm.it_value = tsched->params.edf.active_deadline; ktimer_settime ( tsched->params.edf.deadline_alarm, TIMER_ABSTIME, &alarm, NULL ); } /* is task ready for execution, or must wait until next period*/ if ( time_cmp ( &tsched->params.edf.next_run, &now ) > 0 ) { /* wait till "next_run" */ EDF_LOG ( "%x [EDF WAIT]", kthread ); kthread_enqueue ( kthread, &ksched->params.edf.wait ); edf_schedule (ksched); } else { /* "next_run" has already come, * activate task => move it to "EDF ready tasks" */ EDF_LOG ( "%x [EDF READY]", kthread ); kthread_enqueue ( kthread, &ksched->params.edf.ready ); edf_schedule (ksched); } } else if ( params->edf.flags & EDF_EXIT ) { if ( kthread == ksched->params.edf.active ) ksched->params.edf.active = NULL; if ( edf_check_deadline ( kthread ) ) { EDF_LOG ( "%x [EXIT-error]", kthread ); return EXIT_FAILURE; } EDF_LOG ( "%x [EXIT-normal]", kthread ); if ( tsched->params.edf.period_alarm ) { /* disarm timer */ TIME_RESET ( &alarm.it_interval ); TIME_RESET ( &alarm.it_value ); ktimer_settime ( tsched->params.edf.period_alarm, 0, &alarm, NULL ); } if ( tsched->params.edf.deadline_alarm ) { /* disarm timer */ TIME_RESET ( &alarm.it_interval ); TIME_RESET ( &alarm.it_value ); ktimer_settime ( tsched->params.edf.deadline_alarm, 0, &alarm, NULL ); } kthread_setschedparam ( kthread, SCHED_FIFO, NULL ); } return 0; }