📄 shadow.c
字号:
case __xn_sys_sched: xnpod_schedule(NULL); return; case __xn_sys_attach: __xn_reg_rval(regs) = xnshadow_attach_skin(task, __xn_reg_arg1(regs), __xn_reg_arg2(regs)); return; case __xn_sys_detach: __xn_reg_rval(regs) = xnshadow_detach_skin(task, __xn_reg_arg1(regs)); return; case __xn_sys_sync: /* Do this from the Linux domain. */ adeos_propagate_event(evinfo); return; case __xn_sys_migrate: if (!thread) /* Not a shadow anyway. */ __xn_reg_rval(regs) = 0; else if (__xn_reg_arg1(regs)) /* Linux => RTAI */ { if (!xnthread_test_flags(thread,XNRELAX)) __xn_reg_rval(regs) = 0; else adeos_propagate_event(evinfo); } else /* RTAI => Linux */ { if (xnthread_test_flags(thread,XNRELAX)) __xn_reg_rval(regs) = 0; else { __xn_reg_rval(regs) = 1; xnshadow_relax(); } } return;#if CONFIG_TRACE case 20: TRACE_PROCESS(TRACE_EV_PROCESS_SIGNAL, -888, adp_root->cpudata[0].irq_pending_lo[0]); __xn_reg_rval(regs) = 0; return; case 21: TRACE_PROCESS(TRACE_EV_PROCESS_SIGNAL, -999, 0); __xn_reg_rval(regs) = 0; return;#endif default: __xn_reg_rval(regs) = -ENOSYS; return; } } /* Skin call: check validity. */ if (muxid < 0 || muxid > XENOMAI_MUX_NR || muxop < 0 || muxop >= muxtable[muxid - 1].nrcalls || ((muxtable[muxid - 1].systab[muxop].flags & __xn_flag_anycontext) == 0 && xnshadow_thread(task) == NULL)) { __xn_reg_rval(regs) = -ENOSYS; return; } if ((muxtable[muxid - 1].systab[muxop].flags & __xn_flag_suspensive) != 0 && evinfo->domid != RTAI_DOMAIN_ID) /* This one must be handled in the Linux domain. */ adeos_propagate_event(evinfo); else __xn_reg_rval(regs) = muxtable[muxid - 1].systab[muxop].svc(task,regs);}static void xnshadow_linux_sysentry (adevinfo_t *evinfo){ struct pt_regs *regs = (struct pt_regs *)evinfo->evdata; xnthread_t *thread = xnshadow_thread(current); int muxid, muxop; if (__xn_reg_mux_p(regs)) { /* muxid and muxop have already been checked in the RTAI domain handler. */ muxid = __xn_mux_id(regs); muxop = __xn_mux_op(regs);#if 1 if (traceme) printk("REQ {skin=%d, op=%d} on behalf of thread %s, pid=%d in domain %s\n", muxid, muxop, xnpod_current_thread()->name, current->pid, adp_current->name);#endif if (muxid == 0) { /* These are special built-in services which must be run on behalf of the Linux domain. */ switch (muxop) { case __xn_sys_sync: __xn_reg_rval(regs) = xnshadow_sync_wait((int *)__xn_reg_arg1(regs)); break; case __xn_sys_migrate: __xn_reg_rval(regs) = 1; xnshadow_harden(NULL); return; } } else __xn_reg_rval(regs) = muxtable[muxid - 1].systab[muxop].svc(current,regs); if (thread && testbits(thread->status,XNAUTOSW|XNRELAX) == (XNAUTOSW|XNRELAX)) { xnshadow_harden(NULL); return; } } else { if (thread && xnshadow_substitute_syscall(current,regs,1)) /* This is a Linux syscall issued on behalf of a shadow thread running inside the Linux domain. If the call has been substituted with a RTAI replacement, do not let Linux know about it. */ return; /* Fall back to Linux syscall handling. */ adeos_propagate_event(evinfo); }}static void xnshadow_linux_sysexit (adevinfo_t *evinfo){ xnthread_t *thread = xnshadow_thread(current); if (thread && !signal_pending(current)) {#if 1 if (traceme) printk("__SYSOUT__ %s, pid=%d, autoswitch=%d\n", xnpod_current_thread()->name, current->pid, testbits(thread->status,XNAUTOSW|XNSYSSW) == (XNAUTOSW|XNSYSSW));#endif if (testbits(thread->status,XNAUTOSW|XNSYSSW) == (XNAUTOSW|XNSYSSW)) { clrbits(thread->status,XNSYSSW); xnshadow_harden(NULL); return; } } adeos_propagate_event(evinfo);}static void xnshadow_linux_taskexit (adevinfo_t *evinfo){ xnthread_t *thread = xnshadow_thread(current); if (thread) {#if 1 if (traceme) printk("LINUX EXIT on behalf of thread %s, pid=%d, relaxed? %d\n", thread->name, current->pid, !!testbits(thread->status,XNRELAX));#endif if (xnpod_shadow_p()) xnshadow_relax(); /* So that we won't attempt to further wakeup the exiting task in xnshadow_unmap(). */ xnthread_archtcb(thread)->user_task = NULL; xnshadow_ptd(current) = NULL; xnpod_delete_thread(thread,NULL);#if 1 if (traceme) printk("Cleaned up %s\n",thread->name);#endif } adeos_propagate_event(evinfo);}#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)static struct mmreq { int in, out, count;#define MAX_MM 32 /* Should be more than enough (must be a power of 2). */#define bump_mmreq(x) do { x = (x + 1) & (MAX_MM - 1); } while(0) struct mm_struct *mm[MAX_MM];} mmrqtab[NR_CPUS];#endif /* KERNEL_VERSION < 2.6.0 */static void xnshadow_schedule_head (adevinfo_t *evinfo){ struct { struct task_struct *prev, *next; } *evdata = (__typeof(evdata))evinfo->evdata; struct task_struct *next = evdata->next; int rootprio;#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) struct task_struct *prev = evdata->prev; /* The SCHEDULE_HEAD event is sent by the (Adeosized) Linux kernel each time it's about to switch a process out. This hook is aimed at preventing the last active MM from being dropped during the real-time operations since it is costly. See kernel/sched.c (schedule()) for more. The MM dropping is simply postponed until the SCHEDULE_TAIL event is received, right after the incoming task has been switched in. */ if (!prev->mm) { struct mmreq *p = mmrqtab + task_cpu(prev); struct mm_struct *oldmm = prev->active_mm; BUG_ON(p->count >= MAX_MM); /* Prevent the MM from being dropped in schedule(), then pend a request to drop it later in xnshadow_schedule_tail(). */ atomic_inc(&oldmm->mm_count); p->mm[p->in] = oldmm; bump_mmreq(p->in); p->count++; }#endif /* KERNEL_VERSION < 2.6.0 */ adeos_propagate_event(evinfo); if (!nkpod) return; if (xnshadow_thread(next)) { rootprio = xnshadow_thread(next)->cprio; engage_irq_shield(); } else if (next != gatekeeper) { rootprio = XNPOD_ROOT_PRIO_BASE; disengage_irq_shield(); } else return; /* Current Xenomai thread must be the root one in this context, so we can safely renice Xenomai's runthread (i.e. as returned by xnpod_current_thread()). */ if (xnpod_current_thread()->cprio != rootprio) xnpod_renice_root(rootprio);}static void xnshadow_schedule_tail (adevinfo_t *evinfo){ if (evinfo->domid == RTAI_DOMAIN_ID) /* About to resume in xnshadow_harden() after the gatekeeper switched us back. Do _not_ propagate this event so that Linux's tail scheduling won't be performed. */ return;#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) { struct mmreq *p;#ifdef CONFIG_PREEMPT preempt_disable();#endif /* CONFIG_PREEMPT */ p = mmrqtab + smp_processor_id(); while (p->out != p->in) { struct mm_struct *oldmm = p->mm[p->out]; mmdrop(oldmm); bump_mmreq(p->out); p->count--; }#ifdef CONFIG_PREEMPT preempt_enable();#endif /* CONFIG_PREEMPT */ }#endif /* KERNEL_VERSION < 2.6.0 */ adeos_propagate_event(evinfo);}static void xnshadow_signal_process (adevinfo_t *evinfo){ struct { struct task_struct *task; int sig; } *evdata = (__typeof(evdata))evinfo->evdata; xnthread_t *thread = xnshadow_thread(evdata->task); if (thread && !testbits(thread->status,XNRELAX|XNROOT)) { switch (evdata->sig) { case SIGTERM: case SIGKILL: case SIGQUIT: case SIGINT: /* Let the kick handler process those signals, and let them propagate. */ break; default: /* Instead of having the shadow threads being marked as uninterruptible when running into the RTAI domain, which somewhat breaks Linux's activity counters, we leave them in an interruptible state, but block the signal propagation here when such threads remain under the control of the Xenomai scheduler. */ return; } } adeos_propagate_event(evinfo);}static void xnshadow_kick_process (adevinfo_t *evinfo){ struct { struct task_struct *task; } *evdata = (__typeof(evdata))evinfo->evdata; struct task_struct *task = evdata->task; xnthread_t *thread = xnshadow_thread(task); spl_t s; if (thread && !testbits(thread->status,XNRELAX|XNROOT)) { /* Some kernel-originated signals do not raise an ADEOS_SIGNAL_PROCESS event and cannot be blocked in any way (e.g. group exit signal). So we must interpose on the ADEOS_KICK_PROCESS event in order to be given a chance to see those at least, and unblock their real-time counterpart if they happen to target a real-time shadow. This event is always propagated and cannot be dismissed, but again, at least we have been warned. */ if (sigismember(&task->pending.signal,SIGTERM) || sigismember(&task->pending.signal,SIGKILL) || sigismember(&task->pending.signal,SIGQUIT) || sigismember(&task->pending.signal,SIGINT)) { splhigh(s); thread->signals |= XNTHREAD_SHADOW_SIGKILL; if (!testbits(thread->status,XNSTARTED)) xnshadow_start(thread,0,NULL,NULL,0); else xnpod_unblock_thread(thread); if (testbits(thread->status,XNSUSP)) xnpod_resume_thread(thread,XNSUSP); xnshadow_schedule(); /* Schedule in the RTAI space. */ splexit(s); } }}static void xnshadow_renice_process (adevinfo_t *evinfo){ struct { struct task_struct *task; int policy; struct sched_param *param; } *evdata; xnthread_t *thread; evdata = (__typeof(evdata))evinfo->evdata; thread = xnshadow_thread(evdata->task); if (!thread) { adeos_propagate_event(evinfo); return; /* Not a shadow -- Let Linux handle this one. */ } if (evdata->policy != SCHED_FIFO) /* Bad policy -- Make Linux to ignore the change. */ return; adeos_propagate_event(evinfo); xnpod_renice_thread_inner(thread,evdata->param->sched_priority,0); xnpod_schedule(NULL); /* We are already running into the RTAI domain. */}int xnshadow_register_skin (unsigned magic, int nrcalls, xnsysent_t *systab){ int muxid; spl_t s; /* We can only handle up to 256 syscalls per skin, check for over- and underflow (MKL) */ if (XNARCH_MAX_SYSENT < nrcalls || 0 > nrcalls) return -EINVAL; splhigh(s); for (muxid = 0; muxid < XENOMAI_MUX_NR; muxid++) { if (muxtable[muxid].systab == NULL) { muxtable[muxid].systab = systab; muxtable[muxid].nrcalls = nrcalls; muxtable[muxid].magic = magic; muxtable[muxid].refcnt = 0; splexit(s); return muxid + 1; } } splexit(s); return -ENOSPC;}int xnshadow_unregister_skin (int muxid){ spl_t s; if (--muxid < 0 || muxid >= XENOMAI_MUX_NR) return -EINVAL; if (muxtable[muxid].refcnt > 0) return -EBUSY; splhigh(s); muxtable[muxid].systab = NULL; muxtable[muxid].nrcalls = 0; muxtable[muxid].magic = 0; splexit(s); return 0;}static void xnshadow_irq_trampoline (unsigned irq) { adeos_propagate_irq(irq);}static void xnshadow_shield (int iflag){ unsigned irq; if (iflag) for (irq = 0; irq < IPIPE_NR_XIRQS; irq++) adeos_virtualize_irq(irq, &xnshadow_irq_trampoline, NULL, IPIPE_DYNAMIC_MASK); for (;;) adeos_suspend_domain();}int xnshadow_init (void){ adattr_t attr; adeos_init_attr(&attr); attr.name = "Xenomai"; attr.domid = 0x59454e4f; attr.entry = &xnshadow_shield; attr.priority = ADEOS_ROOT_PRI + 50; if (adeos_register_domain(&irq_shield,&attr)) return -EBUSY; nkgkptd = adeos_alloc_ptdkey(); gkvirq = adeos_alloc_irq(); adeos_virtualize_irq(gkvirq,&xnshadow_wakeup_handler,NULL,IPIPE_HANDLE_MASK); sigvirq = adeos_alloc_irq(); adeos_virtualize_irq(sigvirq,&xnshadow_signal_handler,NULL,IPIPE_HANDLE_MASK); nicevirq = adeos_alloc_irq(); adeos_virtualize_irq(nicevirq,&xnshadow_renice_handler,NULL,IPIPE_HANDLE_MASK); init_MUTEX_LOCKED(&gksync); init_MUTEX_LOCKED(&gkreq); kernel_thread((void *)&gatekeeper_thread,NULL,0); down(&gksync); adeos_catch_event(ADEOS_SYSCALL_PROLOGUE,&xnshadow_linux_sysentry); adeos_catch_event(ADEOS_SYSCALL_EPILOGUE,&xnshadow_linux_sysexit); adeos_catch_event(ADEOS_EXIT_PROCESS,&xnshadow_linux_taskexit); adeos_catch_event(ADEOS_SIGNAL_PROCESS,&xnshadow_signal_process); adeos_catch_event(ADEOS_KICK_PROCESS,&xnshadow_kick_process); adeos_catch_event(ADEOS_SCHEDULE_HEAD,&xnshadow_schedule_head); adeos_catch_event_from(&rtai_domain,ADEOS_SCHEDULE_TAIL,&xnshadow_schedule_tail); adeos_catch_event_from(&rtai_domain,ADEOS_SYSCALL_PROLOGUE,&xnshadow_realtime_sysentry); adeos_catch_event_from(&rtai_domain,ADEOS_RENICE_PROCESS,&xnshadow_renice_process); return 0;}void xnshadow_cleanup (void){ gkstop = 1; up(&gkreq); down(&gksync); adeos_free_irq(gkvirq); adeos_free_irq(sigvirq); adeos_free_irq(nicevirq); adeos_free_ptdkey(nkgkptd); adeos_catch_event(ADEOS_SYSCALL_PROLOGUE,NULL); adeos_catch_event(ADEOS_SYSCALL_EPILOGUE,NULL); adeos_catch_event(ADEOS_EXIT_PROCESS,NULL); adeos_catch_event(ADEOS_SIGNAL_PROCESS,NULL); adeos_catch_event(ADEOS_KICK_PROCESS,NULL); adeos_catch_event(ADEOS_SCHEDULE_HEAD,NULL); adeos_catch_event_from(&rtai_domain,ADEOS_SCHEDULE_TAIL,NULL); adeos_catch_event_from(&rtai_domain,ADEOS_SYSCALL_PROLOGUE,NULL); adeos_catch_event_from(&rtai_domain,ADEOS_RENICE_PROCESS,NULL); adeos_unregister_domain(&irq_shield);}/*@}*/EXPORT_SYMBOL(xnshadow_harden);EXPORT_SYMBOL(xnshadow_map);EXPORT_SYMBOL(xnshadow_register_skin);EXPORT_SYMBOL(xnshadow_relax);EXPORT_SYMBOL(xnshadow_start);EXPORT_SYMBOL(xnshadow_ticks2ts);EXPORT_SYMBOL(xnshadow_ticks2tv);EXPORT_SYMBOL(xnshadow_ts2ticks);EXPORT_SYMBOL(xnshadow_tv2ticks);EXPORT_SYMBOL(xnshadow_unmap);EXPORT_SYMBOL(xnshadow_unregister_skin);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -