📄 pod.c
字号:
* * Context: This routine must be called on behalf of a thread context. */void xnpod_delete_thread (xnthread_t *thread, xnmutex_t *imutex){ xnsched_t *sched; spl_t s; if (testbits(thread->status,XNROOT)) xnpod_fatal("attempt to delete the root thread"); if (nkpod->schedhook) nkpod->schedhook(thread,XNDELETED); sched = thread->sched; splhigh(s); removeq(&nkpod->threadq,&thread->glink); if (!testbits(thread->status,XNTHREAD_BLOCK_BITS)) { if (testbits(thread->status,XNREADY)) { removepq(&sched->readyq,&thread->rlink); clrbits(thread->status,XNREADY); } } else { if (testbits(thread->status,XNDELAY)) xntimer_stop(&thread->timer); if (testbits(thread->status,XNTHREAD_BLOCK_BITS & ~XNDELAY)) removeq(&sched->suspendq,&thread->slink); } xntimer_stop(&thread->atimer); /* Ensure the rescheduling can take place if the deleted thread is the running one. */ if (testbits(thread->status,XNLOCK)) { clrbits(thread->status,XNLOCK); xnarch_atomic_set(&nkpod->schedlck,0); } if (testbits(thread->status,XNPEND)) xnsynch_forget_sleeper(thread); xnsynch_release_all_ownerships(thread);#ifdef CONFIG_RTAI_FPU_SUPPORT if (thread == sched->fpuholder) sched->fpuholder = NULL;#endif /* CONFIG_RTAI_FPU_SUPPORT */ setbits(thread->status,XNZOMBIE); if (sched->runthread == thread) { /* We first need to elect a new runthread before switching out the current one forever. Use the thread zombie state to go through the rescheduling procedure then actually destroy the thread object. */ setbits(nkpod->status,XNSCHED); /* The interface mutex will be cleared by the rescheduling proc. */ xnpod_schedule(imutex); } else { if (countq(&nkpod->tdeleteq) > 0 && !testbits(thread->status,XNTHREAD_SYSTEM_BITS)) xnpod_fire_callouts(&nkpod->tdeleteq,thread); /* Note: the thread control block must remain available until the user hooks have been called. FIXME: Catch 22 here, whether we choose to run on an invalid stack (cleanup then hooks), or to access the TCB space shortly after it has been freed while non-preemptible (hooks then cleanup)... Option #2 is current. */ xnthread_cleanup_tcb(thread); xnarch_finalize_no_switch(xnthread_archtcb(thread)); } splexit(s);}/*! * \fn int xnpod_suspend_thread(xnthread_t *thread, xnflags_t mask, xnticks_t timeout, xnsynch_t *wchan, xnmutex_t *imutex); * \brief Suspend a thread. * * Suspends the execution of a thread according to a given suspensive * condition. This thread will not be eligible for scheduling until it * all the pending suspensive conditions set by this service are * removed by one or more calls to xnpod_resume_thread(). * * @param thread The descriptor address of the suspended thread. * * @param mask The suspension mask specifying the suspensive condition * to add to the thread's wait mask. Possible values usable by the * caller are: * * - XNSUSP. This flag forcibly suspends a thread, regardless of any * resource to wait for. The wchan parameter should not be significant * when using this suspension condition. A reverse call to * xnpod_resume_thread() specifying the XNSUSP bit must be issued to * remove this condition, which is cumulative with other suspension * bits. * * - XNDELAY. This flags denotes a counted delay wait (in ticks) which * duration is defined by the value of the timeout parameter. * * - XNPEND. This flag denotes a wait for a synchronization object to * be signaled. The wchan argument must points to this object. A * timeout value can be passed to bound the wait. This suspension mode * should not be used directly by the upper interface, but rather * through the xnsynch_sleep_on() call. * * @param timeout The timeout which may be used to limit the time the * thread pends for a resource. This value is a wait time given in * ticks. Passing XN_INFINITE specifies an unbounded wait. All other * values are used to initialize a watchdog timer. * * @param wchan The address of a pended resource. This parameter is * used internally by the synchronization object implementation code * to specify on which object the suspended thread pends. * * @param imutex The address of an interface mutex currently held by * the caller which will be subject to a lock-breaking preemption * before the current thread is actually switched out. The * corresponding kernel mutex will be automatically reacquired by the * nanokernel when the suspended thread is eventually resumed, before * xnpod_suspend_thread() returns to its caller. This parameter only * makes sense for self-suspending threads. Passing NULL when no * lock-breaking preemption is required is valid. See xnpod_schedule() * for more on lock-breaking preemption points. * * @return Returns true if a thread switch took place as a * result of this call, false otherwise. * * Side-effect: A rescheduling immediately occurs if the caller * self-suspends, in which case true is always returned. * * Context: This routine can be called on behalf of a thread or IST * context. */int xnpod_suspend_thread (xnthread_t *thread, xnflags_t mask, xnticks_t timeout, xnsynch_t *wchan, xnmutex_t *imutex){ xnsched_t *sched; spl_t s; /* This routine must be free both from interrupt preemption AND mutex ops. */ if (testbits(thread->status,XNSTARTED) && testbits(thread->status,XNROOT|XNISVC)) xnpod_fatal("attempt to suspend system thread %s (from %s)", thread->name, xnpod_current_thread()->name); if (thread->wchan && wchan) xnpod_fatal("invalid conjunctive wait on multiple synch. objects"); splhigh(s); sched = thread->sched; if (thread == sched->runthread) { if (xnpod_locked_p()) xnpod_fatal("suspensive call issued while the scheduler was locked"); setbits(nkpod->status,XNSCHED); } /* We must make sure that we don't clear the wait channel if a thread is first blocked (wchan != NULL) then forcibly suspended (wchan == NULL), since these are conjunctive conditions. */ if (wchan) thread->wchan = wchan; /* Is the thread ready to run? */ if (!testbits(thread->status,XNTHREAD_BLOCK_BITS)) { /* A newly created thread is not linked to the ready thread queue yet. */ if (testbits(thread->status,XNREADY)) { removepq(&sched->readyq,&thread->rlink); clrbits(thread->status,XNREADY); } if ((mask & ~XNDELAY) != 0) /* If the thread is forcibly suspended outside the simple delay condition, link it to suspension queue. */ appendq(&sched->suspendq,&thread->slink); clrbits(thread->status,XNRMID|XNTIMEO|XNBREAK); } else if ((mask & ~XNDELAY) != 0 && !testbits(thread->status,XNTHREAD_BLOCK_BITS & ~XNDELAY)) /* If the thread is forcibly suspended while undergoing a simple delay condition, link it to suspension queue too. */ appendq(&sched->suspendq,&thread->slink); setbits(thread->status,mask); if (timeout != XN_INFINITE) { /* Don't start the timer for a thread indefinitely delayed by a call to xnpod_suspend_thread(thread,XNDELAY,0,NULL). */ setbits(thread->status,XNDELAY); xntimer_start(&thread->timer,timeout,XN_INFINITE); } if (nkpod->schedhook) nkpod->schedhook(thread,mask); if (thread == sched->runthread) xnpod_schedule(imutex); splexit(s); return (thread == sched->runthread);}/*! * \fn void xnpod_resume_thread(xnthread_t *thread, xnflags_t mask); * \brief Resume a thread. * * Resumes the execution of a thread previously suspended by one or * more calls to xnpod_suspend_thread(). This call removes a * suspensive condition affecting the target thread. When all * suspensive conditions are gone, the thread is left in a READY state * at which point it becomes eligible anew for scheduling. * * @param thread The descriptor address of the resumed thread. * * @param mask The suspension mask specifying the suspensive condition * to remove from the thread's wait mask. Possible values usable by * the caller are: * * - XNSUSP. This flag removes the explicit suspension condition. This * condition might be additive to the XNPEND condition. * * - XNDELAY. This flag removes the counted delay wait condition. * * - XNPEND. This flag removes the resource wait condition. If a * watchdog is armed, it is automatically disarmed by this call. * * When the thread is eventually resumed by one or more calls to * xnpod_resume_thread(), the caller of xnpod_suspend_thread() in the * awakened thread that suspended itself should check for the * following bits in its own status mask to determine what caused its * wake up: * * - XNRMID means that the caller must assume that the pended * synchronization object has been destroyed (see xnsynch_flush()). * * - XNTIMEO means that the delay elapsed, or the watchdog went off * before the corresponding synchronization object was signaled. * * - XNBREAK means that the wait has been forcibly broken by a call to * xnpod_unblock_thread(). * * Side-effect: This service does not call the rescheduling procedure * but may affect the ready queue. * * Context: This routine can be called on behalf of a thread or IST * context. */void xnpod_resume_thread (xnthread_t *thread, xnflags_t mask){ xnsched_t *sched; spl_t s; sched = thread->sched; splhigh(s); if (testbits(thread->status,XNTHREAD_BLOCK_BITS)) /* Is thread blocked? */ { clrbits(thread->status,mask); /* Remove suspensive condition(s) */ if (testbits(thread->status,XNTHREAD_BLOCK_BITS)) /* still blocked? */ { if ((mask & XNDELAY) != 0) { /* Watchdog fired or break requested -- stop waiting for the resource. */ xntimer_stop(&thread->timer); mask = testbits(thread->status,XNPEND); if (mask) { if (thread->wchan) xnsynch_forget_sleeper(thread); if (testbits(thread->status,XNTHREAD_BLOCK_BITS)) /* Still blocked? */ { splexit(s); return; } } else { /* The thread is still suspended (XNSUSP) */ splexit(s); return; } } else if (testbits(thread->status,XNDELAY)) { if ((mask & XNPEND) != 0) { /* The thread is woken up due to the availability of the requested resource. Cancel the watchdog timer. */ xntimer_stop(&thread->timer); clrbits(thread->status,XNDELAY); } if (testbits(thread->status,XNTHREAD_BLOCK_BITS)) /* Still blocked? */ { splexit(s); return; } } else { /* The thread is still suspended, but is no more pending on a resource. */ if ((mask & XNPEND) != 0 && thread->wchan) xnsynch_forget_sleeper(thread); splexit(s); return; } } else if ((mask & XNDELAY) != 0) /* The delayed thread is woken up before the delay elapsed. */ xntimer_stop(&thread->timer); if ((mask & ~XNDELAY) != 0) { /* If the thread was actually suspended, remove it from the suspension queue -- this allows requests like xnpod_suspend_thread(...,thread,XNDELAY,0,...) not to run the following code when the suspended thread is woken up while undergoing an infinite delay. */ removeq(&sched->suspendq,&thread->slink); if (thread->wchan) xnsynch_forget_sleeper(thread); } } else if (testbits(thread->status,XNREADY)) { removepq(&sched->readyq,&thread->rlink); clrbits(thread->status,XNREADY); } /* The readied thread is always put at the end of its priority group. */ insertpqf(&sched->readyq,&thread->rlink,thread->cprio); if (thread == sched->runthread) { setbits(thread->status,XNREADY); splexit(s); if (nkpod->schedhook && getheadpq(&sched->readyq) != &thread->rlink) /* The running thread does not lead no more the ready queue. */ nkpod->schedhook(thread,XNREADY); } else if (!testbits(thread->status,XNREADY)) { setbits(thread->status,XNREADY); splexit(s); if (nkpod->schedhook) nkpod->schedhook(thread,XNREADY); } else splexit(s); setbits(nkpod->status,XNSCHED);}/*! * \fn void xnpod_unblock_thread(xnthread_t *thread); * \brief Unblock a thread. * * Breaks the thread out of any wait it is currently in. This call * removes the XNDELAY and XNPEND suspensive conditions previously put * by xnpod_suspend_thread() on the target thread. If all suspensive * conditions are gone, the thread is left in a READY state at which
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -