示例#1
0
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;
}
示例#2
0
double runKernel(double externalTime) {
  
  Task *task, *temp, *newrunning;
  UserTask *usertask;
  InterruptHandler *handler;
  DataNode* dn;

  // If no energy, then we can not run
  if (rtsys->energyLevel <= 0) {
    debugPrintf("'%s': Energy is out at time: %f\n", rtsys->blockName, rtsys->time);
    return TT_MAX_TIMESTEP;
  }
  
  double timeElapsed = externalTime - rtsys->prevHit; // time since last invocation
  rtsys->prevHit = externalTime;  // update previous invocation time

  debugPrintf("'%s': runkernel at %.16f\n", rtsys->blockName, rtsys->time);
  
#ifdef KERNEL_MATLAB
  // Write rtsys pointer to global workspace so that MATLAB kernel
  // primitives can access it
  *((long *)mxGetPr(rtsys->rtsysptr)) = (long)rtsys;
#endif
  
  double timestep = 0.0;
  int niter = 0;

  while (timestep < TT_TIME_RESOLUTION) {
    
    if (++niter == TT_MAX_ITER) {
      mexPrintf("??? Fatal kernel error: maximum number of iterations reached!\n");
      rtsys->error = 1;
      return 0.0;
    }

    // For each CPU, count down execution time for the current task

    for (int i=0; i<rtsys->nbrOfCPUs; i++) {

      debugPrintf("running core %d\n", i);
      
      rtsys->currentCPU = i;
      rtsys->running = rtsys->runnings[i];
      task = rtsys->running;

      if (task != NULL) {
      
	if (task->state == RUNNING) {
	  task->state = READY;
	}

	double duration = timeElapsed * rtsys->cpuScaling;
      
	// Decrease remaining execution time for current segment and increase total CPU time
	task->execTime -= duration;
	task->CPUTime += duration;

	// If user task, call runkernel hook (to e.g. update budgets)
	if (task->isUserTask()) {
	  usertask = (UserTask*)task;
	  usertask->runkernel_hook(usertask,duration);
	}
      
	// Check if task has finished current segment or not yet started
	if (task->execTime / rtsys->cpuScaling < TT_TIME_RESOLUTION) {
	
	  // Execute next segment 
	  task->segment = task->nextSegment;
	  task->nextSegment++; // default, can later be changed by ttSetNextSegment
	
#ifndef KERNEL_MATLAB
	  debugPrintf("'%s': executing code segment %d of task '%s'\n", rtsys->blockName, task->segment, task->name);
	  task->execTime = task->codeFcn(task->segment, task->data);
	  if (rtsys->error) {
	    TT_RUNKERNEL_ERROR(errbuf);
	    mexPrintf("In task ==> '%s', code segment %d\n", task->name, task->segment);
	    return 0.0;
	  }
#else
	  if (task->codeFcnMATLAB == NULL) {
	    task->execTime = task->codeFcn(task->segment, task->data);
	  } else {

	    mxArray *lhs[2];
	    mxArray *rhs[2];

	    debugPrintf("'%s': executing code function '%s'\n", rtsys->blockName, task->codeFcnMATLAB);

	    *mxGetPr(rtsys->segArray) = (double)task->segment;
	    rhs[0] = rtsys->segArray;
	    if (task->dataMATLAB) {
	      rhs[1] = task->dataMATLAB;
	    } else {
	      rhs[1] = mxCreateDoubleMatrix(0, 0, mxREAL);
	    }
	  
	    mexSetTrapFlag(1); // return control to the MEX file after an error
	    lhs[0] = NULL;     // needed not to crash Matlab after an error
	    lhs[1] = NULL;     // needed not to crash Matlab after an error
	    if (mexCallMATLAB(2, lhs, 2, rhs, task->codeFcnMATLAB) != 0) {
	      rtsys->error = true;
	      return 0.0;
	    }

	    if (mxGetClassID(lhs[0]) == mxUNKNOWN_CLASS) {
	      snprintf(errbuf, MAXERRBUF, "Execution time not assigned in code function '%s'", task->codeFcnMATLAB);
	      TT_RUNKERNEL_ERROR(errbuf);
	      rtsys->error = true;
	      return 0.0;
	    }
	  
	    if (!mxIsDoubleScalar(lhs[0])) {
	      snprintf(errbuf, MAXERRBUF, "Illegal execution time returned by code function '%s'", task->codeFcnMATLAB);
	      TT_RUNKERNEL_ERROR(errbuf);
	      rtsys->error = true;
	      return 0.0;
	    }
	  
	    if (mxGetClassID(lhs[1]) == mxUNKNOWN_CLASS) {
	      snprintf(errbuf, MAXERRBUF, "Data not assigned in code function '%s'", task->codeFcnMATLAB);
	      TT_RUNKERNEL_ERROR(errbuf);
	      rtsys->error = true;
	      return 0.0;
	    }

	    //if ( task->dataMATLAB ) {
	    if ( task->dataMATLAB != lhs[1] ) {
	      mxDestroyArray(task->dataMATLAB);
	      //task->dataMATLAB = mxDuplicateArray(lhs[1]);
	      task->dataMATLAB = lhs[1];
	      mexMakeArrayPersistent(task->dataMATLAB);
	    }
	  
	    task->execTime = *mxGetPr(lhs[0]);
	  
	    //mxDestroyArray(rhs[1]);
	    mxDestroyArray(lhs[0]);
	    //mxDestroyArray(lhs[1]);
	  
	  }
	
#endif
	  if (task->execTime < 0.0) { 

	    // Negative execution time = task is finished
	    debugPrintf("'%s': task '%s' finished\n", rtsys->blockName, task->name);
	    task->execTime = 0.0;
	    task->segment = 0;
	    task->nextSegment = 1;
	    
	    // Remove task from readyQ and set running to NULL
	    if (task->state == READY) {
	      task->remove();
	      task->state = SLEEPING;
	    } else {
	      snprintf(errbuf, MAXERRBUF, "Finished task '%s' not in ReadyQ.", task->name);
	      TT_RUNKERNEL_ERROR(errbuf);
	      rtsys->error = true;
	      return 0.0;
	    }
	    
	    rtsys->runnings[i] = NULL;
	    rtsys->running = NULL;
	    
	    if (task->isUserTask()) {
	      // Execute finish-hook 
	      usertask = (UserTask*)task;
	      usertask->finish_hook(usertask);
	      rtsys->runningUserTasks[i] = NULL;
	    }
	    
	    task->nbrInvocations--;
	    if (task->nbrInvocations > 0) {
	      // There are queued invocations, release the next one
	      dn = (DataNode*) task->pending->getFirst();
	      TaskInvocation *ti = (TaskInvocation *)dn->data;
	      if (task->isUserTask()) { 
		usertask = (UserTask*)task;
		usertask->arrival = ti->timestamp;
		usertask->release = rtsys->time;
		usertask->release_hook(usertask);  // could affect task prio
	      }
	      debugPrintf("'%s': releasing task '%s'\n", rtsys->blockName, task->name);
	      task->moveToList(rtsys->readyQs[task->affinity]);  // re-insert task into readyQ
	      task->state = READY;
	      if (task->isHandler()) {
		handler = (InterruptHandler*)task;
		strncpy(handler->invoker, ti->invoker, MAXCHARS);
		handler->timestamp = ti->timestamp;
	      }
	      task->pending->deleteNode(dn);
	      delete ti;
	    } 
	  }
	}
      }
    }

    // Check time queue for possible releases and expired timers
    
    task = (Task*) rtsys->timeQ->getFirst();
    while (task != NULL) {
      if ((task->wakeupTime() - rtsys->time) >= TT_TIME_RESOLUTION) {
	break; // timeQ is sorted by time, no use to go further
      }
      
      // Task to be released 
      temp = task;
      task = (Task*) task->getNext();
      
      if (temp->isTimer()) {
	Timer *timer = (Timer*)temp;
	debugPrintf("'%s': timer '%s' expired at %f\n", rtsys->blockName, timer->name, rtsys->time);
	invoke_task(timer->task, timer->name);
	if (timer->isPeriodic) {
	  // if periodic timer put back in timeQ
	  timer->time += timer->period;
	  timer->moveToList(rtsys->timeQ);
	} else {
	  timer->remove(); // remove timer from timeQ
	  if (!timer->isOverrunTimer) {
	    // delete the timer
	    dn = getNode(timer->name, rtsys->timerList);
	    rtsys->timerList->deleteNode(dn);
	    delete timer;
	  }
	}
      } 
      else if (temp->isUserTask()) {
	
	usertask = (UserTask*)temp;
	debugPrintf("'%s': releasing task '%s'\n", rtsys->blockName, usertask->name);
	usertask->moveToList(rtsys->readyQs[usertask->affinity]);
	usertask->state = READY;
	
      }
      else if (temp->isHandler()) {
	mexPrintf("??? Fatal kernel error: interrupt handler in TimeQ!\n");
	rtsys->error = 1;
	return 0.0;
      }
    } // end: checking timeQ for releases
    
    
    // For each core, determine the task with highest priority and make it running task
    
    for (int i=0; i<rtsys->nbrOfCPUs; i++) {
      
      debugPrintf("scheduling core %d\n", i);
      
      rtsys->currentCPU = i;
      
      newrunning = (Task*) rtsys->readyQs[i]->getFirst();
      
      // If old running has been preempted, execute suspend_hook
      if (rtsys->runnings[i] != NULL && rtsys->runnings[i] != newrunning) {
	if (rtsys->runnings[i]->isUserTask()) {
	  usertask = (UserTask*)rtsys->runnings[i];
	  usertask->suspend_hook(usertask); 
	}
      }
      
      // If new running != old running, execute start_hook or resume_hook
      if (newrunning != NULL && newrunning != rtsys->runnings[i]) {
	if (newrunning->isUserTask()) {
	  usertask = (UserTask*)newrunning;
	  if (usertask->segment == 0) {
	    usertask->segment = 1;
	    usertask->start_hook(usertask);
	  } else {
	    usertask->resume_hook(usertask);
	  }
	  rtsys->runningUserTasks[i] = usertask;
	}
      }
      
      rtsys->runnings[i] = (Task*) rtsys->readyQs[i]->getFirst(); // hooks may have released handlers
      if (rtsys->runnings[i] != NULL) {
	rtsys->runnings[i]->state = RUNNING;
      }

    }
    
    // Determine next invocation of kernel
    
    double compTime;
    timestep = TT_MAX_TIMESTEP;
    
    // Next release from timeQ (user task or timer)
    if (rtsys->timeQ->getFirst() != NULL) {
      Task* t = (Task*) rtsys->timeQ->getFirst();
      timestep = t->wakeupTime() - rtsys->time;
    }
    
    // Remaining execution time of running tasks
    
    for (int i=0; i<rtsys->nbrOfCPUs; i++) {
      if (rtsys->runnings[i] != NULL) {
	compTime = rtsys->runnings[i]->execTime / rtsys->cpuScaling;
	timestep = (timestep < compTime) ? timestep : compTime;
      } 
    }
      
    timeElapsed = 0.0;
      
  } // end: loop while timestep < TT_TIME_RESOLUTION
    
  return timestep;
}