Question on TCB without SC in receiveSignal
Hello guys, I got confused on the implementation of receiveSignal in sel4 with MCS. When the notification status is NtfnState_Active, the kernel will try to donate the notification's schedule context to the thread by calling maybeDonateSchedContext. My confusion point is that: If the thread doesn't have a valid schedule context, the thread will not be able to execute, then how can this thread call receiveSignal to receive the signal? void receiveSignal(tcb_t *thread, cap_t cap, bool_t isBlocking) { notification_t *ntfnPtr; ntfnPtr = NTFN_PTR(cap_notification_cap_get_capNtfnPtr(cap)); switch (notification_ptr_get_state(ntfnPtr)) { .... case NtfnState_Active: setRegister( thread, badgeRegister, notification_ptr_get_ntfnMsgIdentifier(ntfnPtr)); notification_ptr_set_state(ntfnPtr, NtfnState_Idle); #ifdef CONFIG_KERNEL_MCS maybeDonateSchedContext(thread, ntfnPtr); // If the SC has been donated to the current thread (in a reply_recv, send_recv scenario) then // we may need to perform refill_unblock_check if the SC is becoming activated. if (thread->tcbSchedContext != NODE_STATE(ksCurSC) && sc_sporadic(thread->tcbSchedContext)) { refill_unblock_check(thread->tcbSchedContext); } #endif break; } }
Hello, On 2023-12-01 03:23, chenpingyuan--- via Devel wrote:
When the notification status is NtfnState_Active, the kernel will try to donate the notification's schedule context to the thread by calling maybeDonateSchedContext. My confusion point is that: If the thread doesn't have a valid schedule context, the thread will not be able to execute, then how can this thread call receiveSignal to receive the signal?
Have a look at maybeReturnSchedContext(), which is called by receiveSignal(). It will remove the scheduling context from the calling thread if it equals the scheduling context bound to the notification. That means that if a passive thread was running on a borrowed SC, it can do the receive call and then block there after returning the borrowed SC. Your next question will be how to make a thread passive. It used to be fairly complicated, but since the merging of commit e18e32e28e0, which allows lazy SC rebinding, it's much easier to create passive tasks: Just bind the thread's SC to the notification it is going to block on and the SC will be returned automatically when the thread blocks, just like when it's running on a borrowed scheduling context. If the notification is bound to the thread's TCB, it can be a passive server and block on both an endpoint as well as the notification at the same time, if a SC is bound to the notification object. When handling a call, the server runs on the caller's SC, when unblocking because of a notification, it runs on the notification's bound SC. Because of this, even if you just want a passive server that doesn't use notifications, the easiest way to make it passive is by giving it a bound notification object which is bound to the thread's SC. Then the passive server will use the notification's SC for startup and be passive otherwise. The notification itself will be unused then. Greetings, Indan
Thanks Indan for you patient and professional answer. I read your reply more than 10 times, ^_^. Still one thing to confirm: Threads which are blocked waiting for notification/endpoint without schedule context will remain in the ready queue, right?
Hello, On 2023-12-04 13:18, chenpingyuan--- via Devel wrote:
Still one thing to confirm: Threads which are blocked waiting for notification/endpoint without schedule context will remain in the ready queue, right?
It does not matter whether the thread returns a scheduling context, when it blocks it is removed from the ready queue, otherwise it wouldn't block. It can't run because it is waiting for something. When it unblocks it will run immediately or go on the ready queue, but it will always have a scheduling context then, either its own, or a donated one. Greetings, Indan
Thanks Indan. I'll try to have some debugging to fullly understand what you said. Thanks a lot.
Hi Indan, I come back again. It confused me that Chapter 6.1.7 Passive Threads of seL4-manual-latest.pdf said: Threads can be unbound from a scheduling context with seL4_SchedContext_UnbindObject().This is distinct from suspending a thread, in that threads that are blocked waiting in an endpoint or notification queue will remain in the queue and can still recieve messages and signals. However, the unbound thread will not be schedulable again until it receives a scheduling context. Threads without scheduling contexts are referred to as passive threads, as they cannot execute without the action of another thread. By saying " threads that are blocked waiting in an endpoint or notification queue will remain in the queue and can still recieve messages and signals.", does it mean that those threads blocked waiting in an endpoint or notification queue will remain in the READY QUEUE? Or maybe the manual was not accurate?
Hello, On 2023-12-05 01:47, chenpingyuan--- via Devel wrote:
By saying " threads that are blocked waiting in an endpoint or notification queue will remain in the queue and can still recieve messages and signals.", does it mean that those threads blocked waiting in an endpoint or notification queue will remain in the READY QUEUE? Or maybe the manual was not accurate?
The manual is accurate, but it does not document the scheduling queues in detail, like the ready queue (called "scheduling queue" in the manual) or the release queue (queue of threads waiting for more budget, not to be confused with "replenishment queue", which each scheduling context has and doesn't queue threads, but budget refills). It does document the end point queue though in chapter 4.2. Notifications also have a queue which isn't clearly described, but it is very similar to end points, as mentioned in 6.1.7. Every end point and notification object have a queue where threads that block on them will be queued on. All threads can only be in one queue at the time, either one of the scheduling ones, or an end point or notification queue. Because of this it is not possible to wait for multiple end points or notifications at the same time. The only exception is waiting for an end point and a bound notification at the same time, as the end point code does extra checking for bound notifications. For details like these you have to read the seL4 source code, though higher levels things can be hard to extract from the source. Maybe you confused me with "ready queue", as that is the name in the source code for the scheduling queue for active threads, but perhaps you meant the EP/NF queues instead. If that's the case, to perhaps answer your actual previous question: Yes, threads which are blocked waiting for notification/endpoint without schedule context will remain in the object's queue. This is possible because when they unblock, they will get a scheduling context, and this is also the only way to unblock them, so they don't need to be queued anywhere else. For end points the caller's SC will be donated, for notifications the bound SC will be used. However, I don't know what happens if a scheduling context disappears because of a call to seL4_SchedContext_Unbind() and there is no SC bound to the NF (any more). I would the expect the behaviour to be the same as when the thread gets suspended, however, seL4_TCB_Suspend() will call cancelIPC(), but that doesn't seem to happen for seL4_SchedContext_Unbind(). Greetings, Indan
Thanks Indan for your detail reply. By ready queue, I did mean the scheduling queue since the code named it as ksReadyQueues. For threads unbound from a SC, this thread will be removed from both ksReadyQueues and ksReleaseHead according the code below: void schedContext_unbindTCB(sched_context_t *sc, tcb_t *tcb) { assert(sc->scTcb == tcb); /* tcb must already be stalled at this point */ if (tcb == NODE_STATE(ksCurThread)) { rescheduleRequired(); } tcbSchedDequeue(sc->scTcb); tcbReleaseRemove(sc->scTcb); sc->scTcb->tcbSchedContext = NULL; sc->scTcb = NULL; } But for threads which are blocked at waiting for a signal/message, according to your reply and the code, my current understanding is that: Those threads which are in ThreadState_BlockedOnNotification(for example) will be in neither ksReadyQueues nor ksReleaseHead, and these threads will be either notification's queue or endpoint's queue which saves the blocked TCBs. Am I right now?
Hello, On 2023-12-05 11:40, chenpingyuan--- via Devel wrote:
Thanks Indan for your detail reply. By ready queue, I did mean the scheduling queue since the code named it as ksReadyQueues.
Oh, good, I wasn't sure any more.
For threads unbound from a SC, this thread will be removed from both ksReadyQueues and ksReleaseHead according the code below: void schedContext_unbindTCB(sched_context_t *sc, tcb_t *tcb)
Yes, schedContext_unbindTCB() does that, but schedContext_unbind() doesn't. It looks like it works okay, in that if a thread with no SC gets unblocked by a signal, it is removed from the notification queue and put in active state, and not actually ran or added to any scheduler queues by accident.
But for threads which are blocked at waiting for a signal/message, according to your reply and the code, my current understanding is that: Those threads which are in ThreadState_BlockedOnNotification(for example) will be in neither ksReadyQueues nor ksReleaseHead, and these threads will be either notification's queue or endpoint's queue which saves the blocked TCBs.
Am I right now?
Yes. Greetings, Indan
participants (2)
-
chenpingyuan@xiaomi.com
-
Indan Zupancic