mcs: handle endpoint and ntfn queues uniformly
- Introduce functions to append and dequeue to/from endpoint and notification queues, in order to make verification feasible. Handle linked list manipulations with the same functions that were previously used for the ready and release queues, together with a new function that allows for a new item to be inserted into the queue after another item that is already in the queue. - Remove tcbEPNext and tcbEPPrev pointers from the MCS version, and instead use tcbSchedNext and tcbSchedPrev pointers, given that no thread can be simultaneously in any two of the endpoint, notification, ready, or release queues. Signed-off-by: Michael McInerney <michael.mcinerney@proofcraft.systems>
This commit is contained in:
parent
1ff6c16e6f
commit
771c9e43ce
8 changed files with 245 additions and 81 deletions
|
|
@ -30,6 +30,8 @@ void sendIPC(bool_t blocking, bool_t do_call, word_t badge,
|
|||
bool_t canGrant, bool_t canGrantReply, bool_t canDonate, tcb_t *thread,
|
||||
endpoint_t *epptr);
|
||||
void receiveIPC(tcb_t *thread, cap_t cap, bool_t isBlocking, cap_t replyCPtr);
|
||||
void tcbEPAppend(tcb_t *thread, endpoint_t *epptr, bool_t isRecv);
|
||||
void tcbEPDequeue(tcb_t *thread, endpoint_t *epptr);
|
||||
void reorderEP(endpoint_t *epptr, tcb_t *thread);
|
||||
#else
|
||||
void sendIPC(bool_t blocking, bool_t do_call, word_t badge,
|
||||
|
|
|
|||
|
|
@ -18,6 +18,8 @@ void unbindMaybeNotification(notification_t *ntfnPtr);
|
|||
void unbindNotification(tcb_t *tcb);
|
||||
void bindNotification(tcb_t *tcb, notification_t *ntfnPtr);
|
||||
#ifdef CONFIG_KERNEL_MCS
|
||||
void tcbNTFNAppend(tcb_t *thread, notification_t *ntfnPtr);
|
||||
void tcbNTFNDequeue(tcb_t *thread, notification_t *ntfnPtr);
|
||||
void reorderNTFN(notification_t *notification, tcb_t *thread);
|
||||
|
||||
static inline void maybeReturnSchedContext(notification_t *ntfnPtr, tcb_t *tcb)
|
||||
|
|
|
|||
|
|
@ -290,12 +290,17 @@ struct tcb {
|
|||
word_t tcbAffinity;
|
||||
#endif /* ENABLE_SMP_SUPPORT */
|
||||
|
||||
/* Previous and next pointers for scheduler queues , 2 words */
|
||||
/* Previous and next pointers for scheduler queues, 2 words
|
||||
* also used for endpoint and notification queues in MCS */
|
||||
struct tcb *tcbSchedNext;
|
||||
struct tcb *tcbSchedPrev;
|
||||
/* Previous and next pointers for endpoint and notification queues, 2 words */
|
||||
|
||||
#ifndef CONFIG_KERNEL_MCS
|
||||
/* Previous and next pointers for endpoint and notification queues, 2 words
|
||||
* only for non-MCS configurations */
|
||||
struct tcb *tcbEPNext;
|
||||
struct tcb *tcbEPPrev;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_BENCHMARK_TRACK_UTILISATION
|
||||
/* 16 bytes (12 bytes aarch32) */
|
||||
|
|
@ -304,6 +309,12 @@ struct tcb {
|
|||
};
|
||||
typedef struct tcb tcb_t;
|
||||
|
||||
/* To enable more uniform code shape between MCS and non-MCS configurations: */
|
||||
#ifdef CONFIG_KERNEL_MCS
|
||||
#define tcbEPNext tcbSchedNext
|
||||
#define tcbEPPrev tcbSchedPrev
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_DEBUG_BUILD
|
||||
/* This debug_tcb object is inserted into the 'unused' region of a TCB object
|
||||
for debug build configurations. */
|
||||
|
|
|
|||
|
|
@ -128,42 +128,62 @@ void remoteTCBStall(tcb_t *tcb);
|
|||
#define SCHED_APPEND_CURRENT_TCB tcbSchedAppend(NODE_STATE(ksCurThread))
|
||||
|
||||
#ifdef CONFIG_KERNEL_MCS
|
||||
/* Add TCB into the priority ordered endpoint queue */
|
||||
static inline tcb_queue_t tcbEPAppend(tcb_t *tcb, tcb_queue_t queue)
|
||||
|
||||
static inline bool_t PURE higher_than_tcb_prio(tcb_t *tcb, prio_t priority)
|
||||
{
|
||||
/* start at the back of the queue as FIFO is the common case */
|
||||
tcb_t *before = queue.end;
|
||||
tcb_t *after = NULL;
|
||||
|
||||
/* find a place to put the tcb */
|
||||
while (unlikely(before != NULL && tcb->tcbPriority > before->tcbPriority)) {
|
||||
after = before;
|
||||
before = after->tcbEPPrev;
|
||||
}
|
||||
|
||||
if (unlikely(before == NULL)) {
|
||||
/* insert at head */
|
||||
queue.head = tcb;
|
||||
} else {
|
||||
before->tcbEPNext = tcb;
|
||||
}
|
||||
|
||||
if (likely(after == NULL)) {
|
||||
/* insert at tail */
|
||||
queue.end = tcb;
|
||||
} else {
|
||||
after->tcbEPPrev = tcb;
|
||||
}
|
||||
|
||||
tcb->tcbEPNext = after;
|
||||
tcb->tcbEPPrev = before;
|
||||
|
||||
return queue;
|
||||
return tcb != NULL && priority > tcb->tcbPriority;
|
||||
}
|
||||
|
||||
tcb_queue_t tcbEPDequeue(tcb_t *tcb, tcb_queue_t queue);
|
||||
/* Find the rightmost TCB in the given queue that has a priority which is
|
||||
strictly greater than the given priority */
|
||||
static tcb_t *find_tcb_with_higher_prio(tcb_queue_t queue, prio_t priority)
|
||||
{
|
||||
tcb_t *tcb = queue.end;
|
||||
|
||||
while (higher_than_tcb_prio(tcb, priority)) {
|
||||
tcb = tcb->tcbSchedPrev;
|
||||
}
|
||||
|
||||
return tcb;
|
||||
}
|
||||
|
||||
/* Insert a TCB into a queue immediately after another item in the queue
|
||||
(the queue must initially contain at least two items) */
|
||||
static inline void tcb_queue_insert_after(tcb_t *tcb, tcb_t *before)
|
||||
{
|
||||
tcb_t *after;
|
||||
after = before->tcbSchedNext;
|
||||
|
||||
tcb->tcbSchedPrev = before;
|
||||
tcb->tcbSchedNext = after;
|
||||
|
||||
after->tcbSchedPrev = tcb;
|
||||
before->tcbSchedNext = tcb;
|
||||
}
|
||||
|
||||
/* Add TCB into the priority ordered endpoint or notification queue */
|
||||
static inline tcb_queue_t tcbAppend(tcb_t *tcb, tcb_queue_t queue)
|
||||
{
|
||||
prio_t priority = tcb->tcbPriority;
|
||||
tcb_queue_t new_queue = queue;
|
||||
|
||||
if (tcb_queue_empty(queue) || priority > queue.head->tcbPriority) {
|
||||
new_queue = tcb_queue_prepend(queue, tcb);
|
||||
} else {
|
||||
if (queue.end->tcbPriority >= priority) {
|
||||
new_queue = tcb_queue_append(queue, tcb);
|
||||
} else {
|
||||
tcb_t *before;
|
||||
before = find_tcb_with_higher_prio(queue, priority);
|
||||
tcb_queue_insert_after(tcb, before);
|
||||
}
|
||||
}
|
||||
|
||||
return new_queue;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
tcb_queue_t tcbEPAppend(tcb_t *tcb, tcb_queue_t queue);
|
||||
tcb_queue_t tcbEPDequeue(tcb_t *tcb, tcb_queue_t queue);
|
||||
|
||||
|
|
|
|||
|
|
@ -465,7 +465,7 @@ void NORETURN fastpath_reply_recv(word_t cptr, word_t msgInfo)
|
|||
} else {
|
||||
#ifdef CONFIG_KERNEL_MCS
|
||||
/* Update queue. */
|
||||
tcb_queue_t queue = tcbEPAppend(NODE_STATE(ksCurThread), ep_ptr_get_queue(ep_ptr));
|
||||
tcb_queue_t queue = tcbAppend(NODE_STATE(ksCurThread), ep_ptr_get_queue(ep_ptr));
|
||||
endpoint_ptr_set_epQueue_head_np(ep_ptr, TCB_REF(queue.head));
|
||||
endpoint_ptr_mset_epQueue_tail_state(ep_ptr, TCB_REF(queue.end), EPState_Recv);
|
||||
#else
|
||||
|
|
|
|||
|
|
@ -28,7 +28,6 @@ void sendIPC(bool_t blocking, bool_t do_call, word_t badge,
|
|||
case EPState_Idle:
|
||||
case EPState_Send:
|
||||
if (blocking) {
|
||||
tcb_queue_t queue;
|
||||
|
||||
/* Set thread state to BlockedOnSend */
|
||||
thread_state_ptr_set_tsType(&thread->tcbState,
|
||||
|
|
@ -47,10 +46,16 @@ void sendIPC(bool_t blocking, bool_t do_call, word_t badge,
|
|||
scheduleTCB(thread);
|
||||
|
||||
/* Place calling thread in endpoint queue */
|
||||
#ifdef CONFIG_KERNEL_MCS
|
||||
tcbEPAppend(thread, epptr, EPState_Send);
|
||||
#else
|
||||
tcb_queue_t queue;
|
||||
queue = ep_ptr_get_queue(epptr);
|
||||
queue = tcbEPAppend(thread, queue);
|
||||
endpoint_ptr_set_state(epptr, EPState_Send);
|
||||
ep_ptr_set_queue(epptr, queue);
|
||||
#endif /* CONFIG_KERNEL_MCS */
|
||||
|
||||
}
|
||||
break;
|
||||
|
||||
|
|
@ -66,12 +71,16 @@ void sendIPC(bool_t blocking, bool_t do_call, word_t badge,
|
|||
assert(dest);
|
||||
|
||||
/* Dequeue the first TCB */
|
||||
#ifdef CONFIG_KERNEL_MCS
|
||||
tcbEPDequeue(dest, epptr);
|
||||
#else
|
||||
queue = tcbEPDequeue(dest, queue);
|
||||
ep_ptr_set_queue(epptr, queue);
|
||||
|
||||
if (!queue.head) {
|
||||
endpoint_ptr_set_state(epptr, EPState_Idle);
|
||||
}
|
||||
#endif /* CONFIG_KERNEL_MCS */
|
||||
|
||||
/* Do the transfer */
|
||||
doIPCTransfer(thread, epptr, badge, canGrant, dest);
|
||||
|
|
@ -165,7 +174,6 @@ void receiveIPC(tcb_t *thread, cap_t cap, bool_t isBlocking)
|
|||
switch (endpoint_ptr_get_state(epptr)) {
|
||||
case EPState_Idle:
|
||||
case EPState_Recv: {
|
||||
tcb_queue_t queue;
|
||||
|
||||
if (isBlocking) {
|
||||
/* Set thread state to BlockedOnReceive */
|
||||
|
|
@ -187,10 +195,15 @@ void receiveIPC(tcb_t *thread, cap_t cap, bool_t isBlocking)
|
|||
#endif
|
||||
|
||||
/* Place calling thread in endpoint queue */
|
||||
#ifdef CONFIG_KERNEL_MCS
|
||||
tcbEPAppend(thread, epptr, EPState_Recv);
|
||||
#else
|
||||
tcb_queue_t queue;
|
||||
queue = ep_ptr_get_queue(epptr);
|
||||
queue = tcbEPAppend(thread, queue);
|
||||
endpoint_ptr_set_state(epptr, EPState_Recv);
|
||||
ep_ptr_set_queue(epptr, queue);
|
||||
#endif /* CONFIG_KERNEL_MCS */
|
||||
} else {
|
||||
doNBRecvFailedTransfer(thread);
|
||||
}
|
||||
|
|
@ -213,12 +226,16 @@ void receiveIPC(tcb_t *thread, cap_t cap, bool_t isBlocking)
|
|||
assert(sender);
|
||||
|
||||
/* Dequeue the first TCB */
|
||||
#ifdef CONFIG_KERNEL_MCS
|
||||
tcbEPDequeue(sender, epptr);
|
||||
#else
|
||||
queue = tcbEPDequeue(sender, queue);
|
||||
ep_ptr_set_queue(epptr, queue);
|
||||
|
||||
if (!queue.head) {
|
||||
endpoint_ptr_set_state(epptr, EPState_Idle);
|
||||
}
|
||||
#endif /* CONFIG_KERNEL_MCS */
|
||||
|
||||
/* Get sender IPC details */
|
||||
badge = thread_state_ptr_get_blockingIPCBadge(&sender->tcbState);
|
||||
|
|
@ -321,7 +338,6 @@ void cancelIPC(tcb_t *tptr)
|
|||
case ThreadState_BlockedOnReceive: {
|
||||
/* blockedIPCCancel state */
|
||||
endpoint_t *epptr;
|
||||
tcb_queue_t queue;
|
||||
|
||||
epptr = EP_PTR(thread_state_ptr_get_blockingObject(state));
|
||||
|
||||
|
|
@ -329,6 +345,10 @@ void cancelIPC(tcb_t *tptr)
|
|||
assert(endpoint_ptr_get_state(epptr) != EPState_Idle);
|
||||
|
||||
/* Dequeue TCB */
|
||||
#ifdef CONFIG_KERNEL_MCS
|
||||
tcbEPDequeue(tptr, epptr);
|
||||
#else
|
||||
tcb_queue_t queue;
|
||||
queue = ep_ptr_get_queue(epptr);
|
||||
queue = tcbEPDequeue(tptr, queue);
|
||||
ep_ptr_set_queue(epptr, queue);
|
||||
|
|
@ -336,6 +356,7 @@ void cancelIPC(tcb_t *tptr)
|
|||
if (!queue.head) {
|
||||
endpoint_ptr_set_state(epptr, EPState_Idle);
|
||||
}
|
||||
#endif /* CONFIG_KERNEL_MCS */
|
||||
|
||||
#ifdef CONFIG_KERNEL_MCS
|
||||
if (thread_state_ptr_get_tsType(state) == ThreadState_BlockedOnReceive) {
|
||||
|
|
@ -399,6 +420,18 @@ static inline void restart_thread_if_no_fault(tcb_t *thread)
|
|||
setThreadState(thread, ThreadState_Inactive);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void removeAndRestartEPQueuedThread(tcb_t *thread, endpoint_t *epptr)
|
||||
{
|
||||
tcbEPDequeue(thread, epptr);
|
||||
if (thread_state_get_tsType(thread->tcbState) == ThreadState_BlockedOnReceive) {
|
||||
reply_t *reply = REPLY_PTR(thread_state_get_replyObject(thread->tcbState));
|
||||
if (reply != NULL) {
|
||||
reply_unlink(reply, thread);
|
||||
}
|
||||
}
|
||||
restart_thread_if_no_fault(thread);
|
||||
}
|
||||
#endif
|
||||
|
||||
void cancelAllIPC(endpoint_t *epptr)
|
||||
|
|
@ -408,6 +441,18 @@ void cancelAllIPC(endpoint_t *epptr)
|
|||
break;
|
||||
|
||||
default: {
|
||||
/* Clear the queue and set all blocked threads to restart */
|
||||
#ifdef CONFIG_KERNEL_MCS
|
||||
tcb_queue_t queue;
|
||||
tcb_t *thread, *next;
|
||||
|
||||
queue = ep_ptr_get_queue(epptr);
|
||||
|
||||
for (thread = queue.head; thread; thread = next) {
|
||||
next = thread->tcbSchedNext;
|
||||
removeAndRestartEPQueuedThread(thread, epptr);
|
||||
}
|
||||
#else
|
||||
tcb_t *thread = TCB_PTR(endpoint_ptr_get_epQueue_head(epptr));
|
||||
|
||||
/* Make endpoint idle */
|
||||
|
|
@ -415,21 +460,11 @@ void cancelAllIPC(endpoint_t *epptr)
|
|||
endpoint_ptr_set_epQueue_head(epptr, 0);
|
||||
endpoint_ptr_set_epQueue_tail(epptr, 0);
|
||||
|
||||
/* Set all blocked threads to restart */
|
||||
for (; thread; thread = thread->tcbEPNext) {
|
||||
#ifdef CONFIG_KERNEL_MCS
|
||||
if (thread_state_get_tsType(thread->tcbState) == ThreadState_BlockedOnReceive) {
|
||||
reply_t *reply = REPLY_PTR(thread_state_get_replyObject(thread->tcbState));
|
||||
if (reply != NULL) {
|
||||
reply_unlink(reply, thread);
|
||||
}
|
||||
}
|
||||
restart_thread_if_no_fault(thread);
|
||||
#else
|
||||
setThreadState(thread, ThreadState_Restart);
|
||||
SCHED_ENQUEUE(thread);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
rescheduleRequired();
|
||||
break;
|
||||
|
|
@ -437,6 +472,20 @@ void cancelAllIPC(endpoint_t *epptr)
|
|||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIG_KERNEL_MCS
|
||||
static inline void removeAndRestartBadgedThread(tcb_t *thread, endpoint_t *epptr, word_t badge)
|
||||
{
|
||||
word_t b = thread_state_ptr_get_blockingIPCBadge(&thread->tcbState);
|
||||
|
||||
/* senders do not have reply objects in their state, and we are only cancelling sends */
|
||||
assert(thread_state_get_tsType(thread->tcbState) == ThreadState_BlockedOnSend);
|
||||
if (b == badge) {
|
||||
tcbEPDequeue(thread, epptr);
|
||||
restart_thread_if_no_fault(thread);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void cancelBadgedSends(endpoint_t *epptr, word_t badge)
|
||||
{
|
||||
switch (endpoint_ptr_get_state(epptr)) {
|
||||
|
|
@ -448,6 +497,12 @@ void cancelBadgedSends(endpoint_t *epptr, word_t badge)
|
|||
tcb_t *thread, *next;
|
||||
tcb_queue_t queue = ep_ptr_get_queue(epptr);
|
||||
|
||||
#ifdef CONFIG_KERNEL_MCS
|
||||
for (thread = queue.head; thread; thread = next) {
|
||||
next = thread->tcbSchedNext;
|
||||
removeAndRestartBadgedThread(thread, epptr, badge);
|
||||
}
|
||||
#else
|
||||
/* this is a de-optimisation for verification
|
||||
* reasons. it allows the contents of the endpoint
|
||||
* queue to be ignored during the for loop. */
|
||||
|
|
@ -459,27 +514,20 @@ void cancelBadgedSends(endpoint_t *epptr, word_t badge)
|
|||
word_t b = thread_state_ptr_get_blockingIPCBadge(
|
||||
&thread->tcbState);
|
||||
next = thread->tcbEPNext;
|
||||
#ifdef CONFIG_KERNEL_MCS
|
||||
/* senders do not have reply objects in their state, and we are only cancelling sends */
|
||||
assert(thread_state_get_tsType(thread->tcbState) == ThreadState_BlockedOnSend);
|
||||
if (b == badge) {
|
||||
restart_thread_if_no_fault(thread);
|
||||
queue = tcbEPDequeue(thread, queue);
|
||||
}
|
||||
#else
|
||||
|
||||
if (b == badge) {
|
||||
setThreadState(thread, ThreadState_Restart);
|
||||
SCHED_ENQUEUE(thread);
|
||||
queue = tcbEPDequeue(thread, queue);
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
ep_ptr_set_queue(epptr, queue);
|
||||
|
||||
if (queue.head) {
|
||||
endpoint_ptr_set_state(epptr, EPState_Send);
|
||||
}
|
||||
|
||||
#endif /* CONFIG_KERNEL_MCS */
|
||||
rescheduleRequired();
|
||||
|
||||
break;
|
||||
|
|
@ -491,11 +539,39 @@ void cancelBadgedSends(endpoint_t *epptr, word_t badge)
|
|||
}
|
||||
|
||||
#ifdef CONFIG_KERNEL_MCS
|
||||
void tcbEPAppend(tcb_t *thread, endpoint_t *epptr, endpoint_state_t ep_state)
|
||||
{
|
||||
tcb_queue_t queue;
|
||||
tcb_queue_t new_queue;
|
||||
|
||||
queue = ep_ptr_get_queue(epptr);
|
||||
new_queue = tcbAppend(thread, queue);
|
||||
ep_ptr_set_queue(epptr, new_queue);
|
||||
|
||||
/* Update the state of the endpoint with the state that was passed in. If the queue
|
||||
* was previously non-empty this must be the same state the endpoint is currently in. */
|
||||
endpoint_ptr_set_state(epptr, ep_state);
|
||||
}
|
||||
|
||||
void tcbEPDequeue(tcb_t *thread, endpoint_t *epptr)
|
||||
{
|
||||
tcb_queue_t queue;
|
||||
tcb_queue_t new_queue;
|
||||
|
||||
queue = ep_ptr_get_queue(epptr);
|
||||
new_queue = tcb_queue_remove(queue, thread);
|
||||
ep_ptr_set_queue(epptr, new_queue);
|
||||
|
||||
if (tcb_queue_empty(new_queue)) {
|
||||
endpoint_ptr_set_state(epptr, EPState_Idle);
|
||||
}
|
||||
}
|
||||
|
||||
void reorderEP(endpoint_t *epptr, tcb_t *thread)
|
||||
{
|
||||
tcb_queue_t queue = ep_ptr_get_queue(epptr);
|
||||
queue = tcbEPDequeue(thread, queue);
|
||||
queue = tcbEPAppend(thread, queue);
|
||||
queue = tcb_queue_remove(queue, thread);
|
||||
queue = tcbAppend(thread, queue);
|
||||
ep_ptr_set_queue(epptr, queue);
|
||||
}
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -145,6 +145,9 @@ void sendSignal(notification_t *ntfnPtr, word_t badge)
|
|||
assert(dest);
|
||||
|
||||
/* Dequeue TCB */
|
||||
#ifdef CONFIG_KERNEL_MCS
|
||||
tcbNTFNDequeue(dest, ntfnPtr);
|
||||
#else
|
||||
ntfn_queue = tcbEPDequeue(dest, ntfn_queue);
|
||||
ntfn_ptr_set_queue(ntfnPtr, ntfn_queue);
|
||||
|
||||
|
|
@ -152,6 +155,7 @@ void sendSignal(notification_t *ntfnPtr, word_t badge)
|
|||
if (!ntfn_queue.head) {
|
||||
notification_ptr_set_state(ntfnPtr, NtfnState_Idle);
|
||||
}
|
||||
#endif /* CONFIG_KERNEL_MCS */
|
||||
|
||||
setThreadState(dest, ThreadState_Running);
|
||||
setRegister(dest, badgeRegister, badge);
|
||||
|
|
@ -196,7 +200,6 @@ void receiveSignal(tcb_t *thread, cap_t cap, bool_t isBlocking)
|
|||
switch (notification_ptr_get_state(ntfnPtr)) {
|
||||
case NtfnState_Idle:
|
||||
case NtfnState_Waiting: {
|
||||
tcb_queue_t ntfn_queue;
|
||||
|
||||
if (isBlocking) {
|
||||
/* Block thread on notification object */
|
||||
|
|
@ -207,11 +210,16 @@ void receiveSignal(tcb_t *thread, cap_t cap, bool_t isBlocking)
|
|||
scheduleTCB(thread);
|
||||
|
||||
/* Enqueue TCB */
|
||||
#ifdef CONFIG_KERNEL_MCS
|
||||
tcbNTFNAppend(thread, ntfnPtr);
|
||||
#else
|
||||
tcb_queue_t ntfn_queue;
|
||||
ntfn_queue = ntfn_ptr_get_queue(ntfnPtr);
|
||||
ntfn_queue = tcbEPAppend(thread, ntfn_queue);
|
||||
|
||||
notification_ptr_set_state(ntfnPtr, NtfnState_Waiting);
|
||||
ntfn_ptr_set_queue(ntfnPtr, ntfn_queue);
|
||||
#endif /* CONFIG_KERNEL_MCS */
|
||||
|
||||
#ifdef CONFIG_KERNEL_MCS
|
||||
maybeReturnSchedContext(ntfnPtr, thread);
|
||||
|
|
@ -240,47 +248,66 @@ void receiveSignal(tcb_t *thread, cap_t cap, bool_t isBlocking)
|
|||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIG_KERNEL_MCS
|
||||
static inline void removeAndRestartNTFNQueuedThread(tcb_t *thread, notification_t *ntfnPtr)
|
||||
{
|
||||
tcbNTFNDequeue(thread, ntfnPtr);
|
||||
setThreadState(thread, ThreadState_Restart);
|
||||
if (sc_sporadic(thread->tcbSchedContext)) {
|
||||
/* We know that the thread can't have the current SC as its own SC at
|
||||
* this point as it should still be associated with the current thread,
|
||||
* or no thread. This check is added here to reduce the cost of proving
|
||||
* this to be true as a short-term stop-gap. */
|
||||
assert(thread->tcbSchedContext != NODE_STATE(ksCurSC));
|
||||
if (thread->tcbSchedContext != NODE_STATE(ksCurSC)) {
|
||||
refill_unblock_check(thread->tcbSchedContext);
|
||||
}
|
||||
}
|
||||
possibleSwitchTo(thread);
|
||||
}
|
||||
#endif
|
||||
|
||||
void cancelAllSignals(notification_t *ntfnPtr)
|
||||
{
|
||||
if (notification_ptr_get_state(ntfnPtr) == NtfnState_Waiting) {
|
||||
/* Clear the queue and set all blocked threads to Restart */
|
||||
#ifdef CONFIG_KERNEL_MCS
|
||||
tcb_queue_t queue;
|
||||
tcb_t *thread, *next;
|
||||
|
||||
queue = ntfn_ptr_get_queue(ntfnPtr);
|
||||
|
||||
for (thread = queue.head; thread; thread = next) {
|
||||
next = thread->tcbSchedNext;
|
||||
removeAndRestartNTFNQueuedThread(thread, ntfnPtr);
|
||||
}
|
||||
#else
|
||||
tcb_t *thread = TCB_PTR(notification_ptr_get_ntfnQueue_head(ntfnPtr));
|
||||
|
||||
notification_ptr_set_state(ntfnPtr, NtfnState_Idle);
|
||||
notification_ptr_set_ntfnQueue_head(ntfnPtr, 0);
|
||||
notification_ptr_set_ntfnQueue_tail(ntfnPtr, 0);
|
||||
|
||||
/* Set all waiting threads to Restart */
|
||||
for (; thread; thread = thread->tcbEPNext) {
|
||||
setThreadState(thread, ThreadState_Restart);
|
||||
#ifdef CONFIG_KERNEL_MCS
|
||||
if (sc_sporadic(thread->tcbSchedContext)) {
|
||||
/* We know that the thread can't have the current SC
|
||||
* as its own SC as this point as it should still be
|
||||
* associated with the current thread, or no thread.
|
||||
* This check is added here to reduce the cost of
|
||||
* proving this to be true as a short-term stop-gap. */
|
||||
assert(thread->tcbSchedContext != NODE_STATE(ksCurSC));
|
||||
if (thread->tcbSchedContext != NODE_STATE(ksCurSC)) {
|
||||
refill_unblock_check(thread->tcbSchedContext);
|
||||
}
|
||||
}
|
||||
possibleSwitchTo(thread);
|
||||
#else
|
||||
SCHED_ENQUEUE(thread);
|
||||
#endif
|
||||
}
|
||||
#endif /* CONFIG_KERNEL_MCS */
|
||||
rescheduleRequired();
|
||||
}
|
||||
}
|
||||
|
||||
void cancelSignal(tcb_t *threadPtr, notification_t *ntfnPtr)
|
||||
{
|
||||
tcb_queue_t ntfn_queue;
|
||||
|
||||
/* Haskell error "cancelSignal: notification object must be in a waiting" state */
|
||||
assert(notification_ptr_get_state(ntfnPtr) == NtfnState_Waiting);
|
||||
|
||||
/* Dequeue TCB */
|
||||
#ifdef CONFIG_KERNEL_MCS
|
||||
tcbNTFNDequeue(threadPtr, ntfnPtr);
|
||||
#else
|
||||
tcb_queue_t ntfn_queue;
|
||||
ntfn_queue = ntfn_ptr_get_queue(ntfnPtr);
|
||||
ntfn_queue = tcbEPDequeue(threadPtr, ntfn_queue);
|
||||
ntfn_ptr_set_queue(ntfnPtr, ntfn_queue);
|
||||
|
|
@ -289,6 +316,7 @@ void cancelSignal(tcb_t *threadPtr, notification_t *ntfnPtr)
|
|||
if (!ntfn_queue.head) {
|
||||
notification_ptr_set_state(ntfnPtr, NtfnState_Idle);
|
||||
}
|
||||
#endif /* CONFIG_KERNEL_MCS */
|
||||
|
||||
/* Make thread inactive */
|
||||
setThreadState(threadPtr, ThreadState_Inactive);
|
||||
|
|
@ -356,11 +384,36 @@ void bindNotification(tcb_t *tcb, notification_t *ntfnPtr)
|
|||
}
|
||||
|
||||
#ifdef CONFIG_KERNEL_MCS
|
||||
void tcbNTFNAppend(tcb_t *thread, notification_t *ntfnPtr)
|
||||
{
|
||||
tcb_queue_t queue;
|
||||
tcb_queue_t new_queue;
|
||||
|
||||
queue = ntfn_ptr_get_queue(ntfnPtr);
|
||||
new_queue = tcbAppend(thread, queue);
|
||||
ntfn_ptr_set_queue(ntfnPtr, new_queue);
|
||||
notification_ptr_set_state(ntfnPtr, NtfnState_Waiting);
|
||||
}
|
||||
|
||||
void tcbNTFNDequeue(tcb_t *thread, notification_t *ntfnPtr)
|
||||
{
|
||||
tcb_queue_t queue;
|
||||
tcb_queue_t new_queue;
|
||||
|
||||
queue = ntfn_ptr_get_queue(ntfnPtr);
|
||||
new_queue = tcb_queue_remove(queue, thread);
|
||||
ntfn_ptr_set_queue(ntfnPtr, new_queue);
|
||||
|
||||
if (tcb_queue_empty(new_queue)) {
|
||||
notification_ptr_set_state(ntfnPtr, NtfnState_Idle);
|
||||
}
|
||||
}
|
||||
|
||||
void reorderNTFN(notification_t *ntfnPtr, tcb_t *thread)
|
||||
{
|
||||
tcb_queue_t queue = ntfn_ptr_get_queue(ntfnPtr);
|
||||
queue = tcbEPDequeue(thread, queue);
|
||||
queue = tcbEPAppend(thread, queue);
|
||||
queue = tcb_queue_remove(queue, thread);
|
||||
queue = tcbAppend(thread, queue);
|
||||
ntfn_ptr_set_queue(ntfnPtr, queue);
|
||||
}
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -249,7 +249,6 @@ tcb_queue_t tcbEPAppend(tcb_t *tcb, tcb_queue_t queue)
|
|||
|
||||
return queue;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Remove TCB from an endpoint queue */
|
||||
tcb_queue_t tcbEPDequeue(tcb_t *tcb, tcb_queue_t queue)
|
||||
|
|
@ -268,6 +267,7 @@ tcb_queue_t tcbEPDequeue(tcb_t *tcb, tcb_queue_t queue)
|
|||
|
||||
return queue;
|
||||
}
|
||||
#endif /* CONFIG_KERNEL_MCS */
|
||||
|
||||
#ifdef CONFIG_KERNEL_MCS
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue