📄 scheduler.c
字号:
/** * Copyright (c) 2006-2008 iWESUN (ShenZhen) Inf. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the AvrcX MTOS * * Author: Winter Hu <winter.hu@gmail.com> * Create: Nov 28, 2006 *//*Changlog:Jan 4, 2007, Re-write sleep methods in assembler*/#include "scheduler.h"/* Kernel data */KernelData kernel;/** * Initizlize Scheduler * This must be invoked before tasks schedulling */void init_scheduler(void){ into_critical(); kernel.RunQueue.head = NULL; kernel.TimerQueue.head = NULL; kernel.BlockedQueue = NULL; kernel.Running = NULL; kernel.Context = (void*) SP+2; kernel.TmSlices= 0x00; kernel.SysLevel= 0; // Default is kernel mode kernel.SysTicks= 0L;}/** * Start scheduler * This method never return */void start(void){ TCCR0 = TMC8_CK256; TCNT0 = TCNT0_INIT; TIMSK |= _BV(TOIE0); into_critical(); kernel.SysLevel = USER_MODE; prologue(); // Save context swapping(); // Swap a task from RunQueue to kernel epilogue(); // Restore context}/** * Create and resume the task into RunQueue * * @param TCB*, The pointer to the Task Control Block */void run_task(TCB* tcb){ resume_task(create_task(tcb));}/** * Retrieves current running task * * @return PID*, the pointer to the current running task PID */PID* get_running(void){ return kernel.Running;}/** * Retreives system ticks * * @return unsigned long, The ticks from power on */unsigned long get_systicks(void){ return kernel.SysTicks;}/** * Causes the currently executing task to temporarily pause and allow * other tasks to execute. */void yield(void) { into_critical(); prologue(); // Save current task PID locally PID* pid = kernel.Running; // Swap a new task PID from RunQueue swapping(); // Re-schedule previous task resume_task(pid); epilogue();}/** * Causes the currently executing task to temporarily pause in TimQueue * until delay expire. * * @param unsigned int, Ticks for sleeping */// Jan 4, 2007 Implements in assembler// @see scheduler.asm.S/*void NAKED sleep(unsigned int ticks){ into_critical(); prologue(); delayTask(kernel.Running, ticks); swapping(); epilogue();}*//** * Swap the first PID from RunQueue to current env */void swapping(void){ kernel.Running = remove_first(&(kernel.RunQueue)); if (kernel.Running != NULL){ kernel.TmSlices = ((PCB*)(kernel.Running->pData))->tmslices; }}/** * Insert the PID into RunQueue * * @param PID*, The pointer to the PID */void resume_task(PID* pid){ if (pid != NULL){ PCB* pcb = (PCB*)(pid->pData); pid->priority = pcb->priority; pcb->timer.pid= pid; pcb->tid.pData= &(pcb->timer); insert_ordered(&(kernel.RunQueue), pid); //insert_relative(&(kernel.RunQueue), pid); }}/** * Insert the PID into TimerQueue * * @param PID*, The pointer to the PID * @param unsigned int, The ticks to delay */void delay_task(PID* pid, unsigned int ticks){ PCB* pcb = (PCB*)(pid->pData); pcb->status |= TASK_DELAY; if (ticks <= MAX_WAIT_TICKS){ pcb->tid.priority = (unsigned char)ticks; pcb->timer.ticks = 0; }else{ pcb->tid.priority = MAX_WAIT_TICKS; pcb->timer.ticks = ticks - MAX_WAIT_TICKS; } insert_relative(&(kernel.TimerQueue), &(pcb->tid));}void resume_delay(TID*);/** ISR for Timer0 overflow */void NAKED SIG_OVERFLOW0(void);void SIG_OVERFLOW0(void){ into_critical(); prologue(); TCNT0 = TCNT0_INIT; // Increments system ticks kernel.SysTicks++; // Check task delay in TimerQueue TID* tid = get_first(&(kernel.TimerQueue)); if (tid != NULL) resume_delay(tid); PID *pid = kernel.Running; if (pid != NULL){ kernel.TmSlices--; if (kernel.TmSlices <= 0){ // Time slice is exhausted, so swap to next task swapping(); if (kernel.Running != NULL){ resume_task(pid); }else{ kernel.Running = pid; kernel.TmSlices = ((PCB*)(pid->pData))->tmslices; } } }else{ swapping(); } epilogue();}void resume_delay(TID* tid){ PID* pid = ((TSTimer*)(tid->pData))->pid; PCB* pcb = (PCB*)(pid->pData); tid->priority = (tid->priority > 0) ? tid->priority - 1 : 0; if (tid->priority > 0) return; // tid->priority == 0 tid = remove_first(&(kernel.TimerQueue)); TSTimer* tt = (TSTimer*)(tid->pData); if (tt->ticks > 0){ delay_task(pid, tt->ticks); return; } // It's time to wakeup and preemptive pcb->status &= ~TASK_DELAY; if (kernel.Running != NULL){ if (pcb->priority >= ((PCB*)(kernel.Running->pData))->priority){ resume_task(pid); }else{ // preemptived resume_task(kernel.Running); kernel.Running = pid; kernel.TmSlices= pcb->tmslices + 1; } }else{// kernel.Running == NULL kernel.Running = pid; kernel.TmSlices= pcb->tmslices + 1; }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -