public TaskInfo getNextFrameTask(TaskInfo ppTaskInfo) { // return the next frame task. If no frame task is scheduled to run this // frame, // return null. note that this method REMOVES the task from the list, so // the // caller is responsible for either adding it back in (rescheduling) or // deleting it. TaskInfo pNextTask = m_pFrameList; if (pNextTask != null && pNextTask.time.next <= m_clock.getFrame()) { m_pFrameList = pNextTask.pNext; // pNextTask.pNext = null; ppTaskInfo = pNextTask; return ppTaskInfo; } else { return null; } }
public int executeFrame() { // printf("EXEC BEGIN\n"); // // Run one frame. This takes the time stamp marking the end of the frame // and then processes events for that frame retroactively. This method // has // the advantage of flexibility, especially if the frame rate // fluctuates. // However it is always a little behind, because it can't compute the // frame length until the end of the frame is reached. With a fixed // known // frame rate you could optimize things a bit and make the start/end // times // correspond exactly with real time. // m_clock.beginFrame(); // long started = m_clock.GetSystem(); // // Execute any time-based tasks // // (1) Pop the next task off the list. Since the list is always // sorted, the first item in the list is always the next task. // (2) Execute it and update times // (3) If it's expired, delete it // Otherwise, insert it into the list in its new position // TaskInfo pTaskInfo = null; TaskInfo save = m_pTaskList; pTaskInfo = getNextTimeTask(pTaskInfo); while (pTaskInfo != null) { m_clock.advanceTo(pTaskInfo.time.next); pTaskInfo.pTask.execute(pTaskInfo.id, m_clock.getTime(), pTaskInfo.pUser); pTaskInfo.time.last = pTaskInfo.time.next; pTaskInfo.time.next += pTaskInfo.time.period; pTaskInfo = getNextTimeTask(pTaskInfo); } m_pTaskList = save; pTaskInfo = m_pTaskList; while (pTaskInfo != null) { if (pTaskInfo.time.duration == 0 || pTaskInfo.time.duration >= pTaskInfo.time.next) { // re-insert into list with updated time // InsertTimeTask(pTaskInfo); } else { // task is expired, delete it // printf("Sched: Expired %d\n",pTaskInfo->id); // delete pTaskInfo; terminate(pTaskInfo.id); } pTaskInfo = pTaskInfo.pNext; } // // Advance simulation clock to end of frame // m_clock.advanceToEnd(); // // Now execute all frame tasks in round-robin fashion. // Frame tasks always execute at the end of the frame just // before rendering. A priority scheme could be used to // control sequence. It would be more efficient to keep the // list sorted, the same as with time tasks (exe // save = m_pFrameList; pTaskInfo = m_pFrameList; pTaskInfo = getNextFrameTask(pTaskInfo); // TaskInfo * pPrev = NULL; while (pTaskInfo != null) { pTaskInfo.pTask.execute(pTaskInfo.id, m_clock.getFrame(), pTaskInfo.pUser); pTaskInfo.time.last = pTaskInfo.time.next; pTaskInfo.time.next += pTaskInfo.time.period; pTaskInfo = getNextFrameTask(pTaskInfo); } m_pFrameList = save; // 检测是否有到期的任务 pTaskInfo = m_pFrameList; while (pTaskInfo != null) { if (pTaskInfo.time.duration == 0 || pTaskInfo.time.duration >= pTaskInfo.time.next) { // re-insert into list with updated time // InsertFrameTask(pTaskInfo); } else { // task is expired, delete it // printf("Sched: Expired %d\n",pTaskInfo->id); // delete pTaskInfo; terminate(pTaskInfo.id); } pTaskInfo = pTaskInfo.pNext; } m_pFrameList = save; // // render // if (renderTask.pTask != null) { renderTask.pTask.execute(renderTask.id, m_clock.getFrame(), renderTask.pUser); } // // here is where we could do idle processing or load balancing // // long elapsed = m_clock.GetSystem() - started; // long frameLength = m_clock.GetFrameEnd() - m_clock.GetFrameStart(); // printf("Busy %u ms, idle %u ms\n", elapsed, frameLength - elapsed); // // If any tasks are terminated during execution, it is easier to leave // them in the list until we're finished iterating through it, then // sweep // them out later. // // printf("EXEC END\n"); for (Long i : queue) { terminate(i); } sweepGarbage(); return 0; }