void sendSignal(notification_t *ntfnPtr, word_t badge) { switch (notification_ptr_get_state(ntfnPtr)) { case NtfnState_Idle: { tcb_t *tcb = (tcb_t*)notification_ptr_get_ntfnBoundTCB(ntfnPtr); /* Check if we are bound and that thread is waiting for a message */ if (tcb) { if (thread_state_ptr_get_tsType(&tcb->tcbState) == ThreadState_BlockedOnReceive) { /* Send and start thread running */ cancelIPC(tcb); setThreadState(tcb, ThreadState_Running); setRegister(tcb, badgeRegister, badge); switchIfRequiredTo(tcb); } else { ntfn_set_active(ntfnPtr, badge); } } else { ntfn_set_active(ntfnPtr, badge); } break; } case NtfnState_Waiting: { tcb_queue_t ntfn_queue; tcb_t *dest; ntfn_queue = ntfn_ptr_get_queue(ntfnPtr); dest = ntfn_queue.head; /* Haskell error "WaitingNtfn Notification must have non-empty queue" */ assert(dest); /* Dequeue TCB */ ntfn_queue = tcbEPDequeue(dest, ntfn_queue); ntfn_ptr_set_queue(ntfnPtr, ntfn_queue); /* set the thread state to idle if the queue is empty */ if (!ntfn_queue.head) { notification_ptr_set_state(ntfnPtr, NtfnState_Idle); } setThreadState(dest, ThreadState_Running); setRegister(dest, badgeRegister, badge); switchIfRequiredTo(dest); break; } case NtfnState_Active: { word_t badge2; badge2 = notification_ptr_get_ntfnMsgIdentifier(ntfnPtr); badge2 |= badge; notification_ptr_set_ntfnMsgIdentifier(ntfnPtr, badge2); break; } } }
void ipcCancel(tcb_t *tptr) { thread_state_t *state = &tptr->tcbState; switch (thread_state_ptr_get_tsType(state)) { case ThreadState_BlockedOnSend: case ThreadState_BlockedOnReceive: { /* blockedIPCCancel state */ endpoint_t *epptr; tcb_queue_t queue; epptr = EP_PTR(thread_state_ptr_get_blockingIPCEndpoint(state)); /* Haskell error "blockedIPCCancel: endpoint must not be idle" */ assert(endpoint_ptr_get_state(epptr) != EPState_Idle); /* Dequeue TCB */ queue = ep_ptr_get_queue(epptr); queue = tcbEPDequeue(tptr, queue); ep_ptr_set_queue(epptr, queue); if (!queue.head) { endpoint_ptr_set_state(epptr, EPState_Idle); } setThreadState(tptr, ThreadState_Inactive); break; } case ThreadState_BlockedOnAsyncEvent: asyncIPCCancel(tptr, AEP_PTR(thread_state_ptr_get_blockingIPCEndpoint(state))); break; case ThreadState_BlockedOnReply: { cte_t *slot, *callerCap; fault_null_fault_ptr_new(&tptr->tcbFault); /* Get the reply cap slot */ slot = TCB_PTR_CTE_PTR(tptr, tcbReply); callerCap = CTE_PTR(cap_reply_cap_get_capCallerSlot(slot->cap)); if (callerCap) { finaliseCap(callerCap->cap, true, true); callerCap->cap = cap_null_cap_new(); } cap_reply_cap_ptr_set_capCallerSlot(&slot->cap, CTE_REF(NULL)); break; } } }
void cancelIPC(tcb_t *tptr) { thread_state_t *state = &tptr->tcbState; switch (thread_state_ptr_get_tsType(state)) { case ThreadState_BlockedOnSend: case ThreadState_BlockedOnReceive: { /* blockedIPCCancel state */ endpoint_t *epptr; tcb_queue_t queue; epptr = EP_PTR(thread_state_ptr_get_blockingObject(state)); /* Haskell error "blockedIPCCancel: endpoint must not be idle" */ assert(endpoint_ptr_get_state(epptr) != EPState_Idle); /* Dequeue TCB */ queue = ep_ptr_get_queue(epptr); queue = tcbEPDequeue(tptr, queue); ep_ptr_set_queue(epptr, queue); if (!queue.head) { endpoint_ptr_set_state(epptr, EPState_Idle); } setThreadState(tptr, ThreadState_Inactive); break; } case ThreadState_BlockedOnNotification: cancelSignal(tptr, NTFN_PTR(thread_state_ptr_get_blockingObject(state))); break; case ThreadState_BlockedOnReply: { cte_t *slot, *callerCap; tptr->tcbFault = seL4_Fault_NullFault_new(); /* Get the reply cap slot */ slot = TCB_PTR_CTE_PTR(tptr, tcbReply); callerCap = CTE_PTR(mdb_node_get_mdbNext(slot->cteMDBNode)); if (callerCap) { /** GHOSTUPD: "(True, gs_set_assn cteDeleteOne_'proc (ucast cap_reply_cap))" */ cteDeleteOne(callerCap); } break; } } }
void sendSignal(notification_t *ntfnPtr, word_t badge) { switch (notification_ptr_get_state(ntfnPtr)) { case NtfnState_Idle: { tcb_t *tcb = (tcb_t *)notification_ptr_get_ntfnBoundTCB(ntfnPtr); /* Check if we are bound and that thread is waiting for a message */ if (tcb) { if (thread_state_ptr_get_tsType(&tcb->tcbState) == ThreadState_BlockedOnReceive) { /* Send and start thread running */ cancelIPC(tcb); setThreadState(tcb, ThreadState_Running); setRegister(tcb, badgeRegister, badge); possibleSwitchTo(tcb); #ifdef CONFIG_VTX } else if (thread_state_ptr_get_tsType(&tcb->tcbState) == ThreadState_RunningVM) { #ifdef ENABLE_SMP_SUPPORT if (tcb->tcbAffinity != getCurrentCPUIndex()) { ntfn_set_active(ntfnPtr, badge); doRemoteVMCheckBoundNotification(tcb->tcbAffinity, tcb); } else #endif /* ENABLE_SMP_SUPPORT */ { setThreadState(tcb, ThreadState_Running); setRegister(tcb, badgeRegister, badge); Arch_leaveVMAsyncTransfer(tcb); possibleSwitchTo(tcb); } #endif /* CONFIG_VTX */ } else { /* In particular, this path is taken when a thread * is waiting on a reply cap since BlockedOnReply * would also trigger this path. I.e, a thread * with a bound notification will not be awakened * by signals on that bound notification if it is * in the middle of an seL4_Call. */ ntfn_set_active(ntfnPtr, badge); } } else { ntfn_set_active(ntfnPtr, badge); } break; } case NtfnState_Waiting: { tcb_queue_t ntfn_queue; tcb_t *dest; ntfn_queue = ntfn_ptr_get_queue(ntfnPtr); dest = ntfn_queue.head; /* Haskell error "WaitingNtfn Notification must have non-empty queue" */ assert(dest); /* Dequeue TCB */ ntfn_queue = tcbEPDequeue(dest, ntfn_queue); ntfn_ptr_set_queue(ntfnPtr, ntfn_queue); /* set the thread state to idle if the queue is empty */ if (!ntfn_queue.head) { notification_ptr_set_state(ntfnPtr, NtfnState_Idle); } setThreadState(dest, ThreadState_Running); setRegister(dest, badgeRegister, badge); possibleSwitchTo(dest); break; } case NtfnState_Active: { word_t badge2; badge2 = notification_ptr_get_ntfnMsgIdentifier(ntfnPtr); badge2 |= badge; notification_ptr_set_ntfnMsgIdentifier(ntfnPtr, badge2); break; } } }