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

}

 

|= bity;

(12)

pevent->OSEventGrp

pevent->OSEventTbl[y] |= bitx;

 

}

 

 

 

}

 

 

 

OSTCBPrioTbl[newprio] = ptcb;

 

(13)

ptcb->OSTCBPrio

= newprio;

(14)

ptcb->OSTCBY

= y;

 

(15)

ptcb->OSTCBX

= x;

 

 

ptcb->OSTCBBitY

= bity;

 

 

ptcb->OSTCBBitX

= bitx;

 

 

OS_EXIT_CRITICAL();

 

 

 

OSSched();

 

 

(16)

return (OS_NO_ERR);

 

 

 

} else {

 

 

 

OSTCBPrioTbl[newprio] = (OS_TCB *)0;

(17)

OS_EXIT_CRITICAL();

 

 

 

return (OS_PRIO_ERR);

 

 

 

}

}

}

Listing 4.15, OSTaskChangePrio().

4.07 Suspending a Task, OSTaskSuspend()

It is sometimes useful to explicitly suspend the execution of a task. This is accomplished with the OSTaskSuspend() function call. A suspended task can only be resumed by calling the OSTaskResume()

function call. Task suspension is additive. This means that if the task being suspended is also waiting for time to expire then the suspension needs to be removed and the time needs to expire in order for the task to be ready-to-run. A task can either suspend itself or another task.

The code for OSTaskSuspend() is shown in listing 4.16. As usual, we check boundary conditions. First, we must

ensure that your application is not attempting to suspend the idle task L4.16(1). Next, you must specify a valid priority L4.16(2). Remember than the highest valid priority number (i.e. lowest priority) is OS_LOWEST_PRIO. Note that

you can suspend the statistic task. You may have noticed that the first test L4.16(1) is replicated in L4.16(2). I did this to be backward compatible with µC/OS. The first test could be removed to save a little bit of processing time but, this is really insignificant so I decided to leave it.

Next, we check to see if you specified to suspend the calling task L4.16(3) by specifying OS_PRIO_SELF. You could also decided to suspend the calling task by specifying its priority L4.16(4). In both of these cases, the scheduler will need to be called. This is why I created the local variable self which will be examined at the appropriate time. If we are not suspending the calling task then we will not need to run the scheduler because the calling task is suspending a lower priority task.

We then check to see that the task to suspend exist L4.16(5). If the task to suspend exist, we remove it from the ready list L4.16(6). Note that the task to suspend may not be in the ready list because it’s waiting for an event or for time to expire. In this case, the corresponding bit for the task to suspend in OSRdyTbl[] would already be cleared (i.e. 0). Clearing it again is faster than checking to see if it’s clear and then clearing it if it’s not. We then set the OS_STAT_SUSPEND flag in the task’s OS_TCB to indicate that the task is now suspended L4.16(7). Finally, we call the scheduler only if the task being suspended is the calling task L4.16(8).

INT8U OSTaskSuspend (INT8U prio)

 

{

 

 

BOOLEAN

self;

 

OS_TCB

*ptcb;

 

if (prio == OS_IDLE_PRIO) {

(1)

return (OS_TASK_SUSPEND_IDLE);

 

}

 

 

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

(2)

return (OS_PRIO_INVALID);

 

}

 

 

OS_ENTER_CRITICAL();

 

if (prio == OS_PRIO_SELF) {

(3)

prio = OSTCBCur->OSTCBPrio;

 

self = TRUE;

 

} else if (prio == OSTCBCur->OSTCBPrio) {

(4)

self = TRUE;

 

} else {

 

 

self = FALSE;

 

}

 

 

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

(5)

OS_EXIT_CRITICAL();

 

return (OS_TASK_SUSPEND_PRIO);

 

} else {

 

 

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

(6)

}

OSRdyGrp &= ~ptcb->OSTCBBitY;

 

 

 

ptcb->OSTCBStat |= OS_STAT_SUSPEND;

(7)

OS_EXIT_CRITICAL();

 

if (self == TRUE) {

(8)

}

OSSched();

 

 

 

return (OS_NO_ERR);

 

}

}

Listing 4.16, OSTaskSuspend().

4.08 Resuming a Task, OSTaskResume()

As mentioned in the previous section, a suspended task can only be resumed by calling OSTaskResume(). The code for OSTaskResume() is shown in listing 4.17. Because we cannot suspend the idle task we must verify that

your application is not attempting to resume this task L4.17(1). You will note that this test also ensures that you are not trying to resume OS_PRIO_SELF (OS_PRIO_SELF is #defined to 0xFF which is always greater than OS_LOWEST_PRIO) because this wouldn’t make sense.

The task to resume must exist because we will be manipulating its OS_TCB L4.17(2) and, it must also have been suspended L4.17(3). We remove the suspension by clearing the OS_STAT_SUSPEND bit in the OSTCBStat field L4.17(4). For the task to be ready-to-run, the OSTCBDly field must be zero L4.17(5) because there are no flags in OSTCBStat to indicate that a task is waiting for time to expire. The task is made ready -to-run only when both

conditions are satisfied L4.16(6). Finally, the scheduler is called to see if the resumed task has a higher priority than the calling task L4.17(7).

INT8U OSTaskResume (INT8U prio)

{

OS_TCB *ptcb;

if (prio >= OS_LOWEST_PRIO) {

 

(1)

return (OS_PRIO_INVALID);

 

 

}

 

 

OS_ENTER_CRITICAL();

 

 

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

(2)

OS_EXIT_CRITICAL();

 

 

return (OS_TASK_RESUME_PRIO);

 

} else {

 

 

if (ptcb->OSTCBStat & OS_STAT_SUSPEND) {

(3)

if (((ptcb->OSTCBStat &= ~OS_STAT_SUSPEND) == OS_STAT_RDY) &&

(4)

(ptcb->OSTCBDly

== 0)) {

(5)

OSRdyGrp

|= ptcb->OSTCBBitY;

(6)

OSRdyTbl[ptcb->OSTCBY] |= ptcb->OSTCBBitX;

 

OS_EXIT_CRITICAL();

 

OSSched();

 

(7)

} else {

 

 

OS_EXIT_CRITICAL();

 

}

return (OS_NO_ERR);

} else { OS_EXIT_CRITICAL();

return (OS_TASK_NOT_SUSPENDED);

}

}

}

4.09 Getting Information about a Task, OSTaskQuery()

Your application can obtain information about itself or other application tasks by calling OSTaskQuery(). In fact, OSTaskQuery() obtains a copy of the contents of the desired task’s OS_TCB. The fields that are available to you in the OS_TCB depend on the configuration of your application (see OS_CFG.H). Indeed, because µC/OS -II is scalable, it only includes the features that your application requires.

To call OSTaskQuery() , your application must allocate storage for an OS_TCB as shown in listing 4.18. This OS_TCB is in a totally different data space as the OS_TCBs allocated by µC/OS-II. After calling OSTaskQuery(), this OS_TCB will contain a snapshot of theOS_TCB for the desired task. You need to be careful with the links to other OS_TCBs (i.e. OSTCBNext and OSTCBPrev); you don’t want to change what these links are pointing to! In general, you would only use this function to see what a task is doing –a great tool for debugging.

OS_TCB MyTaskData;

 

void MyTask (void *pdata)

 

{

 

pdata = pdata;

 

for (;;) {

*/

/* User code

err = OSTaskQuery(10, &MyTaskData);

/* Examine error code ..

*/

/* User code

*/

}

 

}

 

Listing 4.18, Obtaining information about a task.

The code for OSTaskQuery() is shown in listing 4.19. You should note that I now allow you to examine ALL the tasks, including the idle task L4.19(1). You need to be especially careful NOT to change what OSTCBNext and OSTCBPrev are pointing to. As usual, we check to see if you want information about the current task L4.19(2) and also, the task must have been created in order to obtain information about it L4.19(3). All fields are copied using the assignment shown instead of field by field L4.19(4). This is much faster because the compiler will most likely generate memory copy instructions.

INT8U OSTaskQuery (INT8U prio, OS_TCB *pdata)

{

OS_TCB *ptcb;

 

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

(1)

return (OS_PRIO_INVALID);

 

}

 

OS_ENTER_CRITICAL();

 

if (prio == OS_PRIO_SELF) {

(2)

prio = OSTCBCur->OSTCBPrio;

 

}

 

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

(3)

OS_EXIT_CRITICAL();

 

return (OS_PRIO_ERR);

 

}

 

*pdata = *ptcb;

(4)

OS_EXIT_CRITICAL();

 

return (OS_NO_ERR);

}

Listing 4.19, OSTaskQuery()

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