队列:实用程序服务和数据结构
队列:实用程序服务和数据结构
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.
Service call prototype:
STATUS NUSE_Queue_Reset(NUSE_QUEUE queue);
Parameters:
queue – the index (ID) of the queue to be reset
Returns:
NUSE_SUCCESS – the call was completed successfully
NUSE_INVALID_QUEUE – the queue
index is not valid
Nucleus 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的不同之处在于,它返回的信息较少,因为不支持对象命名、可变消息大小和挂起顺序,并且可能无法启用任务挂起。
Nucleus RTOS API Call for Queue Information
Service call prototype:
STATUS
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);
Parameters:
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
elements in the queue
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
Returns:
NU_SUCCESS – the call was completed successfully
NU_INVALID_QUEUE – the queue
pointer is not valid
Nucleus SE API Call for Queue Information
This API call supports the key functionality of the Nucleus RTOS API.
Service call prototype:
STATUS
NUSE_Queue_Information(NUSE_QUEUE queue,
ADDR *start_address, U8 *queue_size, U8 *available, U8
*messages, U8 *tasks_waiting, NUSE_TASK *first_task);
Parameters:
queue – the index of the queue about which information is being
requested
start_address – a pointer to a
variable of type ADDR ,
which will receive the address of the start of the queue’s data area
queue_size – a pointer to a
variable of type U8 ,
which will receive the total number of messages for which the queue has capacity
available – a pointer to a
variable of type U8 ,
which will receive the number of messages for which the queue has currently
remaining capacity
messages – a pointer to a
variable of type U8 ,
which will receive the number of messages currently in the queue
tasks_waiting – a pointer to a
variable which will receive the number of tasks suspended on this 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)
Returns:
NUSE_SUCCESS – the call was completed successfully
NUSE_INVALID_QUEUE – the queue
index is not valid
NUSE_INVALID_POINTER – one or
more of the pointer parameters is invalid
Nucleus SE Implementation of Queue Information
The implementation of this API call is quite straightforward:
*start_address = NUSE_Queue_Data[queue];*queue_size = NUSE_Queue_Size[queue];*available = NUSE_Queue_Size[queue] - NUSE_Queue_Items[queue];*messages = NUSE_Queue_Items[queue];#if NUSE_BLOCKING_ENABLE *tasks_waiting = NUSE_Queue_Blocking_Count[queue]; if (NUSE_Queue_Blocking_Count[queue] != 0) { U8 index; for (index=0; index<NUSE_TASK_NUMBER; index++) { if ((LONIB(NUSE_Task_Status[index]) == NUSE_QUEUE_SUSPEND) && (HINIB(NUSE_Task_Status[index]) == queue)) { *first_task = index; break; } } } else { *first_task = 0; } #else *tasks_waiting = 0; *first_task = 0; #endif
函数返回队列状态。然后,如果启用了阻塞API调用,则返回等待的任务数和第一个任务的索引(否则这两个参数设置为0)。
获取队列数
此服务调用返回应用程序中配置的队列数。在Nucleus RTOS中,这将随时间而变化,返回的值将表示当前的队列数,而在Nucleus SE中,返回的值在构建时设置,不能更改。
Nucleus RTOS API Call for Queue Count
Service call prototype:
UNSIGNED NU_Established_Queues(VOID);
Parameters:
None
Returns:
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.
Service call prototype:
U8 NUSE_Queue_Count(void);
Parameters:
None
Returns:
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 U8 NUSE_Queue_Head[NUSE_QUEUE_NUMBER];RAM U8 NUSE_Queue_Tail[NUSE_QUEUE_NUMBER];RAM U8 NUSE_Queue_Items[NUSE_QUEUE_NUMBER];#if NUSE_BLOCKING_ENABLE RAM U8 NUSE_Queue_Blocking_Count[NUSE_QUEUE_NUMBER];#endif
用户RAM
用户负责为每个配置的队列提供一个RAM区域用于数据存储。这个RAM区域的大小必须容纳ADDR类型的数组,队列中的每条消息都有一个条目。
ROM数据
这些数据结构包括:
NUSE_Queue_Data[]–这是一个ADDR类型的数组,每个配置的队列有一个条目,它表示每个队列的数据区指针(在上面的用户RAM中讨论过)。
NUSE_Queue_Size[]–这是一个U8类型的数组,每个配置的队列有一个条目,表示每个队列可以容纳的消息数。
这些数据结构都在nuse_config.c中声明和初始化(当然是静态的),因此:
ROM ADDR *NUSE_Queue_Data[NUSE_QUEUE_NUMBER] ={ /* addresses of queue data areas ------ */};ROM U8 NUSE_Queue_Size[NUSE_QUEUE_NUMBER] ={ /* queue sizes ------ */};
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.
Service call prototype:
STATUS NU_Create_Queue(NU_QUEUE *queue, char *name,
VOID *start_address, UNSIGNED queue_size, OPTION
message_type,
UNSIGNED message_size, OPTION suspend_type);
Parameters:
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
Returns:
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
is invalid
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.
Service call prototype:
STATUS NU_Delete_Queue(NU_QUEUE *queue);
Parameters:
queue – pointer to queue control block
Returns:
NU_SUCCESS – indicates successful completion of the service
NU_INVALID_QUEUE – indicates the
queue pointer is invalid
Queue 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.
Service call prototype:
UNSIGNED
NU_Queue_Pointers(NU_QUEUE **pointer_list,
UNSIGNED maximum_pointers);
Parameters:
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
Returns:
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.
Service call prototype:
STATUS
NU_Broadcast_To_Queue(NU_QUEUE *queue, VOID *message,
UNSIGNED size, UNSIGNED suspend);
Parameters:
queue – pointer to queue control block
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.
Returns:
NU_SUCCESS – indicates successful completion of the service
NU_INVALID_QUEUE – indicates the
queue pointer is invalid
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
NU_INVALID_SUSPEND – indicates
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中没有实现。