Real-Time Operating System (RTOS) Task Scheduler Plan

Interactive RTOS Scheduler Plan

Interactive RTOS Scheduler Plan

An interactive guide to the core concepts of a real-time scheduler.

${data.purpose}

    ${data.scope.map(item => `
  • ${item}
  • `).join('')}

Core Requirements

${data.requirements.map(req => `
✓

${req.title}

${req.text}

`).join('')}
`; } function buildDesignHTML() { const data = appData.design; return `

${data.title}

${data.intro}

${data.policy.title}

Preemptive: ${data.policy.preemptive}

Fixed-Priority: ${data.policy.fixedPriority}

${data.algorithm.title}

${data.algorithm.desc}

  • RM Policy: ${data.algorithm.rmPolicy}
  • Benefit: ${data.algorithm.benefit}

Note: ${data.algorithm.note}

`; } function buildStructuresHTML() { const data = appData.structures; return `

${data.title}

${data.intro}

${data.tcb.title}

${data.tcb.desc}

// Task Control Block
struct TCB {
${data.tcb.fields.map(field => `     void*   ${field.name}; // ${field.text}
`).join('')} };

${data.readyQueue.title}

${data.readyQueue.implementation}

    ${data.readyQueue.details.map(item => `
  • ${item}
  • `).join('')}

${data.readyQueue.benefit}

Ready Queue Diagram

Prio[0]
TCB_A → TCB_C
Prio[1]
null
Prio[2]
TCB_B
`; } function buildStatesHTML() { const data = appData.states; let html = `

${data.title}

${data.intro}

${data.states[0].name}
${data.states[1].name}
${data.states[2].name}
${data.states[3].name}
${data.states[4].name}
Scheduled
Preempted
Event Wait
Event Ready
Suspend
Resume
${data.states.map((state, index) => `

${state.name}

${state.desc}

`).join('')}
`; return html; } function buildOperationsHTML() { const data = appData.operations; return `

${data.title}

${data.intro}

${data.scheduler.title}

${data.scheduler.desc}

    ${data.scheduler.steps.map(step => `
  1. ${step}
  2. `).join('')}

${data.contextSwitch.title}

${data.contextSwitch.desc}

Context Switch: Step-by-Step

Task A (pCurrentTask)
CPU Registers
↓
Stack A
Task B (pNextTaskToRun)
CPU Registers
↑
Stack B
${data.contextSwitch.steps.map((step, index) => `
${step.title}: ${step.text}
`).join('')}

${data.sysTick.title}

${data.sysTick.desc}

    ${data.sysTick.steps.map(step => `
  1. ${step}
  2. `).join('')}
`; } function buildInversionHTML() { const data = appData.inversion; return `

${data.title}

${data.intro}

${data.problem.title}

${data.problem.desc}

Task H (Blocked)
Task M (RUNNING)
Task L (Ready)
Task H (High Prio): Blocked, waiting for mutex held by Task L.
Task M (Medium Prio): RUNNING, preempting Task L.
Task L (Low Prio): Ready, but starved by Task M.
`; } function buildTestingHTML() { const data = appData.testing; return `

${data.title}

${data.intro}

${data.plans.map(plan => `

${plan.title}

    ${plan.items.map(item => `
  • ${item}
  • `).join('')}
`).join('')}
`; } // --- 3. EVENT HANDLER ATTACHMENT FUNCTIONS --- function attachStateDiagramListeners() { const stateBoxes = document.querySelectorAll('.state-box'); const stateDescs = document.querySelectorAll('.state-desc'); stateBoxes.forEach(box => { box.addEventListener('click', () => { const targetState = box.dataset.state; // Toggle active class on boxes stateBoxes.forEach(b => b.classList.remove('active-state')); box.classList.add('active-state'); // Show/hide descriptions stateDescs.forEach(desc => { if (desc.dataset.descFor === targetState) { desc.classList.add('active-desc'); } else { desc.classList.remove('active-desc'); } }); }); }); // Pre-activate the first one document.querySelector('.state-box[data-state="running"]')?.classList.add('active-state'); } function attachOperationsListeners() { const opTabs = document.querySelectorAll('.op-tab'); const opContents = document.querySelectorAll('.op-content'); opTabs.forEach(tab => { tab.addEventListener('click', () => { const targetOp = tab.dataset.op; opTabs.forEach(t => { t.classList.remove('active', 'text-sky-700', 'border-sky-700'); t.classList.add('text-stone-500', 'border-transparent'); }); tab.classList.add('active', 'text-sky-700', 'border-sky-700'); tab.classList.remove('text-stone-500', 'border-transparent'); opContents.forEach(content => { content.style.display = content.dataset.opContent === targetOp ? 'block' : 'none'; }); }); }); attachContextSwitchListeners(); } function attachContextSwitchListeners() { const nextBtn = document.getElementById('ctx-next-step'); if (!nextBtn) return; let currentStep = 1; const totalSteps = 6; const highlightIds = [ [], // Step 0 (dummy) ['ctx-task-a', 'ctx-task-b'], // 1. Trigger ['ctx-task-a', 'ctx-regs-a', 'ctx-stack-a'], // 2. Save Context ['ctx-task-a'], // 3. Update State ['ctx-task-a', 'ctx-task-b'], // 4. Switch TCBs ['ctx-task-b', 'ctx-regs-b', 'ctx-stack-b'], // 5. Load Context ['ctx-task-b', 'ctx-regs-b'] // 6. Resume ]; nextBtn.addEventListener('click', () => { currentStep = (currentStep % totalSteps) + 1; // Update step text document.querySelectorAll('.step-desc').forEach(desc => { desc.classList.toggle('active-step', desc.dataset.step == currentStep); }); // Update diagram highlights document.querySelectorAll('.context-box').forEach(box => box.classList.remove('step-highlight')); if (highlightIds[currentStep]) { highlightIds[currentStep].forEach(id => { document.getElementById(id)?.classList.add('step-highlight'); }); } if (currentStep === totalSteps) { nextBtn.textContent = "Reset Steps"; } else { nextBtn.textContent = "Next Step"; } }); } function attachInversionListeners() { const problemBtn = document.getElementById('show-problem'); const solutionBtn = document.getElementById('show-solution'); const problemDiagram = document.getElementById('problem-diagram'); const solutionDiagram = document.getElementById('solution-diagram'); const toggles = [problemBtn, solutionBtn]; if (!problemBtn) return; problemBtn.addEventListener('click', () => { problemDiagram.style.display = 'block'; solutionDiagram.style.display = 'none'; problemBtn.classList.add('active', 'bg-sky-600', 'text-white'); problemBtn.classList.remove('bg-white', 'text-stone-700', 'border'); solutionBtn.classList.remove('active', 'bg-sky-600', 'text-white'); solutionBtn.classList.add('bg-white', 'text-stone-700', 'border'); }); solutionBtn.addEventListener('click', () => { problemDiagram.style.display = 'none'; solutionDiagram.style.display = 'block'; solutionBtn.classList.add('active', 'bg-sky-600', 'text-white'); solutionBtn.classList.remove('bg-white', 'text-stone-700', 'border'); problemBtn.classList.remove('active', 'bg-sky-600', 'text-white'); problemBtn.classList.add('bg-white', 'text-stone-700', 'border'); }); } // --- 4. MAIN RENDER FUNCTION --- const contentPane = document.getElementById('content-pane'); const navTabs = document.querySelectorAll('.nav-tab'); function renderContent(tabId) { // Clear existing content contentPane.innerHTML = ''; let html = ''; switch (tabId) { case 'overview': html = buildOverviewHTML(); break; case 'design': html = buildDesignHTML(); break; case 'structures': html = buildStructuresHTML(); break; case 'states': html = buildStatesHTML(); break; case 'operations': html = buildOperationsHTML(); break; case 'inversion': html = buildInversionHTML(); break; case 'testing': html = buildTestingHTML(); break; default: html = buildOverviewHTML(); } contentPane.innerHTML = html; // Attach listeners for content *after* it's in the DOM if (tabId === 'states') attachStateDiagramListeners(); if (tabId === 'operations') attachOperationsListeners(); if (tabId === 'inversion') attachInversionListeners(); } // --- 5. INITIALIZATION & NAVIGATION BINDING --- navTabs.forEach(tab => { tab.addEventListener('click', (e) => { // Update tab visual state navTabs.forEach(t => t.classList.remove('active')); e.target.classList.add('active'); // Render content const tabId = e.target.dataset.tab; renderContent(tabId); }); }); // Initial render renderContent('overview'); });
Scroll to Top