void InterruptHandler::dispatch_interrupt(REGS * _r) { /* -- INTERRUPT NUMBER */ unsigned int int_no = _r->int_no - IRQ_BASE; //Console::puts("INTERRUPT DISPATCHER: int_no = "); ////Console::putui(int_no); ////Console::puts("\n"); assert((int_no >= 0) && (int_no < IRQ_TABLE_SIZE)); /* -- HAS A HANDLER BEEN REGISTERED FOR THIS INTERRUPT NO? */ InterruptHandler * handler = handler_table[int_no]; /* This is an interrupt that was raised by the interrupt controller. We need to send and end-of-interrupt (EOI) signal to the controller after the interrupt has been handled. */ // When the timer ticks 20ms, an interrupt happens. // Then the interrupt handler will take care of this interrupt and do the following. // In dispatch_interrupt function, it looks at the handler table, finds the right handler, and // then calls the corresponding handler function. // However, this function will not be returned in a short time. // If the new thread does not pend from here, it will return from somewhere else and therefore the // EOI signal will not be sent to PIC soon. Also, if this is the case, when this thread regains // CPU later, it will return from here, causing an unreansonable EOI signal sent. // To avoid this case, we must send EOI signal before the handler function (context switch) is called. /* Check if the interrupt was generated by the slave interrupt controller. If so, send an End-of-Interrupt (EOI) message to the slave controller. */ if (generated_by_slave_PIC(int_no)) { outportb(0xA0, 0x20); } /* Send an EOI message to the master interrupt controller. */ outportb(0x20, 0x20); //Then we call the corresponding handler function if (!handler) { /* --- NO DEFAULT HANDLER HAS BEEN REGISTERED. SIMPLY RETURN AN ERROR. */ Console::puts("INTERRUPT NO: "); Console::puti(int_no); Console::puts("\n"); Console::puts("NO DEFAULT INTERRUPT HANDLER REGISTERED\n"); //abort(); } else { /* -- HANDLE THE INTERRUPT */ handler->handle_interrupt(_r); } }
void InterruptHandler::dispatch_interrupt(REGS * _r) { /* -- INTERRUPT NUMBER */ unsigned int int_no = _r->int_no - IRQ_BASE; //Console::puts("INTERRUPT DISPATCHER: int_no = "); //Console::putui(int_no); //Console::puts("\n"); assert((int_no >= 0) && (int_no < IRQ_TABLE_SIZE)); /* -- HAS A HANDLER BEEN REGISTERED FOR THIS INTERRUPT NO? */ InterruptHandler * handler = handler_table[int_no]; if (!handler) { /* --- NO DEFAULT HANDLER HAS BEEN REGISTERED. SIMPLY RETURN AN ERROR. */ Console::puts("INTERRUPT NO: "); Console::puti(int_no); Console::puts("\n"); Console::puts("NO DEFAULT INTERRUPT HANDLER REGISTERED\n"); // abort(); } else { /* -- HANDLE THE INTERRUPT */ /* This is an interrupt that was raised by the interrupt controller. We need to send and end-of-interrupt (EOI) signal to the controller after the interrupt has been handled. */ /* Check if the interrupt was generated by the slave interrupt controller. If so, send an End-of-Interrupt (EOI) message to the slave controller. */ if (generated_by_slave_PIC(int_no)) {//modified to inform the control the interupt is being handled before the call to the handler outportb(0xA0, 0x20);//this will allow context switch during handler } /* Send an EOI message to the master interrupt controller. */ outportb(0x20, 0x20); // we send interupt has been handled before calling handle interupt to prevent the interupt from not being acknoledged //when a context switch occurs inside of the handler // and when the calling thread finally returns from the context switch to not send the interupt handled message //because at this point it has already been handled and if the PIC is waiting for a handled message it is a different interupt handler->handle_interrupt(_r); //dont do anything after handler to prevent interupts not being handled } }
void InterruptHandler::dispatch_interrupt(REGS * _r) { /* -- INTERRUPT NUMBER */ unsigned int int_no = _r->int_no - IRQ_BASE; //Console::puts("INTERRUPT DISPATCHER: int_no = "); //Console::putui(int_no); //Console::puts("\n"); assert((int_no >= 0) && (int_no < IRQ_TABLE_SIZE)); /* -- HAS A HANDLER BEEN REGISTERED FOR THIS INTERRUPT NO? */ InterruptHandler * handler = handler_table[int_no]; if (!handler) { /* --- NO DEFAULT HANDLER HAS BEEN REGISTERED. SIMPLY RETURN AN ERROR. */ Console::puts("INTERRUPT NO: "); Console::puti(int_no); Console::puts("\n"); Console::puts("NO DEFAULT INTERRUPT HANDLER REGISTERED\n"); // abort(); } else { /* -- HANDLE THE INTERRUPT */ /* Signal PIC that the interrupt has been handled and then make the call to handle interrupt */ if(int_no == 0) outportb(0x20, 0x20); handler->handle_interrupt(_r); } /* This is an interrupt that was raised by the interrupt controller. We need to send and end-of-interrupt (EOI) signal to the controller after the interrupt has been handled. */ /* Check if the interrupt was generated by the slave interrupt controller. If so, send an End-of-Interrupt (EOI) message to the slave controller. */ if (generated_by_slave_PIC(int_no)) { outportb(0xA0, 0x20); } /* Add additional check to see that we don't send EOI for interrupt 0, since its already done*/ /* Send an EOI message to the master interrupt controller. */ outportb(0x20, 0x20); }
void invoke_task(Task *task, const char *invoker) { debugPrintf("'%s': task_invoke('%s','%s') at %f\n", rtsys->blockName, task->name, invoker, rtsys->time); if (task->isUserTask()) { UserTask *usertask = (UserTask*)task; usertask->arrival_hook(usertask); if (usertask->nbrInvocations == 0) { usertask->arrival = rtsys->time; usertask->release = rtsys->time; usertask->release_hook(usertask); usertask->moveToList(rtsys->readyQs[usertask->affinity]); usertask->state = READY; } else { TaskInvocation *ti = new TaskInvocation(); ti->timestamp = rtsys->time; strncpy(ti->invoker, invoker, MAXCHARS); // not used usertask->pending->appendNode(new DataNode(ti, NULL)); } usertask->nbrInvocations++; } else { InterruptHandler *handler = (InterruptHandler*)task; if (handler->nbrInvocations == 0) { handler->timestamp = rtsys->time; strncpy(handler->invoker, invoker, MAXCHARS); handler->moveToList(rtsys->readyQs[handler->affinity]); handler->state = READY; } else { TaskInvocation *ti = new TaskInvocation(); ti->timestamp = rtsys->time; strncpy(ti->invoker, invoker, MAXCHARS); handler->pending->appendNode(new DataNode(ti, NULL)); } handler->nbrInvocations++; } }
bool ttCreatePeriodicTask(char *name, double offset, double period, double priority, double (*codeFcn)(int, void*)) { DataNode* dn; InterruptHandler* hdl; Timer *t; if (ttCreateTask(name, period, priority, codeFcn)) { dn = (DataNode*) rtsys->taskList->getLast(); // last created task // Create interrupt handler invoked periodically to create task jobs // see codefunctions.cpp for the code function hdl = new InterruptHandler("perHandler"); hdl->codeFcn = rtsys->periodicTaskHandlerCode; hdl->handlerID = rtsys->nbrOfHandlers + 1; hdl->priority = -1000.0; hdl->display = false; hdl->data = (UserTask*) dn->data; rtsys->handlerList->appendNode(new DataNode(hdl, NULL)); rtsys->nbrOfHandlers++; // Creating periodic timer that triggers the handler t = new Timer("perTimer"); t->time = offset; // First timer expiry at task offset t->period = period; t->isPeriodic = true; hdl->timer = t; hdl->moveToList(rtsys->timeQ); hdl->type = TIMER; ((UserTask*) dn->data)->periodichandler = hdl; return true; } else { return false; } }
static void mdlOutputs(SimStruct *S, int_T tid) { //printf("mdlOutputs at %g\n", ssGetT(S)); rtsys = (RTsys*) ssGetUserData(S); if (rtsys->init_phase) { /* Failure during initialization */ return; } real_T *y = ssGetOutputPortRealSignal(S,0); real_T *n = ssGetOutputPortRealSignal(S,1); real_T *s = ssGetOutputPortRealSignal(S,2); real_T *m = ssGetOutputPortRealSignal(S,3); real_T *energyConsumption = ssGetOutputPortRealSignal(S,4); int i, j, k, detected; double dTime; DataNode *dn; Task* task; UserTask* t; InterruptHandler* hdl; Monitor *mon; if (!rtsys->started && ssGetT(S) == 0.0) { rtsys->started = true; return; } if (!rtsys->mdlzerocalled) { printf("Zero crossing detection must be turned on in order to run TrueTime!\n"); ssSetErrorStatus(S, "Zero crossing detection must be turned on in order to run TrueTime!"); return; } /* Storing the time */ rtsys->time = ssGetT(S) * rtsys->clockDrift + rtsys->clockOffset; detected = 0; /* Check interrupts */ i = 0; dn = (DataNode*) rtsys->triggerList->getFirst(); while (dn != NULL) { if (fabs(rtsys->interruptinputs[i]-rtsys->oldinterruptinputs[i]) > 0.1) { hdl = (InterruptHandler*) dn->data; Trigger* trig = hdl->trigger; if (rtsys->time - trig->prevHit > trig->latency) { // Trigger interrupt handler if (hdl->myList == rtsys->readyQ) { // handler serving older interrupts hdl->pending++; } else { hdl->moveToList(rtsys->readyQ); detected = 1; } trig->prevHit = rtsys->time; } else { //printf("Call to interrupt handler %s ignored at time %f. Within interrupt latency!\n", hdl->name, rtsys->time); } rtsys->oldinterruptinputs[i] = rtsys->interruptinputs[i]; } i++; dn = (DataNode*) dn->getNext(); } /* Check network */ dn = (DataNode*) rtsys->networkList->getFirst(); while (dn != NULL) { hdl = (InterruptHandler*) dn->data; Network* network = hdl->network; i = network->networkID - 1; //printf("mdlOutputs: checking network #%d inp: %d oldinp: %d\n",i,rtsys->networkinputs[i],rtsys->oldnetworkinputs[i]); if (fabs(rtsys->networkinputs[i] - rtsys->oldnetworkinputs[i]) > 0.1) { hdl->moveToList(rtsys->readyQ); detected = 1; rtsys->oldnetworkinputs[i] = rtsys->networkinputs[i]; } dn = (DataNode*) dn->getNext(); } /* Run kernel? */ double externTime = (rtsys->time- rtsys->clockOffset) / rtsys->clockDrift; if ((externTime >= rtsys->nextHit) || (detected > 0)) { dTime = runKernel(ssGetT(S)); if (rtsys->error) { // Something went wrong executing a code function mxArray *bn[1]; mexCallMATLAB(1, bn, 0, 0, "gcs"); // get current system char buf[200]; mxGetString(bn[0], buf, 200); for (unsigned int i=0; i<strlen(buf); i++) if (buf[i]=='\n') buf[i]=' '; printf("In block ==> '%s'\nSimulation aborted!\n", buf); ssSetStopRequested(S, 1); } else { rtsys->nextHit = (rtsys->time + dTime - rtsys->clockOffset) / rtsys->clockDrift; } } /* Outputs */ for (i=0; i<rtsys->nbrOfOutputs; i++) { y[i] = rtsys->outputs[i]; } /* Network send */ for (i=0; i<rtsys->nbrOfNetworks; i++) { n[i] = rtsys->nwSnd[i]; } /* Task schedule */ i = 0; j = 0; dn = (DataNode*) rtsys->taskList->getFirst(); while (dn != NULL) { t = (UserTask*) dn->data; rtsys->taskSched[i] = (double) (j+1); if (t->display) j++; dn = (DataNode*) dn->getNext(); i++; } task = (Task*) rtsys->readyQ->getFirst(); while (task != NULL) { if (task->isUserTask()) { t = (UserTask*) task; rtsys->taskSched[t->taskID - 1] += 0.25; } task = (Task*) task->getNext(); } if ((rtsys->running != NULL) && (rtsys->running->isUserTask())) { t = (UserTask*) rtsys->running; rtsys->taskSched[t->taskID - 1] += 0.25; } i = 0; j = 0; dn = (DataNode*) rtsys->taskList->getFirst(); while (dn != NULL) { t = (UserTask*) dn->data; if (t->display) { s[j] = rtsys->taskSched[i]; j++; } dn = (DataNode*) dn->getNext(); i++; } /* Handler schedule */ i = 0; j = 0; dn = (DataNode*) rtsys->handlerList->getFirst(); while (dn != NULL) { rtsys->handlerSched[i] = (double) (j+rtsys->nbrOfSchedTasks+2); if (i==0 && rtsys->contextSwitchTime > EPS) { // Context switch schedule, move graph down to task level rtsys->handlerSched[i] = rtsys->handlerSched[i] - 1; } hdl = (InterruptHandler*) dn->data; if (hdl->display) j++; dn = (DataNode*) dn->getNext(); i++; } task = (Task*) rtsys->readyQ->getFirst(); while (task != NULL) { if (!(task->isUserTask())) { hdl = (InterruptHandler*) task; rtsys->handlerSched[hdl->handlerID - 1] += 0.25; } task = (Task*) task->getNext(); } if ((rtsys->running != NULL) && (!(rtsys->running->isUserTask()))) { hdl = (InterruptHandler*) rtsys->running; rtsys->handlerSched[hdl->handlerID - 1] += 0.25; } i = 0; j = 0; dn = (DataNode*) rtsys->handlerList->getFirst(); while (dn != NULL) { hdl = (InterruptHandler*) dn->data; if (hdl->display) { s[j+rtsys->nbrOfSchedTasks] = rtsys->handlerSched[i]; j++; } dn = (DataNode*) dn->getNext(); i++; } /* Monitor graph */ k = 0; dn = (DataNode*) rtsys->monitorList->getFirst(); while (dn != NULL) { mon = (Monitor*) dn->data; for (j=0; j<rtsys->nbrOfTasks; j++) rtsys->monitorGraph[j] = (double) (j+1+k*(1+rtsys->nbrOfTasks)); t = (UserTask*) mon->waitingQ->getFirst(); while (t != NULL) { i = t->taskID; rtsys->monitorGraph[i-1] += 0.25; t = (UserTask*) t->getNext(); } if (mon->heldBy != NULL) { i = mon->heldBy->taskID; rtsys->monitorGraph[i-1] += 0.5; } if (mon->display) { for (j=0; j<rtsys->nbrOfTasks; j++) m[j+k*rtsys->nbrOfTasks] = rtsys->monitorGraph[j]; k++; } dn = (DataNode*) dn->getNext(); } /* Energy consumption */ energyConsumption[0] = rtsys->energyConsumption; }
double runKernel(double externalTime) { double nextHit, timeElapsed; Task *task, *temp, *oldrunning, *newrunning; UserTask *usertask; InterruptHandler *hdl; DataNode* dn; // If no energy, then we can not run if (rtsys->energyLevel <= 0) { //printf("Energy is out at time: %f\n", rtsys->time); return INF; } timeElapsed = externalTime - rtsys->prevHit; // time since last invocation rtsys->prevHit = externalTime; // update previous invocation time nextHit = 0.0; //printf("runkernel at %f\n", rtsys->time); #ifdef KERNEL_MATLAB /* Write rtsys pointer to global workspace */ *((long *)mxGetPr(rtsys->rtsysptr)) = (long)rtsys; #endif while (nextHit < EPS) { // Count down execution time for current task (usertask or handler) // and check if it has finished its execution task = rtsys->running; if (task != NULL) { // Count down execution time task->execTime -= timeElapsed * rtsys->cpuScaling; if (task->execTime < EPS) { // Execute next segment task->segment++; if (task->isUserTask()) { usertask = (UserTask*) task; // Update budget and lastStart variable at segment change usertask->budget -= (rtsys->time - usertask->lastStart); usertask->lastStart = rtsys->time; } // Execute next segment of the code function #ifndef KERNEL_MATLAB task->execTime = task->codeFcn(task->segment, task->data); if (rtsys->error) { printf("Error in ==> task '%s', segment %d\n", task->name, task->segment); return 0.0; } #else if (task->codeFcnMATLAB == NULL) { task->execTime = task->codeFcn(task->segment, task->data); } else { task->execTime = executeCode(task->codeFcnMATLAB, task->segment, task); } if (rtsys->error) { printf("Error in ==> task '%s', segment %d\n", task->name, task->segment); return 0.0; } #endif if (task->execTime < 0.0) { // Negative execution time = task finished task->execTime = 0.0; task->segment = 0; if (task->myList == rtsys->readyQ) { // Remove task from readyQ task->remove(); } if (!(task->isUserTask())) { hdl = (InterruptHandler*) task; if (hdl->type == TIMER) { if (hdl->timer->isPeriodic) { // if periodic timer put back in timeQ hdl->timer->time += hdl->timer->period; hdl->moveToList(rtsys->timeQ); } else { // Remove timer and free up handler dn = getNode(hdl->timer->name, rtsys->timerList); rtsys->timerList->deleteNode(dn); delete hdl->timer; hdl->timer = NULL; hdl->type = UNUSED; } } if (hdl->type == EXTERNAL) { if (hdl->pending > 0) { // new external interrupt occured before handler finished hdl->pending--; hdl->moveToList(rtsys->readyQ); } } } else { // the finished task is a usertask usertask = (UserTask*) task; // Execute finish-hook usertask->finish_hook(usertask); usertask->state = IDLE; // Release next job if any usertask->nbrJobs--; if (usertask->nbrJobs > 0) { // next pending release dn = (DataNode*) usertask->pending->getFirst(); double* release = (double*) dn->data; usertask->release = *release; usertask->absDeadline = *release + usertask->deadline; usertask->moveToList(rtsys->timeQ); usertask->pending->deleteNode(dn); delete release; // Execute release-hook usertask->release_hook(usertask); usertask->state = SLEEPING; } } } } } // end: counting down execution time of running task // Check time queue for possible releases task = (Task*) rtsys->timeQ->getFirst(); while (task != NULL) { if ((task->wakeupTime() - rtsys->time) < EPS) { // Task to be released temp = task; task = (Task*) task->getNext(); temp->moveToList(rtsys->readyQ); if (temp->isUserTask()) { usertask = (UserTask*) temp; usertask->state = READY; } } else { break; } } // end: checking timeQ for releases // Determine task with highest priority and make it running task newrunning = (Task*) rtsys->readyQ->getFirst(); oldrunning = rtsys->running; if (newrunning != NULL) { // Check for suspend- and resume-hooks if (oldrunning != NULL) { // Is oldrunning being suspended? if (oldrunning->isUserTask()) { if (newrunning != oldrunning && ((UserTask*) oldrunning)->state == RUNNING) { usertask = (UserTask*) oldrunning; usertask->state = SUSPENDED; usertask->suspend_hook(usertask); } } } // invocation of hooks may have triggered kernelHandler newrunning = (Task*) rtsys->readyQ->getFirst(); // Is newrunning being resumed? if (newrunning->isUserTask()) { if ( (((UserTask*) newrunning)->state == READY) || (((UserTask*) newrunning)->state == SUSPENDED) ) { // newrunning is being resumed or started usertask = (UserTask*) newrunning; usertask->state = RUNNING; if (usertask->segment == 0) { usertask->start_hook(usertask); } else { usertask->resume_hook(usertask); } } } // invocation of hooks may have triggered kernelHandler rtsys->running = (Task*) rtsys->readyQ->getFirst(); } else { // No tasks in readyQ rtsys->running = NULL; } // end: task dispatching // Determine next invocation of kernel nextHit = getNextInvocation(); timeElapsed = 0.0; } // end: loop while nextHit < EPS return nextHit; }