📄 task.c
字号:
/** * @file * This file is part of the Xenomai project. * * @note Copyright (C) 2004 Philippe Gerum <rpm@xenomai.org> * * 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 task *//*! * \ingroup native * \defgroup task Task management services. * * Xenomai provides a set of multitasking mechanisms. The basic process * object performing actions in Xenomai is a task, a logically complete * path of application code. Each Xenomai task is an independent portion * of the overall application code embodied in a C procedure, which * executes on its own stack context. * * The Xenomai scheduler ensures that concurrent tasks are run according * to one of the supported scheduling policies. Currently, the Xenomai * scheduler supports fixed priority-based FIFO and round-robin * policies. * *@{*/#include <nucleus/pod.h>#include <nucleus/heap.h>#include <nucleus/registry.h>#include <native/task.h>static DECLARE_XNQUEUE(__xeno_task_q);static u_long __xeno_task_stamp;static void __task_delete_hook (xnthread_t *thread){ /* The scheduler is locked while hooks are running. */ RT_TASK *task; if (xnthread_get_magic(thread) != XENO_SKIN_MAGIC) return; task = thread2rtask(thread);#ifdef CONFIG_XENO_OPT_NATIVE_MPS /* The nucleus will reschedule as needed when all the deletion hooks are done. */ xnsynch_destroy(&task->mrecv); xnsynch_destroy(&task->msendq);#endif /* CONFIG_XENO_OPT_NATIVE_MPS */#ifdef CONFIG_XENO_OPT_REGISTRY if (xnthread_handle(&task->thread_base) != XN_NO_HANDLE) xnregistry_remove(xnthread_handle(&task->thread_base));#endif /* CONFIG_XENO_OPT_REGISTRY */ xnsynch_destroy(&task->safesynch); removeq(&__xeno_task_q,&task->link); xeno_mark_deleted(task); if (xnthread_test_flags(&task->thread_base,XNSHADOW)) xnfreesafe(&task->thread_base,task,&task->link);}u_long __native_task_safe (void){ RT_TASK *task = xeno_current_task(); return ++task->safelock;}u_long __native_task_unsafe (void){ /* Must be called nklock locked, interrupts off. */ RT_TASK *task = xeno_current_task(); u_long safelock; if (task->safelock > 0 && --task->safelock == 0 && xnsynch_nsleepers(&task->safesynch) > 0) { xnsynch_flush(&task->safesynch,0); xnpod_schedule(); } safelock = task->safelock; return safelock;}int __native_task_safewait (RT_TASK *task){ /* Must be called nklock locked, interrupts off. */ u_long cstamp; if (task->safelock == 0) return 0; if (task == xeno_current_task()) return -EDEADLK; cstamp = task->cstamp; do { xnsynch_sleep_on(&task->safesynch,TM_INFINITE); if (xnthread_test_flags(&xeno_current_task()->thread_base,XNBREAK)) return -EINTR; } while (task->safelock > 0); if (task->cstamp != cstamp) return -EIDRM; return 0;}int __native_task_pkg_init (void){ xnpod_add_hook(XNHOOK_THREAD_DELETE,&__task_delete_hook); return 0;}void __native_task_pkg_cleanup (void){ xnholder_t *holder; while ((holder = getheadq(&__xeno_task_q)) != NULL) rt_task_delete(link2rtask(holder)); xnpod_remove_hook(XNHOOK_THREAD_DELETE,&__task_delete_hook);}/** * @fn int rt_task_create(RT_TASK *task,const char *name,int stksize,int prio,int mode) * @brief Create a new real-time task. * * Creates a real-time task, either running in a kernel module or in * user-space depending on the caller's context. * * @param task The address of a task descriptor Xenomai will use to store * the task-related data. This descriptor must always be valid while * the task is active therefore it must be allocated in permanent * memory. * * The task is left in an innocuous state until it is actually started * by rt_task_start(). * * @param name An ASCII string standing for the symbolic name of the * task. When non-NULL and non-empty, this string is copied to a safe * place into the descriptor, and passed to the registry package if * enabled for indexing the created task. * * @param stksize The size of the stack (in bytes) for the new * task. If zero is passed, a reasonable pre-defined size will be * substituted. * * @param prio The base priority of the new task. This value must * range from [1 .. 99] (inclusive) where 1 is the lowest effective * priority. * * @param mode The task creation mode. The following flags can be * OR'ed into this bitmask, each of them affecting the new task: * * - T_FPU allows the task to use the FPU whenever available on the * platform. This flag is forced for user-space tasks. * * - T_SUSP causes the task to start in suspended mode. In such a * case, the thread will have to be explicitely resumed using the * rt_task_resume() service for its execution to actually begin. * * - T_CPU(cpuid) makes the new task affine to CPU # @b cpuid. CPU * identifiers range from 0 to RTHAL_NR_CPUS - 1 (inclusive). * * - T_JOINABLE (user-space only) allows another task to wait on the * termination of the new task. This implies that rt_task_join() is * actually called for this task to clean up any user-space located * resources after its termination. * * Passing T_FPU|T_CPU(1) in the @a mode parameter thus creates a task * with FPU support enabled and which will be affine to CPU #1. * * @return 0 is returned upon success. Otherwise: * * - -ENOMEM is returned if the system fails to get enough dynamic * memory from the global real-time heap in order to create or * register the task. * * - -EEXIST is returned if the @a name is already in use by some * registered object. * * - -EPERM is returned if this service was called from an * asynchronous context. * * Environments: * * This service can be called from: * * - Kernel module initialization/cleanup code * - Kernel-based task * - User-space task * * Rescheduling: possible. */int rt_task_create (RT_TASK *task, const char *name, int stksize, int prio, int mode){ int err = 0, cpumask, cpu; xnflags_t bflags; spl_t s; if (prio < T_LOPRIO || prio > T_HIPRIO) return -EINVAL; if (xnpod_asynch_p()) return -EPERM; bflags = mode & (XNFPU|XNSHADOW|XNSHIELD|XNSUSP); if (name) { if (!*name) /* i.e. Anonymous object which must be accessible from user-space. */ xnobject_create_name(task->rname,sizeof(task->rname),task); else xnobject_copy_name(task->rname, name); } if (xnpod_init_thread(&task->thread_base, name, prio, bflags, stksize) != 0) /* Assume this is the only possible failure. */ return -ENOMEM; xnthread_set_magic(&task->thread_base,XENO_SKIN_MAGIC); inith(&task->link); task->suspend_depth = (bflags & XNSUSP) ? 1 : 0; task->overrun = -1; task->cstamp = ++__xeno_task_stamp; task->safelock = 0; xnsynch_init(&task->safesynch,XNSYNCH_FIFO); xnarch_cpus_clear(task->affinity); for (cpu = 0, cpumask = (mode >> 24) & 0xff; cpumask != 0 && cpu < 8; cpu++, cpumask >>= 1) if (cpumask & 1) xnarch_cpu_set(cpu,task->affinity);#ifdef CONFIG_XENO_OPT_NATIVE_MPS xnsynch_init(&task->mrecv,XNSYNCH_FIFO); xnsynch_init(&task->msendq,XNSYNCH_PRIO|XNSYNCH_PIP); xnsynch_set_owner(&task->msendq,&task->thread_base); task->flowgen = 0;#endif /* CONFIG_XENO_OPT_NATIVE_MPS */ xnlock_get_irqsave(&nklock,s); task->magic = XENO_TASK_MAGIC; appendq(&__xeno_task_q,&task->link); xnlock_put_irqrestore(&nklock,s);#ifdef CONFIG_XENO_OPT_REGISTRY /* <!> Since xnregister_enter() may reschedule, only register complete objects, so that the registry cannot return handles to half-baked objects... */ if (name) { err = xnregistry_enter(task->rname, task, &xnthread_handle(&task->thread_base), NULL); if (err) rt_task_delete(task); else if (!*name) /* /proc/xenomai/sched will dump no name for the anonymous task, but the registry still has a stable reference into the TCB to set up a handle for the task. */ xnthread_clear_name(&task->thread_base); }#endif /* CONFIG_XENO_OPT_REGISTRY */ return err;}/** * @fn int rt_task_start(RT_TASK *task,void (*entry)(void *cookie),void *cookie) * @brief Start a real-time task. * * Start a (newly) created task, scheduling it for the first * time. This call releases the target task from the dormant state. * * The TSTART hooks are called on behalf of the calling context (if * any, see rt_task_add_hook()). * * @param task The descriptor address of the affected task which must * have been previously created by the rt_task_create() service. * * @param entry The address of the task's body routine. In other * words, it is the task entry point. * * @param cookie A user-defined opaque cookie the real-time kernel * will pass to the emerging task as the sole argument of its entry * point. * * @return 0 is returned upon success. Otherwise: * * - -EINVAL is returned if @a task is not a task descriptor. * * - -EIDRM is returned if @a task is a deleted task descriptor. * * - -EBUSY is returned if @a task is already started. * * - -EPERM is returned if this service was called from an * asynchronous context. * * Environments: * * This service can be called from: * * - Kernel module initialization/cleanup code * - Kernel-based task * - User-space task * * Rescheduling: possible. */int rt_task_start (RT_TASK *task, void (*entry)(void *cookie), void *cookie){ int err = 0; spl_t s; if (xnpod_asynch_p()) return -EPERM; xnlock_get_irqsave(&nklock,s); task = xeno_h2obj_validate(task,XENO_TASK_MAGIC,RT_TASK); if (!task) { err = xeno_handle_error(task,XENO_TASK_MAGIC,RT_TASK); goto unlock_and_exit; } if (!xnthread_test_flags(&task->thread_base,XNDORMANT)) { err = -EBUSY; /* Task already started. */ goto unlock_and_exit; } xnpod_start_thread(&task->thread_base, 0, 0, task->affinity, entry, cookie); unlock_and_exit: xnlock_put_irqrestore(&nklock,s); return err;}/** * @fn int rt_task_suspend(RT_TASK *task) * @brief Suspend a real-time task. * * Forcibly suspend the execution of a task. This task will not be * eligible for scheduling until it is explicitly resumed by a call to * rt_task_resume(). In other words, the suspended state caused by a * call to rt_task_suspend() is cumulative with respect to the delayed * and blocked states caused by other services, and is managed * separately from them. * * A nesting count is maintained so that rt_task_suspend() and * rt_task_resume() must be used in pairs. * * @param task The descriptor address of the affected task. If @a task * is NULL, the current task is suspended. * * @return 0 is returned upon success. Otherwise: * * - -EINVAL is returned if @a task is not a task descriptor. * * - -EPERM is returned if @a task is NULL but not called from a task * context, or this service was called from a context which cannot * sleep (e.g. interrupt, non-realtime or scheduler locked). * * - -EIDRM is returned if @a task is a deleted task descriptor. * * Environments: * * This service can be called from: * * - Kernel module initialization/cleanup code * - Interrupt service routine * only if @a task is non-NULL. * * - Kernel-based task * - User-space task (switches to primary mode) * * Rescheduling: always if @a task is NULL. */int rt_task_suspend (RT_TASK *task){ int err = 0; spl_t s; if (!task) { if (!xnpod_primary_p()) return -EPERM; task = xeno_current_task(); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -