/*! * Arm/disarm timer * \param timerid Timer descriptor (user descriptor) * \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 sys__timer_settime ( void *p ) { timer_t *timerid; int flags; itimerspec_t *value; itimerspec_t *ovalue; ktimer_t *ktimer; int retval; kobject_t *kobj; timerid = *( (timer_t **) p ); p += sizeof (timer_t *); flags = *( (int *) p ); p += sizeof (int); value = *( (itimerspec_t **) p ); p += sizeof (itimerspec_t *); ovalue = *( (itimerspec_t **) p ); ASSERT_ERRNO_AND_EXIT ( timerid, EINVAL ); kobj = timerid->ptr; ASSERT_ERRNO_AND_EXIT ( kobj, EINVAL ); ASSERT_ERRNO_AND_EXIT ( list_find ( &kobjects, &kobj->list ), EINVAL ); ktimer = kobj->kobject; ASSERT_ERRNO_AND_EXIT ( ktimer && ktimer->id == timerid->id, EINVAL ); retval = ktimer_settime ( ktimer, flags, value, ovalue ); EXIT ( retval ); }
void ksched_rr_start_timer () { sigevent_t evp; itimerspec_t itimer; int retval = 0; if ( rr_ktimer ) return; /* already set */ evp.sigev_notify = SIGEV_THREAD; evp.sigev_value.sival_ptr = NULL; evp.sigev_notify_function = ksched_rr_tick; retval += ktimer_create ( CLOCK_REALTIME, &evp, &rr_ktimer, NULL ); ASSERT ( retval == EXIT_SUCCESS ); TIME_RESET ( &itimer.it_value ); itimer.it_value.tv_sec = 0; itimer.it_value.tv_nsec = SCHED_RR_TICK; itimer.it_interval = itimer.it_value; retval += ktimer_settime ( rr_ktimer, 0, &itimer, NULL ); ASSERT ( retval == EXIT_SUCCESS ); }
/*! * Suspend thread until given time elapses * \param clockid Clock to use * \param flags Flags (TIMER_ABSTIME) * \param request Suspend duration * \param remain Remainder time if interrupted during suspension * \return status */ int sys__clock_nanosleep ( void *p ) { clockid_t clockid; int flags; timespec_t *request; timespec_t *remain; int retval = EXIT_SUCCESS; kthread_t *kthread = kthread_get_active (); ktimer_t *ktimer; sigevent_t evp; itimerspec_t itimer; clockid = *( (clockid_t *) p ); p += sizeof (clockid_t); flags = *( (int *) p ); p += sizeof (int); request = *( (timespec_t **) p ); p += sizeof (timespec_t *); remain = *( (timespec_t **) p ); ASSERT_ERRNO_AND_EXIT ( (clockid==CLOCK_REALTIME || clockid==CLOCK_MONOTONIC) && request && TIME_IS_SET(request), EINVAL ); /* Timers are used for "sleep" operations through steps 1-4 */ /* 1. create timer, but not arm it yet */ evp.sigev_notify = SIGEV_WAKE_THREAD; evp.sigev_value.sival_ptr = kthread; evp.sigev_notify_function = kclock_wake_thread; retval += ktimer_create ( clockid, &evp, &ktimer, kthread ); ASSERT ( retval == EXIT_SUCCESS ); /* save remainder location, if provided */ ktimer->param = remain; /* 2. suspend thread */ kthread_set_private_param ( kthread, ktimer ); retval += kthread_suspend ( kthread, kclock_interrupt_sleep, ktimer ); ASSERT ( retval == EXIT_SUCCESS ); /* 3. arm timer */ TIME_RESET ( &itimer.it_interval ); itimer.it_value = *request; retval += ktimer_settime ( ktimer, flags, &itimer, NULL ); ASSERT ( retval == EXIT_SUCCESS ); /* 4. pick other thread as active */ kthreads_schedule (); EXIT ( retval ); }
static void edf_deadline_alarm ( sigval_t sigev_value ) { kthread_t *kthread = sigev_value.sival_ptr, *test; kthread_sched2_t *tsched; ksched_t *ksched; itimerspec_t alarm; ASSERT ( kthread ); ksched = ksched2_get ( kthread_get_sched_policy (kthread) ); tsched = kthread_get_sched2_param ( kthread ); test = kthreadq_remove ( &ksched->params.edf.wait, kthread ); EDF_LOG ( "%x %x [Deadline alarm]", kthread, test ); if( test == kthread ) { EDF_LOG ( "%x [Waked, but too late]", kthread ); kthread_set_syscall_retval ( kthread, EXIT_FAILURE ); kthread_move_to_ready ( kthread, LAST ); if ( tsched->params.edf.flags & EDF_TERMINATE ) { EDF_LOG ( "%x [EDF_TERMINATE]", kthread ); ktimer_delete ( tsched->params.edf.period_alarm ); tsched->params.edf.period_alarm = NULL; ktimer_delete ( tsched->params.edf.deadline_alarm ); tsched->params.edf.deadline_alarm = NULL; kthread_set_errno ( kthread, ETIMEDOUT ); kthread_exit ( kthread, NULL, TRUE ); } else { edf_schedule (ksched); } } else { /* * thread is not in edf.wait queue, but might be running or its * blocked - it is probable (almost certain) that it missed deadline */ EDF_LOG ( "%x [Not in edf.wait. Missed deadline?]", kthread ); if ( edf_check_deadline ( kthread ) ) { /* what to do if its missed? kill thread? */ if ( tsched->params.edf.flags & EDF_TERMINATE ) { EDF_LOG ( "%x [EDF_TERMINATE]", kthread ); ktimer_delete (tsched->params.edf.period_alarm); tsched->params.edf.period_alarm = NULL; ktimer_delete ( tsched->params.edf.deadline_alarm ); tsched->params.edf.deadline_alarm = NULL; kthread_set_errno ( kthread, ETIMEDOUT ); kthread_exit ( kthread, NULL, TRUE ); } else if ( tsched->params.edf.flags & EDF_CONTINUE ) { /* continue as deadline is not missed */ EDF_LOG ( "%x [EDF_CONTINUE]", kthread ); } else if ( tsched->params.edf.flags & EDF_SKIP ) { /* skip deadline */ /* set times for next period */ EDF_LOG ( "%x [EDF_SKIP]", kthread ); 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; TIME_RESET ( &alarm.it_interval ); alarm.it_value = tsched->params.edf.active_deadline; ktimer_settime ( tsched->params.edf.deadline_alarm, TIMER_ABSTIME, &alarm, NULL ); 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 ); kthread_enqueue (kthread, &ksched->params.edf.ready); edf_schedule (ksched); } } /* moved 1 tab left for readability */ } }
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; }