天天看点

队列:实用程序服务和数据结构

队列:实用程序服务和数据结构

Queues: utility services and data structures

队列实用程序服务             

Nucleus RTOS有四个API调用,它们提供与队列相关的实用函数:重置队列、返回有关队列的信息、返回应用程序中的队列数量以及返回指向应用程序中所有队列的指针。前三个在Nucleus SE中实现。             

重置队列             

此API调用将队列恢复到其未使用的初始状态。队列中存储的所有消息都将丢失。队列上挂起的所有任务都将恢复,并收到返回代码NUSE_queue_WAS_RESET。

队列:实用程序服务和数据结构

Nucleus RTOS API Call for Resetting a Queue

Service call prototype:

STATUS NU_Reset_Queue(NU_QUEUE *queue;

Parameters:

queue – pointer to user-define queue control block

Returns:

NU_SUCCESS – the call was completed successfully

NU_INVALID_QUEUE – the queue

pointer is not valid

Nucleus

SE API Call for Resetting a Queue

This API call supports the key functionality of the Nucleus RTOS

API.

STATUS

NUSE_Queue_Reset(NUSE_QUEUE queue);

queue – the index (ID) of the queue to be reset 

NUSE_SUCCESS – the call was completed successfully

NUSE_INVALID_QUEUE – the queue

index is not valid

SE Implementation of Queue Reset

在参数检查之后,NUSE_Queue_Reset()API函数的最初部分代码非常简单。头和尾索引以及队列的消息计数都设置为零。             

启用阻塞时,其他代码负责唤醒任何挂起的任务,因此:

while (NUSE_Queue_Blocking_Count[queue] != 0){   U8 index;             /* check whether any tasks are blocked */                         /* on this queue */   for (index=0; index<NUSE_TASK_NUMBER; index++)   {      if ((LONIB(NUSE_Task_Status[index]) == NUSE_QUEUE_SUSPEND)           && (HINIB(NUSE_Task_Status[index]) == queue))      {         NUSE_Task_Blocking_Return[index] = NUSE_QUEUE_WAS_RESET;         NUSE_Task_Status[index] = NUSE_READY;         break;      }   }   NUSE_Queue_Blocking_Count[queue]--;}#if NUSE_SCHEDULER_TYPE == NUSE_PRIORITY_SCHEDULER   NUSE_Reschedule(NUSE_NO_TASK);#endif

队列上挂起的每个任务都标记为“就绪”,挂起返回代码NUSE_queue_WAS_RESET。此过程完成后,如果正在使用优先级调度程序,则会调用NUSE_Reschedule(),因为一个或多个优先级较高的任务可能已准备就绪,需要允许其运行。             

队列信息             

此服务调用获取有关队列的信息选择。Nucleus SE实现与Nucleus RTOS的不同之处在于,它返回的信息较少,因为不支持对象命名、可变消息大小和挂起顺序,并且可能无法启用任务挂起。

RTOS API Call for Queue Information

NU_Queue_Information(NU_QUEUE *queue, CHAR *name, 

VOID **start_address,UNSIGNED *queue_size, UNSIGNED

*available, 

UNSIGNED *messages, OPTION *message_type, 

UNSIGNED *message_size, OPTION *suspend_type, 

UNSIGNED *tasks_waiting,  NU_TASK **first_task);

queue – pointer to the user-supplied queue control block

name – pointer to an 8-character

destination area for the message-queue’s name

start_address – a pointer to a

pointer, which will receive the address of the start of the queue’s data area

queue_size – a pointer to a

variable for holding the total number of UNSIGNED data

elements in the queue

available – a pointer to a

variable for holding the number of available UNSIGNED data

messages – a pointer to a

variable for holding the number of messages currently in the queue

message_type – pointer to a

variable for holding the type of messages supported by the queue; valid message

types are NU_FIXED_SIZE and NU_ VARIABLE_SIZE 

message_size – pointer to a

variable for holding the number of UNSIGNED data

elements in each queue message; if the queue supports variable-length messages,

this number is the maximum message size

suspend_type – pointer to a

variable for holding the task suspend type. Valid task suspend types are NU_FIFO and NU_PRIORITY 

tasks_waiting – a pointer to a

variable which will receive the number of tasks suspended on this queue

first_task – a pointer to a task

pointer; the pointer of the first suspended task is placed in this task pointer

SE API Call for Queue Information

NUSE_Queue_Information(NUSE_QUEUE queue, 

ADDR *start_address, U8 *queue_size, U8 *available, U8

*messages, U8 *tasks_waiting, NUSE_TASK *first_task);

queue – the index of the queue about which information is being

requested

variable of type ADDR ,

which will receive the address of the start of the queue’s data area

variable of type U8 ,

which will receive the total number of messages for which the queue has capacity

which will receive the number of messages for which the queue has currently

remaining capacity

which will receive the number of messages currently in the queue

(nothing returned if task suspend is disabled)

first_task – a pointer to a

variable of type NUSE_TASK which

will receive the index of the first suspended task (nothing returned if task

suspend is disabled)

NUSE_INVALID_POINTER – one or

more of the pointer parameters is invalid

SE Implementation of Queue Information

The implementation of this API call is quite straightforward:

函数返回队列状态。然后,如果启用了阻塞API调用,则返回等待的任务数和第一个任务的索引(否则这两个参数设置为0)。             

获取队列数             

此服务调用返回应用程序中配置的队列数。在Nucleus RTOS中,这将随时间而变化,返回的值将表示当前的队列数,而在Nucleus SE中,返回的值在构建时设置,不能更改。

Nucleus RTOS API Call for Queue Count

UNSIGNED NU_Established_Queues(VOID);

None

The number of created queues in the system.

Nucleus SE API Call for Queue Count

This API call supports the key functionality of the Nucleus RTOS API.

U8 NUSE_Queue_Count(void); 

The number of configured queues in the application

队列计数的Nucleus SE实现             

这个API调用的实现非常简单:返回#define symbol NUSE_QUEUE_NUMBER的值。             

数据结构             

队列使用五到六个数据结构—全部在RAM和ROM中—与其他Nucleus SE对象一样,这些数据结构是一系列表,根据配置的队列数量和选择的选项进行包含和标注。             

我强烈建议应用程序代码不要直接访问这些数据结构,而是使用提供的API函数。这避免了与Nucleus SE未来版本的不兼容和不必要的副作用,并简化了将应用程序移植到Nucleus RTOS的过程。这里包含数据结构的详细信息,以便更容易地理解服务调用代码的工作方式和调试。

内核RAM数据             

这些数据结构包括:             

NUSE_Queue_Head[]–这是一个U8类型的数组,每个配置的队列有一个条目,它表示指向消息队列前面的指针。它用作NUSE_Queue_Data[]中地址的索引(见下文)。             

NUSE_Queue_Tail[]–这是一个U8类型的数组,每个配置的队列有一个条目,它表示指向消息队列末尾的指针。它用作NUSE_Queue_Data[]中地址的索引(见下文)。             

NUSE_Queue_Items[]–这是一个U8类型的数组,每个配置的队列有一个条目,表示队列中当前消息数的计数。这个数据可以说是多余的,因为它的值可以从head和tail索引中派生出来,但是存储计数可以简化代码。             

NUSE_Queue_Blocking_Count[]–此类型的U8数组包含每个队列上阻塞的任务数。此数组仅在启用阻止API调用支持时存在。             

当Nucleus SE启动时,这些数据结构都由NUSE_Init_Queue()初始化为零。这是合乎逻辑的,因为它将每个队列呈现为空(未使用)。未来的文章将全面描述Nucleus SE的启动过程。              以下是nuse_init.c文件中这些数据结构的定义:

用户RAM             

用户负责为每个配置的队列提供一个RAM区域用于数据存储。这个RAM区域的大小必须容纳ADDR类型的数组,队列中的每条消息都有一个条目。             

ROM数据             

NUSE_Queue_Data[]–这是一个ADDR类型的数组,每个配置的队列有一个条目,它表示每个队列的数据区指针(在上面的用户RAM中讨论过)。             

NUSE_Queue_Size[]–这是一个U8类型的数组,每个配置的队列有一个条目,表示每个队列可以容纳的消息数。             

这些数据结构都在nuse_config.c中声明和初始化(当然是静态的),因此:

Queue Data Footprint

Like all kernel objects in Nucleus SE, the amount of data memory required for queues is readily predictable.

The ROM data footprint (in bytes) for all the queues in an application may be computed thus:

NUSE_QUEUE_NUMBER * (sizeof(ADDR) + 1)

The kernel RAM data footprint (in bytes) for all the queues in an application, when blocking API calls is enabled, may be computed thus:

NUSE_QUEUE_NUMBER * 3

Otherwise it is:

NUSE_QUEUE_NUMBER * 4

The amount of user RAM (in bytes) required for the queue with index queue is:

NUSE_Queue_Size[queue] * sizeof(ADDR)

Unimplemented API Calls

Four queue API calls found in Nucleus RTOS are not implemented in Nucleus SE:

Create Queue

This API call creates a queue. It is not needed with Nucleus SE, as queues are created statically.

STATUS NU_Create_Queue(NU_QUEUE *queue, char *name, 

VOID *start_address, UNSIGNED queue_size, OPTION

message_type, 

UNSIGNED message_size, OPTION suspend_type);

queue – pointer to a user-supplied queue control block; this

will be used as a “handle” for the queue in other API calls

name – pointers to a 7-character,

null-terminated name for the queue

start_address – starting address

for the queue

message_type – type of message

supported by the queue; may be NU_FIXED_SIZE or NU_VARIABLE_SIZE 

message_size – if the queue

supports fixed size messages, this parameter specifies the exact size of each

message; otherwise, if the queue supports variable sized messages, this is the

maximum message size

suspend_type – specifies how

tasks suspend on the queue. Valid options for this parameter are NU_FIFOand NU_PRIORITY , which represent

First-In-First-Out (FIFO) and priority-order task suspension, respectively

NU_SUCCESS – indicates successful completion of the service

NU_INVALID_QUEUE – indicates the

queue control block pointer is NULL or

already in use

NU_INVALID_MEMORY – indicates the

memory area specified by the start_address is

invalid

NU_INVALID_MESSAGE – indicates

that the message_type parameter

is invalid

NU_INVALID_SIZE – indicates that

either the message size is greater than the queue size, or that the queue size

or message size is zero

NU_INVALID_SUSPEND – indicates

that the suspend_type parameter

Delete

Queue

This API call deletes a previously created queue. It is not

needed with Nucleus SE, as queues are created statically and cannot be deleted.

NU_Delete_Queue(NU_QUEUE *queue);

queue – pointer to queue control block

queue pointer is invalid

Pointers

This API call builds a sequential list of pointers to all queues

in the system. It is not needed with Nucleus SE, as queues are identified by a

simple index, not a pointer, and it would be redundant.

UNSIGNED

NU_Queue_Pointers(NU_QUEUE **pointer_list, 

UNSIGNED maximum_pointers);

pointer_list – pointer to an array of NU_QUEUE pointers;

this array will be filled with pointers to established queues in the system

maximum_pointers – the maximum

number of pointers to place in the array

The number of NU_QUEUE pointers

placed into the array

Broadcast

to Queue

This API call broadcasts a message to all tasks waiting for a

message from the specified queue. It is not implemented with Nucleus SE, as it

would have added excessive complexity.

NU_Broadcast_To_Queue(NU_QUEUE *queue, VOID *message, 

UNSIGNED size, UNSIGNED suspend);

message – pointer to the

broadcast message

size – the number of UNSIGNED data elements in the

message. If the queue supports variable-length messages, this parameter must be

equal to or less than the message size supported by the queue. If the queue

supports fixed-size messages, this parameter must be exactly the same as the

message size supported by the queue

suspend – specifies whether or

not to suspend the calling task if the queue is already full; valid options for

this parameter are NU_NO_SUSPEND , NU_SUSPEND or a timeout value.

NU_INVALID_POINTER – indicates

that the message pointer is NULL 

NU_INVALID_SIZE – Indicates that

the message size specified is not compatible with the size specified when the

queue was created

that suspend attempted from a non-task thread

NU_QUEUE_FULL – indicates that

there is insufficient space in the queue for the message

NU_TIMEOUT – indicates the queue

is still full after the timeout has expired

NU_QUEUE_DELETED – queue was

deleted while task was suspended

NU_QUEUE_RESET – queue was reset

while the task was suspended

与Nucleus RTOS的兼容性             

对于Nucleus SE的各个方面,我的目标是尽可能保持与Nucleus RTOS的高级别应用程序代码兼容性。队列也不例外,从用户的角度来看,它们的实现方式与Nucleus RTOS中的方式大致相同。有一些不兼容的地方,我认为这样的不兼容是可以接受的,因为生成的代码更容易理解,或者更有可能提高内存效率。否则,Nucleus RTOS API调用几乎可以直接映射到Nucleus SE调用上。未来的一篇文章将包括关于为Nucleus RTOS用户使用Nucleus SE的更多信息。             

对象标识符             

在Nucleus RTOS中,所有对象都由具有特定数据类型的数据结构(控制块)来描述。指向此控制块的指针用作队列的标识符。在Nucleus SE中,我决定需要一种不同的方法来提高内存效率,所有的内核对象都由RAM和/或ROM中的许多表来描述,这些表的大小由配置的每个对象类型的数量决定。特定对象的标识符只是这些表的索引。因此,我将NUSE_QUEUE定义为等同于U8;此类型的变量(而不是指针)将用作队列标识符。这是一个小的不兼容性,如果代码被移植到Nucleus RTOS或从Nucleus RTOS移植过来,就很容易处理这个问题。对象标识符通常只是存储和传递,而不是以任何方式操作。             

Nucleus RTOS还支持队列命名。这些名称仅用于基于目标的调试工具。为了节省内存,我把它们从Nucleus SE中省略了。             

消息大小和可变性             

在Nucleus RTOS中,队列可以配置为处理由任意数量的无符号数据元素组成的消息。在Nucleus SE中,队列被简化,只支持单个ADDR消息。管道在Nucleus SE中更为灵活,可能为某些应用程序提供了替代队列的有用方法;本系列的下两篇文章将介绍管道。             

Nucleus RTOS还支持具有可变大小消息的队列,其中仅在创建时指定最大大小。Nucleus SE不支持可变大小的消息。             

队列大小             

Nucleus SE中队列中的消息数被限制为256条,因为所有索引变量和常量都是U8类型。Nucleus RTOS不受此限制。             

未实现的API调用             

Nucleus RTOS支持10个服务调用来处理队列。其中4个在Nucleus SE中没有实现。

人工智能芯片与自动驾驶

继续阅读