void execute_ISR(Interrupt interrupt) { int error; switch (interrupt) { case timer_interrupt: { current_pcb->state = interrupted; char *PCB_string = PCB_toString(current_pcb, &error); printf("Timer interrupt during %s\n", PCB_string); free(PCB_string); runScheduler(timer_interrupt); break; } case io1_interrupt: { current_pcb->state = interrupted; printf("I/O 1 Trap request complete.\n"); runScheduler(io1_interrupt); current_pcb->state = running; break; } case io2_interrupt: { current_pcb->state = interrupted; printf("I/O 2 Trap request complete.\n"); runScheduler(io2_interrupt); current_pcb->state = running; break; } case trap_interrupt: { current_pcb->state = interrupted; char* PCB_string = PCB_toString(current_pcb, &error); printf("Trap requested by %s\n", PCB_string); execute_TSR(trap); break; } case no_interrupt: // This shouldn't happen here. break; } }
void BasicEngine::run() { log->record(GreasyLog::devel, "BasicEngine::run", "Entering..."); runScheduler(); log->record(GreasyLog::devel, "BasicEngine::run", "Exiting..."); }
/** * \fn runSchedulerNotFromSm * \brief Run scheduler due to other events then from SM (static function) * * To comply with the SM behavior, this function is used for any case where the * Mgmt-Queues scheduler may have work to do due to events external to the SM. * If the queues are not empty, this function runs the scheduler. * If the scheduler emptied the queues, update the SM. * * \note * \param pTxMgmtQ - The module's object * \return void * \sa */ static void runSchedulerNotFromSm (TTxMgmtQ *pTxMgmtQ) { /* If the queues are not empty, run the scheduler. */ if ( !ARE_ALL_MGMT_QUEUES_EMPTY(pTxMgmtQ->aQueues) ) { runScheduler (pTxMgmtQ); /* If the queues are now both empty, call the SM with QUEUES_EMPTY event. */ if ( ARE_ALL_MGMT_QUEUES_EMPTY(pTxMgmtQ->aQueues) ) { mgmtQueuesSM (pTxMgmtQ, SM_EVENT_QUEUES_EMPTY); } } }
void mutexUnlock(PCB_p pcb, Mutex_p mutex) { int error; printf("PID %lu: requested unlock on mutex M%lu - ", pcb->PID, mutex->ID); if (Mutex_unlock(mutex, pcb)) { // The mutex unlock succeeded. Resume process operation. printf("succeeded\n"); pcb->state = running; } else { // The mutex unlock has failed. printf("blocked by PID %lu\n", mutex->key->PID); // The process has now been enqueued in the mutex queue, and will get the lock (and thus unlock) when it is its turn. // So enqueue PCB back into the ready queue and run the scheduler to dispatch the next process. // TODO: Move the enqueue into the scheduler. current_pcb->state = waiting; current_pcb->PC--; // Decrement so that the PCB will try to unlock again next time it's run. PriorityQ_enqueue(ready_PCBs, current_pcb, &error); runScheduler( trap_interrupt); // Current process has been blocked, run scheduler to dispatch the next one. } }
/** * \fn runSchedulerNotFromSm * \brief Run scheduler due to other events then from SM (static function) * * To comply with the SM behavior, this function is used for any case where the * Mgmt-Queues scheduler may have work to do due to events external to the SM. * If the queues are not empty, this function runs the scheduler. * If the scheduler emptied the queues, update the SM. * * \note * \param pTxMgmtQ - The module's object * \return void * \sa */ static void runSchedulerNotFromSm (TTxMgmtQ *pTxMgmtQ) { TMgmtLinkQ *pLinkQ; TI_UINT32 uHlid; for (uHlid=0; uHlid<WLANLINKS_MAX_LINKS; uHlid++) { pLinkQ = &pTxMgmtQ->aMgmtLinkQ[uHlid]; /* Link queues */ /* If the queues are not empty, run the scheduler. */ if ( !ARE_LINK_MGMT_QUEUES_EMPTY(pLinkQ->aQueues) ) { runScheduler (pTxMgmtQ); /* If the queues are now both empty, call the SM with QUEUES_EMPTY event. */ if ( ARE_LINK_MGMT_QUEUES_EMPTY(pLinkQ->aQueues) ) { mgmtQueuesSM (pTxMgmtQ, uHlid, SM_EVENT_QUEUES_EMPTY); } } } }
/** * \fn mgmtQueuesSM * \brief The module state-machine (static function) * * The SM follows the system management states (see ETxConnState) and the Mgmt queues * status (empty or not), and contorls the Tx queues flow accordingly (mgmt and data queues). * For detailed explanation, see the Tx-Path LLD document! * * \note To avoid recursion issues, all SM actions are done at the end of the function, * since some of them may invoke the SM again. * \param pTxMgmtQ - The module's object * \param eSmEvent - The event to act upon * \return void * \sa txMgmtQ_SetConnState */ static void mgmtQueuesSM (TTxMgmtQ *pTxMgmtQ, ESmEvent eSmEvent) { ESmState ePrevState = pTxMgmtQ->eSmState; ESmAction eSmAction = SM_ACTION_NULL; switch(eSmEvent) { case SM_EVENT_CLOSE: /* * Tx link is closed (expected in any state), so disable both mgmt queues * and if data-queues are active disable them via txPort module. */ pTxMgmtQ->eSmState = SM_STATE_CLOSE; pTxMgmtQ->aQueueEnabledBySM[QUEUE_TYPE_MGMT] = TI_FALSE; pTxMgmtQ->aQueueEnabledBySM[QUEUE_TYPE_EAPOL] = TI_FALSE; if (ePrevState == SM_STATE_OPEN_DATA) eSmAction = SM_ACTION_ENABLE_MGMT; break; case SM_EVENT_MGMT: /* * Only Mgmt packets are permitted (expected from any state): * - Enable the mgmt queue and disable the Eapol queue. * - If data-queues are active disable them via txPort (this will run the scheduler). * - Else run the scheduler (to send mgmt packets if waiting). */ pTxMgmtQ->eSmState = SM_STATE_MGMT; pTxMgmtQ->aQueueEnabledBySM[QUEUE_TYPE_MGMT] = TI_TRUE; pTxMgmtQ->aQueueEnabledBySM[QUEUE_TYPE_EAPOL] = TI_FALSE; if (ePrevState == SM_STATE_OPEN_DATA) eSmAction = SM_ACTION_ENABLE_MGMT; else eSmAction = SM_ACTION_RUN_SCHEDULER; break; case SM_EVENT_EAPOL: /* * EAPOL packets are also permitted (expected in MGMT or CLOSE state), so enable the * EAPOL queue and run the scheduler (to send packets from EAPOL queue if waiting). */ if ( (ePrevState != SM_STATE_CLOSE) && (ePrevState != SM_STATE_MGMT) ) { TRACE1(pTxMgmtQ->hReport, REPORT_SEVERITY_ERROR, "mgmtQueuesSM: Got SmEvent=EAPOL when eSmState=%d\n", ePrevState); } pTxMgmtQ->eSmState = SM_STATE_EAPOL; pTxMgmtQ->aQueueEnabledBySM[QUEUE_TYPE_MGMT] = TI_TRUE; pTxMgmtQ->aQueueEnabledBySM[QUEUE_TYPE_EAPOL] = TI_TRUE; eSmAction = SM_ACTION_RUN_SCHEDULER; break; case SM_EVENT_OPEN: /* * All packets are now permitted (expected in EAPOL state), so if the mgmt-queues * are empty disable them and enable the data queues via txPort module. */ if (ePrevState != SM_STATE_EAPOL) { TRACE1(pTxMgmtQ->hReport, REPORT_SEVERITY_ERROR, "mgmtQueuesSM: Got SmEvent=OPEN when eSmState=%d\n", ePrevState); } if ( ARE_ALL_MGMT_QUEUES_EMPTY(pTxMgmtQ->aQueues) ) { pTxMgmtQ->eSmState = SM_STATE_OPEN_DATA; pTxMgmtQ->aQueueEnabledBySM[QUEUE_TYPE_MGMT] = TI_FALSE; pTxMgmtQ->aQueueEnabledBySM[QUEUE_TYPE_EAPOL] = TI_FALSE; eSmAction = SM_ACTION_ENABLE_DATA; } else { pTxMgmtQ->eSmState = SM_STATE_OPEN_MGMT; } break; case SM_EVENT_QUEUES_EMPTY: /* * The mgmt-queues are empty, so if in OPEN_MGMT state disable the * mgmt-queues and enable the data-queues via txPort module. */ if (ePrevState == SM_STATE_OPEN_MGMT) { pTxMgmtQ->eSmState = SM_STATE_OPEN_DATA; pTxMgmtQ->aQueueEnabledBySM[QUEUE_TYPE_MGMT] = TI_FALSE; pTxMgmtQ->aQueueEnabledBySM[QUEUE_TYPE_EAPOL] = TI_FALSE; eSmAction = SM_ACTION_ENABLE_DATA; } else { /* This may happen so it's just a warning and not an error. */ TRACE1(pTxMgmtQ->hReport, REPORT_SEVERITY_WARNING, "mgmtQueuesSM: Got SmEvent=QUEUES_EMPTY when eSmState=%d\n", ePrevState); } break; case SM_EVENT_QUEUES_NOT_EMPTY: /* A packet was inserted to the mgmt-queues */ /* * If in OPEN_DATA state, enable mgmt-queues and disable data-queues via txPort module. * * Note: The scheduler is not run here because the txPort will call * txMgmtQueue_wakeAll() which will run the scheduler. */ if (ePrevState == SM_STATE_OPEN_DATA) { pTxMgmtQ->eSmState = SM_STATE_OPEN_MGMT; pTxMgmtQ->aQueueEnabledBySM[QUEUE_TYPE_MGMT] = TI_TRUE; pTxMgmtQ->aQueueEnabledBySM[QUEUE_TYPE_EAPOL] = TI_TRUE; eSmAction = SM_ACTION_ENABLE_MGMT; } /* * If in MGMT or EAPOL state, run the scheduler to transmit the packet. */ else if ( (ePrevState == SM_STATE_MGMT) || (ePrevState == SM_STATE_EAPOL) ) { eSmAction = SM_ACTION_RUN_SCHEDULER; } else { /* This may happen so it's just a warning and not an error. */ TRACE1(pTxMgmtQ->hReport, REPORT_SEVERITY_WARNING, "mgmtQueuesSM: Got SmEvent=QUEUES_NOT_EMPTY when eSmState=%d\n", ePrevState); } break; default: TRACE1(pTxMgmtQ->hReport, REPORT_SEVERITY_ERROR, "mgmtQueuesSM: Unknown SmEvent = %d\n", eSmEvent); break; } TRACE6( pTxMgmtQ->hReport, REPORT_SEVERITY_INFORMATION, "mgmtQueuesSM: <currentState = %d, event = %d> --> nextState = %d, action = %d, MgmtQueEnbl=%d, EapolQueEnbl=%d\n", ePrevState, eSmEvent, pTxMgmtQ->eSmState, eSmAction, pTxMgmtQ->aQueueEnabledBySM[0], pTxMgmtQ->aQueueEnabledBySM[1]); /* * Execute the required action. * Note: This is done at the end of the SM because it may start a sequence that will call the SM again! */ switch (eSmAction) { case SM_ACTION_NULL: break; case SM_ACTION_ENABLE_DATA: txPort_enableData(pTxMgmtQ->hTxPort); break; case SM_ACTION_ENABLE_MGMT: txPort_enableMgmt(pTxMgmtQ->hTxPort); break; case SM_ACTION_RUN_SCHEDULER: runScheduler(pTxMgmtQ); break; default: TRACE1(pTxMgmtQ->hReport, REPORT_SEVERITY_ERROR, ": Unknown SmAction = %d\n", eSmAction); break; } }
void execute_TSR(TSR routine) { int error; switch (routine) { case io1_trap: { current_pcb->state = waiting; FIFOq_enqueue(io1_PCBs, current_pcb, &error); char* PCB_string = PCB_toString(current_pcb, &error); printf("I/O 1 Trap requested by %s\n", PCB_string); free(PCB_string); runScheduler(trap_interrupt); break; } case io2_trap: { current_pcb->state = waiting; FIFOq_enqueue(io2_PCBs, current_pcb, &error); char* PCB_string = PCB_toString(current_pcb, &error); printf("I/O 2 Trap requested by %s\n", PCB_string); free(PCB_string); runScheduler(trap_interrupt); break; } case terminate_trap: { current_pcb->state = terminated; current_pcb->termination = time(NULL); FIFOq_enqueue(terminated_PCBs, current_pcb, &error); processes_terminated++; // Unlock any mutexes that this terminated PCB may have. if (current_pcb->type == consumer || current_pcb->type == producer || current_pcb->type == resource_user_A) { Mutex_remove(current_pcb->mutex_A, current_pcb); } else if (current_pcb->type == resource_user_B) { Mutex_remove(current_pcb->mutex_B, current_pcb); } char* PCB_string = PCB_toString(current_pcb, &error); printf("Terminated process: %s\n", PCB_string); free(PCB_string); current_pcb = NULL; runScheduler(trap_interrupt); break; } case mutex_lock_trap: if (current_pcb->type == resource_user_A) { // If this is a resource_user "A" process lock mutex A then B. if (!Mutex_Is_Locked(current_pcb->mutex_A) || current_pcb->mutex_A->key != current_pcb) { mutexLock(current_pcb, current_pcb->mutex_A); } else if (!Mutex_Is_Locked(current_pcb->mutex_B) || current_pcb->mutex_B->key != current_pcb) { mutexLock(current_pcb, current_pcb->mutex_B); } } else if (current_pcb->type == resource_user_B) { // If this is a resource_user "B" process then lock A then B if no-deadlock, and B then A if deadlock. if (!deadlock) { if (!Mutex_Is_Locked(current_pcb->mutex_A) || current_pcb->mutex_A->key != current_pcb) { mutexLock(current_pcb, current_pcb->mutex_A); } else if (!Mutex_Is_Locked(current_pcb->mutex_B) || current_pcb->mutex_B->key != current_pcb) { mutexLock(current_pcb, current_pcb->mutex_B); } } else { if (!Mutex_Is_Locked(current_pcb->mutex_B) || current_pcb->mutex_B->key != current_pcb) { mutexLock(current_pcb, current_pcb->mutex_B); } else if (!Mutex_Is_Locked(current_pcb->mutex_A) || current_pcb->mutex_A->key != current_pcb) { mutexLock(current_pcb, current_pcb->mutex_A); } } } else { mutexLock(current_pcb, current_pcb->mutex_A); } break; case mutex_unlock_trap: if (current_pcb->type == resource_user_A) { // If this is a resource_user "A" process unlock mutex B then A. if (Mutex_Is_Locked(current_pcb->mutex_B)) { mutexUnlock(current_pcb, current_pcb->mutex_B); } else if (Mutex_Is_Locked(current_pcb->mutex_A)) { mutexUnlock(current_pcb, current_pcb->mutex_A); } } else if (current_pcb->type == resource_user_B) { // If this is a resource_user "B" process then unlock B then A if no-deadlock, and A then B if deadlock. if (!deadlock) { if (Mutex_Is_Locked(current_pcb->mutex_B)) { mutexUnlock(current_pcb, current_pcb->mutex_B); } else if (Mutex_Is_Locked(current_pcb->mutex_A)) { mutexUnlock(current_pcb, current_pcb->mutex_B); } } else { if (Mutex_Is_Locked(current_pcb->mutex_A)) { mutexUnlock(current_pcb, current_pcb->mutex_A); } else if (Mutex_Is_Locked(current_pcb->mutex_B)) { mutexUnlock(current_pcb, current_pcb->mutex_B); } } } else { mutexUnlock(current_pcb, current_pcb->mutex_A); } break; case condition_signal_and_wait_trap: printf("PID %lu: sent signal on condition %lu\n", current_pcb->PID, current_pcb->conditional_variable->ID); PCB_p returnedPCB = Condition_signal(current_pcb->conditional_variable, current_pcb); if (returnedPCB != NULL) { returnedPCB->state = ready; PriorityQ_enqueue(ready_PCBs, returnedPCB, &error); } printf("PID %lu: requested wait on condition %lu with mutex M%lu\n", current_pcb->PID, current_pcb->conditional_variable->ID, current_pcb->mutex_A->ID); Condition_wait(current_pcb->conditional_variable, current_pcb->mutex_A, current_pcb); current_pcb->state = waiting; // Don't enqueue the current PCB as now it's waiting. // Interrupt this PCB and run the scheduler to dispatch the next process. runScheduler(trap_interrupt); break; case no_trap: // This shouldn't happen here. break; } }