Xenomai 再探

一、Xenomai API 接口使用總結

  1. Alarm-操作: 在使用實時任務過程中,採用看門狗定時器進行延時操作時,會產生實時域到非實時域的上下文切換操作,從而導致實時線程實時性受到影響,具體如下:

    void RT_TASK_CallBack_Handle(void *pUsrArg)
    {
        int err;
        T_RT_PARAM *rt_param = (T_RT_PARAM *)pUsrArg;
        rt_printf("## Running=[%d,%d] ##:%s-%d\n", rt_param->Param1, rt_param->Param2, __FUNCTION__, __LINE__);
    
        while(1)
        {
            err = rt_alarm_wait(&rt_param->alarm_desc); // 
    
            rt_printf("Hello Xenomai World!\n");
        }
    }
    

    通過xenomai程序狀態文件查看 MSW 參數的情況,發現其一直在增加:cat sched/stat

    root@MM5718v1:/proc/xenomai# cat sched/stat 
    CPU  PID    MSW        CSW        XSC        PF    STAT       %CPU  NAME
    0  0      0          15690      0          0     00018000   99.8  [ROOT/0]
    0  2869   14         17         77         0     000680c0    0.0  RTDemoExe
    0  2871   1          21         44         0     00040042    0.0  timer-internal
    0  2872   20         40         47         0     00048042    0.0  TEST_TASK
    0  0      0          69867498   0          0     00000000    0.2  [IRQ20: [timer]]
    

    結論:不要在實時線程任務中啓用Alarm函數進行延時處理,會存在上下文切換過程。


  2. Cond-操作: 在使用 err = rt_cond_bind(&cond, "TEST_COND_VAR_NAME", TM_INFINITE); 函數去跨函數綁定條件變量的過程中,此函數必須在實時任務中去調用,否則調用不成功,且不會阻塞等待到該條件變量的創建。 程序按下 s 即可觸發執行

    rt_printf("&&& Hello KeyboardMonitor World!\n");
    err = rt_cond_bind(&cond, "TEST_COND_VAR_NAME", TM_INFINITE);
    rt_printf("### Hello KeyboardMonitor World!\n");
    

    上述代碼塊必須在實時線程中調用纔會生效。bind的功能就像是socket編程中的bind功能,能夠阻塞獲取到指定名稱的信號量對象,從而保證在當前實時線程中也能夠獲取到對應的信號量,從而完成實時線程控制。

    clock_gettime(CLOCK_REALTIME, &time_stamp);
    time_stamp.tv_sec += 5; // 需要將cond等待時間向後設置5s作爲終止時間
    rt_printf("The Current TimeStamp=[%ld:%ld]\n", time_stamp.tv_sec, time_stamp.tv_nsec);
    
    err = rt_cond_wait_timed(&cond, &mutex_var, &time_stamp); // 設置了cond條件等待的時間節點,如果到達時間節點,條件爲被設置則返回超時錯誤 -ETIMEDOUT
    if(0 != err)
    {
        rt_printf("Xenomai-CondVariable wait Error:[%d,%d,%d,%d,%d,%d,%d]!\n", err, -EINVAL, -EIDRM, -EINTR, -EWOULDBLOCK, -ETIMEDOUT, -EPERM);
    }
    

    注意: 目前對於cond條件的 rt_cond_broadcast 以及 rt_cond_signal 還未測試成功!


  3. Queue-操作: Xenomai提供了一套IPC實時線程通信方案 rt_queue , 能夠採用 bind 的方式在不同的實時線程中通過queue的名稱獲取指定的隊列句柄,從而進行數據交換的操作,其基本使用流程如下:

    graph TD; 實時線程Task1-->定義Task1-rt_queue隊列-->阻塞綁定隊列1rt_queue_bind-->定時獲取隊列數據rt_queue_receive_timed-->使用相關數據-->釋放數據內存rt_queue_free 實時線程Task2-->定義Task2-rt_queue隊列-->阻塞綁定隊列2rt_queue_bind-->申請數據內存rt_queue_alloc-->更新內存數據內容-->發送隊列數據rt_queue_send 主實時線程Task-->定義原始rt_queue隊列-->創建相關隊列rt_queue_create-->while

    相關測試代碼如下(編譯程序,輸入i鍵即可):

    void RT_TASK_Queue_CallBack_Handle(void *pUsrArg)
    {
        int err;
        int counter = 0;
        int SamplePeriod = 200000000;
    
        T_RT_PARAM *rt_param = (T_RT_PARAM *)pUsrArg;
        rt_printf("## Running=[%d,%d] ##:%s-%d\n", rt_param->Param1, rt_param->Param2, __FUNCTION__, __LINE__);
    
        RT_QUEUE rt_queue;
        RT_QUEUE_INFO rt_queue_info;
    
        rt_printf("&&& Hello KeyboardMonitor World!\n");
        err = rt_queue_bind(&rt_queue, "RT_QUEUE_DEMO", TM_INFINITE);
        rt_printf("### Hello KeyboardMonitor World!\n");
    
        err = rt_queue_inquire(&rt_queue, &rt_queue_info);
        rt_printf("The KeyBoard RT-Queue[%s]:\n", rt_queue_info.name);
        rt_printf("  Number of task currently waiting on the queue for messages:[%d]\n", rt_queue_info.nwaiters);
        rt_printf("  Number of messages pending in queue:[%d]\n", rt_queue_info.nmessages);
        rt_printf("  Queue Mode Bits:[%d]\n", rt_queue_info.mode);
        rt_printf("  Maximum number of messages in queue:[%d]\n", rt_queue_info.qlimit);
        rt_printf("  Size of memory pool for holding message buffers:[%d]\n", rt_queue_info.poolsize);
        rt_printf("  Amount of memory consumed from the buffer pool:[%d]\n", rt_queue_info.usedmem);
    
        struct timespec time_stamp;
    
        void *buf_addr = NULL;
        ssize_t buf_size;
    
        rt_task_set_periodic(NULL, TM_NOW, SamplePeriod); // 200ms更新一次
        while(1)
        {
            rt_task_wait_period(NULL);
            rt_printf("Hello Xenomai-CondVariable World[%d]!\n", counter);
    
            clock_gettime(CLOCK_REALTIME, &time_stamp);
            time_stamp.tv_nsec += 100000;
            // rt_printf("The Current TimeStamp=[%ld:%ld]\n", time_stamp.tv_sec, time_stamp.tv_nsec);
    
            buf_size = rt_queue_receive_timed(&rt_queue, &buf_addr, &time_stamp);
    
            if(buf_size > 0)
            {
                rt_printf("Show the Buffer Content:");
                for(int i=0 ; i < buf_size ; i++)
                {
                    rt_printf(" %d", ((char *)buf_addr)[i]);
                }
                rt_printf("\n");
            }
            rt_queue_free(&rt_queue, buf_addr);
        }
    
        err = rt_queue_unbind(&rt_queue);
    }
    

  4. HEAP-操作: 在使用Xenomai預先申請的內存池內容時,Xenomai提供了 heap 相關的操作API,在創建heap過程中,如果配置heap模式爲 H_SINGLE 則在 rt_heap_alloc 函數調用時,需要將所有內存全部申請完,否則程序報錯。同時 Heap 內存操作還提供了 rt_heap_bind 的綁定功能,從而能夠方便 RT-Task 之間進行 IPC 內存共享通訊。具體參考程序:MainRTHeap.c

    root@MM5718v1:~/Burnish# ./RTDemoExe 
    Heap Informations:
    Number of tasks waitting for aviliable memory alloc:0
    The Heap Mode Flags given while Creation:0
    Size of the Heap(Bytes) While Create:10 Bytes
    Maximum amount of memory avaliable from heap:1032 Bytes
    Amount of memory currently consumed:3250 Bytes
    Name of memory heap:HeapTest
    The iPointer[0]=
    0 1 2 3 4 5 6 7 8 9 
    

    🐛 Some-Bugs:
    B1: 在一個實時線程中申請超過約 \(1MB\) 的內存時,發生錯誤 [-ENOMEM] ,當前系統配置總內存 \((52428800/1024/1024=50Mb)\) 如下所示:

    root@MM5718v1:~# cat /proc/xenomai/heap 
        TOTAL      FREE  NAME
    52428800  52427776  system heap
    4194304   4194176  shared heap
    

    測試情況如下:

    • Heap 被 rt_heap_bind 接口綁定的情況下只能申請到 200KB 的內存大小。
    • Heap 在單一線程中可申請的最大 Heap 空間爲 \(1MB\) 左右,也就是在 Xenomai 的實時線程中,對於單一實時線程的最大 Heap 申請大小進行了限制,這與Linux系統下的單進程的分配空間存在上限的情形相似。

  5. Mutex-操作: 在使用Xenomai架構支持的Mutex鎖資源的相關接口過程中,基本上和普通線程的 Mutex-Lock 的使用方式基本一致,只是Xenomai的所有資源的共享方式都可以使用 bind 綁定的方式完成,因而無需在線程之間傳遞 Mutex 變量(這是由於Xenomai架構底層決定的,其所有資源的申請都不是臨時/創建時申請的,而是在架構初始化時就完成了相關資源的初始化,後續只是在資源池中取出來分配給大家使用)。MainRTMutex.c

    root@MM5718v1:~# ./Burnish/RTDemoExe 
    ## Running ##:RT_TASK_CallBack_HandleA-68
    Heap Informations:
    Number of tasks waitting for aviliable memory alloc:0
    The Heap Mode Flags given while Creation:1
    Size of the Heap(Bytes) While Create:10 Bytes
    Maximum amount of memory avaliable from heap:1032 Bytes
    Amount of memory currently consumed:3250 Bytes
    Name of memory heap:HeapTest
    Task Get Info Error:[-22,-22,-43,-4,-11,-110,-1,-12,-17]!
    Mutex Informations:
    Owner-Current Mutex Hold Task@Name:»
    Owner-Current Mutex Hold Task@Priority:-1225016136
    Name of Sync Mutex Lock:MutexTest
    The RT_TASK_CallBack_HandleA iPointer[0]=0 0 0 0 0 0 0 0 0 0   ===>   0 1 2 3 4 5 6 7 8 9 
    ## Running ##:RT_TASK_CallBack_HandleB-212
    Heap Informations:
    Number of tasks waitting for aviliable memory alloc:0
    The Heap Mode Flags given while Creation:0
    Size of the Heap(Bytes) While Create:10 Bytes
    Maximum amount of memory avaliable from heap:1032 Bytes
    Amount of memory currently consumed:3274 Bytes
    Name of memory heap:HeapTest
    Task Get Info Error:[-22,-22,-43,-4,-11,-110,-1,-12,-17]!
    Mutex Bind Informations:
    Owner-Current Mutex Hold Task@Name:
    Owner-Current Mutex Hold Task@Priority:0
    Name of Sync Mutex Lock:MutexTest
    The RT_TASK_CallBack_HandleB iPointer[0]=0 1 2 3 4 5 6 7 8 9   ===>   100 101 102 103 104 105 106 107 108 109 
    The RT_TASK_CallBack_HandleA iPointer[0]=100 101 102 103 104 105 106 107 108 109   ===>   0 1 2 3 4 5 6 7 8 9 
    The RT_TASK_CallBack_HandleB iPointer[0]=0 1 2 3 4 5 6 7 8 9   ===>   100 101 102 103 104 105 106 107 108 109 
    The RT_TASK_CallBack_HandleA iPointer[0]=100 101 102 103 104 105 106 107 108 109   ===>   0 1 2 3 4 5 6 7 8 9 
    The RT_TASK_CallBack_HandleB iPointer[0]=0 1 2 3 4 5 6 7 8 9   ===>   100 101 102 103 104 105 106 107 108 109 
    The RT_TASK_CallBack_HandleA iPointer[0]=100 101 102 103 104 105 106 107 108 109   ===>   0 1 2 3 4 5 6 7 8 9 
    The RT_TASK_CallBack_HandleB iPointer[0]=0 1 2 3 4 5 6 7 8 9   ===>   100 101 102 103 104 105 106 107 108 109 
    

  6. Pipe-操作: 管道Pipe作爲一種半雙工的IPC通信方式,在同一時刻只允許有一個進程或者線程對Pipe管道對象進行操作,因此需要在寫入和讀取端之間形成互斥,亦可以通過信號量的方式協調兩端數據的讀取寫入過程,因此在下面的PIPE測試程序中,分別包括的 PipeServer 端、PipeClient 端,分別在兩個終端下執行兩個應用程序,測試其半雙工通信功能。
    RTDemoExePipeServer.c
    I. 數據發送實時線程:

    RT_PIPE pipe;
    const char PipeName[] = "PipeTest";
    
    const char writer_data[] = "Writer PIPE DATA...";
    const char stream_data[] = "Stream PIPE DATA...";
    
    err = rt_pipe_create(&pipe, PipeName, 1, 1000); // minor 用來配置在Linux設備端創建 /dev/rtpN 的過程中配置 N 的號碼,當minor=1時,則創建的設備爲 /dev/rtp1, 如果設置爲P_MINOR_AUTO:設備Pipe節點自動創建功能  poolsize:0 Pipe管道緩衝池的大小,設置爲0時則直接使用 Xenomai 系統的Heap空間
    if(0 != err)
    {
        rt_printf("Pipe Create Error:[%d,%d,%d,%d,%d,%d,%d,%d,%d]!\n", err, -EINVAL, -EIDRM, -EINTR, -EWOULDBLOCK, -ETIMEDOUT, -EPERM, -ENOMEM, -EEXIST);
    }
    
    while(1)
    {
        data_count = rt_pipe_write(&pipe, writer_data, strlen(writer_data), P_NORMAL); // 使用write的方式完成Pipe數據的傳輸過程 mode:P_URGENT 標識數據的後入先出順序 LIFO | P_NORMAL==>FIFO
        rt_task_sleep(10); // rt-thread 實時線程延遲函數 相對延時函數 最小延遲精度 clock ticks 需要絕對延時時間使用 rt_task_sleep_until() 接口
        data_count = rt_pipe_stream(&pipe, stream_data, strlen(writer_data)); // 使用流的方式Stream傳輸數據
        rt_printf("RT_TASK_CallBack_HandleA %d Datas Send over...\n", data_count);
        rt_task_wait_period(NULL);
    }
    
    err = rt_pipe_delete(&pipe); // 清理mutex資源 對於 Xenomai 的數據資源使用完之後一定要嚴格回收,否則會導致資源流失,影響整個系統的資源獲取
    if(0 != err)
    {
        rt_printf("Pipe Delete Error:[%d,%d,%d,%d,%d,%d,%d,%d,%d]!\n", err, -EINVAL, -EIDRM, -EINTR, -EWOULDBLOCK, -ETIMEDOUT, -EPERM, -ENOMEM, -EEXIST);
    }
    

    II. 數據接收實時線程:

    RT_PIPE pipe;
    const char PipeName[] = "PipeTest";
    err = rt_pipe_bind(&pipe, PipeName, TM_NONBLOCK); // 不限時等待綁定 TM_INFINTE TM_NONBLOCK
    if(0 != err)
    {
        rt_printf("Pipe Create Error:[%d,%d,%d,%d,%d,%d,%d,%d,%d]!\n", err, -EINVAL, -EIDRM, -EINTR, -EWOULDBLOCK, -ETIMEDOUT, -EPERM, -ENOMEM, -EEXIST);
    }
    
    ssize_t DataLen = 0;
    char data_read[10]={0};
    while(1)
    {
        rt_task_wait_period(NULL); // 不能放在 continue 的下面
        DataLen = rt_pipe_read(&pipe, data_read, 10, TM_NONBLOCK); // TM_INFINITE 永久等待讀取到Pipe中的數據 
        if(DataLen < 0)
        {
            rt_printf("Pipe No Data Recieved Error:[%d,%d,%d,%d,%d,%d,%d,%d,%d]!\n", DataLen, -EINVAL, -EIDRM, -EINTR, -EWOULDBLOCK, -ETIMEDOUT, -EPERM, -ENOMEM, -EEXIST);
            continue;
        }
        rt_printf("Recieve Data[%d]: %s\n", DataLen, data_read);
    }
    
    err = rt_pipe_unbind(&pipe); // TM_INFINITE 永久等待 TM_NONBLOCK
    if(0 != err)
    {
        rt_printf("Pipe Unbind Error:[%d,%d,%d,%d,%d,%d,%d,%d,%d]!\n", err, -EINVAL, -EIDRM, -EINTR, -EWOULDBLOCK, -ETIMEDOUT, -EPERM, -ENOMEM, -EEXIST);
    }
    

    RTDemoExePipeClient.c
    數據發送接收普通線程: RTDemoExePipeClient.c

    FILE *PipeHandle = NULL;
    char DataBuffer[30];
    PipeHandle = fopen("/dev/rtp1", "r"); // /dev/rtp1 此設備爲 rtpN創建 Pipe 過程中產生的,N的編號爲 rt_pipe_create 時,minor參數決定的
    
    ssize_t DataLen = 0;
    
    while(1)
    {
        DataLen = fread(DataBuffer, 1, 30, PipeHandle);
        if( DataLen > 0 )
        {
            for(int i = 0 ; i < DataLen ; i++)
            {
                printf("%c", DataBuffer[i]);
            }
            printf("\n");
        }
        usleep(1000);
    }
    

         通過 rt_pipe_create 接口創建了管道Pipe之後,會在 /proc/xenomai/registry 目錄下產生 /rtipc/xddp/PipeTest 文件句柄,此句柄實際上爲 /dev/rtp1 設備的 SymbolLink ,如下所示:

    root@MM5718v1:~# ls -al /proc/xenomai/registry/rtipc/xddp/PipeTest 
    lrwxrwxrwx    1 root     root             9 Nov 28 03:55 /proc/xenomai/registry/rtipc/xddp/PipeTest -> /dev/rtp1
    

    我們可以通過 cat /proc/xenomai/registry/rtipc/xddp/PipeTest 命令來查看寫入到 PipeTest 管道中的數據:

    Writer PIPE DATA...Stream PIPE DATA...Stream PIPE DATA...Stream PIPE DATA...Stream PIPE DATA...Stream PIPE DATA...
    

    🐛 Some-Bugs:
    B1: 在使用Xenomai提供的實時線程接口創建Pipe管道的過程中,由於Pipe是用來進行核間跨域通信的接口,不要在兩個實時線程中嘗試使用 Pipe ,經測試是無法完成數據傳輸功能的,所以這裏一定需要注意!


  7. Task-操作:
    Step1. 創建實時任務回調函數:

    void RT_TASK_CallBack_HandleA(void *pUsrArg)
    {
        int ret,err;
        int SamplePeriod = 200000000;
        rt_task_set_periodic(NULL, TM_NOW, SamplePeriod); // 200ms更新一次
        while(1)
        {
            // do something ...
            rt_task_wait_period(NULL); // 等待下一個執行週期的到達
        }
    }
    

    Step2. 在主進程中創建並啓動一個實時任務:

    RT_TASK RTTaskHandleA;
    ret = rt_task_create(&RTTaskHandleA, "RTTaskHandleA", TASK_STKSZ, TASK_PRIO, TASK_MODE); // 創建一個實時線程
    ret = rt_task_start(&RTTaskHandleA, &RT_TASK_CallBack_HandleA, NULL); // 啓動一個普通的實時任務,不通過 rt_alarm_wait 看門狗定時器延遲等待
    

    Some-Bugs:
    🐛 B1 @ CPU死機?
         在使用Xenomai提供的實時線程接口創建實時任務的過程中,如果在While循環當中使用了 rt_task_wait_period(NULL); 接口來等待當前實時任務的完成,則不能跳過此函數重複執行While,否則將導致CPU被完全佔用(死機),具體錯誤代碼示例如下:

        while(1)
        {
            rt_task_wait_period(NULL); // 允許的 rt_task_wait_period 接口位置
            DataLen = rt_pipe_read(&pipe, data_read, 10, TM_NONBLOCK); // TM_INFINITE 永久等待讀取到Pipe中的數據 
            if(DataLen < 0)
            {
                rt_printf("Pipe No Data Recieved Error:[%d,%d,%d,%d,%d,%d,%d,%d,%d]!\n", DataLen, -EINVAL, -EIDRM, -EINTR, -EWOULDBLOCK, -ETIMEDOUT, -EPERM, -ENOMEM, -EEXIST);
                continue;
            }
            // cotinue 一下的位置則不允許的 rt_task_wait_period 調用
            rt_printf("Recieve Data[%d]: %s\n", DataLen, data_read);
        }
    

         因此,從這個角度上可以猜測到 rt_task_wait_period 的功能在於針對確定定時範圍內需要完成的任務,如果在定時任務定時範圍之內完成的任務,則調用 rt_task_wait_period 接口後會延遲直到定時任務時間到達爲止,如果跳過此環節將會導致CPU被獨佔死機。
    🐛 B2 @ 出現了段錯誤 rt_task_join 出現了段錯誤的問題?
         究其原因一定是傳入到該函數的 task-handle 任務句柄存在問題,通過排查發現是因爲 rt_task_join 函數傳入了一個無效的句柄,是由於在申請實時線程資源時未成功申請到而導致的結果。
    🐛 B3 @ 出現了 Lack of Core Thread EGAIN 導致無法正常申請到線程鎖,任務無法正常啓用?
         排查過程如下,由於出現了線程資源匱乏的問題,考慮到使用的是實時線程,首先針對實時線程的記錄文件進行排查,通過查看 cat /proc/xenomai/register/usage 可以觀察線程使用的情況,根據實驗結果查看,發現線程數量的確在不斷的增加,此時考慮到實時線程中某些特殊操作可能影響線程的因素,其中就包括了線程鎖的安全問題,具體:由於實時線程的安全鎖問題,當使用 rt_task_delete&rt_task_join 函數接口對實時線程進行刪除回收時,可以發現實際上線程並未完成回收,儘管此時通過 cat /proc/xenomai/sched/threads 查看到的RT_Task只有幾個,實際上是因爲 thread 文件中之記錄了會被調度到的線程,而其他被刪除後的線程不會再被調度了,導致之一問題的原因可能是因爲該線程並未釋放或者銷燬其使用的線程鎖,如果其他線程使用了對應的線程鎖,將有可能導致該線程死鎖,因此考慮到安全問題,被刪除終止的實時線程實際上資源並未回收完成,並一直佔用了實施線程資源池,通過排查發現,在實時線程初通過 pthread_mutex_create() 創建的鎖資源未解鎖及釋放,因此需要使用 pthread_mutex_unlock & pthread_mutex_destroy 釋放銷燬即可。
    🐛 B4 @ 反覆創建刪除 RT_Task 過程中出現了內存增長的問題,而線程數量是未增漲?
         這個問題涉及到了實時線程銷燬回收的問題,由於 Destroy 接口並不需要等到該線程的終止,在創建 TrajectoryDestroy_V1 資源回收線程的過程中,由於我使用了 T_JOINABLE 模式創建了該線程,因此在線程結束後的資源回收應該需要 rt_task_join 對該線程進行回收操作才能完成所有資源回收。由於該線程無需 阻塞 join ,故此直接在創建該線程時採用 #define POSGEN_TASK_MODE 0 /* No flags */ 即可,再運行時則發現無內存增漲的情況。


  8. Semaphore-操作: PV-IPC信號操作作爲實時線程間的互斥IPC通信方式,用於線程之間的數據信息同步操作,其功能類似於 mutex 的功能,但PV操作在阻塞的情況下可能會出現 優先級翻轉的現象 ,而 Mutex 則不會出現這樣的情況。
    MainRTSem.c

    RT_SEM sem;
    const char SEMName[] = "SemTest";
    err = rt_sem_create(&sem, SEMName, 2, S_FIFO); // S_PRIO 以優先級排隊領取可用Sem S_FIFO 以先到先得的方式領取可用Sem
    if(0 != err)
    {
        printf("Sem Create Error:[%d,%d,%d,%d,%d,%d,%d,%d,%d]!\n", err, -EINVAL, -EIDRM, -EINTR, -EWOULDBLOCK, -ETIMEDOUT, -EPERM, -ENOMEM, -EEXIST);
    }
    
    RT_SEM_INFO seminfo;
    err = rt_sem_inquire(&sem, &seminfo); // H_PRIO 以優先級排隊領取可用heap H_FIFO 以先到先得的方式領取可用heap  H_SINGLE 將創建的 heap內存當作一整個內存,在alloc申請時必須整塊申請,否則會報錯
    if(0 != err)
    {
        printf("Sem Get Info Error:[%d,%d,%d,%d,%d,%d,%d,%d,%d]!\n", err, -EINVAL, -EIDRM, -EINTR, -EWOULDBLOCK, -ETIMEDOUT, -EPERM, -ENOMEM, -EEXIST);
    }
    printf("Sem Informations:\n");
    printf("  Current Semaphore Value:%ld\n", seminfo.count);
    printf("  Number of tasks waitting for this Semaphore:%d\n", seminfo.nwaiters);
    printf("  Name of Semaphore:%s\n", seminfo.name);
    
    int SamplePeriod = 200000000;
    rt_task_set_periodic(NULL, TM_NOW, SamplePeriod); // 200ms更新一次
    
    while(1)
    {
        rt_sem_p(&sem, TM_INFINITE); // 永久等待 Semaphore 釋放
    
        rt_printf("## Running ##:%s-%d\n", __FUNCTION__, __LINE__);
    
    #if SEMAPHORE_BROADCAST_TSET
        rt_sem_broadcast(&sem);
    #else
        rt_sem_v(&sem); // Unblock the semaphore
    #endif
        rt_task_wait_period(NULL);
    }
    
    err = rt_sem_delete(&sem); // 清理mutex資源 對於 Xenomai 的數據資源使用完之後一定要嚴格回收,否則會導致資源流失,影響整個系統的資源獲取
    if(0 != err)
    {
        printf("Semaphore Delete Error:[%d,%d,%d,%d,%d,%d,%d,%d,%d]!\n", err, -EINVAL, -EIDRM, -EINTR, -EWOULDBLOCK, -ETIMEDOUT, -EPERM, -ENOMEM, -EEXIST);
    }
    

    實驗結果如下:

    root@MM5718v1:~# ./Burnish/RTDemoExe
    Sem Informations:
    Current Semaphore Value:2
    Number of tasks waitting for this Semaphore:0
    Name of Semaphore:SemTest
    ## Running-SemaphoreValue[1] ##:RT_TASK_CallBack_HandleA-104
    Sem Bind Informations:
    Current Semaphore Value:2
    Number of tasks waitting for this Semaphore:0
    Name of Semaphore:SemTest
    ## Running-SemaphoreValue[1] ##:RT_TASK_CallBack_HandleB-170
    ## Running-SemaphoreValue[1] ##:RT_TASK_CallBack_HandleA-104
    ...
    

    Some-Bugs:
    🐛 B1 @ 運行相關程序運行後報如下錯誤? 0"000.000| BUG in low_init(): [main] Cobalt core not enabled in kernel

    1. 可能是由於在內核編譯的過程中未使能 Xenomai 的部分,或者在Linux編譯前,Kernel源代碼的實時內核Xenomai補丁未打.

二、Source Code & Compile System

1. main.c

主要測試了 ALRAM;COND;QUEUE;EVENT 相關內容

點擊查看代碼
#include <time.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <pthread.h>
#include <sys/time.h>

#include <unistd.h>
#include <time.h>

#include <native/timer.h>
#include <native/task.h>
#include <native/alarm.h>
#include <native/cond.h>
#include <native/queue.h>
#include <native/event.h>

#define ALRAM_DEBUG_MACRO 0
#define COND_DEBUG_MACRO 0
#define QUEUE_DEBUG_MACRO 0
#define EVENT_DEBUG_MACRO 1

#define TASK_PRIO 99 /* Highest RT Priority */
#define TASK_MODE 0  /* No Flags */
#define TASK_STKSZ 0 /* Stack Size(Use Default One) */

void RTKeyboardMonitor(void *arg);
void *KeyboardMonitor(void *arg);

typedef struct ST_RT_PARAM{
    int Param1;
    int Param2;
    RT_ALARM alarm_desc;
    RT_TASK server_desc;
}T_RT_PARAM;

void RT_TASK_CallBack_Handle(void *pUsrArg);
void RT_TASK_CallBack_Handle1(void *pUsrArg);
void RT_TASK_Cond_CallBack_Handle(void *pUsrArg);
void RT_TASK_Queue_CallBack_Handle(void *pUsrArg);
void RT_TASK_Event_CallBack_Handle(void *pUsrArg);

int main(int argc, char *argv[])
{
    int ret,err;
    pthread_t ThreadM;
    T_RT_PARAM *rt_param = (T_RT_PARAM *)malloc(sizeof(T_RT_PARAM));

#if ALRAM_DEBUG_MACRO // Alarm 看門狗定時器測試用例
    unsigned int ALARM_VALUE = 500000; /* Firstshot at now + 500us */
    unsigned long long ALARM_INTERVAL = 2500000000; /* Period is 250us */

    ret = rt_alarm_create(&rt_param->alarm_desc, "TEST_ALARM"); // ret = rt_alarm_create(&alarm, "TEST_ALARM", RT_TASK_CallBack_Handle, rt_param);
    if(ret != 0)
    {
        printf("rt_alarm_create Error...\n");
    }

    ret = rt_alarm_start(&rt_param->alarm_desc, ALARM_VALUE, ALARM_INTERVAL); // 配置了 看門狗定時器的整體延遲時間

    // 普通實時線程創建 不調用 rt_alarm_wait
    ret = rt_task_create(&rt_param->server_desc, "TEST_TASK", TASK_STKSZ, TASK_PRIO, TASK_MODE); // 創建一個實時線程
    ret = rt_task_start(&rt_param->server_desc, &RT_TASK_CallBack_Handle1, rt_param); // 啓動一個普通的實時任務,不通過 rt_alarm_wait 看門狗定時器延遲等待

    // 使用看門狗定時器的任務
    RT_TASK server1_desc;
    ret = rt_task_create(&server1_desc, "server1_desc", TASK_STKSZ, TASK_PRIO, TASK_MODE);
    ret = rt_task_start(&server1_desc, &RT_TASK_CallBack_Handle, rt_param);

#endif

#if COND_DEBUG_MACRO // Cond 條件變量測試

    // pthread_create(&ThreadM, NULL, KeyboardMonitor, NULL);

    RT_TASK server1_desc, server2_desc, keyboard_desc;
    ret = rt_task_create(&server1_desc, "server1_desc", TASK_STKSZ, TASK_PRIO, TASK_MODE);
    ret = rt_task_start(&server1_desc, &RT_TASK_CallBack_Handle1, rt_param);

    ret = rt_task_create(&server2_desc, "server2_desc", TASK_STKSZ, TASK_PRIO, TASK_MODE);
    ret = rt_task_start(&server2_desc, &RT_TASK_Cond_CallBack_Handle, rt_param);

    ret = rt_task_create(&keyboard_desc, "keyboard_desc", TASK_STKSZ, TASK_PRIO, TASK_MODE);
    ret = rt_task_start(&keyboard_desc, &RTKeyboardMonitor, NULL);

    usleep(1000000);

    RT_COND cond;
    RT_COND_INFO cond_info;

    ret = rt_cond_create(&cond, "TEST_COND_VAR_NAME");
    ret = rt_cond_inquire(&cond, &cond_info);
    rt_printf("The Condition Name:%s\n", cond_info.name);

    while(1)
    {
        usleep(1000);
    }

    rt_cond_delete(&cond);

#endif

#if QUEUE_DEBUG_MACRO // Buffer 線程IPC通信測試

    size_t pool_size = 100;
    size_t qlimit = 1000;
    int Mode = Q_FIFO;

    RT_QUEUE rt_queue;
    RT_QUEUE_INFO rt_queue_info;
    RT_TASK server1_desc, server2_desc, keyboard_desc;

    ret = rt_task_create(&server2_desc, "server2_desc", TASK_STKSZ, TASK_PRIO, TASK_MODE);
    ret = rt_task_start(&server2_desc, &RT_TASK_Queue_CallBack_Handle, rt_param);

    ret = rt_task_create(&keyboard_desc, "keyboard_desc", TASK_STKSZ, TASK_PRIO, TASK_MODE);
    ret = rt_task_start(&keyboard_desc, &RTKeyboardMonitor, NULL);

    err = rt_queue_create(&rt_queue, "RT_QUEUE_DEMO", pool_size, qlimit, Mode);

    err = rt_queue_inquire(&rt_queue, &rt_queue_info);
    rt_printf("The Main RT-Queue[%s]:\n", rt_queue_info.name);
    rt_printf("  Number of task currently waiting on the queue for messages:[%d]\n", rt_queue_info.nwaiters);
    rt_printf("  Number of messages pending in queue:[%d]\n", rt_queue_info.nmessages);
    rt_printf("  Queue Mode Bits:[%d]\n", rt_queue_info.mode);
    rt_printf("  Maximum number of messages in queue:[%d]\n", rt_queue_info.qlimit);
    rt_printf("  Size of memory pool for holding message buffers:[%d]\n", rt_queue_info.poolsize);
    rt_printf("  Amount of memory consumed from the buffer pool:[%d]\n", rt_queue_info.usedmem);


    while(1)
    {
        usleep(10000);
    }

    rt_queue_delete(&rt_queue);
#endif

#if EVENT_DEBUG_MACRO // Event 事件觸發測試
    int ivalue = 0x11;
    int Mode = EV_ANY;

    RT_EVENT rt_event;
    RT_EVENT_INFO rt_event_info;
    RT_TASK server1_desc, server2_desc, keyboard_desc;

    ret = rt_task_create(&server2_desc, "server2_desc", TASK_STKSZ, TASK_PRIO, TASK_MODE);
    ret = rt_task_start(&server2_desc, &RT_TASK_Event_CallBack_Handle, rt_param);

    ret = rt_task_create(&keyboard_desc, "keyboard_desc", TASK_STKSZ, TASK_PRIO, TASK_MODE);
    ret = rt_task_start(&keyboard_desc, &RTKeyboardMonitor, NULL);

    err = rt_event_create(&rt_event, "RT_EVENT_DEMO", ivalue, Mode);

    err = rt_event_inquire(&rt_event, &rt_event_info);
    rt_printf("The KeyBoard RT-Event[%s]:\n", rt_event_info.name);
    rt_printf("  Current value of the event flag group:[%d]\n", rt_event_info.nwaiters);
    rt_printf("  Number of tasks currently waiting for events:[%d]\n", rt_event_info.value);


    while(1)
    {
        usleep(10000);
    }

    rt_event_delete(&rt_event);
#endif

    while(1)
    {
        usleep(1000);
    }

    return 0;
}

void clean_up(T_RT_PARAM *rt_param)
{
    rt_alarm_delete(&rt_param->alarm_desc);
    rt_task_delete(&rt_param->server_desc);
}

void RTKeyboardMonitor(void *arg)
{
	int flag, err;
    char Key = 0;

#if EVENT_DEBUG_MACRO
    RT_EVENT rt_event;
    RT_EVENT_INFO rt_event_info;

    rt_printf("&&& Hello KeyboardMonitor World!\n");
    err = rt_event_bind(&rt_event, "RT_EVENT_DEMO", TM_INFINITE);
    rt_printf("### Hello KeyboardMonitor World!\n");

    err = rt_event_inquire(&rt_event, &rt_event_info);
    rt_printf("The KeyBoard RT-Event[%s]:\n", rt_event_info.name);
    rt_printf("  Current value of the event flag group:[%d]\n", rt_event_info.nwaiters);
    rt_printf("  Number of tasks currently waiting for events:[%d]\n", rt_event_info.value);
#endif

#if QUEUE_DEBUG_MACRO
    RT_QUEUE rt_queue;
    RT_QUEUE_INFO rt_queue_info;

    rt_printf("&&& Hello KeyboardMonitor World!\n");
    err = rt_queue_bind(&rt_queue, "RT_QUEUE_DEMO", TM_INFINITE); // bind 綁定Xenomai-RT Task 的全局 Queue 資源
    rt_printf("### Hello KeyboardMonitor World!\n");

    err = rt_queue_inquire(&rt_queue, &rt_queue_info); // 獲取queue相關的基礎信息
    rt_printf("The KeyBoard RT-Queue[%s]:\n", rt_queue_info.name);
    rt_printf("  Number of task currently waiting on the queue for messages:[%d]\n", rt_queue_info.nwaiters);
    rt_printf("  Number of messages pending in queue:[%d]\n", rt_queue_info.nmessages);
    rt_printf("  Queue Mode Bits:[%d]\n", rt_queue_info.mode);
    rt_printf("  Maximum number of messages in queue:[%d]\n", rt_queue_info.qlimit);
    rt_printf("  Size of memory pool for holding message buffers:[%d]\n", rt_queue_info.poolsize);
    rt_printf("  Amount of memory consumed from the buffer pool:[%d]\n", rt_queue_info.usedmem);
#endif

#if COND_DEBUG_MACRO
    RT_COND cond;
    RT_COND_INFO cond_info;

    rt_printf("&&& Hello KeyboardMonitor World!\n");
    err = rt_cond_bind(&cond, "TEST_COND_VAR_NAME", TM_INFINITE);
    rt_printf("### Hello KeyboardMonitor World!\n");

    err = rt_cond_inquire(&cond, &cond_info);
    rt_printf("The Condition Name:%s\n", cond_info.name);
#endif

    while(1)
    {
        Key = getchar();
        if(Key == 10) continue; // continue:避免重複輸出getchar緩衝區中的內容
        if('B' == Key)
        {
#if COND_DEBUG_MACRO
            flag = rt_cond_broadcast(&cond);
#endif
            rt_printf("rt_cond_broadcast:%d\n", flag);
        }
        if('s' == Key)
        {
#if COND_DEBUG_MACRO
            flag = rt_cond_signal(&cond);
#endif
            rt_printf("rt_cond_signal:%d\n", flag);
        }
        if('i' == Key)
        {
#if QUEUE_DEBUG_MACRO
            char *buffers = rt_queue_alloc(&rt_queue, 10);
            for(int i=0; i < 10 ; i++)
            {
                buffers[i] = i;
            }
            flag = rt_queue_send(&rt_queue, buffers, 10, Q_NORMAL);
#endif
            rt_printf("rt_queue_send:%d\n", flag);
        }
        if('e' == Key)
        {
#if EVENT_DEBUG_MACRO
            err = rt_event_signal(&rt_event, 0x11);
#endif
            rt_printf("rt_event_signal:%d\n", err);
        }
        if('k' == Key)
        {
            exit(0);
        }
    }
}

void *KeyboardMonitor(void *arg)
{
	int flag, err;
    char Key = 0;

    RT_COND cond;

    rt_printf("&&& Hello KeyboardMonitor World!\n");
    err = rt_cond_bind(&cond, "TEST_COND_VAR_NAME", TM_INFINITE);
    rt_printf("### Hello KeyboardMonitor World!\n");

    while(1)
    {
        Key = getchar();
        if(Key == 10) continue; // continue:避免重複輸出getchar緩衝區中的內容
        if('B' == Key)
        {
            flag = rt_cond_broadcast(&cond);
        }
        if('s' == Key)
        {
            flag = rt_cond_signal(&cond);
        }
        if('k' == Key)
        {
            exit(0);
        }
    }
    return NULL;
}

void RT_TASK_CallBack_Handle(void *pUsrArg)
{
    int err;
    T_RT_PARAM *rt_param = (T_RT_PARAM *)pUsrArg;
    rt_printf("## Running=[%d,%d] ##:%s-%d\n", rt_param->Param1, rt_param->Param2, __FUNCTION__, __LINE__);

    while(1)
    {
        err = rt_alarm_wait(&rt_param->alarm_desc); // 這裏會存在 切換到 Secondery Mode 的情況,導致MSW一直增加

        rt_printf("Hello Xenomai World!\n");
    }
}

void RT_TASK_CallBack_Handle1(void *pUsrArg)
{
    int err;
    int SamplePeriod = 200000000;
 
    T_RT_PARAM *rt_param = (T_RT_PARAM *)pUsrArg;
    rt_printf("## Running=[%d,%d] ##:%s-%d\n", rt_param->Param1, rt_param->Param2, __FUNCTION__, __LINE__);

    rt_task_set_periodic(NULL, TM_NOW, SamplePeriod); // 200ms更新一次
    while(1)
    {
        rt_task_wait_period(NULL);

        rt_printf("Hello Xenomai World-1!\n");
    }
}

void RT_TASK_Cond_CallBack_Handle(void *pUsrArg)
{
    int err;
    int counter = 0;
    int SamplePeriod = 200000000;
 
    T_RT_PARAM *rt_param = (T_RT_PARAM *)pUsrArg;
    rt_printf("## Running=[%d,%d] ##:%s-%d\n", rt_param->Param1, rt_param->Param2, __FUNCTION__, __LINE__);

    RT_COND cond;
    RT_COND_INFO cond_info;
    RT_MUTEX mutex_var;

    err = rt_mutex_create(&mutex_var, "rt_mutex");

    err = rt_cond_bind(&cond, "TEST_COND_VAR_NAME", TM_INFINITE);
    rt_printf("### Hello Xenomai-CondVariable World!\n");

    err = rt_cond_inquire(&cond, &cond_info);
    rt_printf("The Condition Name:%s\n", cond_info.name);

    struct timespec time_stamp;

    rt_task_set_periodic(NULL, TM_NOW, SamplePeriod); // 200ms更新一次
    while(1)
    {
        rt_task_wait_period(NULL);

        rt_printf("Hello Xenomai-CondVariable World[%d]!\n", counter);

        if(counter > 50)
        {
            clock_gettime(CLOCK_REALTIME, &time_stamp);
            time_stamp.tv_sec += 5;
            rt_printf("The Current TimeStamp=[%ld:%ld]\n", time_stamp.tv_sec, time_stamp.tv_nsec);

            err = rt_cond_wait_timed(&cond, &mutex_var, &time_stamp); // 設置了cond條件等待的時間節點,如果到達時間節點,條件爲被設置則返回超時錯誤 -ETIMEDOUT
            if(0 != err)
            {
                rt_printf("Xenomai-CondVariable wait Error:[%d,%d,%d,%d,%d,%d,%d]!\n", err, -EINVAL, -EIDRM, -EINTR, -EWOULDBLOCK, -ETIMEDOUT, -EPERM);
            }
            counter = 0;
        }
        counter++;
    }

    err = rt_cond_unbind(&cond);
}

void RT_TASK_Queue_CallBack_Handle(void *pUsrArg)
{
    int err;
    int counter = 0;
    int SamplePeriod = 200000000;
 
    T_RT_PARAM *rt_param = (T_RT_PARAM *)pUsrArg;
    rt_printf("## Running=[%d,%d] ##:%s-%d\n", rt_param->Param1, rt_param->Param2, __FUNCTION__, __LINE__);

    RT_QUEUE rt_queue;
    RT_QUEUE_INFO rt_queue_info;

    rt_printf("&&& Hello KeyboardMonitor World!\n");
    err = rt_queue_bind(&rt_queue, "RT_QUEUE_DEMO", TM_INFINITE);
    rt_printf("### Hello KeyboardMonitor World!\n");

    err = rt_queue_inquire(&rt_queue, &rt_queue_info);
    rt_printf("The KeyBoard RT-Queue[%s]:\n", rt_queue_info.name);
    rt_printf("  Number of task currently waiting on the queue for messages:[%d]\n", rt_queue_info.nwaiters);
    rt_printf("  Number of messages pending in queue:[%d]\n", rt_queue_info.nmessages);
    rt_printf("  Queue Mode Bits:[%d]\n", rt_queue_info.mode);
    rt_printf("  Maximum number of messages in queue:[%d]\n", rt_queue_info.qlimit);
    rt_printf("  Size of memory pool for holding message buffers:[%d]\n", rt_queue_info.poolsize);
    rt_printf("  Amount of memory consumed from the buffer pool:[%d]\n", rt_queue_info.usedmem);

    struct timespec time_stamp;

    void *buf_addr = NULL;
    ssize_t buf_size;

    rt_task_set_periodic(NULL, TM_NOW, SamplePeriod); // 200ms更新一次
    while(1)
    {
        rt_task_wait_period(NULL);
        rt_printf("Hello Xenomai-CondVariable World[%d]!\n", counter);

        clock_gettime(CLOCK_REALTIME, &time_stamp);
        time_stamp.tv_nsec += 100000;
        // rt_printf("The Current TimeStamp=[%ld:%ld]\n", time_stamp.tv_sec, time_stamp.tv_nsec);

        buf_size = rt_queue_receive_timed(&rt_queue, &buf_addr, &time_stamp);

        if(buf_size > 0)
        {
            rt_printf("Show the Buffer Content:");
            for(int i=0 ; i < buf_size ; i++)
            {
                rt_printf(" %d", ((char *)buf_addr)[i]);
            }
            rt_printf("\n");
        }
        rt_queue_free(&rt_queue, buf_addr);
    }

    err = rt_queue_unbind(&rt_queue);
}

void RT_TASK_Event_CallBack_Handle(void *pUsrArg)
{
    int err;
    int counter = 0;
    int SamplePeriod = 200000000;
 
    T_RT_PARAM *rt_param = (T_RT_PARAM *)pUsrArg;
    rt_printf("## Running=[%d,%d] ##:%s-%d\n", rt_param->Param1, rt_param->Param2, __FUNCTION__, __LINE__);

    RT_EVENT rt_event;
    RT_EVENT_INFO rt_event_info;

    rt_printf("&&& Hello KeyboardMonitor World!\n");
    err = rt_event_bind(&rt_event, "RT_EVENT_DEMO", TM_INFINITE);
    rt_printf("### Hello KeyboardMonitor World!\n");

    err = rt_event_inquire(&rt_event, &rt_event_info);
    rt_printf("The KeyBoard RT-Event[%s]:\n", rt_event_info.name);
    rt_printf("  Current value of the event flag group:[%d]\n", rt_event_info.nwaiters);
    rt_printf("  Number of tasks currently waiting for events:[%d]\n", rt_event_info.value);

    struct timespec time_stamp;

    unsigned int mask = 0x11;
    unsigned int mask_r;
    int mode = EV_ANY;

    rt_task_set_periodic(NULL, TM_NOW, SamplePeriod); // 200ms更新一次
    while(1)
    {
        rt_task_wait_period(NULL);
        rt_printf("Hello Xenomai-CondVariable World[%d]:%d!\n", counter, mask_r);

        clock_gettime(CLOCK_REALTIME, &time_stamp);
        time_stamp.tv_sec += 5;
        // rt_printf("The Current TimeStamp=[%ld:%ld]\n", time_stamp.tv_sec, time_stamp.tv_nsec);

        err = rt_event_wait_timed(&rt_event, mask, &mask_r, mode, &time_stamp);
        if(0 != err)
        {
            rt_printf("Xenomai-CondVariable wait Error:[%d,%d,%d,%d,%d,%d,%d]!\n", err, -EINVAL, -EIDRM, -EINTR, -EWOULDBLOCK, -ETIMEDOUT, -EPERM);
        }
    }

    err = rt_event_unbind(&rt_event);
}

2. MainRTHeap.c

主要測試了 HEAP 相關內容

點擊查看代碼
#include <time.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <pthread.h>
#include <sys/time.h>

#include <unistd.h>
#include <time.h>

#include <native/timer.h>
#include <native/task.h>
#include <native/alarm.h>
#include <native/cond.h>
#include <native/queue.h>
#include <native/event.h>

#include <native/heap.h>

#define TASK_PRIO 99 /* Highest RT Priority */
#define TASK_MODE 0  /* No Flags */
#define TASK_STKSZ 0 /* Stack Size(Use Default One) */

#define TEST_HEAP_BYTE_SIZE 1024*1536 // *1024*3

void RTKeyboardMonitor(void *arg);

#define PointerCastTest 0

#if PointerCastTest
typedef void * vaddr_t;
#endif

int main(int argc, char *argv[])
{
    int ret,err;

#if PointerCastTest
    vaddr_t p;
    p = (vaddr_t)malloc(64);
    *(int *)p = 10;
    for(int i=0; i<64 ; i++)
    {
        *(int *)(p+i) = 10;
        // printf("The Data Content of P[%d]:%x\n", i, *(int *)(p+i));
    }
    vaddr_t PTest = p;
    printf("PTest = %p=%p @ PTest Address:%p  Content:%x\n", PTest, p, &PTest, *(int *)PTest);
    PTest = *((vaddr_t*)PTest);
    printf("PTest = %p=%p @ PTest Address:%p  Content:%x\n", PTest, p, &PTest, *(int *)p);
#endif

    // RT_HEAP *heap = NULL; // 這樣申請時錯誤的,實際上rt_heap_create只是創建了以及ID號給heap,需要一個實體
    RT_HEAP heap;

    // int Array[1024*1024*3];
    int *Array = malloc(1024*1024*3*sizeof(int));

    const char HeapName[] = "HeapTest";
    err = rt_heap_create(&heap, HeapName, TEST_HEAP_BYTE_SIZE, H_SINGLE); // H_PRIO 以優先級排隊領取可用heap H_FIFO 以先到先得的方式領取可用heap  H_SINGLE 將創建的 heap內存當作一整個內存,在alloc申請時必須整塊申請,否則會報錯
    if(0 != err)
    {
        printf("Heap Create Error:[%d,%d,%d,%d,%d,%d,%d,%d,%d]!\n", err, -EINVAL, -EIDRM, -EINTR, -EWOULDBLOCK, -ETIMEDOUT, -EPERM, -ENOMEM, -EEXIST);
    }

#if 0 // 測試一下分兩次創建 Heap 的容量大小 發現能夠申請到的最大內存約爲 800KB
    RT_HEAP HeapBlock0;
    err = rt_heap_create(&HeapBlock0, "HeapBlock0", TEST_HEAP_BYTE_SIZE, H_SINGLE); // H_PRIO 以優先級排隊領取可用heap H_FIFO 以先到先得的方式領取可用heap  H_SINGLE 將創建的 heap內存當作一整個內存,在alloc申請時必須整塊申請,否則會報錯
    if(0 != err)
    {
        printf("HeapBlock0 Create Error:[%d,%d,%d,%d,%d,%d,%d,%d,%d]!\n", err, -EINVAL, -EIDRM, -EINTR, -EWOULDBLOCK, -ETIMEDOUT, -EPERM, -ENOMEM, -EEXIST);
    }
#endif

    usleep(1000);

    RT_HEAP_INFO heapinfo;
    err = rt_heap_inquire(&heap, &heapinfo); // H_PRIO 以優先級排隊領取可用heap H_FIFO 以先到先得的方式領取可用heap  H_SINGLE 將創建的 heap內存當作一整個內存,在alloc申請時必須整塊申請,否則會報錯
    if(0 != err)
    {
        printf("Heap Get Info Error:[%d,%d,%d,%d,%d,%d,%d,%d,%d]!\n", err, -EINVAL, -EIDRM, -EINTR, -EWOULDBLOCK, -ETIMEDOUT, -EPERM, -ENOMEM, -EEXIST);
    }
    printf("Heap Informations:\n");
    printf("  Number of tasks waitting for aviliable memory alloc:%d\n", heapinfo.nwaiters);
    printf("  The Heap Mode Flags given while Creation:%d\n", heapinfo.mode);
    printf("  Size of the Heap(Bytes) While Create:%d Bytes\n", heapinfo.heapsize);
    printf("  Maximum amount of memory avaliable from heap:%d Bytes\n", heapinfo.usablemem);
    printf("  Amount of memory currently consumed:%d Bytes\n", heapinfo.usedmem);
    printf("  Name of memory heap:%s\n", heapinfo.name);

    char *iPointer = NULL;
    err = rt_heap_alloc(&heap, TEST_HEAP_BYTE_SIZE, TM_NONBLOCK, (void **)&iPointer); // TM_INFINITE 永久等待 TM_NONBLOCK 不等待直接返回
    if(0 != err)
    {
        printf("Heap Alloc Error:[%d,%d,%d,%d,%d,%d,%d,%d,%d]!\n", err, -EINVAL, -EIDRM, -EINTR, -EWOULDBLOCK, -ETIMEDOUT, -EPERM, -ENOMEM, -EEXIST);
    }

    printf("The iPointer[%d]=KB\n", TEST_HEAP_BYTE_SIZE/1024);
    for(int i=0; i < TEST_HEAP_BYTE_SIZE ; i++)
    {
        iPointer[i] = i; // 對申請到的內存進行賦值操作
        // printf("%d ",iPointer[i]);
    }
    printf("\n");

    err = rt_heap_free(&heap, iPointer); // TM_INFINITE 永久等待 TM_NONBLOCK
    if(0 != err)
    {
        printf("Heap Free Error:[%d,%d,%d,%d,%d,%d,%d,%d,%d]!\n", err, -EINVAL, -EIDRM, -EINTR, -EWOULDBLOCK, -ETIMEDOUT, -EPERM, -ENOMEM, -EEXIST);
    }

    err = rt_heap_delete(&heap); // H_PRIO 以優先級排隊領取可用heap H_FIFO 以先到先得的方式領取可用heap
    if(0 != err)
    {
        printf("Heap Delete Error:[%d,%d,%d,%d,%d,%d,%d,%d,%d]!\n", err, -EINVAL, -EIDRM, -EINTR, -EWOULDBLOCK, -ETIMEDOUT, -EPERM, -ENOMEM, -EEXIST);
    }

    usleep(1000);

    return 0;
}

3. MainRTMutex.c

主要測試了 MUTEX 相關內容

點擊查看代碼
#include <time.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <pthread.h>
#include <sys/time.h>

#include <unistd.h>
#include <time.h>

#include <native/timer.h>
#include <native/task.h>
#include <native/alarm.h>
#include <native/cond.h>
#include <native/queue.h>
#include <native/event.h>

#include <native/heap.h>
#include <native/mutex.h>

#define DEBUG 0
#define HEAP_MAX_CREATE_TEST 1

#if DEBUG
    #define debug_rt_printf(...) rt_printf(__VA_ARGS__);
#else
    #define debug_rt_printf(...) ;
#endif

#define TASK_PRIO 99 /* Highest RT Priority */
#define TASK_MODE 0  /* No Flags */
#define TASK_STKSZ 0 /* Stack Size(Use Default One) */

#define TEST_HEAP_BYTE_SIZE 1024*200 // 1024*800 // 10

void RT_TASK_CallBack_HandleA(void *pUsrArg);
void RT_TASK_CallBack_HandleB(void *pUsrArg);

int main(int argc, char *argv[])
{
    int ret,err;

    RT_TASK RTTaskHandleA;
    ret = rt_task_create(&RTTaskHandleA, "RTTaskHandleA", TASK_STKSZ, TASK_PRIO, TASK_MODE); // 創建一個實時線程
    ret = rt_task_start(&RTTaskHandleA, &RT_TASK_CallBack_HandleA, NULL); // 啓動一個普通的實時任務,不通過 rt_alarm_wait 看門狗定時器延遲等待

    RT_TASK RTTaskHandleB;
    ret = rt_task_create(&RTTaskHandleB, "RTTaskHandleB", TASK_STKSZ, TASK_PRIO - 80, TASK_MODE); // 創建一個實時線程 線程優先級可以測試 但是未發現影響 可能定時完成時間充足,未發現阻塞的情況
    ret = rt_task_start(&RTTaskHandleB, &RT_TASK_CallBack_HandleB, NULL); // 啓動一個普通的實時任務,不通過 rt_alarm_wait 看門狗定時器延遲等待

    while(1)
    {
        usleep(1000);
    }

    return 0;
}

/**********************************************************************
* 函數名稱: // void RT_TASK_CallBack_HandleA(void *pUsrArg)

* 功能描述: // 創建共享 Heap 堆內存 以及 Mutex 鎖,並通過 RT_Mutex 鎖獲取搶佔共享資源
* 訪問的表: //
* 修改的表: //
* 輸出參數: // 對輸出參數的說明
* 返 回 值: // 
* 其它說明: // 其它說明
* 修改日期       修改人	     修改內容
* -----------------------------------------------
* 2021/11/02	  	    XXXX	      XXXX
***********************************************************************/
void RT_TASK_CallBack_HandleA(void *pUsrArg)
{
    int ret,err;

    rt_printf("## Running ##:%s-%d\n", __FUNCTION__, __LINE__);
    // RT_HEAP *heap = NULL; // 這樣申請時錯誤的,實際上rt_heap_create只是創建了以及ID號給heap,需要一個實體
    RT_HEAP heap;
    const char HeapName[] = "HeapTest";
    err = rt_heap_create(&heap, HeapName, TEST_HEAP_BYTE_SIZE, H_SINGLE); // H_PRIO 以優先級排隊領取可用heap H_FIFO 以先到先得的方式領取可用heap  H_SINGLE 將創建的 heap內存當作一整個內存,在alloc申請時必須整塊申請,否則會報錯
    if(0 != err)
    {
        debug_rt_printf("Heap Create Error:[%d,%d,%d,%d,%d,%d,%d,%d,%d]!\n", err, -EINVAL, -EIDRM, -EINTR, -EWOULDBLOCK, -ETIMEDOUT, -EPERM, -ENOMEM, -EEXIST);
    }

    // usleep(1000);

    RT_HEAP_INFO heapinfo;
    err = rt_heap_inquire(&heap, &heapinfo); // H_PRIO 以優先級排隊領取可用heap H_FIFO 以先到先得的方式領取可用heap  H_SINGLE 將創建的 heap內存當作一整個內存,在alloc申請時必須整塊申請,否則會報錯
    if(0 != err)
    {
        debug_rt_printf("Heap Get Info Error:[%d,%d,%d,%d,%d,%d,%d,%d,%d]!\n", err, -EINVAL, -EIDRM, -EINTR, -EWOULDBLOCK, -ETIMEDOUT, -EPERM, -ENOMEM, -EEXIST);
    }
    rt_printf("Heap Informations:\n");
    rt_printf("  Number of tasks waitting for aviliable memory alloc:%d\n", heapinfo.nwaiters);
    rt_printf("  The Heap Mode Flags given while Creation:%d\n", heapinfo.mode);
    rt_printf("  Size of the Heap(Bytes) While Create:%d Bytes\n", heapinfo.heapsize);
    rt_printf("  Maximum amount of memory avaliable from heap:%d Bytes\n", heapinfo.usablemem);
    rt_printf("  Amount of memory currently consumed:%d Bytes\n", heapinfo.usedmem);
    rt_printf("  Name of memory heap:%s\n", heapinfo.name);

    char *iPointer = NULL;
    err = rt_heap_alloc(&heap, TEST_HEAP_BYTE_SIZE, TM_NONBLOCK, (void **)&iPointer); // TM_INFINITE 永久等待 TM_NONBLOCK 不等待直接返回 從堆當中獲取對應大小的 Heap 資源
    if(0 != err)
    {
        rt_printf("Heap Alloc Error:[%d,%d,%d,%d,%d,%d,%d,%d,%d]!\n", err, -EINVAL, -EIDRM, -EINTR, -EWOULDBLOCK, -ETIMEDOUT, -EPERM, -ENOMEM, -EEXIST);
    }


    RT_MUTEX mutex;
    const char MutexName[] = "MutexTest";
    err = rt_mutex_create(&mutex, MutexName); // 創建一個鎖變量
    if(0 != err)
    {
        debug_rt_printf("Mutex Create Error:[%d,%d,%d,%d,%d,%d,%d,%d,%d]!\n", err, -EINVAL, -EIDRM, -EINTR, -EWOULDBLOCK, -ETIMEDOUT, -EPERM, -ENOMEM, -EEXIST);
    }

    rt_task_sleep(1000); // nano second

    RT_MUTEX_INFO mutexinfo; // 獲取鎖的基本信息
    err = rt_mutex_inquire(&mutex, &mutexinfo); // RT_MUTEX_INFO 結構體當中的第一個成員變量爲 RT_TASK結構體,標識了當前鎖被某一個實時任務佔用着,可以通過  rt_task_inquire() 函數接口實現對任務信息的獲取
    if(0 != err)
    {
        debug_rt_printf("Mutex Get Info Error:[%d,%d,%d,%d,%d,%d,%d,%d,%d]!\n", err, -EINVAL, -EIDRM, -EINTR, -EWOULDBLOCK, -ETIMEDOUT, -EPERM, -ENOMEM, -EEXIST);
    }
    
    RT_TASK_INFO taskinfo; // 獲取Task任務的基本信息-通過鎖中保存的實時任務基本結構
    err = rt_task_inquire(&mutexinfo.owner, &taskinfo); // RT_MUTEX_INFO 結構體當中的第一個成員變量爲 RT_TASK結構體,標識了當前鎖被某一個實時任務佔用着,可以通過  rt_task_inquire() 函數接口實現對任務信息的獲取
    if(0 != err)
    {
        debug_rt_printf("Task Get Info Error:[%d,%d,%d,%d,%d,%d,%d,%d,%d]!\n", err, -EINVAL, -EIDRM, -EINTR, -EWOULDBLOCK, -ETIMEDOUT, -EPERM, -ENOMEM, -EEXIST);
    }

    debug_rt_printf("Mutex Informations:\n");
    debug_rt_printf("  Owner-Current Mutex Hold Task@Name:%s\n", taskinfo.name);
    debug_rt_printf("  Owner-Current Mutex Hold Task@Priority:%d\n", taskinfo.prio);
    debug_rt_printf("  Name of Sync Mutex Lock:%s\n", mutexinfo.name);

    int SamplePeriod = 200000000;
    rt_task_set_periodic(NULL, TM_NOW, SamplePeriod); // 200ms更新一次

    while(1)
    {

        // Get the Mutex Lock
        err = rt_mutex_acquire(&mutex, TM_INFINITE); // 清理mutex資源 對於 Xenomai 的數據資源使用完之後一定要嚴格回收,否則會導致資源流失,影響整個系統的資源獲取  TM_INFINITE 一直等待鎖的獲取
        if(0 != err)
        {
            debug_rt_printf("Task Get Info Error:[%d,%d,%d,%d,%d,%d,%d,%d,%d]!\n", err, -EINVAL, -EIDRM, -EINTR, -EWOULDBLOCK, -ETIMEDOUT, -EPERM, -ENOMEM, -EEXIST);
        }

        debug_rt_printf("The RT_TASK_CallBack_HandleA iPointer[%d]=");
        for(int i=0; i < TEST_HEAP_BYTE_SIZE ; i++)
        {
            debug_rt_printf("%d ",iPointer[i]); // 打印被實時線程B修改後的 共享內存Heap中的值
        }

        debug_rt_printf("  ===>   ");

        for(int i=0; i < TEST_HEAP_BYTE_SIZE ; i++)
        {
            iPointer[i] = i; // 對申請到的內存進行賦值操作
            debug_rt_printf("%d ",iPointer[i]);
        }

        debug_rt_printf("\n");

        // Release the Mutex Lock
        err = rt_mutex_release(&mutex); // 清理mutex資源 對於 Xenomai 的數據資源使用完之後一定要嚴格回收,否則會導致資源流失,影響整個系統的資源獲取
        if(0 != err)
        {
            debug_rt_printf("Task Get Info Error:[%d,%d,%d,%d,%d,%d,%d,%d,%d]!\n", err, -EINVAL, -EIDRM, -EINTR, -EWOULDBLOCK, -ETIMEDOUT, -EPERM, -ENOMEM, -EEXIST);
        }

        rt_task_wait_period(NULL);
    }

    err = rt_heap_free(&heap, iPointer); // TM_INFINITE 永久等待 TM_NONBLOCK
    if(0 != err)
    {
        debug_rt_printf("Heap Free Error:[%d,%d,%d,%d,%d,%d,%d,%d,%d]!\n", err, -EINVAL, -EIDRM, -EINTR, -EWOULDBLOCK, -ETIMEDOUT, -EPERM, -ENOMEM, -EEXIST);
    }

    err = rt_heap_delete(&heap); // H_PRIO 以優先級排隊領取可用heap H_FIFO 以先到先得的方式領取可用heap
    if(0 != err)
    {
        debug_rt_printf("Heap Delete Error:[%d,%d,%d,%d,%d,%d,%d,%d,%d]!\n", err, -EINVAL, -EIDRM, -EINTR, -EWOULDBLOCK, -ETIMEDOUT, -EPERM, -ENOMEM, -EEXIST);
    }

    err = rt_mutex_release(&mutex); // 清理mutex資源 對於 Xenomai 的數據資源使用完之後一定要嚴格回收,否則會導致資源流失,影響整個系統的資源獲取
    if(0 != err)
    {
        debug_rt_printf("Task Get Info Error:[%d,%d,%d,%d,%d,%d,%d,%d,%d]!\n", err, -EINVAL, -EIDRM, -EINTR, -EWOULDBLOCK, -ETIMEDOUT, -EPERM, -ENOMEM, -EEXIST);
    }

    err = rt_mutex_delete(&mutex); // 清理mutex資源 對於 Xenomai 的數據資源使用完之後一定要嚴格回收,否則會導致資源流失,影響整個系統的資源獲取
    if(0 != err)
    {
        debug_rt_printf("Task Get Info Error:[%d,%d,%d,%d,%d,%d,%d,%d,%d]!\n", err, -EINVAL, -EIDRM, -EINTR, -EWOULDBLOCK, -ETIMEDOUT, -EPERM, -ENOMEM, -EEXIST);
    }
}

/**********************************************************************
* 函數名稱: // void RT_TASK_CallBack_HandleB(void *pUsrArg)

* 功能描述: // 通過 Bind 相關接口,獲取實時線程A中創建的Heap以及Mutex,從而通過獲取Mutex的權限對共享內存Heap的內容進行修改
* 訪問的表: //
* 修改的表: //
* 輸出參數: // 對輸出參數的說明
* 返 回 值: // 
* 其它說明: // 其它說明
* 修改日期       修改人	     修改內容
* -----------------------------------------------
* 2021/11/02	  	    XXXX	      XXXX
***********************************************************************/
void RT_TASK_CallBack_HandleB(void *pUsrArg)
{
    int ret,err;

#if HEAP_MAX_CREATE_TEST // 在這裏有兩個 RT-Task 都進行了 Heap 內存空間的申請操作,發現兩邊都可以申請到Heap空間
    RT_HEAP heap1;
    const char HeapName1[] = "HeapTest1";
    err = rt_heap_create(&heap1, HeapName1, TEST_HEAP_BYTE_SIZE*4, H_SINGLE); // H_PRIO 以優先級排隊領取可用heap H_FIFO 以先到先得的方式領取可用heap  H_SINGLE 將創建的 heap內存當作一整個內存,在alloc申請時必須整塊申請,否則會報錯
    if(0 != err)
    {
        rt_printf("Heap1 Create Error:[%d,%d,%d,%d,%d,%d,%d,%d,%d]!\n", err, -EINVAL, -EIDRM, -EINTR, -EWOULDBLOCK, -ETIMEDOUT, -EPERM, -ENOMEM, -EEXIST);
    }

    RT_HEAP_INFO heapinfo1;
    err = rt_heap_inquire(&heap1, &heapinfo1); // H_PRIO 以優先級排隊領取可用heap H_FIFO 以先到先得的方式領取可用heap  H_SINGLE 將創建的 heap內存當作一整個內存,在alloc申請時必須整塊申請,否則會報錯
    if(0 != err)
    {
        rt_printf("Heap1 Create Get Info Error:[%d,%d,%d,%d,%d,%d,%d,%d,%d]!\n", err, -EINVAL, -EIDRM, -EINTR, -EWOULDBLOCK, -ETIMEDOUT, -EPERM, -ENOMEM, -EEXIST);
    }
    rt_printf("Heap1 Informations:\n");
    rt_printf("  Number of tasks waitting for aviliable memory alloc:%d\n", heapinfo1.nwaiters);
    rt_printf("  The Heap Mode Flags given while Creation:%d\n", heapinfo1.mode);
    rt_printf("  Size of the Heap(Bytes) While Create:%d Bytes\n", heapinfo1.heapsize);
    rt_printf("  Maximum amount of memory avaliable from heap:%d Bytes\n", heapinfo1.usablemem);
    rt_printf("  Amount of memory currently consumed:%d Bytes\n", heapinfo1.usedmem);
    rt_printf("  Name of memory heap:%s\n", heapinfo1.name);
#endif

    rt_printf("## Running ##:%s-%d\n", __FUNCTION__, __LINE__);
    // RT_HEAP *heap = NULL; // 這樣申請時錯誤的,實際上rt_heap_create只是創建了以及ID號給heap,需要一個實體
    RT_HEAP heap;
    const char HeapName[] = "HeapTest";
    err = rt_heap_bind(&heap, HeapName, TM_INFINITE); // TM_INFINITE 無限時間等待bind到指定的heap內存堆
    if(0 != err)
    {
        debug_rt_printf("Heap Bind Error:[%d,%d,%d,%d,%d,%d,%d,%d,%d]!\n", err, -EINVAL, -EIDRM, -EINTR, -EWOULDBLOCK, -ETIMEDOUT, -EPERM, -ENOMEM, -EEXIST);
    }

    RT_HEAP_INFO heapinfo;
    err = rt_heap_inquire(&heap, &heapinfo); // H_PRIO 以優先級排隊領取可用heap H_FIFO 以先到先得的方式領取可用heap  H_SINGLE 將創建的 heap內存當作一整個內存,在alloc申請時必須整塊申請,否則會報錯
    if(0 != err)
    {
        rt_printf("Heap Bind Get Info Error:[%d,%d,%d,%d,%d,%d,%d,%d,%d]!\n", err, -EINVAL, -EIDRM, -EINTR, -EWOULDBLOCK, -ETIMEDOUT, -EPERM, -ENOMEM, -EEXIST);
    }
    rt_printf("Heap Bind Informations:\n");
    rt_printf("  Number of tasks waitting for aviliable memory alloc:%d\n", heapinfo.nwaiters);
    rt_printf("  The Heap Mode Flags given while Creation:%d\n", heapinfo.mode);
    rt_printf("  Size of the Heap(Bytes) While Create:%d Bytes\n", heapinfo.heapsize);
    rt_printf("  Maximum amount of memory avaliable from heap:%d Bytes\n", heapinfo.usablemem);
    rt_printf("  Amount of memory currently consumed:%d Bytes\n", heapinfo.usedmem);
    rt_printf("  Name of memory heap:%s\n", heapinfo.name);

    char *iPointer = NULL;
    err = rt_heap_alloc(&heap, TEST_HEAP_BYTE_SIZE, TM_NONBLOCK, (void **)&iPointer); // TM_INFINITE 永久等待 TM_NONBLOCK 不等待直接返回
    if(0 != err)
    {
        debug_rt_printf("Heap Alloc Error:[%d,%d,%d,%d,%d,%d,%d,%d,%d]!\n", err, -EINVAL, -EIDRM, -EINTR, -EWOULDBLOCK, -ETIMEDOUT, -EPERM, -ENOMEM, -EEXIST);
    }

    RT_MUTEX mutex;
    const char MutexName[] = "MutexTest";
    err = rt_mutex_bind(&mutex, MutexName, TM_INFINITE); // 創建一個鎖變量
    if(0 != err)
    {
        debug_rt_printf("Mutex Bind Error:[%d,%d,%d,%d,%d,%d,%d,%d,%d]!\n", err, -EINVAL, -EIDRM, -EINTR, -EWOULDBLOCK, -ETIMEDOUT, -EPERM, -ENOMEM, -EEXIST);
    }

    // usleep(1000);

    RT_MUTEX_INFO mutexinfo; // 獲取鎖的基本信息
    err = rt_mutex_inquire(&mutex, &mutexinfo); // RT_MUTEX_INFO 結構體當中的第一個成員變量爲 RT_TASK結構體,標識了當前鎖被某一個實時任務佔用着,可以通過  rt_task_inquire() 函數接口實現對任務信息的獲取
    if(0 != err)
    {
        debug_rt_printf("Mutex Bind Get Info Error:[%d,%d,%d,%d,%d,%d,%d,%d,%d]!\n", err, -EINVAL, -EIDRM, -EINTR, -EWOULDBLOCK, -ETIMEDOUT, -EPERM, -ENOMEM, -EEXIST);
    }
    
    RT_TASK_INFO taskinfo; // 獲取Task任務的基本信息-通過鎖中保存的實時任務基本結構
    err = rt_task_inquire(&mutexinfo.owner, &taskinfo); // RT_MUTEX_INFO 結構體當中的第一個成員變量爲 RT_TASK結構體,標識了當前鎖被某一個實時任務佔用着,可以通過  rt_task_inquire() 函數接口實現對任務信息的獲取
    if(0 != err)
    {
        debug_rt_printf("Task Get Info Error:[%d,%d,%d,%d,%d,%d,%d,%d,%d]!\n", err, -EINVAL, -EIDRM, -EINTR, -EWOULDBLOCK, -ETIMEDOUT, -EPERM, -ENOMEM, -EEXIST);
    }

    debug_rt_printf("Mutex Bind Informations:\n");
    debug_rt_printf("  Owner-Current Mutex Hold Task@Name:%s\n", taskinfo.name);
    debug_rt_printf("  Owner-Current Mutex Hold Task@Priority:%d\n", taskinfo.prio);
    debug_rt_printf("  Name of Sync Mutex Lock:%s\n", mutexinfo.name);


    int SamplePeriod = 200000000;
    rt_task_set_periodic(NULL, TM_NOW, SamplePeriod); // 200ms更新一次

    while(1)
    {
        // Get the Mutex Lock
        err = rt_mutex_acquire(&mutex, TM_INFINITE); // 清理mutex資源 對於 Xenomai 的數據資源使用完之後一定要嚴格回收,否則會導致資源流失,影響整個系統的資源獲取  TM_INFINITE 一直等待鎖的獲取
        if(0 != err)
        {
            debug_rt_printf("Task Get Info Error:[%d,%d,%d,%d,%d,%d,%d,%d,%d]!\n", err, -EINVAL, -EIDRM, -EINTR, -EWOULDBLOCK, -ETIMEDOUT, -EPERM, -ENOMEM, -EEXIST);
        }

        debug_rt_printf("The RT_TASK_CallBack_HandleB iPointer[%d]=");
        for(int i=0; i < TEST_HEAP_BYTE_SIZE ; i++)
        {
            debug_rt_printf("%d ",iPointer[i]); // 打印被實時線程B修改後的 共享內存Heap中的值
        }

        debug_rt_printf("  ===>   ");

        for(int i=0; i < TEST_HEAP_BYTE_SIZE ; i++)
        {
            iPointer[i] = i+100; // 對申請到的內存進行賦值操作
            debug_rt_printf("%d ",iPointer[i]);
        }

        debug_rt_printf("\n");

        // Release the Mutex Lock
        err = rt_mutex_release(&mutex); // 清理mutex資源 對於 Xenomai 的數據資源使用完之後一定要嚴格回收,否則會導致資源流失,影響整個系統的資源獲取
        if(0 != err)
        {
            debug_rt_printf("Task Get Info Error:[%d,%d,%d,%d,%d,%d,%d,%d,%d]!\n", err, -EINVAL, -EIDRM, -EINTR, -EWOULDBLOCK, -ETIMEDOUT, -EPERM, -ENOMEM, -EEXIST);
        }

        rt_task_wait_period(NULL);
    }

    err = rt_heap_unbind(&heap); // TM_INFINITE 永久等待 TM_NONBLOCK
    if(0 != err)
    {
        debug_rt_printf("Heap Unbind Error:[%d,%d,%d,%d,%d,%d,%d,%d,%d]!\n", err, -EINVAL, -EIDRM, -EINTR, -EWOULDBLOCK, -ETIMEDOUT, -EPERM, -ENOMEM, -EEXIST);
    }

    err = rt_mutex_unbind(&mutex); // TM_INFINITE 永久等待 TM_NONBLOCK
    if(0 != err)
    {
        debug_rt_printf("Mutex Unbind Error:[%d,%d,%d,%d,%d,%d,%d,%d,%d]!\n", err, -EINVAL, -EIDRM, -EINTR, -EWOULDBLOCK, -ETIMEDOUT, -EPERM, -ENOMEM, -EEXIST);
    }

}

4. MainRTPipeClient.c

主要測試了 PipeClient 相關內容,需要配合 MainRTPipeServer.c

點擊查看代碼
#include <time.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <pthread.h>
#include <sys/time.h>

#include <unistd.h>
#include <time.h>

#include <native/timer.h>
#include <native/task.h>
#include <native/alarm.h>
#include <native/cond.h>
#include <native/queue.h>
#include <native/event.h>

#include <native/heap.h>
#include <native/mutex.h>
#include <native/pipe.h>

#define TASK_PRIO 99 /* Highest RT Priority */
#define TASK_MODE 0  /* No Flags */
#define TASK_STKSZ 0 /* Stack Size(Use Default One) */

#define TEST_HEAP_BYTE_SIZE 10

void RT_TASK_CallBack_HandleA(void *pUsrArg);
void RT_TASK_CallBack_HandleB(void *pUsrArg);

int main(int argc, char *argv[])
{
    int ret,err;

    // RT_TASK RTTaskHandleB;
    // err = rt_task_create(&RTTaskHandleB, "RTTaskHandleB", TASK_STKSZ, TASK_PRIO, TASK_MODE); // 創建一個實時線程 線程優先級可以測試 但是未發現影響 可能定時完成時間充足,未發現阻塞的情況
    // if(0 != err)
    // {
    //     printf("Pipe Create Error:[%d,%d,%d,%d,%d,%d,%d,%d,%d]!\n", err, -EINVAL, -EIDRM, -EINTR, -EWOULDBLOCK, -ETIMEDOUT, -EPERM, -ENOMEM, -EEXIST);
    // }
    // err = rt_task_start(&RTTaskHandleB, &RT_TASK_CallBack_HandleB, NULL); // 啓動一個普通的實時任務,不通過 rt_alarm_wait 看門狗定時器延遲等待
    // if(0 != err)
    // {
    //     printf("Pipe Create Error:[%d,%d,%d,%d,%d,%d,%d,%d,%d]!\n", err, -EINVAL, -EIDRM, -EINTR, -EWOULDBLOCK, -ETIMEDOUT, -EPERM, -ENOMEM, -EEXIST);
    // }
    

    rt_printf("## Running ##:%s-%d\n", __FUNCTION__, __LINE__);

    FILE *PipeHandle = NULL;
    char DataBuffer[30];
    PipeHandle = fopen("/dev/rtp1", "r");

    ssize_t DataLen = 0;

    while(1)
    {
        DataLen = fread(DataBuffer, 1, 30, PipeHandle);
        if( DataLen > 0 )
        {
            for(int i = 0 ; i < DataLen ; i++)
            {
                printf("%c", DataBuffer[i]);
            }
            printf("\n");
        }
        usleep(1000);
    }


    // RT_PIPE pipe;
    // const char PipeName[] = "/proc/xenomai/registry/rtipc/xddp/PipeTest"; // "PipeTest";
    // err = rt_pipe_bind(&pipe, PipeName, TM_INFINITE); // 不限時等待綁定 TM_INFINITE TM_NONBLOCK
    // if(0 != err)
    // {
    //     rt_printf("Pipe Create Error:[%d,%d,%d,%d,%d,%d,%d,%d,%d]!\n", err, -EINVAL, -EIDRM, -EINTR, -EWOULDBLOCK, -ETIMEDOUT, -EPERM, -ENOMEM, -EEXIST);
    // }

    // int SamplePeriod = 200000000;
    // rt_task_set_periodic(NULL, TM_NOW, SamplePeriod); // 200ms更新一次

    // ssize_t DataLen = 0;
    // char data_read[10]={0};
    // while(1)
    // {
    //     rt_task_wait_period(NULL);
    //     DataLen = rt_pipe_read(&pipe, data_read, 10, TM_NONBLOCK); // TM_INFINITE 永久等待讀取到Pipe中的數據 
    //     if(DataLen < 0)
    //     {
    //         rt_printf("Pipe No Data Recieved Error:[%d,%d,%d,%d,%d,%d,%d,%d,%d]!\n", DataLen, -EINVAL, -EIDRM, -EINTR, -EWOULDBLOCK, -ETIMEDOUT, -EPERM, -ENOMEM, -EEXIST);
    //         continue;
    //     }
    //     rt_printf("Recieve Data[%d]: %s\n", DataLen, data_read);
    // }

    // err = rt_pipe_unbind(&pipe); // TM_INFINITE 永久等待 TM_NONBLOCK
    // if(0 != err)
    // {
    //     rt_printf("Pipe Unbind Error:[%d,%d,%d,%d,%d,%d,%d,%d,%d]!\n", err, -EINVAL, -EIDRM, -EINTR, -EWOULDBLOCK, -ETIMEDOUT, -EPERM, -ENOMEM, -EEXIST);
    // }

    while(1)
    {
        usleep(1000);
    }

    return 0;
}

/**********************************************************************
* 函數名稱: // void RT_TASK_CallBack_HandleA(void *pUsrArg)

* 功能描述: // 創建共享 Heap 堆內存 以及 Mutex 鎖,並通過 RT_Mutex 鎖獲取搶佔共享資源
* 訪問的表: //
* 修改的表: //
* 輸出參數: // 對輸出參數的說明
* 返 回 值: // 
* 其它說明: // 其它說明
* 修改日期       修改人	     修改內容
* -----------------------------------------------
* 2021/11/02	  	    XXXX	      XXXX
***********************************************************************/
void RT_TASK_CallBack_HandleA(void *pUsrArg)
{
    int ret,err;

    rt_printf("## Running ##:%s-%d\n", __FUNCTION__, __LINE__);

    RT_PIPE pipe;
    const char PipeName[] = "PipeTest";
    err = rt_pipe_create(&pipe, PipeName, 1, 1000); // P_MINOR_AUTO:設備Pipe節點自動創建功能  poolsize:0 Pipe管道緩衝池的大小,設置爲0時則直接使用 Xenomai 系統的Heap空間
    if(0 != err)
    {
        rt_printf("Pipe Create Error:[%d,%d,%d,%d,%d,%d,%d,%d,%d]!\n", err, -EINVAL, -EIDRM, -EINTR, -EWOULDBLOCK, -ETIMEDOUT, -EPERM, -ENOMEM, -EEXIST);
    }

    int SamplePeriod = 200000000;
    rt_task_set_periodic(NULL, TM_NOW, SamplePeriod); // 200ms更新一次

    size_t data_count;

    const char writer_data[] = "Writer PIPE DATA...";
    const char stream_data[] = "Stream PIPE DATA...";

    // unsigned long long st = rt_timer_read(); // 獲取 Xenomai 的實時線程當前時間

    while(1)
    {
        data_count = rt_pipe_write(&pipe, writer_data, strlen(writer_data), P_NORMAL); // 使用write的方式完成Pipe數據的傳輸過程 mode:P_URGENT 標識數據的後入先出順序 LIFO | P_NORMAL==>FIFO

        rt_task_sleep(10); // rt-thread 實時線程延遲函數 相對延時函數 最小延遲精度 clock ticks 需要絕對延時時間使用 rt_task_sleep_until() 接口 單位納秒 ns

        data_count = rt_pipe_stream(&pipe, stream_data, strlen(writer_data)); // 使用流的方式Stream傳輸數據

        rt_printf("RT_TASK_CallBack_HandleA %d Datas Send over...\n", data_count);

        rt_task_wait_period(NULL);
    }

    err = rt_pipe_delete(&pipe); // 清理mutex資源 對於 Xenomai 的數據資源使用完之後一定要嚴格回收,否則會導致資源流失,影響整個系統的資源獲取
    if(0 != err)
    {
        rt_printf("Pipe Delete Error:[%d,%d,%d,%d,%d,%d,%d,%d,%d]!\n", err, -EINVAL, -EIDRM, -EINTR, -EWOULDBLOCK, -ETIMEDOUT, -EPERM, -ENOMEM, -EEXIST);
    }
}

/**********************************************************************
* 函數名稱: // void RT_TASK_CallBack_HandleB(void *pUsrArg)

* 功能描述: // 通過 Bind 相關接口,獲取實時線程A中創建的Heap以及Mutex,從而通過獲取Mutex的權限對共享內存Heap的內容進行修改
* 訪問的表: //
* 修改的表: //
* 輸出參數: // 對輸出參數的說明
* 返 回 值: // 
* 其它說明: // 其它說明
* 修改日期       修改人	     修改內容
* -----------------------------------------------
* 2021/11/02	  	    XXXX	      XXXX
***********************************************************************/
void RT_TASK_CallBack_HandleB(void *pUsrArg)
{
    int ret,err;

    rt_printf("## Running ##:%s-%d\n", __FUNCTION__, __LINE__);
    
    int SamplePeriod = 200000000;
    rt_task_set_periodic(NULL, TM_NOW, SamplePeriod); // 200ms更新一次

    RT_PIPE pipe;
    const char PipeName[] = "PipeTest";
    err = rt_pipe_bind(&pipe, PipeName, TM_NONBLOCK); // 不限時等待綁定 TM_INFINTE TM_NONBLOCK
    if(0 != err)
    {
        rt_printf("Pipe Create Error:[%d,%d,%d,%d,%d,%d,%d,%d,%d]!\n", err, -EINVAL, -EIDRM, -EINTR, -EWOULDBLOCK, -ETIMEDOUT, -EPERM, -ENOMEM, -EEXIST);
    }

    ssize_t DataLen = 0;
    char data_read[10]={0};
    while(1)
    {
        rt_task_wait_period(NULL);
        DataLen = rt_pipe_read(&pipe, data_read, 10, TM_NONBLOCK); // TM_INFINITE 永久等待讀取到Pipe中的數據 
        if(DataLen < 0)
        {
            rt_printf("Pipe No Data Recieved Error:[%d,%d,%d,%d,%d,%d,%d,%d,%d]!\n", DataLen, -EINVAL, -EIDRM, -EINTR, -EWOULDBLOCK, -ETIMEDOUT, -EPERM, -ENOMEM, -EEXIST);
            continue;
        }
        rt_printf("Recieve Data[%d]: %s\n", DataLen, data_read);
    }

    err = rt_pipe_unbind(&pipe); // TM_INFINITE 永久等待 TM_NONBLOCK
    if(0 != err)
    {
        rt_printf("Pipe Unbind Error:[%d,%d,%d,%d,%d,%d,%d,%d,%d]!\n", err, -EINVAL, -EIDRM, -EINTR, -EWOULDBLOCK, -ETIMEDOUT, -EPERM, -ENOMEM, -EEXIST);
    }
}

5. MainRTPipeServer.c

主要測試了 PipeClient 相關內容,需要配合 MainRTPipeClient.c

點擊查看代碼
#include <time.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <pthread.h>
#include <sys/time.h>

#include <unistd.h>
#include <time.h>

#include <native/timer.h>
#include <native/task.h>
#include <native/alarm.h>
#include <native/cond.h>
#include <native/queue.h>
#include <native/event.h>

#include <native/heap.h>
#include <native/mutex.h>
#include <native/pipe.h>

#define TASK_PRIO 99 /* Highest RT Priority */
#define TASK_MODE 0  /* No Flags */
#define TASK_STKSZ 0 /* Stack Size(Use Default One) */

#define TEST_HEAP_BYTE_SIZE 10

#define FORK_DEBUG 0

void RT_TASK_CallBack_HandleA(void *pUsrArg);
void RT_TASK_CallBack_HandleB(void *pUsrArg);

int main(int argc, char *argv[])
{
    int ret,err;

    printf("Master Process PID:%ld\n", (long)getpid());

    RT_TASK RTTaskHandleA;
    err = rt_task_create(&RTTaskHandleA, "RTTaskHandleA", TASK_STKSZ, TASK_PRIO, TASK_MODE); // 創建一個實時線程
    if(0 != err)
    {
        printf("Pipe Create Error:[%d,%d,%d,%d,%d,%d,%d,%d,%d]!\n", err, -EINVAL, -EIDRM, -EINTR, -EWOULDBLOCK, -ETIMEDOUT, -EPERM, -ENOMEM, -EEXIST);
    }
    err = rt_task_start(&RTTaskHandleA, &RT_TASK_CallBack_HandleA, NULL); // 啓動一個普通的實時任務,不通過 rt_alarm_wait 看門狗定時器延遲等待
    if(0 != err)
    {
        printf("Pipe Create Error:[%d,%d,%d,%d,%d,%d,%d,%d,%d]!\n", err, -EINVAL, -EIDRM, -EINTR, -EWOULDBLOCK, -ETIMEDOUT, -EPERM, -ENOMEM, -EEXIST);
    }

#if FORK_DEBUG

    pid_t sub_pid = 0;
    sub_pid = fork();

    if(sub_pid == 0) // 只有子進程才創建接收端的 PIPE 實時線程
    {
        RT_TASK RTTaskHandleA;
        err = rt_task_create(&RTTaskHandleA, "RTTaskHandleA", TASK_STKSZ, TASK_PRIO, TASK_MODE); // 創建一個實時線程
        if(0 != err)
        {
            printf("Pipe Create Error:[%d,%d,%d,%d,%d,%d,%d,%d,%d]!\n", err, -EINVAL, -EIDRM, -EINTR, -EWOULDBLOCK, -ETIMEDOUT, -EPERM, -ENOMEM, -EEXIST);
        }
        err = rt_task_start(&RTTaskHandleA, &RT_TASK_CallBack_HandleA, NULL); // 啓動一個普通的實時任務,不通過 rt_alarm_wait 看門狗定時器延遲等待
        if(0 != err)
        {
            printf("Pipe Create Error:[%d,%d,%d,%d,%d,%d,%d,%d,%d]!\n", err, -EINVAL, -EIDRM, -EINTR, -EWOULDBLOCK, -ETIMEDOUT, -EPERM, -ENOMEM, -EEXIST);
        }

        RT_TASK RTTaskHandleB;
        ret = rt_task_create(&RTTaskHandleB, "RTTaskHandleB", TASK_STKSZ, TASK_PRIO, TASK_MODE); // 創建一個實時線程 線程優先級可以測試 但是未發現影響 可能定時完成時間充足,未發現阻塞的情況
        ret = rt_task_start(&RTTaskHandleB, &RT_TASK_CallBack_HandleB, NULL); // 啓動一個普通的實時任務,不通過 rt_alarm_wait 看門狗定時器延遲等待
        while(1)
        {
            // printf("Child Process PID:%ld\n", (long)getpid());
            usleep(500000);
        }
    }
    else
    {
        RT_TASK RTTaskHandleB;
        err = rt_task_create(&RTTaskHandleB, "RTTaskHandleB", TASK_STKSZ, TASK_PRIO, TASK_MODE); // 創建一個實時線程 線程優先級可以測試 但是未發現影響 可能定時完成時間充足,未發現阻塞的情況
        if(0 != err)
        {
            printf("Pipe Create Error:[%d,%d,%d,%d,%d,%d,%d,%d,%d]!\n", err, -EINVAL, -EIDRM, -EINTR, -EWOULDBLOCK, -ETIMEDOUT, -EPERM, -ENOMEM, -EEXIST);
        }
        err = rt_task_start(&RTTaskHandleB, &RT_TASK_CallBack_HandleB, NULL); // 啓動一個普通的實時任務,不通過 rt_alarm_wait 看門狗定時器延遲等待
        if(0 != err)
        {
            printf("Pipe Create Error:[%d,%d,%d,%d,%d,%d,%d,%d,%d]!\n", err, -EINVAL, -EIDRM, -EINTR, -EWOULDBLOCK, -ETIMEDOUT, -EPERM, -ENOMEM, -EEXIST);
        }
        while(1)
        {
            printf("Parent Process PID:%ld\n", (long)getpid());
            usleep(500000);
        }
    }
#endif

    while(1)
    {
        usleep(1000);
    }

    return 0;
}

/**********************************************************************
* 函數名稱: // void RT_TASK_CallBack_HandleA(void *pUsrArg)

* 功能描述: // 創建共享 Heap 堆內存 以及 Mutex 鎖,並通過 RT_Mutex 鎖獲取搶佔共享資源
* 訪問的表: //
* 修改的表: //
* 輸出參數: // 對輸出參數的說明
* 返 回 值: // 
* 其它說明: // 其它說明
* 修改日期       修改人	     修改內容
* -----------------------------------------------
* 2021/11/02	  	    XXXX	      XXXX
***********************************************************************/
void RT_TASK_CallBack_HandleA(void *pUsrArg)
{
    int ret,err;

    rt_printf("## Running ##:%s-%d\n", __FUNCTION__, __LINE__);

    int SamplePeriod = 200000000;
    rt_task_set_periodic(NULL, TM_NOW, SamplePeriod); // 200ms更新一次

    size_t data_count;

    // unsigned long long st = rt_timer_read(); // 獲取 Xenomai 的實時線程當前時間

    RT_PIPE pipe;
    const char PipeName[] = "PipeTest";
    err = rt_pipe_create(&pipe, PipeName, 1, 1000); // minor 用來配置在Linux設備端創建 /dev/rtpN 的過程中配置 N 的號碼,當minor=1時,則創建的設備爲 /dev/rtp1, 如果設置爲P_MINOR_AUTO:設備Pipe節點自動創建功能  poolsize:0 Pipe管道緩衝池的大小,設置爲0時則直接使用 Xenomai 系統的Heap空間
    if(0 != err)
    {
        rt_printf("Pipe Create Error:[%d,%d,%d,%d,%d,%d,%d,%d,%d]!\n", err, -EINVAL, -EIDRM, -EINTR, -EWOULDBLOCK, -ETIMEDOUT, -EPERM, -ENOMEM, -EEXIST);
    }

    const char writer_data[] = "Writer PIPE DATA...";
    const char stream_data[] = "Stream PIPE DATA...";

    while(1)
    {
        data_count = rt_pipe_write(&pipe, writer_data, strlen(writer_data), P_NORMAL); // 使用write的方式完成Pipe數據的傳輸過程 mode:P_URGENT 標識數據的後入先出順序 LIFO | P_NORMAL==>FIFO

        rt_task_sleep(10); // rt-thread 實時線程延遲函數 相對延時函數 最小延遲精度 clock ticks 需要絕對延時時間使用 rt_task_sleep_until() 接口

        data_count = rt_pipe_stream(&pipe, stream_data, strlen(writer_data)); // 使用流的方式Stream傳輸數據

        rt_printf("RT_TASK_CallBack_HandleA %d Datas Send over...\n", data_count);

        rt_task_wait_period(NULL);
    }

    err = rt_pipe_delete(&pipe); // 清理mutex資源 對於 Xenomai 的數據資源使用完之後一定要嚴格回收,否則會導致資源流失,影響整個系統的資源獲取
    if(0 != err)
    {
        rt_printf("Pipe Delete Error:[%d,%d,%d,%d,%d,%d,%d,%d,%d]!\n", err, -EINVAL, -EIDRM, -EINTR, -EWOULDBLOCK, -ETIMEDOUT, -EPERM, -ENOMEM, -EEXIST);
    }
}

/**********************************************************************
* 函數名稱: // void RT_TASK_CallBack_HandleB(void *pUsrArg)

* 功能描述: // 通過 Bind 相關接口,獲取實時線程A中創建的Heap以及Mutex,從而通過獲取Mutex的權限對共享內存Heap的內容進行修改
* 訪問的表: //
* 修改的表: //
* 輸出參數: // 對輸出參數的說明
* 返 回 值: // 
* 其它說明: // 其它說明
* 修改日期       修改人	     修改內容
* -----------------------------------------------
* 2021/11/02	  	    XXXX	      XXXX
***********************************************************************/
void RT_TASK_CallBack_HandleB(void *pUsrArg)
{
    int ret,err;

    rt_printf("## Running ##:%s-%d\n", __FUNCTION__, __LINE__);

    RT_PIPE pipe;
    const char PipeName[] = "PipeTest";
    err = rt_pipe_bind(&pipe, PipeName, TM_INFINITE); // 不限時等待綁定 TM_INFINTE
    if(0 != err)
    {
        rt_printf("Pipe Create Error:[%d,%d,%d,%d,%d,%d,%d,%d,%d]!\n", err, -EINVAL, -EIDRM, -EINTR, -EWOULDBLOCK, -ETIMEDOUT, -EPERM, -ENOMEM, -EEXIST);
    }

    int SamplePeriod = 200000000;
    rt_task_set_periodic(NULL, TM_NOW, SamplePeriod); // 200ms更新一次

    ssize_t DataLen = 0;
    char data_read[10]={0};
    while(1)
    {
        rt_task_wait_period(NULL);
        DataLen = rt_pipe_read(&pipe, data_read, 10, TM_NONBLOCK); // TM_INFINITE 永久等待讀取到Pipe中的數據 
        if(DataLen < 0)
        {
            rt_printf("Pipe No Data Recieved Error:[%d,%d,%d,%d,%d,%d,%d,%d,%d]!\n", DataLen, -EINVAL, -EIDRM, -EINTR, -EWOULDBLOCK, -ETIMEDOUT, -EPERM, -ENOMEM, -EEXIST);
            continue;
        }
        rt_printf("Recieve Data[%d]: %s\n", DataLen, data_read);
    }

    err = rt_pipe_unbind(&pipe); // TM_INFINITE 永久等待 TM_NONBLOCK
    if(0 != err)
    {
        rt_printf("Pipe Unbind Error:[%d,%d,%d,%d,%d,%d,%d,%d,%d]!\n", err, -EINVAL, -EIDRM, -EINTR, -EWOULDBLOCK, -ETIMEDOUT, -EPERM, -ENOMEM, -EEXIST);
    }
}

6. MainRTSem.c

主要測試了 Sem 相關內容

點擊查看代碼
#include <time.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <pthread.h>
#include <sys/time.h>

#include <unistd.h>
#include <time.h>

#include <native/timer.h>
#include <native/task.h>
#include <native/alarm.h>
#include <native/cond.h>
#include <native/queue.h>
#include <native/event.h>

#include <native/heap.h>
#include <native/mutex.h>
#include <native/sem.h>

#define TASK_PRIO 99 /* Highest RT Priority */
#define TASK_MODE 0  /* No Flags */
#define TASK_STKSZ 0 /* Stack Size(Use Default One) */

#define SEMAPHORE_BROADCAST_TSET 0

void RT_TASK_CallBack_HandleA(void *pUsrArg);
void RT_TASK_CallBack_HandleB(void *pUsrArg);
void RT_TASK_CallBack_HandleC(void *pUsrArg);

int main(int argc, char *argv[])
{
    int ret,err;

    RT_TASK RTTaskHandleA;
    ret = rt_task_create(&RTTaskHandleA, "RTTaskHandleA", TASK_STKSZ, TASK_PRIO, TASK_MODE); // 創建一個實時線程
    ret = rt_task_start(&RTTaskHandleA, &RT_TASK_CallBack_HandleA, NULL); // 啓動一個普通的實時任務,不通過 rt_alarm_wait 看門狗定時器延遲等待

    RT_TASK RTTaskHandleB;
    ret = rt_task_create(&RTTaskHandleB, "RTTaskHandleB", TASK_STKSZ, TASK_PRIO, TASK_MODE); // 創建一個實時線程 線程優先級可以測試 但是未發現影響 可能定時完成時間充足,未發現阻塞的情況
    ret = rt_task_start(&RTTaskHandleB, &RT_TASK_CallBack_HandleB, NULL); // 啓動一個普通的實時任務,不通過 rt_alarm_wait 看門狗定時器延遲等待

#if SEMAPHORE_BROADCAST_TSET
    RT_TASK RTTaskHandleC;
    ret = rt_task_create(&RTTaskHandleC, "RTTaskHandleC", TASK_STKSZ, TASK_PRIO, TASK_MODE); // 創建一個實時線程 線程優先級可以測試 但是未發現影響 可能定時完成時間充足,未發現阻塞的情況
    ret = rt_task_start(&RTTaskHandleC, &RT_TASK_CallBack_HandleC, NULL); // 啓動一個普通的實時任務,不通過 rt_alarm_wait 看門狗定時器延遲等待

#endif 

    while(1)
    {
        usleep(1000);
    }

    return 0;
}

/**********************************************************************
* 函數名稱: // void RT_TASK_CallBack_HandleA(void *pUsrArg)

* 功能描述: // 創建共享 Heap 堆內存 以及 Mutex 鎖,並通過 RT_Mutex 鎖獲取搶佔共享資源
* 訪問的表: //
* 修改的表: //
* 輸出參數: // 對輸出參數的說明
* 返 回 值: // 
* 其它說明: // 其它說明
* 修改日期       修改人	     修改內容
* -----------------------------------------------
* 2021/11/02	  	    XXXX	      XXXX
***********************************************************************/
void RT_TASK_CallBack_HandleA(void *pUsrArg)
{
    int ret,err;

    RT_SEM sem;
    const char SEMName[] = "SemTest";
    err = rt_sem_create(&sem, SEMName, 2, S_FIFO); // S_PRIO 以優先級排隊領取可用Sem S_FIFO 以先到先得的方式領取可用Sem
    if(0 != err)
    {
        printf("Sem Create Error:[%d,%d,%d,%d,%d,%d,%d,%d,%d]!\n", err, -EINVAL, -EIDRM, -EINTR, -EWOULDBLOCK, -ETIMEDOUT, -EPERM, -ENOMEM, -EEXIST);
    }

    RT_SEM_INFO seminfo;
    err = rt_sem_inquire(&sem, &seminfo); // H_PRIO 以優先級排隊領取可用heap H_FIFO 以先到先得的方式領取可用heap  H_SINGLE 將創建的 heap內存當作一整個內存,在alloc申請時必須整塊申請,否則會報錯
    if(0 != err)
    {
        printf("Sem Get Info Error:[%d,%d,%d,%d,%d,%d,%d,%d,%d]!\n", err, -EINVAL, -EIDRM, -EINTR, -EWOULDBLOCK, -ETIMEDOUT, -EPERM, -ENOMEM, -EEXIST);
    }
    printf("Sem Informations:\n");
    printf("  Current Semaphore Value:%ld\n", seminfo.count);
    printf("  Number of tasks waitting for this Semaphore:%d\n", seminfo.nwaiters);
    printf("  Name of Semaphore:%s\n", seminfo.name);

    int SamplePeriod = 200000000;
    rt_task_set_periodic(NULL, TM_NOW, SamplePeriod); // 200ms更新一次

    while(1)
    {
        rt_sem_p(&sem, TM_INFINITE); // 永久等待 Semaphore 釋放

        rt_sem_inquire(&sem, &seminfo);
        rt_printf("## Running-SemaphoreValue[%ld] ##:%s-%d\n", seminfo.count, __FUNCTION__, __LINE__);

        // rt_task_sleep(2000000000); // 延遲一點時間

#if SEMAPHORE_BROADCAST_TSET
        rt_sem_broadcast(&sem);
        // rt_sem_v(&sem); // Unblock the semaphore
#else
        rt_sem_v(&sem); // Unblock the semaphore
#endif
        rt_task_wait_period(NULL);
    }

    err = rt_sem_delete(&sem); // 清理mutex資源 對於 Xenomai 的數據資源使用完之後一定要嚴格回收,否則會導致資源流失,影響整個系統的資源獲取
    if(0 != err)
    {
        printf("Semaphore Delete Error:[%d,%d,%d,%d,%d,%d,%d,%d,%d]!\n", err, -EINVAL, -EIDRM, -EINTR, -EWOULDBLOCK, -ETIMEDOUT, -EPERM, -ENOMEM, -EEXIST);
    }
}

/**********************************************************************
* 函數名稱: // void RT_TASK_CallBack_HandleB(void *pUsrArg)

* 功能描述: // 通過 Bind 相關接口,獲取實時線程A中創建的Heap以及Mutex,從而通過獲取Mutex的權限對共享內存Heap的內容進行修改
* 訪問的表: //
* 修改的表: //
* 輸出參數: // 對輸出參數的說明
* 返 回 值: // 
* 其它說明: // 其它說明
* 修改日期       修改人	     修改內容
* -----------------------------------------------
* 2021/11/02	  	    XXXX	      XXXX
***********************************************************************/
void RT_TASK_CallBack_HandleB(void *pUsrArg)
{
    int ret,err;

    // rt_printf("## Running ##:%s-%d\n", __FUNCTION__, __LINE__);
    // RT_HEAP *heap = NULL; // 這樣申請時錯誤的,實際上rt_heap_create只是創建了以及ID號給heap,需要一個實體
    RT_SEM sem;
    const char SEMName[] = "SemTest";
    err = rt_sem_bind(&sem, SEMName, TM_INFINITE); //
    if(0 != err)
    {
        printf("Sem Bind Error:[%d,%d,%d,%d,%d,%d,%d,%d,%d]!\n", err, -EINVAL, -EIDRM, -EINTR, -EWOULDBLOCK, -ETIMEDOUT, -EPERM, -ENOMEM, -EEXIST);
    }

    RT_SEM_INFO seminfo;
    err = rt_sem_inquire(&sem, &seminfo); // H_PRIO 以優先級排隊領取可用heap H_FIFO 以先到先得的方式領取可用heap  H_SINGLE 將創建的 heap內存當作一整個內存,在alloc申請時必須整塊申請,否則會報錯
    if(0 != err)
    {
        printf("Bind Sem Get Info Error:[%d,%d,%d,%d,%d,%d,%d,%d,%d]!\n", err, -EINVAL, -EIDRM, -EINTR, -EWOULDBLOCK, -ETIMEDOUT, -EPERM, -ENOMEM, -EEXIST);
    }
    printf("Sem Bind Informations:\n");
    printf("  Current Semaphore Value:%ld\n", seminfo.count);
    printf("  Number of tasks waitting for this Semaphore:%d\n", seminfo.nwaiters);
    printf("  Name of Semaphore:%s\n", seminfo.name);

    int SamplePeriod = 200000000;
    rt_task_set_periodic(NULL, TM_NOW, SamplePeriod); // 200ms更新一次

    while(1)
    {
        rt_sem_p(&sem, TM_INFINITE); // 永久等待 Semaphore 釋放

        rt_sem_inquire(&sem, &seminfo);
        rt_printf("## Running-SemaphoreValue[%ld] ##:%s-%d\n", seminfo.count, __FUNCTION__, __LINE__);

        rt_sem_v(&sem); // Unblock the semaphore
        rt_task_wait_period(NULL);
    }

    err = rt_sem_unbind(&sem); // 清理mutex資源 對於 Xenomai 的數據資源使用完之後一定要嚴格回收,否則會導致資源流失,影響整個系統的資源獲取
    if(0 != err)
    {
        printf("Semaphore Unbind Error:[%d,%d,%d,%d,%d,%d,%d,%d,%d]!\n", err, -EINVAL, -EIDRM, -EINTR, -EWOULDBLOCK, -ETIMEDOUT, -EPERM, -ENOMEM, -EEXIST);
    }
}

/**********************************************************************
* 函數名稱: // void RT_TASK_CallBack_HandleC(void *pUsrArg)

* 功能描述: // 通過 Bind 相關接口,獲取實時線程A中創建的Heap以及Mutex,從而通過獲取Mutex的權限對共享內存Heap的內容進行修改
* 訪問的表: //
* 修改的表: //
* 輸出參數: // 對輸出參數的說明
* 返 回 值: // 
* 其它說明: // 其它說明
* 修改日期       修改人	     修改內容
* -----------------------------------------------
* 2021/11/02	  	    XXXX	      XXXX
***********************************************************************/
void RT_TASK_CallBack_HandleC(void *pUsrArg)
{
    int ret,err;

    // rt_printf("## Running ##:%s-%d\n", __FUNCTION__, __LINE__);
    // RT_HEAP *heap = NULL; // 這樣申請時錯誤的,實際上rt_heap_create只是創建了以及ID號給heap,需要一個實體
    RT_SEM sem;
    const char SEMName[] = "SemTest";
    err = rt_sem_bind(&sem, SEMName, TM_INFINITE); //
    if(0 != err)
    {
        printf("Sem Bind Error:[%d,%d,%d,%d,%d,%d,%d,%d,%d]!\n", err, -EINVAL, -EIDRM, -EINTR, -EWOULDBLOCK, -ETIMEDOUT, -EPERM, -ENOMEM, -EEXIST);
    }

    RT_SEM_INFO seminfo;
    err = rt_sem_inquire(&sem, &seminfo); // H_PRIO 以優先級排隊領取可用heap H_FIFO 以先到先得的方式領取可用heap  H_SINGLE 將創建的 heap內存當作一整個內存,在alloc申請時必須整塊申請,否則會報錯
    if(0 != err)
    {
        printf("Bind Sem Get Info Error:[%d,%d,%d,%d,%d,%d,%d,%d,%d]!\n", err, -EINVAL, -EIDRM, -EINTR, -EWOULDBLOCK, -ETIMEDOUT, -EPERM, -ENOMEM, -EEXIST);
    }
    printf("Sem Bind Informations:\n");
    printf("  Current Semaphore Value:%ld\n", seminfo.count);
    printf("  Number of tasks waitting for this Semaphore:%d\n", seminfo.nwaiters);
    printf("  Name of Semaphore:%s\n", seminfo.name);

    int SamplePeriod = 200000000;
    rt_task_set_periodic(NULL, TM_NOW, SamplePeriod); // 200ms更新一次

    while(1)
    {
        rt_sem_p(&sem, TM_INFINITE); // 永久等待 Semaphore 釋放

        rt_sem_inquire(&sem, &seminfo);
        rt_printf("## Running-SemaphoreValue[%ld] ##:%s-%d\n", seminfo.count, __FUNCTION__, __LINE__);

        rt_sem_v(&sem); // Unblock the semaphore
        rt_task_wait_period(NULL);
    }

    err = rt_sem_unbind(&sem); // 清理mutex資源 對於 Xenomai 的數據資源使用完之後一定要嚴格回收,否則會導致資源流失,影響整個系統的資源獲取
    if(0 != err)
    {
        printf("Semaphore Unbind Error:[%d,%d,%d,%d,%d,%d,%d,%d,%d]!\n", err, -EINVAL, -EIDRM, -EINTR, -EWOULDBLOCK, -ETIMEDOUT, -EPERM, -ENOMEM, -EEXIST);
    }
}

7. MAKEFILE

# Makefile for Basler pylon C sample program
.PHONY: all clean

# The program to build
EXECUTABLE := RTDemoExe # RTDemoExePipeServer RTDemoExePipeClient RTDemoExe
TARGET_IP := 188.188.0.32
# Installation directories for pylon

# Build tools and flags
CC = arm-linux-gnueabihf-gcc
XENO_CONFIG := xgrosconfig
CFLAGS := $(shell $(XENO_CONFIG) --opencv --pylon6 --compat --posix --alchemy --cflags)
LD     := $(shell $(XENO_CONFIG) --opencv --pylon6 --compat --posix --alchemy --ldflags --mysqlc)
LD     := $(LD) -lrt -lpthread -ldl -lm -lcJSON -lcrypto -lssl -lethercat_rtdm
CFLAGS     := $(CFLAGS) -I ../src/ -g

MAKETIME := $(shell date "+%G.%m.%d-%H.%M.%S")
EXEVERSION := 1.0.01N

src = $(wildcard ../src/*.c)
src :=$(src) MainRTHeap.c # MainRTSem.c MainRTPipeClient.c MainRTPipeServer.c MainRTMutex.c MainRTHeap.c main.c
obj = $(patsubst %.c, %.o, $(src))
all: $(EXECUTABLE)
$(EXECUTABLE): $(obj)
	$(CC) -o $@ $^ $(LD)
	scp ./$(EXECUTABLE) root@$(TARGET_IP):~/MMWorkSpace/

%.o:%.c
	$(CC) -o $@ -c $<  $(CFLAGS)

.PHONY: clean
clean:
	rm -f $(EXECUTABLE) $(obj)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章