600 lines
16 KiB
C
600 lines
16 KiB
C
/*
|
|
* Copyright (C) 1999-2013 Paolo Mantegazza <mantegazza@aero.polimi.it>
|
|
* Copyright (C) 2019 Alec Ari <neotheuser@ymail.com>
|
|
*
|
|
* 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, see <http://www.gnu.org/licenses/>.
|
|
*
|
|
*/
|
|
|
|
|
|
#ifndef _RTAI_SCHEDCORE_H
|
|
#define _RTAI_SCHEDCORE_H
|
|
|
|
#ifdef __KERNEL__
|
|
|
|
#include <linux/module.h>
|
|
#include <linux/init.h>
|
|
#include <linux/kernel.h>
|
|
#include <linux/version.h>
|
|
#include <linux/errno.h>
|
|
#include <linux/slab.h>
|
|
#include <linux/timex.h>
|
|
#include <linux/sched.h>
|
|
#include <asm/param.h>
|
|
#include <asm/io.h>
|
|
#include <linux/oom.h>
|
|
#include <rtai_lxrt.h>
|
|
#include <rtai_sched.h>
|
|
#include <rtai_malloc.h>
|
|
#include <rtai_trace.h>
|
|
#include <rtai_sem.h>
|
|
#include <rtai_rwl.h>
|
|
#include <rtai_spl.h>
|
|
#include <rtai_scb.h>
|
|
#include <rtai_mbx.h>
|
|
#include <rtai_msg.h>
|
|
#include <rtai_fifos.h>
|
|
#include <rtai_shm.h>
|
|
|
|
|
|
#ifdef OOM_DISABLE
|
|
#define RTAI_OOM_DISABLE() \
|
|
do { current->signal->oom_score_adj = OOM_DISABLE; } while (0)
|
|
#else
|
|
#define RTAI_OOM_DISABLE()
|
|
#endif
|
|
|
|
#define NON_RTAI_TASK_SUSPEND(task) \
|
|
do { (task->lnxtsk)->state = TASK_SOFTREALTIME; } while (0)
|
|
|
|
#define NON_RTAI_TASK_RESUME(ready_task) \
|
|
do { pend_wake_up_srq(ready_task->lnxtsk, rtai_cpuid()); } while (0)
|
|
|
|
#define REQUEST_RESUME_SRQs_STUFF() \
|
|
do { \
|
|
if (!(wake_up_srq[0].srq = hal_alloc_irq())) { \
|
|
printk("*** ABORT, NO VIRQ AVAILABLE FOR THE WAKING UP SRQ. ***\n"); \
|
|
return -1; \
|
|
} \
|
|
ipipe_request_irq(hal_root_domain, wake_up_srq[0].srq, (void *)wake_up_srq_handler, NULL, NULL); \
|
|
} while (0)
|
|
|
|
#define RELEASE_RESUME_SRQs_STUFF() \
|
|
do { \
|
|
ipipe_free_irq(hal_root_domain, wake_up_srq[0].srq); \
|
|
hal_free_irq(wake_up_srq[0].srq); \
|
|
} while (0)
|
|
|
|
extern RT_TASK rt_smp_linux_task[];
|
|
|
|
extern RT_TASK *rt_smp_current[];
|
|
|
|
extern RTIME rt_smp_time_h[];
|
|
|
|
extern volatile int rt_sched_timed;
|
|
|
|
RT_TASK *rt_get_base_linux_task(RT_TASK **base_linux_task);
|
|
|
|
RT_TASK *rt_alloc_dynamic_task(void);
|
|
|
|
void rt_enq_ready_edf_task(RT_TASK *ready_task);
|
|
|
|
void rt_enq_ready_task(RT_TASK *ready_task);
|
|
|
|
int rt_renq_ready_task(RT_TASK *ready_task,
|
|
int priority);
|
|
|
|
void rt_rem_ready_task(RT_TASK *task);
|
|
|
|
void rt_rem_ready_current(RT_TASK *rt_current);
|
|
|
|
void rt_enq_timed_task(RT_TASK *timed_task);
|
|
|
|
void rt_rem_timed_task(RT_TASK *task);
|
|
|
|
void rt_dequeue_blocked(RT_TASK *task);
|
|
|
|
#ifdef CONFIG_RTAI_MALLOC
|
|
#ifdef CONFIG_RTAI_MALLOC_BUILTIN
|
|
#define sched_mem_init() \
|
|
{ if(__rtai_heap_init() != 0) { \
|
|
return(-ENOMEM); \
|
|
} }
|
|
#define sched_mem_end() __rtai_heap_exit()
|
|
#else /* CONFIG_RTAI_MALLOC_BUILTIN */
|
|
#define sched_mem_init()
|
|
#define sched_mem_end()
|
|
#endif /* !CONFIG_RTAI_MALLOC_BUILTIN */
|
|
#define call_exit_handlers(task) __call_exit_handlers(task)
|
|
#define set_exit_handler(task, fun, arg1, arg2) __set_exit_handler(task, fun, arg1, arg2)
|
|
#else /* !CONFIG_RTAI_MALLOC */
|
|
#define sched_mem_init()
|
|
#define sched_mem_end()
|
|
#define call_exit_handlers(task)
|
|
#define set_exit_handler(task, fun, arg1, arg2)
|
|
#endif /* CONFIG_RTAI_MALLOC */
|
|
|
|
#define SEMHLF 0x0000FFFF
|
|
#define RPCHLF 0xFFFF0000
|
|
#define RPCINC 0x00010000
|
|
|
|
#define DECLARE_RT_CURRENT int cpuid; RT_TASK *rt_current
|
|
#define ASSIGN_RT_CURRENT rt_current = rt_smp_current[cpuid = rtai_cpuid()]
|
|
#define RT_CURRENT rt_smp_current[rtai_cpuid()]
|
|
|
|
#define MAX_LINUX_RTPRIO 99
|
|
#define MIN_LINUX_RTPRIO 1
|
|
|
|
#ifdef CONFIG_RTAI_SCHED_ISR_LOCK
|
|
void rtai_handle_isched_lock(int nesting);
|
|
#endif /* CONFIG_RTAI_SCHED_ISR_LOCK */
|
|
|
|
#ifdef CONFIG_SMP
|
|
#define rt_time_h (rt_smp_time_h[cpuid])
|
|
#define rt_linux_task (rt_smp_linux_task[cpuid])
|
|
#else
|
|
#define rt_time_h (rt_smp_time_h[0])
|
|
#define rt_linux_task (rt_smp_linux_task[0])
|
|
#endif
|
|
|
|
/*
|
|
* WATCH OUT for the max expected number of arguments of rtai funs and
|
|
* their scattered around different calling ways.
|
|
*/
|
|
|
|
#define RTAI_MAX_FUN_ARGS 9
|
|
struct fun_args { unsigned long a[RTAI_MAX_FUN_ARGS]; RTAI_SYSCALL_MODE long long (*fun)(unsigned long, ...); };
|
|
//used in sys.c
|
|
#define RTAI_FUN_ARGS arg[0],arg[1],arg[2],arg[3],arg[4],arg[5],arg[6],arg[7],arg[RTAI_MAX_FUN_ARGS - 1]
|
|
//used in sched.c (generalised calls from soft threads)
|
|
#define RTAI_FUNARGS funarg->a[0],funarg->a[1],funarg->a[2],funarg->a[3],funarg->a[4],funarg->a[5],funarg->a[6],funarg->a[7],funarg->a[RTAI_MAX_FUN_ARGS - 1]
|
|
|
|
#ifdef CONFIG_SMP
|
|
|
|
static inline void send_sched_ipi(unsigned long dest)
|
|
{
|
|
_send_sched_ipi(dest);
|
|
}
|
|
|
|
#define RT_SCHEDULE_MAP(schedmap) \
|
|
do { if (schedmap) send_sched_ipi(schedmap); } while (0)
|
|
|
|
#define RT_SCHEDULE_MAP_BOTH(schedmap) \
|
|
do { if (schedmap) send_sched_ipi(schedmap); rt_schedule(); } while (0)
|
|
|
|
#define RT_SCHEDULE(task, cpuid) \
|
|
do { \
|
|
if ((task)->runnable_on_cpus != (cpuid)) { \
|
|
send_sched_ipi(1 << (task)->runnable_on_cpus); \
|
|
} else { \
|
|
rt_schedule(); \
|
|
} \
|
|
} while (0)
|
|
|
|
#define RT_SCHEDULE_BOTH(task, cpuid) \
|
|
{ \
|
|
if ((task)->runnable_on_cpus != (cpuid)) { \
|
|
send_sched_ipi(1 << (task)->runnable_on_cpus); \
|
|
} \
|
|
rt_schedule(); \
|
|
}
|
|
|
|
#else /* !CONFIG_SMP */
|
|
|
|
#define send_sched_ipi(dest)
|
|
|
|
#define RT_SCHEDULE_MAP_BOTH(schedmap) rt_schedule()
|
|
|
|
#define RT_SCHEDULE_MAP(schedmap) rt_schedule()
|
|
|
|
#define RT_SCHEDULE(task, cpuid) rt_schedule()
|
|
|
|
#define RT_SCHEDULE_BOTH(task, cpuid) rt_schedule()
|
|
|
|
#endif /* CONFIG_SMP */
|
|
|
|
#define BASE_SOFT_PRIORITY 1000000000
|
|
|
|
#ifndef TASK_NOWAKEUP
|
|
#define TASK_NOWAKEUP TASK_UNINTERRUPTIBLE
|
|
#endif
|
|
|
|
#define TASK_HARDREALTIME (TASK_INTERRUPTIBLE) // | TASK_NOWAKEUP)
|
|
#define TASK_RTAISRVSLEEP (TASK_INTERRUPTIBLE) // | TASK_NOWAKEUP)
|
|
#define TASK_SOFTREALTIME TASK_INTERRUPTIBLE
|
|
|
|
static inline void enq_ready_edf_task(RT_TASK *ready_task)
|
|
{
|
|
RT_TASK *task;
|
|
#ifdef CONFIG_SMP
|
|
task = rt_smp_linux_task[ready_task->runnable_on_cpus].rnext;
|
|
#else
|
|
task = rt_smp_linux_task[0].rnext;
|
|
#endif
|
|
while (task->policy < 0 && ready_task->period >= task->period) {
|
|
task = task->rnext;
|
|
}
|
|
task->rprev = (ready_task->rprev = task->rprev)->rnext = ready_task;
|
|
ready_task->rnext = task;
|
|
}
|
|
|
|
struct epoch_struct { spinlock_t lock; volatile int touse; volatile RTIME time[2][2]; };
|
|
|
|
#ifdef CONFIG_RTAI_CLOCK_REALTIME
|
|
#define REALTIME2COUNT(rtime) \
|
|
if (rtime > boot_epoch.time[boot_epoch.touse][0]) { \
|
|
rtime -= boot_epoch.time[boot_epoch.touse][0]; \
|
|
}
|
|
#else
|
|
#define REALTIME2COUNT(rtime)
|
|
#endif
|
|
|
|
#define MAX_WAKEUP_SRQ (1 << 6)
|
|
|
|
struct klist_t { int srq; volatile unsigned long in, out; void *task[MAX_WAKEUP_SRQ]; };
|
|
extern struct klist_t wake_up_srq[];
|
|
|
|
#define pend_wake_up_srq(lnxtsk, cpuid) \
|
|
do { \
|
|
wake_up_srq[cpuid].task[wake_up_srq[cpuid].in++ & (MAX_WAKEUP_SRQ - 1)] = lnxtsk; \
|
|
hal_pend_uncond(wake_up_srq[0].srq, cpuid); \
|
|
} while (0)
|
|
|
|
static inline void enq_ready_task(RT_TASK *ready_task)
|
|
{
|
|
RT_TASK *task;
|
|
if (ready_task->is_hard) {
|
|
#ifdef CONFIG_SMP
|
|
task = rt_smp_linux_task[ready_task->runnable_on_cpus].rnext;
|
|
#else
|
|
task = rt_smp_linux_task[0].rnext;
|
|
#endif
|
|
while (ready_task->priority >= task->priority) {
|
|
if ((task = task->rnext)->priority < 0) break;
|
|
}
|
|
task->rprev = (ready_task->rprev = task->rprev)->rnext = ready_task;
|
|
ready_task->rnext = task;
|
|
} else {
|
|
ready_task->state |= RT_SCHED_SFTRDY;
|
|
NON_RTAI_TASK_RESUME(ready_task);
|
|
}
|
|
}
|
|
|
|
static inline int renq_ready_task(RT_TASK *ready_task, int priority)
|
|
{
|
|
int retval;
|
|
if ((retval = ready_task->priority != priority)) {
|
|
ready_task->priority = priority;
|
|
if (ready_task->state == RT_SCHED_READY) {
|
|
(ready_task->rprev)->rnext = ready_task->rnext;
|
|
(ready_task->rnext)->rprev = ready_task->rprev;
|
|
enq_ready_task(ready_task);
|
|
}
|
|
}
|
|
return retval;
|
|
}
|
|
|
|
static inline void rem_ready_task(RT_TASK *task)
|
|
{
|
|
if (task->state == RT_SCHED_READY) {
|
|
if (!task->is_hard) {
|
|
NON_RTAI_TASK_SUSPEND(task);
|
|
}
|
|
// task->unblocked = 0;
|
|
(task->rprev)->rnext = task->rnext;
|
|
(task->rnext)->rprev = task->rprev;
|
|
}
|
|
}
|
|
|
|
static inline void rem_ready_current(RT_TASK *rt_current)
|
|
{
|
|
if (!rt_current->is_hard) {
|
|
NON_RTAI_TASK_SUSPEND(rt_current);
|
|
}
|
|
// rt_current->unblocked = 0;
|
|
(rt_current->rprev)->rnext = rt_current->rnext;
|
|
(rt_current->rnext)->rprev = rt_current->rprev;
|
|
}
|
|
|
|
#ifdef CONFIG_RTAI_LONG_TIMED_LIST
|
|
|
|
/* BINARY TREE */
|
|
static inline void enq_timed_task(RT_TASK *timed_task)
|
|
{
|
|
RT_TASK *taskh, *tsknxt, *task;
|
|
rb_node_t **rbtn, *rbtpn = NULL;
|
|
#ifdef CONFIG_SMP
|
|
task = taskh = &rt_smp_linux_task[timed_task->runnable_on_cpus];
|
|
#else
|
|
task = taskh = &rt_smp_linux_task[0];
|
|
#endif
|
|
rbtn = &taskh->rbr.rb_node;
|
|
|
|
while (*rbtn) {
|
|
rbtpn = *rbtn;
|
|
tsknxt = rb_entry(rbtpn, RT_TASK, rbn);
|
|
if (timed_task->resume_time > tsknxt->resume_time) {
|
|
rbtn = &(rbtpn)->rb_right;
|
|
} else {
|
|
rbtn = &(rbtpn)->rb_left;
|
|
task = tsknxt;
|
|
}
|
|
}
|
|
rb_link_node(&timed_task->rbn, rbtpn, rbtn);
|
|
rb_insert_color(&timed_task->rbn, &taskh->rbr);
|
|
task->tprev = (timed_task->tprev = task->tprev)->tnext = timed_task;
|
|
timed_task->tnext = task;
|
|
}
|
|
|
|
#define rb_erase_task(task, cpuid) \
|
|
rb_erase(&(task)->rbn, &rt_smp_linux_task[cpuid].rbr);
|
|
|
|
#else /* !CONFIG_RTAI_LONG_TIMED_LIST */
|
|
|
|
/* LINEAR */
|
|
static inline void enq_timed_task(RT_TASK *timed_task)
|
|
{
|
|
RT_TASK *task;
|
|
#ifdef CONFIG_SMP
|
|
task = rt_smp_linux_task[timed_task->runnable_on_cpus].tnext;
|
|
#else
|
|
task = rt_smp_linux_task[0].tnext;
|
|
#endif
|
|
while (timed_task->resume_time > task->resume_time) {
|
|
task = task->tnext;
|
|
}
|
|
task->tprev = (timed_task->tprev = task->tprev)->tnext = timed_task;
|
|
timed_task->tnext = task;
|
|
}
|
|
|
|
#define rb_erase_task(task, cpuid)
|
|
|
|
#endif /* !CONFIG_RTAI_LONG_TIMED_LIST */
|
|
|
|
static inline void rem_timed_task(RT_TASK *task)
|
|
{
|
|
if ((task->state & RT_SCHED_DELAYED)) {
|
|
(task->tprev)->tnext = task->tnext;
|
|
(task->tnext)->tprev = task->tprev;
|
|
#ifdef CONFIG_SMP
|
|
rb_erase_task(task, task->runnable_on_cpus);
|
|
#else
|
|
rb_erase_task(task, 0);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
static inline void wake_up_timed_tasks(int cpuid)
|
|
{
|
|
RT_TASK *taskh, *task;
|
|
#ifdef CONFIG_SMP
|
|
task = (taskh = &rt_smp_linux_task[cpuid])->tnext;
|
|
#else
|
|
task = (taskh = &rt_smp_linux_task[0])->tnext;
|
|
#endif
|
|
if (task->resume_time - task->schedlat <= rt_time_h) {
|
|
do {
|
|
if ((task->state & RT_SCHED_SUSPENDED) && task->suspdepth > 0) {
|
|
task->suspdepth = 0;
|
|
}
|
|
if ((task->state &= ~(RT_SCHED_DELAYED | RT_SCHED_SUSPENDED | RT_SCHED_SEMAPHORE | RT_SCHED_RECEIVE | RT_SCHED_SEND | RT_SCHED_RPC | RT_SCHED_RETURN | RT_SCHED_MBXSUSP | RT_SCHED_POLL)) == RT_SCHED_READY) {
|
|
if (task->policy < 0) {
|
|
enq_ready_edf_task(task);
|
|
} else {
|
|
enq_ready_task(task);
|
|
}
|
|
#if ((CONFIG_RTAI_USER_BUSY_ALIGN_RET_DELAY > 0 || CONFIG_RTAI_KERN_BUSY_ALIGN_RET_DELAY > 0))
|
|
task->busy_time_align = 1;
|
|
#endif
|
|
}
|
|
rb_erase_task(task, cpuid);
|
|
task = task->tnext;
|
|
} while (task->resume_time <= rt_time_h);
|
|
#ifdef CONFIG_SMP
|
|
rt_smp_linux_task[cpuid].tnext = task;
|
|
task->tprev = &rt_smp_linux_task[cpuid];
|
|
#else
|
|
rt_smp_linux_task[0].tnext = task;
|
|
task->tprev = &rt_smp_linux_task[0];
|
|
#endif
|
|
}
|
|
}
|
|
|
|
#define get_time() rt_get_time()
|
|
|
|
static inline void enqueue_blocked(RT_TASK *task, QUEUE *queue, int qtype)
|
|
{
|
|
QUEUE *q;
|
|
task->blocked_on = (q = queue);
|
|
if (!qtype) {
|
|
while ((q = q->next) != queue && (q->task)->priority <= task->priority);
|
|
}
|
|
q->prev = (task->queue.prev = q->prev)->next = &(task->queue);
|
|
task->queue.next = q;
|
|
}
|
|
|
|
|
|
static inline void dequeue_blocked(RT_TASK *task)
|
|
{
|
|
task->prio_passed_to = NULL;
|
|
(task->queue.prev)->next = task->queue.next;
|
|
(task->queue.next)->prev = task->queue.prev;
|
|
task->blocked_on = NULL;
|
|
}
|
|
|
|
static inline unsigned long pass_prio(RT_TASK *to, RT_TASK *from)
|
|
{
|
|
QUEUE *q, *blocked_on;
|
|
#ifdef CONFIG_SMP
|
|
RT_TASK *rhead;
|
|
unsigned long schedmap;
|
|
schedmap = 0;
|
|
#endif
|
|
// from->prio_passed_to = to;
|
|
while (to && to->priority > from->priority) {
|
|
to->priority = from->priority;
|
|
if (to->state == RT_SCHED_READY) {
|
|
if ((to->rprev)->priority > to->priority || (to->rnext)->priority < to->priority) {
|
|
#ifdef CONFIG_SMP
|
|
rhead = rt_smp_linux_task[to->runnable_on_cpus].rnext;
|
|
#endif
|
|
(to->rprev)->rnext = to->rnext;
|
|
(to->rnext)->rprev = to->rprev;
|
|
enq_ready_task(to);
|
|
#ifdef CONFIG_SMP
|
|
if (rhead != rt_smp_linux_task[to->runnable_on_cpus].rnext) {
|
|
__set_bit(to->runnable_on_cpus & 0x1F, &schedmap);
|
|
}
|
|
#endif
|
|
}
|
|
break;
|
|
// } else if ((void *)(q = to->blocked_on) > RTE_HIGERR && !((to->state & RT_SCHED_SEMAPHORE) && ((SEM *)q)->qtype)) {
|
|
} else if ((unsigned long)(blocked_on = to->blocked_on) > RTE_HIGERR && (((to->state & RT_SCHED_SEMAPHORE) && ((SEM *)blocked_on)->type > 0) || (to->state & (RT_SCHED_SEND | RT_SCHED_RPC | RT_SCHED_RETURN)))) {
|
|
if (to->queue.prev != blocked_on) {
|
|
q = blocked_on;
|
|
(to->queue.prev)->next = to->queue.next;
|
|
(to->queue.next)->prev = to->queue.prev;
|
|
while ((q = q->next) != blocked_on && (q->task)->priority <= to->priority);
|
|
q->prev = (to->queue.prev = q->prev)->next = &(to->queue);
|
|
to->queue.next = q;
|
|
if (to->queue.prev != blocked_on) {
|
|
break;
|
|
}
|
|
}
|
|
to = (to->state & RT_SCHED_SEMAPHORE) ? ((SEM *)blocked_on)->owndby : blocked_on->task;
|
|
}
|
|
// to = to->prio_passed_to;
|
|
}
|
|
#ifdef CONFIG_SMP
|
|
return schedmap;
|
|
#else
|
|
return 0;
|
|
#endif
|
|
}
|
|
|
|
static inline RT_TASK *_rt_whoami(void)
|
|
{
|
|
#ifdef CONFIG_SMP
|
|
RT_TASK *rt_current;
|
|
unsigned long flags;
|
|
flags = rt_global_save_flags_and_cli();
|
|
rt_current = RT_CURRENT;
|
|
rt_global_restore_flags(flags);
|
|
return rt_current;
|
|
#else
|
|
return rt_smp_current[0];
|
|
#endif
|
|
}
|
|
|
|
static inline void __call_exit_handlers(RT_TASK *task)
|
|
{
|
|
XHDL *pt, *tmp;
|
|
|
|
pt = task->ExitHook; // Initialise ExitHook in rt_task_init()
|
|
while ( pt ) {
|
|
(*pt->fun) (pt->arg1, pt->arg2);
|
|
tmp = pt;
|
|
pt = pt->nxt;
|
|
rt_free(tmp);
|
|
}
|
|
task->ExitHook = 0;
|
|
}
|
|
|
|
static inline XHDL *__set_exit_handler(RT_TASK *task, void (*fun) (void *, int), void *arg1, int arg2)
|
|
{
|
|
XHDL *p;
|
|
|
|
// exit handler functions are automatically executed at terminattion time by rt_task_delete()
|
|
// in the reverse order they were created (like C++ destructors behave).
|
|
if (task->magic != RT_TASK_MAGIC) return 0;
|
|
if (!(p = (XHDL *) rt_malloc (sizeof(XHDL)))) return 0;
|
|
p->fun = fun;
|
|
p->arg1 = arg1;
|
|
p->arg2 = arg2;
|
|
p->nxt = task->ExitHook;
|
|
return (task->ExitHook = p);
|
|
}
|
|
|
|
static inline int rtai_init_features (void)
|
|
|
|
{
|
|
#ifdef CONFIG_RTAI_SEM_BUILTIN
|
|
__rtai_sem_init();
|
|
#endif /* CONFIG_RTAI_SEM_BUILTIN */
|
|
#ifdef CONFIG_RTAI_MSG_BUILTIN
|
|
__rtai_msg_init();
|
|
#endif /* CONFIG_RTAI_MSG_BUILTIN */
|
|
#ifdef CONFIG_RTAI_MBX_BUILTIN
|
|
__rtai_mbx_init();
|
|
#endif /* CONFIG_RTAI_MBX_BUILTIN */
|
|
#ifdef CONFIG_RTAI_FIFOS_BUILTIN
|
|
__rtai_fifos_init();
|
|
#endif /* CONFIG_RTAI_FIFOS_BUILTIN */
|
|
#ifdef CONFIG_RTAI_SHM_BUILTIN
|
|
__rtai_shm_init();
|
|
#endif /* CONFIG_RTAI_SHM_BUILTIN */
|
|
#ifdef CONFIG_RTAI_MATH_BUILTIN
|
|
__rtai_math_init();
|
|
#endif /* CONFIG_RTAI_MATH_BUILTIN */
|
|
|
|
return 0;
|
|
}
|
|
|
|
static inline void rtai_cleanup_features (void) {
|
|
|
|
#ifdef CONFIG_RTAI_MATH_BUILTIN
|
|
__rtai_math_exit();
|
|
#endif /* CONFIG_RTAI_MATH_BUILTIN */
|
|
#ifdef CONFIG_RTAI_SHM_BUILTIN
|
|
__rtai_shm_exit();
|
|
#endif /* CONFIG_RTAI_SHM_BUILTIN */
|
|
#ifdef CONFIG_RTAI_FIFOS_BUILTIN
|
|
__rtai_fifos_exit();
|
|
#endif /* CONFIG_RTAI_FIFOS_BUILTIN */
|
|
#ifdef CONFIG_RTAI_MBX_BUILTIN
|
|
__rtai_mbx_exit();
|
|
#endif /* CONFIG_RTAI_MBX_BUILTIN */
|
|
#ifdef CONFIG_RTAI_MSG_BUILTIN
|
|
__rtai_msg_exit();
|
|
#endif /* CONFIG_RTAI_MSG_BUILTIN */
|
|
#ifdef CONFIG_RTAI_SEM_BUILTIN
|
|
__rtai_sem_exit();
|
|
#endif /* CONFIG_RTAI_SEM_BUILTIN */
|
|
}
|
|
|
|
int rt_check_current_stack(void);
|
|
|
|
int rt_kthread_init_old(RT_TASK *task,
|
|
void (*rt_thread)(long),
|
|
long data,
|
|
int stack_size,
|
|
int priority,
|
|
int uses_fpu,
|
|
void(*signal)(void));
|
|
|
|
int rt_kthread_init_cpuid(RT_TASK *task,
|
|
void (*rt_thread)(long),
|
|
long data,
|
|
int stack_size,
|
|
int priority,
|
|
int uses_fpu,
|
|
void(*signal)(void),
|
|
unsigned int cpuid);
|
|
|
|
#else /* !__KERNEL__ */
|
|
|
|
#endif /* __KERNEL__ */
|
|
|
|
#endif /* !_RTAI_SCHEDCORE_H */
|