📄 common.c
字号:
/** * @ingroup lxrt * @file * Common scheduling function * @author Paolo Mantegazza * * This file is part of the RTAI project. * * @note Copyright © 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. */#include <rtai_schedcore.h>#include <rtai_registry.h>#include <linux/module.h>/* ++++++++++++++++++++++++ COMMON FUNCTIONALITIES ++++++++++++++++++++++++++ *//* +++++++++++++++++++++++++ PRIORITY MANAGEMENT ++++++++++++++++++++++++++++ */void rt_set_sched_policy(RT_TASK *task, int policy, int rr_quantum_ns){ if ((task->policy = policy ? 1 : 0)) { task->rr_quantum = nano2count_cpuid(rr_quantum_ns, task->runnable_on_cpus); if ((task->rr_quantum & 0xF0000000) || !task->rr_quantum) {#ifdef CONFIG_SMP task->rr_quantum = sqilter ? rt_smp_times[task->runnable_on_cpus].linux_tick : rt_times.linux_tick;#else task->rr_quantum = rt_times.linux_tick;#endif } task->rr_remaining = task->rr_quantum; task->yield_time = 0; }}/** * @anchor rt_get_prio * @brief Check a task priority. * * rt_get_prio returns the base priority of task @e task. * * Recall that a task has a base native priority, assigned at its * birth or by @ref rt_change_prio(), and an actual, inherited, * priority. They can be different because of priority inheritance. * * @param task is the affected task. * * @return rt_get_prio returns the priority of task @e task. * * @note To be used only with RTAI24.x.xx. */int rt_get_prio(RT_TASK *task){ if (task->magic != RT_TASK_MAGIC) { return -EINVAL; } return task->base_priority;}/** * @anchor rt_get_inher_prio * @brief Check a task priority. * * rt_get_prio returns the base priority task @e task has inherited * from other tasks, either blocked on resources owned by or waiting * to pass a message to task @e task. * * Recall that a task has a base native priority, assigned at its * birth or by @ref rt_change_prio(), and an actual, inherited, * priority. They can be different because of priority inheritance. * * @param task is the affected task. * * @return rt_get_inher_prio returns the priority of task @e task. * * @note To be used only with RTAI24.x.xx. */int rt_get_inher_prio(RT_TASK *task){ if (task->magic != RT_TASK_MAGIC) { return -EINVAL; } return task->base_priority;}/** * @anchor rt_change_prio * @brief Change a task priority. * * rt_change_prio changes the base priority of task @e task to @e * prio. * * Recall that a task has a base native priority, assigned at its * birth or by @ref rt_change_prio(), and an actual, inherited, * priority. They can be different because of priority inheritance. * * @param task is the affected task. * * @param priority is the new priority, it can range within 0 < prio < * RT_SCHED_LOWEST_PRIORITY. * * @return rt_change_prio returns the base priority task @e task had * before the change. * * @note To be used only with RTAI24.x.xx (FIXME). */int rt_change_prio(RT_TASK *task, int priority){ unsigned long flags; int prio; if (task->magic != RT_TASK_MAGIC || priority < 0) { return -EINVAL; } prio = task->base_priority; flags = rt_global_save_flags_and_cli(); if ((task->base_priority = priority) < task->priority) { unsigned long schedmap; QUEUE *q; schedmap = 0; do { task->priority = priority; if (task->state == RT_SCHED_READY) { (task->rprev)->rnext = task->rnext; (task->rnext)->rprev = task->rprev; enq_ready_task(task);#ifdef CONFIG_SMP set_bit(task->runnable_on_cpus & 0x1F, &schedmap);#else schedmap = 1;#endif } else if ((q = task->blocked_on) && !((task->state & RT_SCHED_SEMAPHORE) && ((SEM *)q)->qtype)) { (task->queue.prev)->next = task->queue.next; (task->queue.next)->prev = task->queue.prev; while ((q = q->next) != task->blocked_on && (q->task)->priority <= priority); q->prev = (task->queue.prev = q->prev)->next = &(task->queue); task->queue.next = q;#ifdef CONFIG_SMP set_bit(task->runnable_on_cpus & 0x1F, &schedmap);#else schedmap = 1;#endif } } while ((task = task->prio_passed_to) && task->priority > priority); if (schedmap) {#ifdef CONFIG_SMP if (test_and_clear_bit(hard_cpu_id(), &schedmap)) { RT_SCHEDULE_MAP_BOTH(schedmap); } else { RT_SCHEDULE_MAP(schedmap); }#else rt_schedule();#endif } } rt_global_restore_flags(flags); return prio;}/* +++++++++++++++++++++ TASK RELATED SCHEDULER SERVICES ++++++++++++++++++++ *//** * @anchor rt_whoami * @brief Get the task pointer of the current task. * * Calling rt_whoami from a task can get a pointer to its own task * structure. * * @return The pointer to the current task. */RT_TASK *rt_whoami(void){ return _rt_whoami();}/** * @anchor rt_task_yield * Yield the current task. * * @ref rt_task_yield() stops the current task and takes it at the end * of the list of ready tasks having its same priority. The scheduler * makes the next ready task of the same priority active. * * Recall that RTAI schedulers allow only higher priority tasks to * preempt the execution of lower priority ones. So equal priority * tasks cannot preempt each other and @ref rt_task_yield() should be * used if a user needs a cooperative time slicing among equal * priority tasks. The implementation of the related policy is wholly * in the hand of the user. It is believed that time slicing is too * much an overhead for the most demanding real time applications, so * it is left up to you. */void rt_task_yield(void){ RT_TASK *rt_current, *task; unsigned long flags; flags = rt_global_save_flags_and_cli(); task = (rt_current = RT_CURRENT)->rnext; while (rt_current->priority == task->priority) { task = task->rnext; } if (task != rt_current->rnext) { (rt_current->rprev)->rnext = rt_current->rnext; (rt_current->rnext)->rprev = rt_current->rprev; task->rprev = (rt_current->rprev = task->rprev)->rnext = rt_current; rt_current->rnext = task; rt_schedule(); } rt_global_restore_flags(flags);}/** * @anchor rt_task_suspend * rt_task_suspend suspends execution of the task task. * * It will not be executed until a call to @ref rt_task_resume() or * @ref rt_task_make_periodic() is made. No account is made for * multiple suspends, i.e. a multiply suspended task is made ready as * soon as it is rt_task_resumed, thus immediately resuming its * execution if it is the highest in priority. * * @param task pointer to a task structure. * * @return 0 on success. A negative value on failure as described below: * - @b EINVAL: task does not refer to a valid task. * * @note the new RTAI 24.1.xx (FIXME) development releases take into * account multiple suspend and require as many @ref rt_task_resume() * as the rt_task_suspends placed on a task. */int rt_task_suspend(RT_TASK *task){ unsigned long flags; if (!task) { task = RT_CURRENT; } else if (task->magic != RT_TASK_MAGIC) { return -EINVAL; } flags = rt_global_save_flags_and_cli(); if (!task->suspdepth++ && !task->owndres) { rem_ready_task(task); task->state |= RT_SCHED_SUSPENDED; if (task == RT_CURRENT) { rt_schedule(); } } rt_global_restore_flags(flags); return 0;}/** * @anchor rt_task_resume * Resume a task. * * rt_task_resume resumes execution of the task @e task previously * suspended by @ref rt_task_suspend(), or makes a newly created task * ready to run, if it makes the task ready. Since no account is made * for multiple suspend rt_task_resume unconditionally resumes any * task it makes ready. * * @param task pointer to a task structure. * * @return 0 on success. A negative value on failure as described below: * - @b EINVAL: task does not refer to a valid task. * * @note the new RTAI 24.1.xx (FIXME) development releases take into * account multiple suspend and require as many rt_task_resumes * as the rt_task_suspends placed on a task. */int rt_task_resume(RT_TASK *task){ unsigned long flags; if (task->magic != RT_TASK_MAGIC) { return -EINVAL; } flags = rt_global_save_flags_and_cli(); if (!(--task->suspdepth)) { rem_timed_task(task); if (((task->state &= ~RT_SCHED_SUSPENDED) & ~RT_SCHED_DELAYED) == RT_SCHED_READY) { enq_ready_task(task); RT_SCHEDULE(task, hard_cpu_id()); } } rt_global_restore_flags(flags); return 0;}/** * @anchor rt_get_task_state * Query task state * * rt_get_task_state returns the state of a real time task. * * @param task is a pointer to the task structure. * * Task state is formed by the bitwise OR of one or more of the * following flags: * * @retval READY Task @e task is ready to run (i.e. unblocked). * Note that on a UniProcessor machine the currently running task is * just in READY state, while on MultiProcessors can be (READY | * RUNNING), see below. * @retval SUSPENDED Task @e task blocked waiting for a resume. * @retval DELAYED Task @e task blocked waiting for its next running * period or expiration of a timeout. * @retval SEMAPHORE Task @e task blocked on a semaphore, waiting for * the semaphore to be signaled. * @retval SEND Task @e task blocked on sending a message, receiver * was not in RECEIVE state. * @retval RECEIVE Task @e task blocked waiting for incoming messages, * sends or rpcs. * @retval RPC Task @e task blocked on a Remote Procedure Call, * receiver was not in RECEIVE state. * @retval RETURN Task @e task blocked waiting for a return from a * Remote Procedure Call, receiver got the RPC but has not replied * yet. * @retval RUNNING Task @e task is running, used only for SMP * schedulers. * * The returned task state is just an approximate information. Timer * and other hardware interrupts may cause a change in the state of * the queried task before the caller could evaluate the returned * value. Caller should disable interrupts if it wants reliable info * about an other task. rt_get_task_state does not perform any check * on pointer task. */int rt_get_task_state(RT_TASK *task){ return task->state;}/** * @anchor rt_linux_use_fpu * @brief Set indication of FPU usage. * * rt_linux_use_fpu informs the scheduler that floating point * arithmetic operations will be used also by foreground Linux * processes, i.e. the Linux kernel itself (unlikely) and any of its * processes. * * @param use_fpu_flag If this parameter has a nonzero value, the * Floating Point Unit (FPU) context is also switched when @e task or * the kernel becomes active. * This makes task switching slower, negligibly, on all 32 bits CPUs * but 386s and the oldest 486s. * This flag can be set also by rt_task_init when the real time task * is created. With UP and MUP schedulers care is taken to avoid * useless saves/ restores of the FPU environment. * Under SMP tasks can be moved from CPU to CPU so saves/restores for * tasks using the FPU are always carried out. * Note that by default Linux has this flag cleared. Beside by using * rt_linux_use_fpu you can change the Linux FPU flag when you insmod * any RTAI scheduler module by setting the LinuxFpu command line * parameter of the rtai_sched module itself. * * @return 0 on success. A negative value on failure as described below: * - @b EINVAL: task does not refer to a valid task. * * See also: @ref rt_linux_use_fpu(). */void rt_linux_use_fpu(int use_fpu_flag){ int cpuid; for (cpuid = 0; cpuid < num_online_cpus(); cpuid++) { rt_linux_task.uses_fpu = use_fpu_flag ? 1 : 0; }}/** * @anchor rt_task_use_fpu * @brief * * rt_task_use_fpu informs the scheduler that floating point * arithmetic operations will be used by the real time task @e task. * * @param task is a pointer to the real time task. * * @param use_fpu_flag If this parameter has a nonzero value, the * Floating Point Unit (FPU) context is also switched when @e task or * the kernel becomes active. * This makes task switching slower, negligibly, on all 32 bits CPUs * but 386s and the oldest 486s. * This flag can be set also by @ref rt_task_init() when the real time * task is created. With UP and MUP schedulers care is taken to avoid * useless saves/restores of the FPU environment. * Under SMP tasks can be moved from CPU to CPU so saves/restores for * tasks using the FPU are always carried out. * * @return 0 on success. A negative value on failure as described below: * - @b EINVAL: task does not refer to a valid task. * * See also: @ref rt_linux_use_fpu(). */int rt_task_use_fpu(RT_TASK *task, int use_fpu_flag){ if (task->magic != RT_TASK_MAGIC) { return -EINVAL; } task->uses_fpu = use_fpu_flag ? 1 : 0; return 0;}/** * @anchor rt_task_signal_handler * @brief Set the signal handler of a task. * * rt_task_signal_handler installs, or changes, the signal function * of a real time task. * * @param task is a pointer to the real time task. * * @param handler is the entry point of the signal function. * * A signal handler function can be set also when the task is newly * created with @ref rt_task_init(). The signal handler is a function * called within the task environment and with interrupts disabled, * when the task becomes the current running task after a context * switch, except at its very first scheduling. It allows you to * implement whatever signal management policy you think useful, and * many other things as well (FIXME). * * @return 0 on success.A negative value on failure as described below: * - @b EINVAL: task does not refer to a valid task. */int rt_task_signal_handler(RT_TASK *task, void (*handler)(void)){ if (task->magic != RT_TASK_MAGIC) { return -EINVAL; } task->signal = handler; return 0;}/* ++++++++++++++++++++++++++++ MEASURING TIME ++++++++++++++++++++++++++++++ */void rt_gettimeorig(RTIME time_orig[]){ unsigned long flags; struct timeval tv; hard_save_flags_and_cli(flags); do_gettimeofday(&tv); time_orig[0] = rdtsc(); hard_restore_flags(flags); time_orig[0] = tv.tv_sec*(long long)tuned.cpu_freq + llimd(tv.tv_usec, tuned.cpu_freq, 1000000) - time_orig[0]; time_orig[1] = llimd(time_orig[0], 1000000000, tuned.cpu_freq);}/* +++++++++++++++++++++++++++ CONTROLLING TIME ++++++++++++++++++++++++++++++ *//** * @anchor rt_task_make_periodic_relative_ns * Make a task run periodically. * * rt_task_make_periodic_relative_ns mark the task @e task, previously
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -