📄 pod.c
字号:
/*!\file pod.c * \brief Real-time pod services. * \author Philippe Gerum * * Copyright (C) 2001,2002,2003 Philippe Gerum <rpm@xenomai.org>. * * Xenomai 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. * * Xenomai 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 Xenomai; if not, write to the Free Software Foundation, * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * As a special exception, the RTAI project gives permission * for additional uses of the text contained in its release of * Xenomai. * * The exception is that, if you link the Xenomai libraries with other * files to produce an executable, this does not by itself cause the * resulting executable to be covered by the GNU General Public License. * Your use of that executable is in no way restricted on account of * linking the Xenomai libraries code into it. * * This exception does not however invalidate any other reasons why * the executable file might be covered by the GNU General Public * License. * * This exception applies only to the code released by the * RTAI project under the name Xenomai. If you copy code from other * RTAI project releases into a copy of Xenomai, as the General Public * License permits, the exception does not apply to the code that you * add in this way. To avoid misleading anyone as to the status of * such modified files, you must delete this exception notice from * them. * * If you write modifications of your own for Xenomai, it is your * choice whether to permit this exception to apply to your * modifications. If you do not wish that, delete this exception * notice. * * \ingroup pod *//*! * \defgroup xenomai Xenomai scheduler. * * A scheduler for mimicking real-time operating systems. * * Xenomai is an RTAI scheduler which provides generic real-time operating * services suited for the implementation of real-time operating system * interfaces. *//*! * \ingroup xenomai * \defgroup pod Real-time pod services. * * Real-time pod services. *@{*/#define XENO_POD_MODULE#include <stdarg.h>#include "rtai_config.h"#include "xenomai/pod.h"#include "xenomai/mutex.h"#include "xenomai/synch.h"#include "xenomai/heap.h"#include "xenomai/intr.h"#include "xenomai/module.h"xnpod_t *nkpod = NULL;xnintr_t nkclock;const char *xnpod_fatal_helper (const char *format, ...){ static char buf[256]; xnholder_t *holder; va_list ap; spl_t s; splhigh(s); va_start(ap,format); vsprintf(buf,format,ap); va_end(ap); if (!nkpod || testbits(nkpod->status,XNFATAL)) goto out; setbits(nkpod->status,XNFATAL); xntimer_freeze(); xnprintf("--%-12s PRI STATUS\n","THREAD"); holder = getheadq(&nkpod->threadq); while (holder) { xnthread_t *thread = link2thread(holder,glink); xnprintf("%c %-12s %4d 0x%lx\n", thread == xnpod_current_thread() ? '>' : ' ', thread->name, thread->cprio,thread->status); holder = nextq(&nkpod->threadq,holder); } if (testbits(nkpod->status,XNTIMED)) { if (testbits(nkpod->status,XNTMPER)) xnprintf("Timer: periodic [tickval=%luus, elapsed=%Lu]\n", xnpod_get_tickval() / 1000, nkpod->jiffies); else xnprintf("Timer: aperiodic.\n"); } else xnprintf("Timer: none.\n"); out: splexit(s); return buf;}/* * xnpod_fault_handler -- The default fault handler. */static int xnpod_fault_handler (xnarch_fltinfo_t *fltinfo){ if (!xnpod_userspace_p()) { xnprintf("Xenomai: suspending kernel thread %p ('%s') at 0x%lx after exception #%u\n", xnpod_current_thread(), xnpod_current_thread()->name, xnarch_fault_pc(fltinfo), xnarch_fault_trap(fltinfo)); /* Put the faulting thread in dormant state since XNSUSP might be cleared as the application continues. */ xnpod_suspend_thread(xnpod_current_thread(),XNDORMANT,XN_INFINITE,NULL,NULL); return 1; }#ifdef __KERNEL__ /* If we experienced a trap on behalf of a shadow thread, just move the second to the Linux domain, so that the host O/S (e.g. Linux) can attempt to process the first. This is especially useful in order to handle user-space errors gracefully. */ if (xnpod_shadow_p()) { xnshadow_relax(); return 1; }#endif /* __KERNEL__ */ return 0;}static void xnpod_host_tick (void *cookie) { /* Host tick relay handler */ xnarch_relay_tick();}/*! * \fn void xnpod_init(xnpod_t *pod, int minpri, int maxpri, xnflags_t flags); * \brief Initialize a new pod. * * Initializes a new pod which can subsequently be used to start * real-time activities. Once a pod is active, real-time APIs can be * stacked over. There can only be a single pod active in the host * environment. Such environment can be confined to a process though * (e.g. MVM or POSIX layers), or expand to the whole system * (e.g. Adeos or RTAI). * * @param pod The address of a pod descriptor Xenomai will use to * store the pod-specific data. This descriptor must always be valid * while the pod is active therefore it must be allocated in permanent * memory. * * @param minpri The value of the lowest priority level which is valid * for threads created on behalf of this pod. * * @param maxpri The value of the highest priority level which is * valid for threads created on behalf of this pod. * * @param flags A set of creation flags affecting the operation. The * only defined flag is XNDREORD (Disable REORDering), which tells the * nanokernel that the (xnsynch_t) pend queue should not be reordered * whenever the priority of a blocked thread it holds is changed. If * this flag is not specified, changing the priority of a blocked * thread using xnpod_renice_thread() will cause the pended queue to * be reordered according to the new priority level, provided the * synchronization object makes the waiters wait by priority order on * the awaited resource (XNSYNCH_PRIO). * * minpri might be numerically higher than maxpri if the upper * real-time interface exhibits a reverse priority scheme. For * instance, some APIs may define a range like minpri=255, maxpri=0 * specifying that thread priorities increase as the priority level * decreases numerically. * * Context: This routine must be called on behalf of a context * allowing immediate memory allocation requests (e.g. an * init_module() routine). */int xnpod_init (xnpod_t *pod, int minpri, int maxpri, xnflags_t flags){ xnsched_t *sched; u_long rem; int rc, n; nkpod = pod; if (minpri > maxpri) /* The lower the value, the higher the priority */ flags |= XNRPRIO; /* Flags must be set before xnpod_get_qdir() is called */ pod->status = (flags & (XNRPRIO|XNDREORD)); initq(&xnmod_glink_queue); initq(&pod->threadq); initq(&pod->tstartq); initq(&pod->tswitchq); initq(&pod->tdeleteq); for (n = 0; n < XNTIMER_WHEELSIZE; n++) initq(&pod->timerwheel[n]); xntimer_init(&pod->htimer,&xnpod_host_tick,NULL); xnarch_atomic_set(&pod->schedlck,0); pod->minpri = minpri; pod->maxpri = maxpri; pod->jiffies = 0; pod->wallclock = 0; pod->tickvalue = XNARCH_DEFAULT_TICK; pod->ticks2sec = xnarch_ulldiv(1000000000LL,XNARCH_DEFAULT_TICK,&rem); pod->svctable.shutdown = &xnpod_shutdown; pod->svctable.settime = &xnpod_set_time; pod->svctable.tickhandler = NULL; pod->svctable.faulthandler = &xnpod_fault_handler; pod->schedhook = NULL; pod->latency = xnarch_ns_to_tsc(XNARCH_SCHED_LATENCY); sched = &pod->sched; initq(&sched->suspendq); initpq(&sched->readyq,xnpod_get_qdir(pod)); sched->inesting = 0; sched->runthread = NULL; /* This fools xnheap_init() */ sched->usrthread = NULL; pod->root_prio_base = xnpod_get_minprio(pod,1); pod->isvc_prio_idle = xnpod_get_minprio(pod,2); if (xnheap_init(&kheap,NULL,XNPOD_HEAPSIZE,XNPOD_PAGESIZE) != XN_OK) return XNERR_NOMEM; /* Create the root thread -- it might be a placeholder for the current context or a real thread, it depends on the real-time layer. */ rc = xnthread_init(&sched->rootcb, "ROOT", XNPOD_ROOT_PRIO_BASE, XNROOT|XNSTARTED#ifdef CONFIG_RTAI_FPU_SUPPORT /* If the host environment has a FPU, the root thread must care for the FPU context. */ |XNFPU#endif /* CONFIG_RTAI_FPU_SUPPORT */ , XNARCH_ROOT_STACKSZ, NULL, 0); if (rc) return rc; sched->runthread = &sched->rootcb; sched->usrthread = &sched->rootcb;#ifdef CONFIG_RTAI_FPU_SUPPORT sched->fpuholder = &sched->rootcb;#endif /* CONFIG_RTAI_FPU_SUPPORT */ appendq(&pod->threadq,&sched->rootcb.glink); xnarch_init_root_tcb(xnthread_archtcb(&sched->rootcb), &sched->rootcb, xnthread_name(&sched->rootcb)); xnarch_notify_ready(); return XN_OK;}/*! * \fn void xnpod_shutdown(int xtype); * \brief Default shutdown handler. * * Forcibly shutdowns the active pod. All existing nanokernel threads * (but the root one) are terminated, and the system heap is freed. * * @param xtype An exit code passed to the host environment who * started the nanokernel. Zero is always interpreted as a successful * return. * * The nanokernel will not call this routine directly but rather use * the routine pointed at by the pod.svctable.shutdown member in the * service table. This allows upper interfaces to interpose their own * shutdown handlers so that they have their word before any action is * taken. Usually, the interface-defined handlers should end up * calling xnpod_shutdown() after their own housekeeping chores have * been carried out. * * Context: This routine must be called on behalf of the root thread * (e.g. a cleanup_module() routine). */void xnpod_shutdown (int xtype){ xnholder_t *holder, *nholder; xnthread_t *thread; spl_t s; if (!nkpod) return; /* No-op */ xnpod_stop_timer(); splhigh(s); nholder = getheadq(&nkpod->threadq); while ((holder = nholder) != NULL) { nholder = nextq(&nkpod->threadq,holder); thread = link2thread(holder,glink); if (!testbits(thread->status,XNROOT)) xnpod_delete_thread(thread,NULL); } splexit(s); xnheap_destroy(&kheap); xntimer_destroy(&nkpod->htimer); nkpod = NULL;}static inline void xnpod_fire_callouts (xnqueue_t *hookq, xnthread_t *thread){ xnholder_t *holder, *nholder; setbits(nkpod->status,XNKCOUT); /* The callee is allowed to alter the hook queue when running */ nholder = getheadq(hookq); while ((holder = nholder) != NULL) { xnhook_t *hook = link2hook(holder); nholder = nextq(hookq,holder); hook->routine(thread); } clrbits(nkpod->status,XNKCOUT);}/*! * \fn void xnpod_preempt_current_thread(void); * \brief Preempts the current thread - INTERNAL. * * Preempts the running thread (because a more prioritary thread has * just been readied). The thread is re-inserted at the front of its * priority group in the ready thread queue. */static inline void xnpod_preempt_current_thread (void){ xnthread_t *thread; xnsched_t *sched; spl_t s; sched = xnpod_current_sched(); thread = sched->runthread; splhigh(s); insertpql(&sched->readyq,&thread->rlink,thread->cprio); setbits(thread->status,XNREADY); setbits(nkpod->status,XNSCHED); splexit(s); if (!nkpod->schedhook) return; if (getheadpq(&sched->readyq) != &thread->rlink) nkpod->schedhook(thread,XNREADY); else if (countpq(&sched->readyq) > 1) { /* The running thread is still heading the ready queue and more than one thread is linked to this queue, so we may refer to the following element as a thread object
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -