📄 sched_up.c
字号:
}/** * @ingroup timer * @anchor rt_set_periodic_mode * @brief Set timer mode. * * rt_set_periodic_mode sets the periodic mode for the timer. It * consists of a fixed frequency timing of the tasks in multiple of * the period set with a call to @ref start_rt_timer(). The resolution * is that of the 8254 (1193180 Hz) on a UP machine, or if the 8254 * based SMP scheduler is being used. For the SMP scheduler timed by * the local APIC timer and for the MUP scheduler the timer resolution * is that of the local APIC timer frequency, generally the bus * frequency divided 16. Any timing request not being an integer * multiple of the set timer period is satisfied at the closest period * tick. It is the default mode when no call is made to set the * oneshot mode. * * @note Stopping the timer by @ref stop_rt_timer() sets the timer back * into its default (periodic) mode. Always call @ref * rt_set_oneshot_mode() before each @ref start_rt_timer() if you want to * be sure to have it oneshot on multiple insmod without rmmoding the * RTAI scheduler in use. */void rt_set_periodic_mode(void){ stop_rt_timer(); oneshot_timer = oneshot_running = 0;}/** * @ingroup timer * @anchor rt_set_oneshot_mode * @brief Set timer mode. * * rt_set_periodic_mode sets the periodic mode for the timer. It * consists of a fixed frequency timing of the tasks in multiple of * the period set with a call to @ref start_rt_timer(). The resolution * is that of the 8254 (1193180 Hz) on a UP machine, or if the 8254 * based SMP scheduler is being used. For the SMP scheduler timed by * the local APIC timer and for the MUP scheduler the timer resolution * is that of the local APIC timer frequency, generally the bus * frequency divided 16. Any timing request not being an integer * multiple of the set timer period is satisfied at the closest period * tick. It is the default mode when no call is made to set the * oneshot mode. * * @note Stopping the timer by @ref stop_rt_timer() sets the timer back * into its default (periodic) mode. Always call @ref * rt_set_oneshot_mode() before each @ref start_rt_timer() if you want to * be sure to have it oneshot on multiple insmod without rmmoding the * RTAI scheduler in use. */void rt_set_oneshot_mode(void){ stop_rt_timer(); oneshot_timer = 1;}int rt_get_timer_cpu(void){ return -EINVAL;}DECLR_8254_TSC_EMULATION;/** * @ingroup timer * @anchor start_rt_timer * @brief Start timer. * * start_rt_timer starts the timer with a period @e period. The * period is in internal count units and is required only for the * periodic mode. In the oneshot mode the period value is ignored. * This functions uses the 8254 with the UP and the 8254 based SMP * scheduler. * Otherwise it uses a single local APIC with the APIC based SMP * schedulers and an APIC for each CPU with the MUP scheduler. In the * latter case all local APIC timers are paced in the same way, * according to the timer mode set. * * @return The period in internal count units. */RTIME start_rt_timer(int period){ unsigned long flags; hard_save_flags_and_cli(flags); if (oneshot_timer) { SETUP_8254_TSC_EMULATION; rt_request_timer(rt_timer_handler, 0, 0); tuned.timers_tol[0] = rt_half_tick = tuned.latency; oneshot_running = shot_fired = 1; } else { rt_request_timer(rt_timer_handler, period > LATCH ? LATCH : period, 0); tuned.timers_tol[0] = rt_half_tick = (rt_times.periodic_tick + 1)>>1; } rt_time_h = rt_times.tick_time + rt_half_tick; hard_restore_flags(flags); rt_request_linux_irq(TIMER_8254_IRQ, recover_jiffies, "rtai_jif_chk", recover_jiffies); return period;}RTIME start_rt_timer_cpuid(int period, int cpuid){ return start_rt_timer(period);}/** * @ingroup timer * @anchor start_rt_apic_timer * @brief Start local apic timer. * * start_rt_apic_timers starts local APIC timers according to what is * found in @e setup_data. * * @param setup_mode is a pointer to an array of structures * apic_timer_setup_data, see function rt_setup_apic_timers * (FIXME) in RTAI module functions described further on in * this manual. * @param rcvr_jiffies_cpuid is the CPU number whose time log has to * be used to keep Linux timing and pacing in tune. * This function is specific to the MUP scheduler. If it is * called with either the UP or SMP scheduler it will use: * - a periodic timer if all local APIC timers are periodic * with the same period; * - a oneshot timer if all the local APIC timers are oneshot, * or have different timing modes, are periodic with * different periods. */void start_rt_apic_timers(struct apic_timer_setup_data *setup_mode, unsigned int rcvr_jiffies_cpuid){ int cpuid, period; period = 0; for (cpuid = 0; cpuid < NR_RT_CPUS; cpuid++) { period += setup_mode[cpuid].mode; } if (period == NR_RT_CPUS) { period = 2000000000; for (cpuid = 0; cpuid < NR_RT_CPUS; cpuid++) { if (setup_mode[cpuid].count < period) { period = setup_mode[cpuid].count; } } start_rt_timer(nano2count(period)); } else { rt_set_oneshot_mode(); start_rt_timer(0); }}/** * @ingroup timer * @anchor stop_rt_timer * @brief Stop timer. * * stop_rt_timer stops the timer. The timer mode is set to periodic. * * @return The period in internal count units. */void stop_rt_timer(void){ unsigned long flags; rt_free_linux_irq(TIMER_8254_IRQ, recover_jiffies); hard_save_flags_and_cli(flags); CLEAR_8254_TSC_EMULATION; rt_free_timer(); oneshot_timer = oneshot_running = 0; hard_restore_flags(flags);}int rt_sched_type(void){ return RT_SCHED_UP;}/** * @ingroup tasks * @anchor rt_preempt_always * @brief Enable hard preemption * * In the oneshot mode the next timer expiration is programmed after a * timer shot by choosing among the timed tasks the one with a * priority higher than the task chosen to run as current, with the * constraint of always assuring a correct Linux timing. In such a * view there is no need to fire the timer immediately. In fact it can * happen that the current task can be so fast to get suspended and * rerun before the one that was devised to time the next shot when it * was made running. In such a view @b RTAI schedulers try to shoot * only when strictly needed. This minimizes the number of slow setups * of the 8254 timer used with UP and 8254 based SMP * schedulers. While such a policy minimizes the number of actual * shots, greatly enhancing efficiency, it can be unsuitable when an * application has to be guarded against undesired program loops or * other unpredicted error causes. * Calling these functions with a nonzero value assures that a timed * high priority preempting task is always programmed to be fired * while another task is currently running. The default is no * immediate preemption in oneshot mode, i.e. firing of the next shot * programmed only when strictly needed to satisfy tasks timings. * * @note With UP and SMP schedulers there is always only a timing * source so that cpu_idinrt_preempt_always_cpuid is not used. With * the MUP scheduler you have an independent timer for each CPU, so * rt_preempt_always applies to all the CPUs while * rt_preempt_always_cpuid should be used when preemption is to be * forced only on a specific CPU. */void rt_preempt_always(int yes_no){ preempt_always = yes_no ? 1 : 0;}/** * @ingroup tasks * @anchor rt_preempt_always_cpuid * @brief Enable hard preemption * * In the oneshot mode the next timer expiration is programmed after a * timer shot by choosing among the timed tasks the one with a * priority higher than the task chosen to run as current, with the * constraint of always assuring a correct Linux timing. In such a * view there is no need to fire the timer immediately. In fact it can * happen that the current task can be so fast to get suspended and * rerun before the one that was devised to time the next shot when it * was made running. In such a view @b RTAI schedulers try to shoot * only when strictly needed. This minimizes the number of slow setups * of the 8254 timer used with UP and 8254 based SMP * schedulers. While such a policy minimizes the number of actual * shots, greatly enhancing efficiency, it can be unsuitable when an * application has to be guarded against undesired program loops or * other unpredicted error causes. * Calling these functions with a nonzero value assures that a timed * high priority preempting task is always programmed to be fired * while another task is currently running. The default is no * immediate preemption in oneshot mode, i.e. firing of the next shot * programmed only when strictly needed to satisfy tasks timings. * * @note With UP and SMP schedulers there is always only a timing * source so that cpu_idinrt_preempt_always_cpuid is not used. With * the MUP scheduler you have an independent timer for each CPU, so * rt_preempt_always applies to all the CPUs while * rt_preempt_always_cpuid should be used when preemption is to be * forced only on a specific CPU. */void rt_preempt_always_cpuid(int yes_no, unsigned int cpuid){ rt_preempt_always(yes_no);}RT_TRAP_HANDLER rt_set_task_trap_handler( RT_TASK *task, unsigned int vec, RT_TRAP_HANDLER handler){ RT_TRAP_HANDLER old_handler; if (!task || (vec >= RTAI_NR_TRAPS)) { return (RT_TRAP_HANDLER) -EINVAL; } old_handler = task->task_trap_handler[vec]; task->task_trap_handler[vec] = handler; return old_handler;}int rt_trap_handler(int vec, int signo, struct pt_regs *regs, void *dummy_data){ if (!rt_current) { return 0; } if (rt_current->task_trap_handler[vec]) { return rt_current->task_trap_handler[vec]( vec, signo, regs, rt_current); } rt_printk("Default Trap Handler: vector %d: Suspend RT task %p\n", vec,rt_current); rt_task_suspend(rt_current); rt_task_delete(rt_current); // In case the suspend does not work ? return 1;}static int OneShot = ONE_SHOT;MODULE_PARM(OneShot, "i");static int Preempt_Always = PREEMPT_ALWAYS;MODULE_PARM(Preempt_Always, "i");static int LinuxFpu = LINUX_FPU;MODULE_PARM(LinuxFpu, "i");static int Latency = LATENCY_8254;MODULE_PARM(Latency, "i");static int SetupTimeTIMER = SETUP_TIME_8254;MODULE_PARM(SetupTimeTIMER, "i");static void frstk_srq_handler(void){ while (frstk_srq.out != frstk_srq.in) { sched_free(frstk_srq.mp[frstk_srq.out]); frstk_srq.out = (frstk_srq.out + 1) & (MAX_FRESTK_SRQ - 1); }}static void init_sched_entries(void);/* ++++++++++++++++++++++++++ TIME CONVERSIONS +++++++++++++++++++++++++++++ *//** * @ingroup timer * @anchor count2nano * @brief Convert internal count units to nanoseconds. * * This function converts the time of timercounts internal count units * into nanoseconds. * Remember that the count units are related to the time base being * used (see functions @ref rt_set_oneshot_mode() and @ref * rt_set_periodic_mode() for an explanation). * * @param counts internal count units. * * @return The given time in nanoseconds is returned. */RTIME count2nano(RTIME counts){ int sign; if (counts > 0) { sign = 1; } else { sign = 0; counts = - counts; } counts = oneshot_timer ? llimd(counts, 1000000000, tuned.cpu_freq): llimd(counts, 1000000000, TIMER_FREQ); return sign ? counts : - counts;}/** * @ingroup timer * @anchor nano2count * @brief Convert nanoseconds to internal count units. * * This function converts the time of nanosecs @e nanoseconds into * internal counts units. * Remember that the count units are related to the time base being * used (see functions @ref rt_set_oneshot_mode() and @ref * rt_set_periodic_mode() for an explanation). * * The versions ending with_cpuid are to be used with the MUP * scheduler since with such a scheduler it is possible to have * independent timers, i.e. periodic of different periods or a mixing * of periodic and oneshot, so that it is impossible to establish * which conversion units should be used in the case one asks for a * conversion from any CPU for any other CPU. All these functions have * the same behavior with UP and SMP schedulers. * * @param ns Number of nanoseconds. * * @return The given time in nanoseconds is returned. */RTIME nano2count(RTIME ns){ int sign; if (ns > 0) { sign = 1; } else { sign = 0; ns = - ns; } ns = oneshot_timer ? llimd(ns, tuned.cpu_freq, 1000000000) : llimd(ns, TIMER_FREQ, 1000000000); return sign ? ns : - ns;}/** * @ingroup timer * @anchor count2nano_cpuid * @brief Convert internal count units to nanoseconds. * * This function converts the time of timercounts internal count units * into nanoseconds. * It is to be used with the MUP scheduler since with such a scheduler * it is possible to have independent timers, i.e. periodic of * different periods or a mixing of periodic and oneshot, so that it * is impossible to establish which conversion units should be used in * the case one asks for a conversion from any CPU for any other * CPU. All these functions have the same behavior with UP and SMP * schedulers. * * @param counts internal count units. * * @param cpuid Identifier of the CPU (FIXME). * * @return The given time in nanoseconds is returned. */RTIME count2nano_cpuid(RTIME counts, unsigned int cpuid){ return count2nano(counts);}/** * @ingroup timer * @anchor nano2count_cpuid * @brief Convert nanoseconds to internal count units. * * This function converts the time of nanosecs @e nanoseconds into * internal counts units. * Remember that the count units are related to the time base being * used (see functions @ref rt_set_oneshot_mode() and @ref * rt_set_periodic_mode() for an explanation). * * This function is to be used with the MUP scheduler since with such * a scheduler it is possible to have independent timers, * i.e. periodic of different periods or a mixing of periodic and * oneshot, so that it is impossible to establish which conversion * units should be used in the case one asks for a conversion from * any CPU for any other CPU. All these functions have the same * behavior with UP and SMP schedulers. * * @param ns Number of nanoseconds. * * @param cpuid Identifier of the CPU (FIXME). * * @return The given time in nanoseconds is returned. */RTIME nano2count_cpuid(RTIME ns, unsigned int cpuid){ return nano2count(ns);}/* +++++++++++++++++++++++++++++++ TIMINGS ++++++++++++++++++++++++++++++++++ *//**
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -