• 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的名称获取指定的队列句柄,从而进行数据交换的操作,其基本使用流程如下:

      实时线程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 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    
    #include 
    #include 
    
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    
    #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 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    
    #include 
    #include 
    
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    
    #include 
    
    #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 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    
    #include 
    #include 
    
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    
    #include 
    #include 
    
    #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 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    
    #include 
    #include 
    
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    
    #include 
    #include 
    #include 
    
    #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 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    
    #include 
    #include 
    
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    
    #include 
    #include 
    #include 
    
    #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 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    
    #include 
    #include 
    
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    
    #include 
    #include 
    #include 
    
    #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)
    
  • 相关阅读:
    写文档是件大事情,怎么弄好它?
    微信小程序|基于小程序实现人脸数量检测
    mongdb迁移方案及比对方案
    自动化测试框架知识,居然这么详细?有这一篇完全够了......
    为什么win11连接wifi频繁掉线?
    [HDLBits] Lemmings4
    【测试】测试执行流程
    IM6ULL学习总结(四-七-1)输入系统应用编程
    Centos7更新php7.2版本升级
    cesium影像推送
  • 原文地址:https://www.cnblogs.com/uestc-mm/p/17246221.html