一、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

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);
}

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;
}

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);
} }

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);
}
}

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);
}
}

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/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);
}
}

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)

Xenomai 再探的更多相关文章

  1. 【再探backbone 02】集合-Collection

    前言 昨天我们一起学习了backbone的model,我个人对backbone的熟悉程度提高了,但是也发现一个严重的问题!!! 我平时压根没有用到model这块的东西,事实上我只用到了view,所以昨 ...

  2. ViewPager+Fragment再探:和TAB滑动条一起三者结合

    Fragment前篇: <Android Fragment初探:静态Fragment组成Activity> ViewPager前篇: <Android ViewPager初探:让页面 ...

  3. 再探jQuery

    再探jQuery 前言:在使用jQuery的时候发现一些知识点记得并不牢固,因此希望通过总结知识点加深对jQuery的应用,也希望和各位博友共同分享. jQuery是一个JavaScript库,它极大 ...

  4. [老老实实学WCF] 第五篇 再探通信--ClientBase

    老老实实学WCF 第五篇 再探通信--ClientBase 在上一篇中,我们抛开了服务引用和元数据交换,在客户端中手动添加了元数据代码,并利用通道工厂ChannelFactory<>类创 ...

  5. Spark Streaming揭秘 Day7 再探Job Scheduler

    Spark Streaming揭秘 Day7 再探Job Scheduler 今天,我们对Job Scheduler再进一步深入一下,对一些更加细节的源码进行分析. Job Scheduler启动 在 ...

  6. 再探ASP.NET 5(转载)

    就在最近一段时间,微软又有大动作了,在IDE方面除了给我们发布了Viausl Studio 2013 社区版还发布了全新的Visual Studio 2015 Preview. Visual Stud ...

  7. 再探java基础——break和continue的用法

    再探java基础——break和continue的用法 break break可用于循环和switch...case...语句中. 用于switch...case中: 执行完满足case条件的内容内后 ...

  8. 第四节:SignalR灵魂所在Hub模型及再探聊天室样例

    一. 整体介绍 本节:开始介绍SignalR另外一种通讯模型Hub(中心模型,或者叫集线器模型),它是一种RPC模式,允许客户端和服务器端各自自定义方法并且相互调用,对开发者来说相当友好. 该节包括的 ...

  9. 深入出不来nodejs源码-内置模块引入再探

    我发现每次细看源码都能发现我之前写的一些东西是错误的,去改掉吧,又很不协调,不改吧,看着又脑阔疼…… 所以,这一节再探,是对之前一些说法的纠正,另外再缝缝补补一些新的内容. 错误在哪呢?在之前的初探中 ...

  10. 再探Redux Middleware

    前言 在初步了解Redux中间件演变过程之后,继续研究Redux如何将中间件结合.上次将中间件与redux硬结合在一起确实有些难看,现在就一起看看Redux如何加持中间件. 中间件执行过程 希望借助图 ...

随机推荐

  1. ie8 不支持 trim方法

    那就自己写一个trim()  String.prototype.trim = function() {                 return this.replace(/(^\s*)|(\s* ...

  2. vue后台管理系统

    1. 项目概述: 根据不同的应用场景,电商系统一般都提供了 PC 端.移动 APP.移动 Web.微信小程序等多种终端访问方式. 2. 电商后台管理系统的功能 电商后台管理系统用于管理用户账号.商品分 ...

  3. 1903021126 申文骏 Java 第四周作业 Java分支语句学习

    项目 内容 课程班级博客链接 19级信计班(本) 作业要求链接 Java第四周作业 博客名称 1903021126  申文骏  Java 第四周作业 Java分支语句学习 要求 每道题要有题目,代码( ...

  4. jenkins - Asp.net 环境搭建(Windows)

    jenkins - Asp.net 环境搭建(Windows) 安装环境 通过 Chocolatey自动安装 choco install ojdkbuild11 #或 choco install jd ...

  5. ceph 集群 健康状态报 clock skew detected on mon.tg-ceph-mon-2

    1.现象: health: HEALTH_WARN no active mgr mons are allowing insecure global_id reclaim clock skew dete ...

  6. api接口基础Day1

    精华笔记: String: String的常用方法: length():获取字符串的长度(字符个数) trim():去除当前字符串两边的空白字符 toUpperCase()/toLowerCase() ...

  7. RKO组——冲刺随笔(1)

    这个作业属于哪个课程 至诚软工实践F班 这个作业要求在哪里 第五次团队作业:项目冲刺 这个作业的目标 记录冲刺计划.要求包括当天会议照片.会议内容以及项目燃尽图(项目进度) 1.昨日进展 小组成员讨论 ...

  8. Kicad使用技巧--原理图复用

    平时主要使用AD.kicad和立创eda,最近在琢磨一下各个软件的使用技巧,提升一下画图效率,首先想到的就是原理图复用,我想象中的原理图复用应该像AutoCAD的图块功能一样. 这次先说kicad,摸 ...

  9. Flask-Migrate数据库模型映射

    1.Flask-Migrate介绍 flask-migrate可以十分方便的进行数据库的迁移与映射,将我们修改过的ORM模型映射到数据库中.flask-migrate是基于Alembic进行的一个封装 ...

  10. java输入一个字符串,要求将该字符串中出现的英文字母, * 按照顺序输出,区分大小写,且大写优先

    public static void main(String[] args) { String input ="A8r4c5jaAjp#7"; //转为char[] char[] ...