📄 synch.c
字号:
* This service gives the ownership of a synchronization object to the * thread which is currently leading the object's pending list. The * sleeping thread is unblocked, but no action is taken regarding the * previous owner of the resource. * * This service should be called by upper interfaces wanting to signal * the given resource so that a single waiter is resumed. * * @param synch The descriptor address of the synchronization object * whose ownership is changed. * * @return The descriptor address of the unblocked thread. * * Side-effects: * * - The effective priority of the previous resource owner might be * lowered to its base priority value as a consequence of the priority * inheritance boost being cleared. * * - The synchronization object ownership is transfered to the * unblocked thread. * * - This routine does not call the rescheduling procedure. * * Context: This routine must be called on behalf of a thread or IST * context. */xnthread_t *xnsynch_wakeup_one_sleeper (xnsynch_t *synch){ xnthread_t *thread = NULL, *lastowner = synch->owner; xnpholder_t *holder; spl_t s; splhigh(s); holder = getpq(xnsynch_wait_queue(synch)); if (holder) { thread = link2thread(holder,plink); thread->wchan = NULL; synch->owner = thread; xnpod_resume_thread(thread,XNPEND); } else synch->owner = NULL; if (testbits(synch->status,XNSYNCH_CLAIMED)) xnsynch_clear_boost(synch,lastowner); splexit(s); xnarch_post_graph_if(synch,0,countpq(&synch->pendq) == 0); return thread;}/*! * \fn void xnsynch_wakeup_this_sleeper(xnsynch_t *synch, xnpholder_t *holder); * \brief Give the resource ownership to a given waiting thread. * * This service gives the ownership of a given synchronization object * to a specific thread which is currently pending on it. The sleeping * thread is unblocked from its pending state. No action is taken * regarding the previous resource owner. * * This service should be called by upper interfaces wanting to signal * the given resource so that a specific waiter is resumed. * * @param synch The descriptor address of the synchronization object * whose ownership is changed. * * @param holder The link holder address of the thread to unblock * (&thread->plink) which MUST currently be linked to the * synchronization object's pending queue (i.e. synch->pendq). * * @return The link address of the unblocked thread in the * synchronization object's pending queue. * * Side-effects: * * - The effective priority of the previous resource owner might be * lowered to its base priority value as a consequence of the priority * inheritance boost being cleared. * * - The synchronization object ownership is transfered to the * unblocked thread. * * - This routine does not call the rescheduling procedure. * * Context: This routine must be called on behalf of a thread or IST * context. */xnpholder_t *xnsynch_wakeup_this_sleeper (xnsynch_t *synch, xnpholder_t *holder){ xnthread_t *thread, *lastowner = synch->owner; xnpholder_t *nholder; spl_t s; splhigh(s); nholder = poppq(xnsynch_wait_queue(synch),holder); thread = link2thread(holder,plink); thread->wchan = NULL; synch->owner = thread; xnpod_resume_thread(thread,XNPEND); if (testbits(synch->status,XNSYNCH_CLAIMED)) xnsynch_clear_boost(synch,lastowner); splexit(s); xnarch_post_graph_if(synch,0,countpq(&synch->pendq) == 0); return nholder;}/*! * \fn void xnsynch_flush(xnsynch_t *synch, xnflags_t reason); * \brief Unblock all waiters pending on a resource. * * This service atomically releases all threads which currently sleep * on a given resource. * * This service should be called by upper interfaces under * circumstances requiring that the pending queue of a given resource * is cleared, such as before the resource is deleted. * * @param synch The descriptor address of the synchronization object * whose ownership is changed. * * @param reason Some flags to set in the status mask of every * unblocked thread. The following bits are pre-defined by the * nanokernel: * * - XNRMID should be set to indicate that the synchronization object * is about to be destroyed (see xnpod_resume_thread()). * * - XNBREAK should be set to indicate that the wait has been forcibly * interrupted (see xnpod_unblock_thread()). * * @return XNSYNCH_RESCHED is returned if at least one thread * is unblocked, which means the caller should invoke xnpod_schedule() * for applying the new scheduling state. Otherwise, XNSYNCH_DONE is * returned. * * Side-effects: * * - The effective priority of the previous resource owner might be * lowered to its base priority value as a consequence of the priority * inheritance boost being cleared. * * - The synchronization object is no more owned by any thread. * * - This routine does not call the rescheduling procedure. * * Context: This routine must be called on behalf of a thread or IST * context. */int xnsynch_flush (xnsynch_t *synch, xnflags_t reason){ xnpholder_t *holder; int status; spl_t s; splhigh(s); status = countpq(&synch->pendq) > 0 ? XNSYNCH_RESCHED : XNSYNCH_DONE; while ((holder = getpq(&synch->pendq)) != NULL) { xnthread_t *sleeper = link2thread(holder,plink); setbits(sleeper->status,reason); sleeper->wchan = NULL; xnpod_resume_thread(sleeper,XNPEND); } if (testbits(synch->status,XNSYNCH_CLAIMED)) { xnsynch_clear_boost(synch,synch->owner); status = XNSYNCH_RESCHED; } synch->owner = NULL; splexit(s); xnarch_post_graph_if(synch,0,countpq(&synch->pendq) == 0); return status;}/*! * \fn void xnsynch_forget_sleeper(xnthread_t *thread); * \brief Abort a wait for a resource - INTERNAL. * * Performs all the necessary housekeeping chores to stop a thread * from waiting on a given synchronization object. * * @param thread The descriptor address of the affected thread. * * When the trace support is enabled (i.e. MVM), the idle state is * posted to the synchronization object's state diagram (if any) * whenever no thread remains blocked on it. The real-time interfaces * must ensure that such condition (i.e. EMPTY/IDLE) is mapped to * state #0. */void xnsynch_forget_sleeper (xnthread_t *thread) /* INTERNAL */{ xnsynch_t *synch = thread->wchan; clrbits(thread->status,XNPEND); thread->wchan = NULL; removepq(&synch->pendq,&thread->plink); if (testbits(synch->status,XNSYNCH_CLAIMED)) { /* Find the highest priority needed to enforce the PIP. */ xnthread_t *owner = synch->owner; int rprio; if (countpq(&synch->pendq) == 0) /* No more sleepers: clear the boost. */ xnsynch_clear_boost(synch,owner); else if (getheadpq(&synch->pendq)->prio != getheadpq(&owner->claimq)->prio) { /* Reorder the claim queue, and lower the priority to the required minimum needed to prevent priority inversion. */ removepq(&owner->claimq,&synch->link); insertpqf(&owner->claimq, &synch->link, getheadpq(&synch->pendq)->prio); rprio = getheadpq(&owner->claimq)->prio; if (xnpod_priocompare(rprio,owner->cprio) < 0) xnsynch_renice_thread(owner,rprio); } } xnarch_post_graph_if(synch,0,countpq(&synch->pendq) == 0);}/*! * \fn void xnsynch_release_all_ownerships(xnthread_t *thread); * \brief Release all ownerships - INTERNAL. * * This call is used internally to release all the ownerships obtained * by a thread on synchronization objects. This routine must be * entered interrupts off. * * @param thread The descriptor address of the affected thread. */void xnsynch_release_all_ownerships (xnthread_t *thread) /* INTERNAL */{ xnpholder_t *holder, *nholder; xnsynch_t *synch; holder = getheadpq(&thread->claimq); while ((synch = link2synch(holder)) != NULL) { /* Since xnsynch_wakeup_one_sleeper() alters the claim queue, we need to be conservative while skulking it. */ nholder = nextpq(&thread->claimq,holder); if (!testbits(synch->status,XNSYNCH_KMUTEX)) xnsynch_wakeup_one_sleeper(synch); holder = nholder; }}/*@}*/EXPORT_SYMBOL(xnsynch_flush);EXPORT_SYMBOL(xnsynch_forget_sleeper);EXPORT_SYMBOL(xnsynch_init);EXPORT_SYMBOL(xnsynch_release_all_ownerships);EXPORT_SYMBOL(xnsynch_renice_sleeper);EXPORT_SYMBOL(xnsynch_sleep_on);EXPORT_SYMBOL(xnsynch_wakeup_one_sleeper);EXPORT_SYMBOL(xnsynch_wakeup_this_sleeper);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -