📄 ucos.c
字号:
return(OS_PRIO_EXIST); } /* ELSE */ /* check if old priority task exists */ if (OSTCBPrioTbl[oldp] == (OS_TCB *)0) { OS_EXIT_CRITICAL(); return(OS_PRIO_ERR); /* Task to change didn't exist */ } /* ELSE */ ptcb = OSTCBPrioTbl[oldp]; /* get the ptcb first! GIC 94Jul11 */ OSTCBPrioTbl[oldp] = (OS_TCB *)0; /* Remove TCB from old priority */ pevent = ptcb->OSTCBEventPtr; /* Get pointer to event control block */ if (OSRdyTbl[ptcb->OSTCBY] & ptcb->OSTCBBitX) /* if task is ready make it not ready */ { if ((OSRdyTbl[ptcb->OSTCBY] &= ~ptcb->OSTCBBitX) == 0) { OSRdyGrp &= ~(ptcb->OSTCBBitY); } rdy = TRUE; } else { rdy = FALSE; if (pevent != (OS_EVENT *)0) /* remove from event wait list */ { if ((pevent->OSEventTbl[ptcb->OSTCBY] &= ~ptcb->OSTCBBitX) == 0) { pevent->OSEventGrp &= ~ptcb->OSTCBBitY; } } } if (ptcb->OSTCBPrev == (OS_TCB *)0) /* remove from TCB linked list */ { ptcb->OSTCBNext->OSTCBPrev = (OS_TCB *)0; OSTCBList = ptcb->OSTCBNext; } else { ptcb->OSTCBPrev->OSTCBNext = ptcb->OSTCBNext; ptcb->OSTCBNext->OSTCBPrev = ptcb->OSTCBPrev; } OS_EXIT_CRITICAL(); ptcb->OSTCBPrio = newp; /* setup task control block with new values */ ptcb->OSTCBY = newp >> 3; ptcb->OSTCBBitY = OSMapTbl[newp >> 3]; ptcb->OSTCBX = newp & 0x07; ptcb->OSTCBBitX = OSMapTbl[newp & 0x07]; OS_ENTER_CRITICAL(); /* make new priority ready to run if old one was ready */ if (rdy) /* if task was ready ... */ { OSRdyGrp |= ptcb->OSTCBBitY; /* ...make new priority ready to run */ OSRdyTbl[ptcb->OSTCBY] |= ptcb->OSTCBBitX; } else { if (pevent != (OS_EVENT *)0) /* wait for event if old was waiting */ { pevent->OSEventTbl[ptcb->OSTCBY] |= ptcb->OSTCBBitX; pevent->OSEventGrp |= ptcb->OSTCBBitY; } } OSTCBPrioTbl[newp] = ptcb; /* place TCB pointer at the new priority */ OSTCBList->OSTCBPrev = ptcb; /* link TCB to the top of the list */ OSTCBList = ptcb; /* assuming the idle task is in the list */ OS_EXIT_CRITICAL(); OSSched(); /* run highest priority task ready */ return(OS_NO_ERR);} /* OSTaskChangePrio *//* * O S T a s k D e l * * delete a task * * NOTE: VLSI rearrange the logic so that the ELSE is implied */int OSTaskDel(uint prio){ OS_EVENT *pevent; /* VLSI org prefixed with 'register' */ OS_TCB *ptcb; /* VLSI org prefixed with 'register' */ if (prio == OS_LO_PRIO) { return(OS_TASK_DEL_IDLE); /* not allowed to delete idle task */ } /* ELSE */ OS_ENTER_CRITICAL(); if (OSTCBPrioTbl[prio] == (OS_TCB *)0) /* does task to delete exist ? */ { OS_EXIT_CRITICAL(); return(OS_TASK_DEL_ERR); /* NO */ } /* ELSE task exists */ ptcb = OSTCBPrioTbl[prio]; OSTCBPrioTbl[prio] = (OS_TCB *)0; /* clear old TCB entry */ if ((OSRdyTbl[ptcb->OSTCBY] &= ~(ptcb->OSTCBBitX)) == 0) { OSRdyGrp &= ~(ptcb->OSTCBBitY); /* make task not ready */ } if (ptcb->OSTCBPrev == (OS_TCB *)0) { ptcb->OSTCBNext->OSTCBPrev = (OS_TCB *)0; /* remove from TCB linked list */ OSTCBList = ptcb->OSTCBNext; } else { ptcb->OSTCBPrev->OSTCBNext = ptcb->OSTCBNext; ptcb->OSTCBNext->OSTCBPrev = ptcb->OSTCBPrev; } /* if task waiting on event remove it from event control block */ if ((pevent = ptcb->OSTCBEventPtr) != (OS_EVENT *)0) { if ((pevent->OSEventTbl[ptcb->OSTCBY] &= ~ptcb->OSTCBBitX) == 0) { pevent->OSEventGrp &= ~(ptcb->OSTCBBitY); } } ptcb->OSTCBNext = OSTCBFreeList; /* return TCB to the free list */ OSTCBFreeList = ptcb; OS_EXIT_CRITICAL(); OSSched(); /* find new highest priority task */ return(OS_NO_ERR);} /* OSTaskDel *//* * O S T i m e D l y * * delay the current task */void OSTimeDly(uint ticks){ if( ticks > 0 ) /* GIC 94Jul11 restored as per manual */ { OS_ENTER_CRITICAL(); /* suspend the current task */ if ((OSRdyTbl[OSTCBCur->OSTCBY] &= ~OSTCBCur->OSTCBBitX) == 0) { OSRdyGrp &= ~OSTCBCur->OSTCBBitY; /* then group not ready */ } OSTCBCur->OSTCBDly = ticks; /* load number of ticks in TCB */ OS_EXIT_CRITICAL(); OSSched(); /* find a new task to run */ }} /* OSTimeDly *//****************************************************************************** * O S T i m e T i c k * * This is an IRQ interrupt routine. Only FIQ might be enabled. * * process system tick * * The code here differs from the manual in that if you are using a Timer * and it is an IRQ then a context switch is set up and the code to change * context has been added here. In the ARM one normally finds that the natural * order is USER mode (except for system calls) which can be interrupted by * IRQ which in turn could be interrupted by an FIQ. On a PID the FIQ is not * used except with an extender board. An IRQ is NOT normally nestable. Upon * entry the I bit is set. If you reset this bit prior to removing the cause * of the IRQ your program will lock up in an endless loop. If you reset this * bit prior to saving your context (or at least your lr_irq) your program * will get lost. */void OSTimeTick(void){ OS_TCB *ptcb; /* VLSI org prefixed with 'register' */ uint y; /* VLSI org is 'register UBYTE y' */#if 0 /* see the comment in the OSIntEnter routine */ OS_ENTER_CRITICAL();#endif OSTime++; /* Always increment on a TICK */ if( OSRunning ) /* scan all TCB in list */ { for (ptcb = OSTCBList; ptcb->OSTCBPrio != OS_LO_PRIO; ptcb = ptcb->OSTCBNext) { if (ptcb->OSTCBDly > 0) { if (--ptcb->OSTCBDly == 0) { /* make task ready to run */ OSRdyGrp |= ptcb->OSTCBBitY; /* be sure group is ready */ OSRdyTbl[ptcb->OSTCBY] |= ptcb->OSTCBBitX; /* and task is ready */ } } } if (OSLockNesting == 0 && OSIntNesting == 0) /* VLSI task scheduling enabled and not interrupt level */ { y = OSUnMapTbl[OSRdyGrp]; /* get pointer to highest task ready to run */ OSTCBHighRdy = OSTCBPrioTbl[(y << 3) + OSUnMapTbl[OSRdyTbl[y]]]; if (OSTCBHighRdy != OSTCBCur) /* make sure this is not the current running task */ { OSCtxSwCtr++; /* increment context switch counter */ } } }#if 0 /* see the comment in the OSIntEnter routine */ OS_EXIT_CRITICAL();#endif} /* OSTimeTick *//* * O S T i m e S e t * * set system time */void OSTimeSet(uint ticks){ OS_ENTER_CRITICAL(); OSTime = ticks; OS_EXIT_CRITICAL();}/* * O S T i m e G e t * * get system time * * NOTE: The manual suggests that OS_ENTER_CRITICAL and OS_EXIT_CRITICAL be used * but unless a process is setting the time while this one is trying * to read it (or even then?), it seems like one should be able to * read without using CRITICAL macros. */uint OSTimeGet(void){ return(OSTime);}/* * O S S e m C r e a t e * * create a semaphore * * NOTE: VLSI rearrange the logic so that the ELSE is implied */OS_EVENT *OSSemCreate(int cnt){ OS_EVENT *pevent; /* VLSI org prefixed with 'register' */ OS_ENTER_CRITICAL(); pevent = OSEventFreeList; /* get next available event CB */ /* update free list */ if (OSEventFreeList) /* See if pool of free ECB pool was empty */ { OSEventFreeList = (OS_EVENT *)OSEventFreeList->OSEventPtr; } OS_EXIT_CRITICAL(); if (pevent == (OS_EVENT *)0) { return((OS_EVENT *)0); /* ran out of event CB */ } /* ELSE */ if (cnt < 0) /* semaphore cannot start negative */ { OS_ENTER_CRITICAL(); /* return event CB back to the free list */ pevent->OSEventPtr = (void *)OSEventFreeList; OSEventFreeList = pevent; OS_EXIT_CRITICAL(); return((OS_EVENT *)0); } /* ELSE */ /* set semaphore values */ pevent->OSEventCnt = cnt; pevent->OSEventGrp = 0; pevent->OSEventTbl[0] = 0; pevent->OSEventTbl[1] = 0; pevent->OSEventTbl[2] = 0; pevent->OSEventTbl[3] = 0; pevent->OSEventTbl[4] = 0; pevent->OSEventTbl[5] = 0; pevent->OSEventTbl[6] = 0; pevent->OSEventTbl[7] = 0; return(pevent);}/* * O S S e m P e n d * * wait semaphore * * NOTE: VLSI rearrange the logic so that the ELSE is implied */void OSSemPend(OS_EVENT *pevent, uint timeout, uint *err){ OS_ENTER_CRITICAL(); if (pevent->OSEventCnt-- > 0) { OS_EXIT_CRITICAL(); /* resource available */ *err = OS_NO_ERR; return; } /* ELSE resource not available, sleep on semaphore */ OSTCBCur->OSTCBStat = OS_STAT_SEM; /* pend on semaphore */ OSTCBCur->OSTCBDly = timeout; /* store pend timeout in TCB */ /* suspend task */ if ((OSRdyTbl[OSTCBCur->OSTCBY] &= ~OSTCBCur->OSTCBBitX) == 0) { OSRdyGrp &= ~OSTCBCur->OSTCBBitY; /* Task no longer ready */ } pevent->OSEventTbl[OSTCBCur->OSTCBY] |= OSTCBCur->OSTCBBitX; /* put task in waiting list */ pevent->OSEventGrp |= OSTCBCur->OSTCBBitY; OS_EXIT_CRITICAL(); OSSched(); /* find next task ready to run */ OS_ENTER_CRITICAL(); if (OSTCBCur->OSTCBStat == OS_STAT_SEM) /* must have timed out if still waiting for event */ { /* still pending on semaphore: timeout */ if ((pevent->OSEventTbl[OSTCBCur->OSTCBY] &= ~OSTCBCur->OSTCBBitX) ==0) { pevent->OSEventGrp &= ~OSTCBCur->OSTCBBitY; } OSTCBCur->OSTCBStat = OS_STAT_RDY; /* set status to ready */ OSTCBCur->OSTCBEventPtr = (OS_EVENT *)0; /* no longer waiting for event */ OS_EXIT_CRITICAL(); *err = OS_TIMEOUT; /* signal time'ed out */ } else { OSTCBCur->OSTCBEventPtr = (OS_EVENT *)0; OS_EXIT_CRITICAL(); *err = OS_NO_ERR; }}/* * O S S e m P o s t * * signal semaphore */uint OSSemPost(OS_EVENT *pevent){ OS_ENTER_CRITICAL(); if (pevent->OSEventCnt >= INT_MAX) /* VLSI INT_MAX defined in OSDEFS.H */ { OS_EXIT_CRITICAL(); /* semaphore overflow */ return(OS_SEM_OVF); } /* ELSE */ if (pevent->OSEventCnt++ >= 0) { OS_EXIT_CRITICAL(); } else /* negative semaphore means tasks pending */ { if (pevent->OSEventGrp) /* see if any task pending on semaphore */ { OS_EXIT_CRITICAL(); OSEventTaskResume(pevent); /* resume highest priority task pending on semaphore */ OSSched(); /* find highest priority task ready to run */ } } return(OS_NO_ERR);}/* * O S M b o x C r e a t e * * create mailbox */OS_EVENT *OSMboxCreate(void *msg){ OS_EVENT *pevent; OS_ENTER_CRITICAL(); pevent = OSEventFreeList; /* get next available event CB */ /* update free list */ if (OSEventFreeList) /* see if pool of free ECB pool was empty */ { OSEventFreeList = (OS_EVENT *)OSEventFreeList->OSEventPtr; } OS_EXIT_CRITICAL(); if (pevent != (OS_EVENT *)0) { pevent->OSEventPtr = msg; /* set mailbox values */ pevent->OSEventGrp = 0; pevent->OSEventTbl[0] = 0; pevent->OSEventTbl[1] = 0; pevent->OSEventTbl[2] = 0; pevent->OSEventTbl[3] = 0; pevent->OSEventTbl[4] = 0; pevent->OSEventTbl[5] = 0; pevent->OSEventTbl[6] = 0; pevent->OSEventTbl[7] = 0; } return(pevent);}/* * O S M b o x P e n d * * pend for mbox message */void *OSMboxPend(OS_EVENT *pevent, uint timeout, uint *err){ void *msg; OS_ENTER_CRITICAL(); /* check if the mailbox already has a message */ if ((msg = pevent->OSEventPtr) != (void *)0) /* already a message ? */ { pevent->OSEventPtr = (void *)0; /* clear the mailbox */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -