📄 sched_up.c
字号:
/** * @file * Scheduling function for uni-processor. * @author Paolo Mantegazza * * This file is part of the RTAI project. * * @note Copyright (C) 1999-2003 Paolo Mantegazza * <mantegazza@aero.polimi.it> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * @ingroup tasks timer *//*ACKNOWLEDGMENTS: - Steve Papacharalambous (stevep@zentropix.com) has contributed a very informative proc filesystem procedure.- Stuart Hughes (sehughes@zentropix.com) has helped in porting this module to 2.4.xx.- Stefano Picerno (stefanopp@libero.it) for suggesting a simple fix to distinguish a timeout from an abnormal retrun in timed sem waits.- Geoffrey Martin (gmartin@altersys.com) for a fix to functions with timeouts.*//** * @defgroup sched RTAI schedulers modules * * RTAI schedulers. * * The functions described here are provided for : * - uniprocessor (UP) scheduler; * - symmetric multi processors (SMP) scheduler; * - multi uni processors (MUP) scheduler. * . * * For more details, * see the @ref sched_overview "the overview of RTAI schedulers". *//** * @ingroup sched * @defgroup tasks Task functions *//** * @ingroup sched * @defgroup timer Timer functions */#ifdef CONFIG_RTAI_MAINTAINER_PMA#define ALLOW_RR 1#define ONE_SHOT 0#define PREEMPT_ALWAYS 0#define LINUX_FPU 1#else /* STANDARD SETTINGS */#define ALLOW_RR 1#define ONE_SHOT 0#define PREEMPT_ALWAYS 0#define LINUX_FPU 1#endif#include <linux/module.h>#include <linux/kernel.h>#include <linux/version.h>#include <linux/errno.h>#include <linux/slab.h>#include <linux/kernel.h>#include <linux/timex.h>#include <linux/sched.h>#include <asm/param.h>#include <asm/system.h>#include <asm/io.h>#include <asm/segment.h>#ifdef CONFIG_PROC_FS#include <linux/stat.h>#include <linux/proc_fs.h>#include <rtai_proc_fs.h>#endif#include <rtai.h>#include <asm/rtai_sched.h>#include <rtai_sched.h>#include <rtai_trace.h>#include <rtai_schedcore.h>#undef DECLARE_RT_CURRENT#undef ASSIGN_RT_CURRENT#undef RT_CURRENTMODULE_LICENSE("GPL");/* +++++++++++++++++ WHAT MUST BE AVAILABLE EVERYWHERE ++++++++++++++++++++++ */RT_TASK rt_smp_linux_task[1];RT_TASK *rt_smp_current[1];RTIME rt_smp_time_h[1];int rt_smp_oneshot_timer[1];struct klist_t wake_up_srq;/* +++++++++++++++ END OF WHAT MUST BE AVAILABLE EVERYWHERE +++++++++++++++++ */#define TIMER_FREQ FREQ_8254#ifdef CONFIG_PROC_FSstatic int rtai_proc_sched_register(void);static void rtai_proc_sched_unregister(void);#endif#define rt_current (rt_smp_current[0])static int sched_rqsted;static RT_TASK *fpu_task;#define rt_linux_task (rt_smp_linux_task[0])DEFINE_LINUX_CR0#undef rt_time_h#define rt_time_h (rt_smp_time_h[0])static int rt_half_tick;#undef oneshot_timer#define oneshot_timer (rt_smp_oneshot_timer[0])static int oneshot_running;static int shot_fired;static int preempt_always;static RT_TASK *wdog_task;static int rt_next_tid = 1; /* Next task ID */#define MAX_FRESTK_SRQ 64static struct { int srq, in, out; void *mp[MAX_FRESTK_SRQ]; } frstk_srq;/* ++++++++++++++++++++++++++++++++ TASKS ++++++++++++++++++++++++++++++++++ */#define TASK_TO_SCHEDULE() \ do { prio = (new_task = rt_linux_task.rnext)->priority; } while(0);static void rt_startup(void(*rt_thread)(int), int data){ hard_sti(); rt_current->exectime[1] = rdtsc(); rt_thread(data); rt_task_delete(rt_current);}/** * @ingroup tasks * @anchor rt_task_init * Creates a new real time task. * * The newly created real time task is initially in a suspend * state. It can be made active by calling: rt_task_make_periodic, * rt_task_make_periodic_relative_ns, rt_task_resume. * * When used with the MUP scheduler rt_task_init automatically selects * which CPU the task will run on, while with the SMP scheduler the * task defaults to using any of the available CPUs. This assignment * may be changed by calling rt_set_runnable_on_cpus. * * @param task is a pointer to an RT_TASK type structure whose space * must be provided by the application. It must be kept during * the whole lifetime of the real time task. * * @param rt_thread is the entry point of the task function. * * @param data The parent task can pass a single integer value data to * the new task being created. Recall that an appropriately * type casting allows data to be a pointer to whatever data * structure one would like to pass to the task, so you can * indirectly pass whatever you want to the task. * * @param stack_size is the size of the stack to be used by the new * task. In sizing it, recall to make room for any * real time interrupt handler, as real time * interrupts run on the stack of the task they * interrupt. So try to avoid being too sparing. * * @param priority is the priority to be given to the task. The * highest priority is 0, while the lowest is * RT_SCHED_LOWEST_PRIORITY. * * @param uses_fpu is a flag. A nonzero value indicates that the task * will use the floating point unit. * * @param signal is a function that is called, within the task * environment and with interrupts disabled, when the task * becomes the current running task after a context * switch. Note however that signal is not called at the very * first scheduling of the task. Such a function can be * assigned and/or changed dynamically whenever needed (see * function rt_task_signal_handler.) * * @return 0 on success. A negative value on failure as described * below: * - @b EINVAL: task structure pointed by task is already in use; * - @b ENOMEM: stack_size bytes could not be allocated for the stack. * * See also: @ref rt_task_init_cpuid(). */int rt_task_init(RT_TASK *task, void (*rt_thread)(int), int data, int stack_size, int priority, int uses_fpu, void(*signal)(void)){ int *st, i; unsigned long flags; if (task->magic == RT_TASK_MAGIC || priority < 0) { return -EINVAL; }// If the task struct is unaligned, we'll get problems later if ((unsigned long)task & 0xf){ return -EFAULT; }#ifndef CONFIG_RTAI_FPU_SUPPORT if (uses_fpu) { return -EINVAL; }#endif if (!(st = (int *)sched_malloc(stack_size))) { return -ENOMEM; } if (wdog_task && wdog_task != task && priority == RT_SCHED_HIGHEST_PRIORITY) { rt_printk("Highest priority reserved for RTAI watchdog\n"); return -EBUSY; } memset(task, 0, sizeof(*task)); task->bstack = task->stack = (int *)(((unsigned long)st + stack_size - 0x10) & ~0xF); task->stack[0] = 0; task->uses_fpu = uses_fpu ? 1 : 0; *(task->stack_bottom = st) = 0; task->runnable_on_cpus = 1; task->lnxtsk = 0; task->magic = RT_TASK_MAGIC; task->policy = 0; task->is_hard = 1; task->suspdepth = 1; task->state = (RT_SCHED_SUSPENDED | RT_SCHED_READY); task->owndres = 0; task->priority = task->base_priority = priority; task->prio_passed_to = 0; task->period = 0; task->resume_time = RT_TIME_END; task->queue.prev = &(task->queue); task->queue.next = &(task->queue); task->queue.task = task; task->msg_queue.prev = &(task->msg_queue); task->msg_queue.next = &(task->msg_queue); task->msg_queue.task = task; task->msg = 0; task->ret_queue.prev = &(task->ret_queue); task->ret_queue.next = &(task->ret_queue); task->ret_queue.task = NOTHING; task->tprev = task->tnext = task->rprev = task->rnext = task; task->blocked_on = NOTHING; task->signal = signal; for (i = 0; i < RTAI_NR_TRAPS; i++) { task->task_trap_handler[i] = NULL; } task->tick_queue = NOTHING; task->trap_handler_data = NOTHING; task->resync_frame = 0; task->ExitHook = 0; task->tid = rt_next_tid++; task->exectime[0] = 0; task->system_data_ptr = 0; TRACE_RTAI_TASK(TRACE_RTAI_EV_TASK_INIT, task->tid, (uint32_t)rt_thread, priority); init_arch_stack(); hard_save_flags_and_cli(flags); init_fp_env(); rt_linux_task.prev->next = task; task->prev = rt_linux_task.prev; task->next = 0; rt_linux_task.prev = task; hard_restore_flags(flags); return 0;}/** * @ingroup tasks * @anchor rt_task_init_cpuid * Creates a new real time task and assigns it to a single specific * CPU. * * The newly created real time task is initially in a suspend * state. It can be made active by calling: rt_task_make_periodic, * rt_task_make_periodic_relative_ns, rt_task_resume. * * * When used with the MUP scheduler rt_task_init automatically selects * which CPU the task will run on, while with the SMP scheduler the * task defaults to using any of the available CPUs. This assignment * may be changed by calling rt_set_runnable_on_cpus or * rt_set_runnable_on_cpuid. If cpuid is invalid rt_task_init_cpuid * falls back to automatic CPU selection. * * Whatever scheduler is used on multiprocessor systems * rt_task_init_cpuid allows to create a task and assign it to a * single specific CPU cpuid from its very beginning, without any need * to call rt_set_runnable_on_cpuid later on. * * @param task is a pointer to an RT_TASK type structure whose space * must be provided by the application. It must be kept during * the whole lifetime of the real time task. * * @param rt_thread is the entry point of the task function. * * @param data The parent task can pass a single integer value data to * the new task being created. Recall that an * appropriately type casting allows data to be a pointer * to whatever data structure one would like to pass to * the task, so you can indirectly pass whatever you want * to the task. * * @param stack_size is the size of the stack to be used by the new * task. In sizing it recall to make room for any real time * interrupt handler, as real time interrupts run on the stack * of the task they interrupt. So try to avoid being too * sparing. * * @param priority is the priority to be given to the task. The * highest priority is 0, while the lowest is * RT_SCHED_LOWEST_PRIORITY. * * @param uses_fpu is a flag. A nonzero value indicates that the task * will use the floating point unit. * * @param signal is a function that is called, within the task * environment and with interrupts disabled, when the task * becomes the current running task after a context * switch. Note however that signal is not called at the very * first scheduling of the task. Such a function can be * assigned and/or changed dynamically whenever needed (see * function rt_task_signal_handler.) * * @param cpuid FIXME * * @return 0 on success. A negative value on failure as described * below: * - @b EINVAL: task structure pointed by task is already in use; * - @b ENOMEM: stack_size bytes could not be allocated for the stack. * * See also: @ref rt_task_init(). */int rt_task_init_cpuid(RT_TASK *task, void (*rt_thread)(int), int data, int stack_size, int priority, int uses_fpu, void(*signal)(void), unsigned int cpuid){ return rt_task_init(task, rt_thread, data, stack_size, priority, uses_fpu, signal);}int rt_kthread_init_cpuid(RT_TASK *task, void (*rt_thread)(int), int data, int stack_size, int priority, int uses_fpu, void(*signal)(void), unsigned int cpuid){ return 0;}int rt_kthread_init(RT_TASK *task, void (*rt_thread)(int), int data, int stack_size, int priority, int uses_fpu, void(*signal)(void)){ return 0;}/** * @ingroup tasks * @anchor rt_set_runnable_on_cpus * @brief Assign CPUs to a task. * * rt_set_runnable_on_cpus selects one or more CPUs which are allowed * to run task @e task. * rt_set_runnable_on_cpus behaves differently for MUP and SMP * schedulers. Under the SMP scheduler bit<n> of cpu_mask enables the * task to run on CPU<n>. Under the MUP scheduler it selects the CPU * with less running tasks among those allowed by cpu_mask. * Recall that with MUP a task must be bounded to run on a single CPU. * If no CPU, as selected by cpu_mask or cpuid, is available, both * functions choose a possible CPU automatically, following the same * rule as above. * * @note This call has no effect on UniProcessor (UP) systems. * * See also: @ref rt_set_runnable_on_cpuid(). */void rt_set_runnable_on_cpus(RT_TASK *task, unsigned long runnable_on_cpus) { }/** * @ingroup tasks * @anchor rt_set_runnable_on_cpuid * @brief Assign CPUs to a task. * * rt_set_runnable_on_cpuid select one or more CPUs which are allowed * to run task @e task. * * rt_set_runnable_on_cpuid assigns a task to a single specific CPU. * If no CPU, as selected by cpu_mask or cpuid, is available, both * functions choose a possible CPU automatically, following the same * rule as above. * * @note This call has no effect on UniProcessor (UP) systems. * * See also: @ref rt_set_runnable_on_cpus(). */void rt_set_runnable_on_cpuid(RT_TASK *task, unsigned int cpuid) { }int rt_check_current_stack(void){ char *sp; if (rt_current != &rt_linux_task) { sp = get_stack_pointer(); return (sp - (char *)(rt_current->stack_bottom));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -