管道:介绍和基本服务
管道:介紹和基本服務
Pipes introduction and basic services
與郵箱或隊列相比,它們提供了在任務之間傳遞簡單消息的更靈活的方式。
使用管道
在Nucleus SE中,管道是在構建時配置的。一個應用程序最多可以配置16個管道。如果未配置管道,則應用程序中不會包含與管道相關的數據結構或服務調用代碼。
管道僅僅是一組存儲位置,每個存儲位置都足夠大,足以容納一個用戶定義字節長度的數據項,對這些數據項的訪問是受控制的,以便可以由多個任務安全地使用它。任務可以重復寫入管道,直到所有位置都已滿。任務可以從管道中讀取,數據通常以先進先出(FIFO)的方式接收。嘗試發送到完整管道或從空管道讀取可能會導致錯誤或任務掛起,具體取決于在API調用和Nucleus SE配置中選擇的選項。
管道和隊列
Nucleus SE還支持隊列,管道和隊列之間的主要區別是消息大小。隊列攜帶由單個ADDR組成的消息,這些地址通常是指針。管道承載任意字節長的消息;應用程序中每個管道的大小是固定的,并在配置時設置。
配置管道
管道數量
與Nucleus SE的大多數方面一樣,管道的配置主要由nuse_config.h中的#define語句控制。鍵設置是NUSE_PIPE_NUMBER,它確定為應用程序配置了多少個管道。默認設置為0(即沒有管道正在使用),您可以將其設置為最大16的任何值。錯誤的值將導致編譯時錯誤,該錯誤由nuse_config_check.h中的測試生成(此錯誤包含在nuse_config.c中,因此使用此模塊進行編譯),從而導致編譯一個#錯誤語句。
選擇非零值是管道的“主啟用”。這將導致一些數據結構被相應地定義和調整大小,在下一篇文章中會有更多內容。它還激活API啟用設置。
API啟用
Nucleus SE中的每個API函數(服務調用)在nuse_config.h中都有一個啟用的#define符號。對于管道,包括:
NUSE_PIPE_SEND
NUSE_PIPE_RECEIVE
NUSE_PIPE_JAM
NUSE_PIPE_RESET
NUSE_PIPE_INFORMATION
NUSE_PIPE_COUNT
默認情況下,所有這些都設置為FALSE,從而禁用每個服務調用并禁止包含任何實現代碼。要為應用程序配置管道,需要選擇要使用的API調用,并將其啟用符號設置為TRUE。
下面是從默認nuse_config.h文件中提取的內容。
#define NUSE_PIPE_NUMBER 0 /* Number of pipes in the
system – 0-16 */
/* Service call enablers */
#define
NUSE_PIPE_SEND FALSE
#define
NUSE_PIPE_RECEIVE FALSE
#define
NUSE_PIPE_JAM FALSE
#define
NUSE_PIPE_RESET FALSE
#define
NUSE_PIPE_INFORMATION FALSE
#define
NUSE_PIPE_COUNT FALSE
如果啟用了管道API函數而未配置管道(除非始終允許使用NUSE_pipe_Count()),則會導致編譯時錯誤。如果您的代碼使用尚未啟用的API調用,則會導致鏈接時間錯誤,因為應用程序中不會包含任何實現代碼。
管道服務電話
Nucleus RTOS支持10個與管道相關的服務調用,它們提供以下功能:
向管道發送消息。由Nucleus SE中的NUSE_Pipe_Send()實現。
從管道接收消息。由Nucleus SE中的NUSE_Pipe_Receive()實現。
在管道前面發個信息。由Nucleus SE中的NUSE_Pipe_Jam()實現。
將管道恢復到未使用狀態,不暫停任何任務(重置)。由Nucleus SE中的NUSE_Pipe_Reset()實現。
提供有關指定管道的信息。由Nucleus SE中的NUSE_Pipe_Information()實現。
返回(當前)為應用程序配置的管道數的計數。由Nucleus SE中的NUSE_Pipe_Count()實現。
向應用程序添加新管道(創建)。未在Nucleus SE中實現。
從應用程序中刪除管道(刪除)。未在Nucleus SE中實現。
返回指向應用程序中所有管道(當前)的指針。未在Nucleus SE中實現。
向管道(廣播)上掛起的所有任務發送消息。未在Nucleus SE中實現。
將詳細檢查每個服務調用的實現。
管道讀寫服務
可以在管道上執行的基本操作是向管道寫入數據(有時稱為發送)和從中讀取數據(也稱為接收)。也可以將數據寫入管道前端,這也被稱為堵塞。Nucleus RTOS和Nucleus SE各自為這些操作提供了三個基本API調用,這里將對此進行討論。
寫在管道上
Nucleus RTOS API對管道的寫入調用非常靈活,允許您無限期地掛起,或者在操作無法立即完成的情況下暫停,也就是說,您嘗試寫入一個完整的管道。Nucleus SE提供相同的服務,除了task suspend是可選的并且不實現timeout。
Nucleus RTOS還提供了一個向管道廣播的功能,但Nucleus
SE不支持這種功能。
Nucleus RTOS API Call for Sending to a Pipe
Service call prototype:
STATUS NU_Send_To_Pipe(NU_PIPE *pipe, VOID *message,
UNSIGNED size, UNSIGNED suspend);
Parameters:
pipe – pointer to the user-supplied pipe control block
message – a pointer to the message to be sent
size – the number of bytes in the message. If the pipe supports variable-length messages, this parameter must be equal to or less than the message size supported by the pipe. If the pipe supports fixed-size messages, this parameter must be exactly the same as the message size supported by the pipe
suspend – specification for task suspend; may be NU_NO_SUSPEND or NU_SUSPEND or a timeout value
Returns:
NU_SUCCESS – the call was completed successfully
NU_INVALID_PIPE – the pipe pointer is invalid
NU_INVALID_POINTER – the message pointer is NULL
NU_INVALID_SIZE – the message size is incompatible with the message size supported by the pipe
NU_INVALID_SUSPEND – suspend was attempted from a non-task thread
NU_PIPEE_FULL – the pipe is full and suspend was not specified
NU_TIMEOUT – the pipe is still full even after suspending for the specified timeout value
NU_PIPE_DELETED – the pipe was deleted while the task was suspended
NU_PIPE_RESET – the pipe was reset while the task was suspended
Nucleus SE API Call for Sending to a Pipe
This API call supports the key functionality of the Nucleus RTOS API.
Service call prototype:
<="" font="" style=“box-sizing: inherit;”>
<="" font="" style=“box-sizing: inherit;”>
STATUS NUSE_Pipe_Send(NUSE_PIPE pipe, U8 *message,
U8 suspend);
Parameters:
pipe – the index (ID) of the pipe to be utilized
message – a pointer to the message to be sent, which is a sequence of bytes as long as the configured message size of the pipe
suspend – specification for task suspend; may be NUSE_NO_SUSPEND or NUSE_SUSPEND
Returns:
NUSE_SUCCESS – the call was completed successfully
NUSE_INVALID_PIPE – the pipe index is invalid
NUSE_INVALID_POINTER – the message pointer is NULL
NUSE_INVALID_SUSPEND – suspend was attempted from a non-task
thread or when blocking API calls were not enabled
NUSE_PIPE_FULL – the pipe is full and suspend was not specified
NUSE_PIPE_WAS_RESET – the pipe was reset while the task was
suspended
管道發送的核SE實現
NUSE_Pipe_Send()–檢查API函數是否已啟用suspend()的條件編譯(取決于u)的API是否已啟用。我們將在這里分別研究這兩種變體。
如果未啟用阻塞,則此API調用的代碼非常簡單:
if (NUSE_Pipe_Items[pipe] == NUSE_Pipe_Size[pipe]) /* pipe full /{ return_value = NUSE_PIPE_FULL;}else / pipe element available */{ data = &NUSE_Pipe_Data[pipe][NUSE_Pipe_Head[pipe]]; for (i=0; i<msgsize; i++) { *data++ = *message++; } NUSE_Pipe_Head[pipe] += msgsize; if (NUSE_Pipe_Head[pipe] == (NUSE_Pipe_Size[pipe] * msgsize)) { NUSE_Pipe_Head[pipe] = 0; } NUSE_Pipe_Items[pipe]++; return_value = NUSE_SUCCESS;}
該函數只檢查管道中是否有空間,并使用NUSE_pipe_Head[]索引將消息存儲在管道的數據區域中。
啟用阻塞后,代碼會變得更復雜:
do{ if (NUSE_Pipe_Items[pipe] == NUSE_Pipe_Size[pipe]) /* pipe full / { if (suspend == NUSE_NO_SUSPEND) { return_value = NUSE_PIPE_FULL; } else { / block task / NUSE_Pipe_Blocking_Count[pipe]++; NUSE_Suspend_Task(NUSE_Task_Active, (pipe << 4) | NUSE_PIPE_SUSPEND); return_value = NUSE_Task_Blocking_Return[NUSE_Task_Active]; if (return_value != NUSE_SUCCESS) { suspend = NUSE_NO_SUSPEND; } } } else / pipe element available */ { data = &NUSE_Pipe_Data[pipe][NUSE_Pipe_Head[pipe]]; for (i=0; i<msgsize; i++) { *data++ = message++; } NUSE_Pipe_Head[pipe] += msgsize; if (NUSE_Pipe_Head[pipe] == (NUSE_Pipe_Size[pipe] * msgsize)) { NUSE_Pipe_Head[pipe] = 0; } NUSE_Pipe_Items[pipe]++; if (NUSE_Pipe_Blocking_Count[pipe] != 0) { U8 index; / check whether a task is blocked on this pipe */ NUSE_Pipe_Blocking_Count[pipe]–; for (index=0; index<NUSE_TASK_NUMBER; index++) { if ((LONIB(NUSE_Task_Status[index]) == NUSE_PIPE_SUSPEND) && (HINIB(NUSE_Task_Status[index]) == pipe)) { NUSE_Task_Blocking_Return[index] = NUSE_SUCCESS; NUSE_Wake_Task(index); break; } } } return_value = NUSE_SUCCESS; suspend = NUSE_NO_SUSPEND; }} while (suspend == NUSE_SUSPEND);
對代碼的一些解釋可能有用:
代碼包含在do…while循環中,當參數suspend的值為NUSE_suspend時,循環將繼續。
如果管道已滿,并且suspend設置為NUSE_NO_suspend,則API調用將以NUSE_pipe_full退出。如果suspend設置為NUSE_suspend,則任務將被掛起。返回時(即,當任務被喚醒時),如果返回值為NUSE_SUCCESS,表示任務被喚醒是因為消息已被讀取(而不是重置管道),則代碼循環返回頂部。
如果管道未滿,則使用NUSE_pipe_Head[]索引存儲提供的消息,以將消息存儲在管道的數據區域中。檢查管道上是否有任何任務掛起(等待接收)。如果有任務等待,第一個任務被喚醒。suspend變量被設置為NUSE_NO_suspend,API調用將退出并返回NUSE_SUCCESS。
從管子里讀東西
從管道讀取的Nucleus RTOS API調用非常靈活,使您能夠無限期地掛起,或者在操作無法立即完成的情況下暫停,也就是說,您嘗試從空管道中讀取。Nucleus SE提供相同的服務,除了task suspend是可選的并且不實現timeout。
ucleus RTOS API Call for Receiving from a Pipe
Service call prototype:
STATUS NU_Receive_From_Pipe(NU_PIPE *pipe, VOID *message, UNSIGNED size, UNSIGNED *actual_size, UNSIGNED suspend);
Parameters:
pipe – pointer to user-supplied pipe control block
message – pointer to storage for the message to be received
size –
the number of bytes in the message. This number must correspond to the message size defined when the pipe was created
suspend – specification for task suspend; may be NU_NO_SUSPEND or NU_SUSPEND or a timeout value
Returns:
NU_SUCCESS – the call was completed successfully
NU_INVALID_PIPE – the pipe pointer is invalid
NU_INVALID_POINTER – the message pointer is NULL
NU_INVALID_SUSPEND – suspend was attempted from a non-task
NU_PIPE_EMPTY – the pipe is empty and suspend was not specified
NU_TIMEOUT – indicates that the pipe is still empty even after suspending for the specified timeout value
NU_PIPE_DELETED –
the pipe was deleted while the task was suspended
NU_PIPE_RESET – the pipe was reset while the task was suspended
Nucleus SE API Call for Receiving from a Pipe
This API call supports the key functionality of the Nucleus RTOS API.
Service call prototype:
STATUS NUSE_Pipe_Receive(NUSE_PIPE pipe, U8 *message,
U8 suspend);
Parameters:
pipe – the index (ID) of the pipe to be utilized
message – a pointer to storage for the message to be received, which is a sequence of bytes as long as the configured message size of the pipe
suspend – specification for task suspend; may be NUSE_NO_SUSPEND or NUSE_SUSPEND
Returns:
NUSE_SUCCESS – the call was completed successfully
NUSE_INVALID_PIPE – the pipe index is invalid
NUSE_INVALID_POINTER – the message pointer is NULL
NUSE_INVALID_SUSPEND – suspend was attempted from a non-task thread or when blocking API calls were not enabled
NUSE_PIPE_EMPTY – the pipe is empty and suspend was not specified
NUSE_PIPE_WAS_RESET – the pipe was reset while the task was suspended
Nucleus SE Implementation of Pipe Receive
管道接收的核SE實現
NUSE_Pipe_Receive()API函數的大部分代碼(在參數檢查之后)是通過條件編譯選擇的,這取決于是否啟用了對阻塞(任務掛起)API調用的支持。我們將在這里分別研究這兩種變體。
如果未啟用阻塞,則此API調用的代碼非常簡單:
if (NUSE_Pipe_Items[pipe] == 0) /* pipe empty /{ return_value = NUSE_PIPE_EMPTY;}else{ / message available */ data = &NUSE_Pipe_Data[pipe][NUSE_Pipe_Tail[pipe]]; for (i=0; i<msgsize; i++) { *message++ = *data++; } NUSE_Pipe_Tail[pipe] += msgsize; if (NUSE_Pipe_Tail[pipe] == (NUSE_Pipe_Size[pipe] * msgsize)) { NUSE_Pipe_Tail[pipe] = 0; } NUSE_Pipe_Items[pipe]–; *actual_size = msgsize; return_value = NUSE_SUCCESS;}
只需使用管道中的指針NUSE_Pipe_Tail[]從數據管道中返回數據,并通過管道返回數據。 啟用阻塞后,代碼會變得更復雜:
do{ if (NUSE_Pipe_Items[pipe] == 0) /* pipe empty / { if (suspend == NUSE_NO_SUSPEND) { return_value = NUSE_PIPE_EMPTY; } else { / block task / NUSE_Pipe_Blocking_Count[pipe]++; NUSE_Suspend_Task(NUSE_Task_Active, (pipe << 4) | NUSE_PIPE_SUSPEND); return_value = NUSE_Task_Blocking_Return[NUSE_Task_Active]; if (return_value != NUSE_SUCCESS) { suspend = NUSE_NO_SUSPEND; } } } else { / message available */ data = &NUSE_Pipe_Data[pipe][NUSE_Pipe_Tail[pipe]]; for (i=0; i<msgsize; i++) { *message++ = data++; } NUSE_Pipe_Tail[pipe] += msgsize; if (NUSE_Pipe_Tail[pipe] == (NUSE_Pipe_Size[pipe] * msgsize)) { NUSE_Pipe_Tail[pipe] = 0; } NUSE_Pipe_Items[pipe]–; if (NUSE_Pipe_Blocking_Count[pipe] != 0) { U8 index; / check whether a task is blocked / / on this pipe */ NUSE_Pipe_Blocking_Count[pipe]–; for (index=0; index<NUSE_TASK_NUMBER; index++) { if ((LONIB(NUSE_Task_Status[index]) == NUSE_PIPE_SUSPEND) && (HINIB(NUSE_Task_Status[index]) == pipe)) { NUSE_Task_Blocking_Return[index] = NUSE_SUCCESS; NUSE_Wake_Task(index); break; } } } *actual_size = msgsize; return_value = NUSE_SUCCESS; suspend = NUSE_NO_SUSPEND; }} while (suspend == NUSE_SUSPEND);
對代碼的一些解釋可能有用:
代碼包含在do…while循環中,當參數suspend的值為NUSE_suspend時,循環將繼續。
如果管道為空,并且suspend設置為NUSE_NO_suspend,則API調用將以NUSE_pipe_empty退出。如果suspend設置為NUSE_suspend,則任務將被掛起。返回時(即,當任務被喚醒時),如果返回值為NUSE_SUCCESS,表示任務因已發送消息而被喚醒(而不是重置管道),則代碼循環返回頂部。
如果管道包含任何消息,則使用NUSE_pipe_Tail[]索引返回存儲的消息,以從管道的數據區域獲取消息。檢查管道上是否有任何任務被掛起(等待發送)。如果有任務等待,第一個任務被喚醒。suspend變量被設置為NUSE_NO_suspend,API調用將退出并返回NUSE_SUCCESS。
寫在管道前面
Nucleus RTOS-API調用寫入管道的前端非常靈活,允許您無限期地掛起,或者在操作無法立即完成的情況下暫停超時;也就是說,您嘗試寫入一個完整的管道。Nucleus SE提供相同的服務,除了task suspend是可選的并且不實現timeout。
Nucleus RTOS API Call for Jamming to a Pipe
Service call prototype:
STATUS NU_Send_To_Front_Of_Pipe(NU_PIPE *pipe, VOID *message,
UNSIGNED size, UNSIGNED suspend);
Parameters:
pipe – pointer to a user-supplied pipe control block
message – a pointer to the message to be sent
size – the number of bytes in the message. If the pipe supports variable-length messages, this parameter must be equal to or less than the message size supported by the pipe. If the pipe supports fixed-size messages, this parameter must be exactly the same as the message size supported by the pipe.
suspend – specification for task suspend; may be NU_NO_SUSPEND or NU_SUSPEND or a timeout value
Returns:
NU_SUCCESS – the call was completed successfully
NU_INVALID_PIPE – the pipe pointer is invalid
NU_INVALID_POINTER – the message pointer is NULL
NU_INVALID_SIZE – the message size is incompatible with the message size supported by the pipe
NU_INVALID_SUSPEND – suspend was attempted from a non-task thread
NU_PIPE_FULL – the pipe is full and suspend was not specified
NU_TIMEOUT – the pipe is still full even after suspending for the specified timeout value
NU_PIPE_DELETED – the pipe was deleted while the task was suspended
NU_PIPE_RESET – the pipe was reset while the task was suspended
Nucleus SE API Call for Jamming to a Pipe
This API call supports the key functionality of the Nucleus RTOS API.
Service call prototype:
STATUS NUSE_Pipe_Jam(NUSE_PIPE pipe, ADDR *message,
U8 suspend);
Parameters:
pipe – the index (ID) of the pipe to be utilized
message – a pointer to the message to be sent, which is a sequence of bytes as long as the configured message size of the pipe
suspend – specification for task suspend; may be NUSE_NO_SUSPEND or NUSE_SUSPEND
Returns:
NUSE_SUCCESS – the call was completed successfully
NUSE_INVALID_PIPE – the pipe index is invalid
NUSE_INVALID_POINTER – the message pointer is NULL
NUSE_INVALID_SUSPEND – suspend was attempted from a non-task thread or when blocking API calls were not enabled
NUSE_PIPE_FULL – the pipe is full and suspend was not specified
NUSE_PIPE_WAS_RESET – the pipe was reset while the task was suspended
Nucleus SE Implementation of Jamming to a Pipe
The bulk of the code of the NUSE_Pipe_Jam() API function is very similar to that of NUSE_Pipe_Send() , except that the data is stored using the NUSE_Pipe_Tail[] index,
thus:
if (NUSE_Pipe_Items[pipe] == NUSE_Pipe_Size[pipe]) /* pipe full /{ return_value = NUSE_PIPE_FULL;}else / pipe element available */{ if (NUSE_Pipe_Tail[pipe] == 0) { NUSE_Pipe_Tail[pipe] = (NUSE_Pipe_Size[pipe] - 1) * msgsize; } else { NUSE_Pipe_Tail[pipe] -= msgsize; } data = &NUSE_Pipe_Data[pipe][NUSE_Pipe_Tail[pipe]]; for (i=0; i<msgsize; i++) { *data++ = *message++; } NUSE_Pipe_Items[pipe]++; return_value = NUSE_SUCCESS;}
總結
以上是生活随笔為你收集整理的管道:介绍和基本服务的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 管道:实用程序服务和数据结构
- 下一篇: 队列:实用程序服务和数据结构