Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
2012 / uCOS / uCOSII_ebook.pdf
Скачиваний:
70
Добавлен:
10.02.2015
Размер:
1.08 Mб
Скачать

OS_EXIT_CRITICAL(); return (OS_TASK_DEL_ISR);

}

 

 

if (prio == OS_PRIO_SELF) {

(4)

prio = OSTCBCur->OSTCBPrio;

 

}

 

 

if ((ptcb = OSTCBPrioTbl[prio]) != (OS_TCB *)0) {

(5)

if ((OSRdyTbl[ptcb->OSTCBY] &= ~ptcb->OSTCBBitX) == 0) {

(6)

OSRdyGrp &= ~ptcb->OSTCBBitY;

 

}

 

 

if ((pevent = ptcb->OSTCBEventPtr) != (OS_EVENT *)0) {

(7)

if ((pevent->OSEventTbl[ptcb->OSTCBY] &= ~ptcb->OSTCBBitX) == 0) {

pevent->OSEventGrp &= ~ptcb->OSTCBBitY;

 

}

 

 

}

 

 

ptcb->OSTCBDly

= 0;

(8)

ptcb->OSTCBStat = OS_STAT_RDY;

(9)

OSLockNesting++;

(10)

OS_EXIT_CRITICAL();

(11)

OSDummy();

 

(12)

OS_ENTER_CRITICAL();

 

OSLockNesting--;

(13)

OSTaskDelHook(ptcb);

(14)

OSTaskCtr--;

 

 

OSTCBPrioTbl[prio] = (OS_TCB *)0;

(15)

if (ptcb->OSTCBPrev == (OS_TCB *)0) {

(16)

ptcb->OSTCBNext->OSTCBPrev = (OS_TCB *)0;

 

OSTCBList

= ptcb->OSTCBNext;

 

} else {

 

 

ptcb->OSTCBPrev->OSTCBNext = ptcb->OSTCBNext;

 

ptcb->OSTCBNext->OSTCBPrev = ptcb->OSTCBPrev;

 

}

 

 

ptcb->OSTCBNext = OSTCBFreeList;

(17)

OSTCBFreeList

= ptcb;

 

OS_EXIT_CRITICAL();

 

OSSched();

 

(18)

return (OS_NO_ERR);

 

} else {

 

 

OS_EXIT_CRITICAL(); return (OS_TASK_DEL_ERR);

}

}

Listing 4.11, Task Delete

4.05 Requesting to delete a task, OSTaskDelReq()

Sometimes, a task may own resources such as a memory buffers or a semaphore. If another task attempts to delete this task then, the resource would not be freed and thus would be lost. In this type of situation, you would need to somehow signal the task that owns these resources to tell it to delete itself when it’s done with the resources. You can accomplish this with the OSTaskDelReq() function.

Both the requestor and the task to be deleted need to call OSTaskDelReq(). The requestor code would look as shown in listing 4.12. The task that makes the request needs to determine what condition(s) will cause a request for the task to be deleted L4.12(1). In other words, your application will determine what condition(s) will lead to this decision. If the task needs to be deleted then you call OSTaskDelReq() by passing the priority of the task to be deleted L4.12(2). If the task to delete does not exist then OSTaskDelReq() returns OS_TASK_NOT_EXIST. You would get this if the task to delete has already been deleted or, it has not been created yet. If the return value isOS_NO_ERR then, the request has been accepted but the task has not been deleted yet. You may want to wait until the task to be

deleted does in fact delete itself. You can do this by delaying the requestor for a certain amount of time like I did in L4.12(3). I decided to delay for one tick but you can certainly wait longer if needed. When the requested task eventually deletes itself, the return value in L4.12(2) would be OS_TASK_NOT_EXIST and the loop would exit L4.12(4).

void RequestorTask (void *pdata)

{

INT8U err;

 

pdata = pdata;

 

for (;;) {

 

/* Application code */

 

if (‘TaskToBeDeleted()’ needs to be deleted) {

(1)

while (OSTaskDelReq(TASK_TO_DEL_PRIO) != OS_TASK_NOT_EXIST) {

(2)

OSTimeDly(1);

(3)

}

 

}

 

/* Application code */

(4)

}

 

}

Listing 4.12, Requesting a task to delete itself.

The code for the task that needs to delete itself is shown in listing 4.13. This task basically needs to ‘poll’a flag that resides inside the task’s OS_TCB. The value of this flag is obtained by calling OSTaskDelReq(OS_PRIO_SELF). When OSTaskDelReq() returns OS_TASK_DEL_REQ L4.13(1) to its caller, it indicates that another task has

requested that this task needs to be deleted. In this case, the task to be deleted releases any resources owned L4.13(2) and calls OSTaskDel(OS_PRIO_SELF) to delete itself L4.13(3). As previously mentioned, the code for the task is not actually deleted. Instead, µC/OS-II will simply not schedule the task for execution. In other word, the task code will no longer run. You can, however, re -create the task by calling either OSTaskCreate() or

OSTaskCreateExt().

void TaskToBeDeleted (void *pdata)

{

INT8U err;

 

pdata = pdata;

 

for (;;) {

 

/* Application code */

 

if (OSTaskDelReq(OS_PRIO_SELF) == OS_TASK_DEL_REQ) {

(1)

Release any owned resources;

(2)

De-allocate any dynamic memory;

 

OSTaskDel(OS_PRIO_SELF);

(3)

} else {

 

/* Application code */

}

}

}

Listing 4.13, Requesting a task to delete itself.

The code forOSTaskDelReq() is shown in listing 4.14. As usual, we need to check for boundary conditions. First,

we notify the caller in case he requests to delete the idle task L4.14(1). Next, we trying to request to delete an invalid priority L4.14(2). If the caller is the task to OS_TCBwill be returned L4.14(3). If you specified a task with a priority other than

must ensure that the caller is not be deleted, the flag stored in the OS_PRIO_SELF then, if the task

exist L4.14(4),

we set the internal

flag for that task L4.14(5). If the task does

not exist, we return

OS_TASK_NOT_EXIST to indicate that the task must have deleted itself L4.14(6).

 

 

 

INT8U OSTaskDelReq (INT8U prio)

 

{

stat;

 

 

BOOLEAN

 

 

INT8U

err;

 

 

OS_TCB

*ptcb;

 

 

if (prio == OS_IDLE_PRIO) {

(1)

return (OS_TASK_DEL_IDLE);

 

}

 

 

 

if (prio >= OS_LOWEST_PRIO && prio != OS_PRIO_SELF) {

(2)

return (OS_PRIO_INVALID);

 

}

 

 

 

if (prio == OS_PRIO_SELF) {

(3)

OS_ENTER_CRITICAL();

 

 

stat = OSTCBCur->OSTCBDelReq;

 

OS_EXIT_CRITICAL();

 

 

return (stat);

 

 

} else {

 

 

 

OS_ENTER_CRITICAL();

 

 

if ((ptcb = OSTCBPrioTbl[prio]) != (OS_TCB *)0) {

(4)

 

ptcb->OSTCBDelReq = OS_TASK_DEL_REQ;

(5)

 

err

= OS_NO_ERR;

 

} else {

= OS_TASK_NOT_EXIST;

(6)

}

err

 

 

 

OS_EXIT_CRITICAL();

 

 

return (err);

 

 

}

 

 

 

}

 

 

 

Listing 4.14, OSTaskDelReq().

4.06 Changing a Task’s Priority, OSTaskChangePrio()

When you create a task, you assign the task a priority. At run-time, you can change the priority of any task by calling OSTaskChangePrio(). In other words, µC/OS-II allows you to change priorities dynamically.

The code for OSTaskChangePrio() is shown in listing 4.15. You cannot change the priority of the idle task

L4.15(1). You can either change the priority of the calling task or another task. To change the priority of the calling task you can must either specify the ‘old’ priority of that task or specify OS_PRIO_SELF and OSTaskChangePrio() will determine what the priority of the calling task is for you. You must also specify the ‘new’(i.e. desired) priority. Because µC/OS -II cannot have multiple tasks running at the same priority, we need to

check that the desired priority is available L4.15(2). If the desired priority is available, µC/OS-II reserves the priority by loading ‘something’in the OSTCBPrioTbl[] thus reserving that entry L4.15(3). This allows us to re-enable

interrupts and know that no other task can either create a task at the desired priority or have another task call OSTaskChangePrio() by specifying the same ‘new’priority. This is done so that we can pre -compute some

values that will be stored in the task’s OS_TCB L4.15(4). These values are used to put or remove the task in or from the ready list (s ee section 3.04, Ready List).

We then check to see if the current task is attempting to change its priority L4.15(5). Next, we need to see if the task for which we are trying to change the priority exist L4.15(6). Obviously, if it’s the current task then this test will succeed. However, if we are trying to change the priority of a task that doesn’t exist then, we must relinquish the ‘reserved’priority back to the priority table, OSTCBPrioTbl[] L4.15(17), and return an error code to the caller.

We now remove the pointer to the OS_TCB of the task from the priority table by inserting a NULL pointer L4.15(7).

This will make the ‘old’priority available for reuse. Then, we check to see if the task for which we are changing the priority is ready-to-run L4. 15(8). If it is, it must be removed from the ready list at the current priority L4.15(9) and inserted back in the ready list at the new priority L4.15(10). Note here that we use our pre -computed values L4.15(4) to insert the task in the ready list.

Ift he task is ready then, it could be waiting on a semaphore, a mailbox or a queue. We know that the task is waiting for one of these events if the OSTCBEventPtr is non-NULL L4.15(11). If the task is waiting for an event, we must remove the task from the wa it list (at the old priority) of the event control block (see section 6.00,Event Control Block) and insert the task back in the wait list but this time at the new priority L4.15(12). The task could be waiting for time to expire (see chapter 5, Time Management) or the task could be suspended (see section 4.07, Suspending a Task, OSTaskSuspend()). In these cases, items L4.15(8) through L4.15(12) would be skipped.

Next, we store a pointer to the task’s OS_TCB in the priority table, OSTCBPrioTbl[] L4.15(13). The new priority is saved in the OS_TCB L4.15(14) and the pre -computed values are also saved in the OS_TCB L4.15(15). After we

exit the critical section, the scheduler is called in case the new priority is higher than the old priority or the priority of the calling task L4.15(16).

INT8U OSTaskChangePrio (INT8U oldprio, INT8U newprio)

{

OS_TCB

*ptcb;

OS_EVENT *pevent;

INT8U

x;

INT8U

y;

INT8U

bitx;

INT8U

bity;

if ((oldprio >= OS_LOWEST_PRIO && oldprio != OS_PRIO_SELF) ||

(1)

newprio >= OS_LOWEST_PRIO) {

 

return (OS_PRIO_INVALID);

 

}

 

 

 

OS_ENTER_CRITICAL();

 

 

if (OSTCBPrioTbl[newprio] != (OS_TCB *)0) {

(2)

OS_EXIT_CRITICAL();

 

 

return (OS_PRIO_EXIST);

 

} else {

 

 

 

OSTCBPrioTbl[newprio] = (OS_TCB *)1;

(3)

OS_EXIT_CRITICAL();

 

 

y

= newprio >> 3;

(4)

bity = OSMapTbl[y];

 

 

x

= newprio & 0x07;

 

bitx = OSMapTbl[x];

 

 

OS_ENTER_CRITICAL();

 

if (oldprio == OS_PRIO_SELF) {

(5)

}

oldprio = OSTCBCur->OSTCBPrio;

 

 

 

 

if ((ptcb = OSTCBPrioTbl[oldprio]) != (OS_TCB *)0) {

(6)

 

OSTCBPrioTbl[oldprio] = (OS_TCB *)0;

(7)

 

if (OSRdyTbl[ptcb->OSTCBY] & ptcb->OSTCBBitX) {

(8)

 

if ((OSRdyTbl[ptcb->OSTCBY] &= ~ptcb->OSTCBBitX) == 0) {

(9)

 

OSRdyGrp &= ~ptcb->OSTCBBitY;

 

 

}

 

 

 

OSRdyGrp

|= bity;

(10)

 

OSRdyTbl[y] |= bitx;

 

 

} else {

 

(11)

 

if ((pevent = ptcb->OSTCBEventPtr) != (OS_EVENT *)0) {

if ((pevent->OSEventTbl[ptcb->OSTCBY] &= ~ptcb->OSTCBBitX) == 0) { pevent->OSEventGrp &= ~ptcb->OSTCBBitY;

Соседние файлы в папке uCOS