做过一个有关RTLinux的项目,时间一长,差不多忘光了,现在尽量把原来做过的东西总结一下,以备后用,同时正在做类似项目的一个借鉴
平台
主机:redhat 8.0
目标机:PC104模块、ISA总线脉冲输出、实时串口通信
         linux-2.4.18.tar.bz2 +rtlinux-3.2-pre1.tar.bz2
简述
Linux是典型的分时应用系统,对于实时性要求很高的应用,必须对内核本身动手术。而RTLinux则采取了一种比较聪明也比较折中的办法:他们实现一个最底层的精简的调度器,用于调度实时线程,原来的内核本身则成为实时调度器的一个优先级最低的任务。这样,当有实时任务时,普通内核已经建立于其上的普通进程被强制中断,实时线程被强制执行;只有当若有实时线程都让出cpu之后,普通内核才被运行,再由普通内核去调度执行普通的应用程序……
实例

  1. #include <rtl_fifo.h>
  2. #include <rtl.h>
  3. #include <rtl_sched.h>
  4. #include <time.h>
  5. #include <pthread.h>
  6. #include <rtl_time.h>
  7. #include <signal.h>
  8. #include "rt_com.h"
  9. #include <linux/kernel.h>
  10. #include <linux/module.h>
  11. MODULE_LICENSE("GPL v2");
  12. MODULE_AUTHOR("Wind-Son");
  13. MODULE_DESCRIPTION("Pulse-Control system");
  14. typedef unsigned short __u16;
  15. void io_bit_on(__u16 port, unsigned int pos, __u16 *status)
  16. {
  17. __asm__ __volatile__(
  18. "movl %1,%?x\n\t"
  19. "movl %0,%?x\n\t"
  20. "btsl %2,(%?x)\n\t"
  21. "mov (%?x),%%al\n\t"
  22. "out %%al,(%%dx)\n\t"
  23. "out %%al,$0x80\n\t"
  24. :
  25. :"m"(status), "rm"(port), "Ir"(pos)
  26. );
  27. }
  28. void io_bit_off(__u16 port, unsigned int pos, __u16 *status)
  29. {
  30. __asm__ __volatile__(
  31. "movl %1,%?x\n\t"
  32. "movl %0,%?x\n\t"
  33. "btrl %2,(%?x)\n\t"
  34. "mov (%?x),%%al\n\t"
  35. "out %%al,(%%dx)\n\t"
  36. "out %%al,$0x80\n\t"
  37. :
  38. :"m"(status), "rm"(port), "Ir"(pos)
  39. );
  40. }
  41. #define dbg_print rtl_printf
  42. #define MIN_TIME              5000
  43. static void get_time_interval(void)
  44. {
  45. }
  46. void* pulse_generate_thread(void *arg)
  47. {
  48. static __u16 io_status = 0;
  49. struct sched_param p;
  50. hrtime_t current_time;
  51. REAL_TIME_GET_ENABLE;
  52. int intrrupt_sched_period = 180000;
  53. p.sched_priority = 1;
  54. struct timespec resolution;
  55. rtl_setclockmode(CLOCK_REALTIME, RTL_CLOCK_MODE_PERIODIC,
  56. intrrupt_sched_period);
  57. clock_getres(rtl_getschedclock(), &resolution);
  58. intrrupt_sched_period = timespec_to_ns(&resolution);
  59. pthread_make_periodic_np(pthread_self(), clock_gethrtime(rtl_getschedclock()),
  60. intrrupt_sched_period);
  61. pthread_setschedparam (pthread_self(), SCHED_FIFO, &p);
  62. for (;;) {
  63. dbg_print("debug entry\n");
  64. while (!ready)
  65. pthread_wait_np();
  66. dbg_print("debug exit\n");
  67. if (!init_rt_clock) {
  68. init_rt_clock = 1;
  69. pthread_wait_np();
  70. current_time = clock_gethrtime(CLOCK_REALTIME);
  71. } else {
  72. if (intrrupt_sched_period < MIN_TIME)
  73. intrrupt_sched_period = MIN_TIME;
  74. current_time += intrrupt_sched_period;
  75. clock_nanosleep(CLOCK_REALTIME, TIMER_ABSTIME, hrt2ts(current_time), NULL);
  76. }
  77. io_bit_on(IO_PORT_OUT, XPULSE, &io_status);
  78. intrrupt_sched_period = get_time_interval();
  79. }
  80. return 0;
  81. }
  82. static void init_for_rt_mm(void)
  83. {
  84. }
  85. static void rt_alloc_mm(void)
  86. {
  87. thread_wait_np();
  88. buf = kmalloc(size, GFP_ATOMIC);
  89. }
  90. static int kmalloc_thread(void * kthread_arg)
  91. {
  92. unsigned long timeout = HZ;
  93. init_for_rt_mm();
  94. for (;;) {
  95. while (!get_flag(MM_ALLOC_FLAG)) {
  96. if( signal_pending(current))
  97. return 0;
  98. timeout = interruptible_sleep_on_timeout(&wq, timeout);
  99. }
  100. rt_alloc_mm();
  101. clear_flag(MM_ALLOC_FLAG);
  102. }
  103. return -1;
  104. }
  105. wait_queue_head_t wq;
  106. static pid_t kmalloc_kthread_id;
  107. static int kmalloc_kthread_state = 1;
  108. static int pulse_generate_thread_created = 0;
  109. static int main_ctrl_thread_created = 0;
  110. static pthread_t pulse_generate_pthread;
  111. static pthread_t main_ctrl_pthread;
  112. static pthread_mutex_t cache_mutex;
  113. void rt_mm_request(void)
  114. {
  115. set_flag(MM_ALLOC_FLAG);
  116. while(get_flag(MM_ALLOC_FLAG))
  117. pthread_wait_np();
  118. }
  119. void* main_ctrl_thread(void *arg)
  120. {
  121. int work_sched_period = 160000;
  122. struct timespec resolution;
  123. int ret1 = rtl_setclockmode(rtl_getschedclock(), RTL_CLOCK_MODE_PERIODIC,
  124. work_sched_period);
  125. if (ret1) {
  126. dbg_print("seting periodic mode failed\n");
  127. clear_flag(WORK_SCHED_MODE);
  128. }
  129. clock_getres(rtl_getschedclock(), &resolution);
  130. work_sched_period = timespec_to_ns(&resolution);
  131. pthread_make_periodic_np(pthread_self(), clock_gethrtime(rtl_getschedclock()),
  132. work_sched_period);
  133. init_task();
  134. for (;;) {
  135. if (work) {
  136. dbg_print("work\n");
  137. rt_mm_request();
  138. calc_time_interval();
  139. if (exit)
  140. break;
  141. } else
  142. pthread_wait_np();
  143. }
  144. exit_task();
  145. return 0;
  146. }
  147. int init_module(void)
  148. {
  149. pthread_attr_t attr;
  150. struct sched_param p;
  151. int ret;
  152. rtf_destroy(0);
  153. rtf_destroy(1);
  154. rt_com_clr_in(0);
  155. rt_com_clr_out(0);
  156. int fifo_status = rtf_create(0,100);
  157. if(fifo_status)
  158. dbg_print("FIFO Create failed!");
  159. fifo_status = rtf_create(1, 4000);
  160. if(fifo_status)
  161. dbg_print("FIFO Create failed!");
  162. rt_com_setup(0, 9600, RT_COM_PARITY_NONE, 1, 8);
  163. hrtime_t now = gethrtime();
  164. pthread_attr_init(&attr);
  165. pthread_mutex_init(&cache_mutex, NULL);
  166. pthread_attr_setfp_np(&attr, 1);
  167. ret = pthread_create(&pulse_generate_pthread, &attr,
  168. pulse_generate_thread, (void *)0);
  169. if (!ret)
  170. pulse_generate_thread_created = 1;
  171. pthread_make_periodic_np (pulse_generate_pthread, now + 2 * 240000, 80000);
  172. p . sched_priority = 1;
  173. pthread_setschedparam (pulse_generate_pthread, SCHED_FIFO, &p);
  174. ret = pthread_create(&main_ctrl_pthread, &attr, main_ctrl_thread, (void *)1);
  175. if (!ret)
  176. main_ctrl_thread_created=1;
  177. pthread_make_periodic_np (main_ctrl_pthread, now + 2 * 160000, 30000);
  178. p . sched_priority = 2;
  179. pthread_setschedparam (main_ctrl_pthread, SCHED_FIFO, &p);
  180. init_waitqueue_head(&wq);
  181. kmalloc_kthread_id = kernel_thread(kmalloc_thread, NULL, 0);
  182. if (kmalloc_kthread_id < 0) {
  183. printk(KERN_ERR "fork failed, errno %d\n", -kmalloc_kthread_id);
  184. return kmalloc_kthread_id;
  185. }
  186. return ret;
  187. }
  188. void cleanup_module(void)
  189. {
  190. int ret = kill_proc(kmalloc_kthread_id, SIGKILL, 1);
  191. if (!ret) {
  192. int count = 10 * HZ;
  193. while (kmalloc_kthread_state && --count) {
  194. current->state = TASK_INTERRUPTIBLE;
  195. schedule_timeout(1);
  196. }
  197. }
  198. if (main_ctrl_thread_created) {
  199. pthread_cancel(main_ctrl_pthread);
  200. pthread_join(main_ctrl_pthread, NULL);
  201. pthread_delete_np(main_ctrl_pthread);
  202. }
  203. if (pulse_generate_thread_created) {
  204. pthread_cancel(pulse_generate_pthread);
  205. pthread_join(pulse_generate_pthread, NULL);
  206. pthread_delete_np(pulse_generate_pthread);
  207. }
  208. rt_com_setup(0, -1, 0, 0, 0);
  209. rtf_destroy(0);
  210. rtf_destroy(1);
  211. pthread_mutex_destroy (&cache_mutex);
  212. }

复制代码

其实现在有关Linux实时应用的原理和应用方面的介绍已经不少,所以我主要是想从自己的亲身实践中的经验教训出发总结一下。
我遇到的主要问题主要有以下几个:
1、硬实时调度精度不够的问题。刚开始产生脉冲驱动的线程我按照例子程序采样如下方式
   pthread_make_periodic_np();  //设置调度方式和周期等参数
    pthread_setschedparam (pthread_self(), SCHED_FIFO, &p);
    pthread_wait_np(); //让出cpu进入睡眠
  可实际情况总是不理想,输出波形不够稳定,离预想的效果也很远。试着将调度策略SCHED_FIFO改其他几种方式,也一样。最后尝试用clock_nanosleep()才达到了比较理想的效果。理论上clock_nanosleep()应该达到ns级别的精度,当然实际精度还要取决于硬件。
2、实时线程所能到达的实时效果和精度极限也就是定时器本身的精度了。有过在51上做开发经验的都有这样一个意识:定时器中断处理例程里尽量只做最简单、最必须的工作,但毕竟还是有开销的。如果你对精度还有更高的要求,可在main_ctrl_thread()即负责计算脉冲间隔时间的例程中加入补偿值,以抵消脉冲输出例程中的时间开销。
3、实时线程中频繁的动态申请内存时常宕机。后来经过实验摸索才采取了上面代码中所述的拐弯抹角的办法。如果谁碰到过类似问题有更好的办法,还望指出。
4、应用程序直接向串口输出时总出错。
   开始方法是system("/bin/ls ./data/ >> /dev/ttyS0";在没有实时线程的影响的情况下,这样是没有问题。开启实时线程后就老出错。
后改成如下方式就好了:由实时模块通过实时调用rt_com_write()和rt_com_read()读写串口;再通过实时管道rtl_fifo转发到应用程序
另外,纯粹经验谈,实时线程如果不主动让出cpu,任何用户程序无法运行,包括你的键盘响应!如果你的某个环节可能陷入循环,你能做的就只有poweroff了;被迫重启后在ext2文件系统上随之而来的是漫长的fscheck……所以我在调试阶段,基本上是只要有循环的的方,就加上pthread_wait_np();以后再慢慢把不必要的去掉。

RTLinux编程总结的更多相关文章

  1. Linux下的C编程实战

    Linux下的C编程实战(一) ――开发平台搭建 1.引言 Linux操作系统在服务器领域的应用和普及已经有较长的历史,这源于它的开源特点以及其超越Windows的安全性和稳定性.而近年来, Linu ...

  2. Linux下的编程实战【转】

    一篇比较不错的文章, 降到了 makefile make , gcc编译器,GDB调试器, Linux文件系统,Linux文件API,.C语言库函数(C库函数的文件操作实际上是独立于具体的操作系统平台 ...

  3. 从直播编程到直播教育:LiveEdu.tv开启多元化的在线学习直播时代

    2015年9月,一个叫Livecoding.tv的网站在互联网上引起了编程界的注意.缘于Pingwest品玩的一位编辑在上网时无意中发现了这个网站,并写了一篇文章<一个比直播睡觉更奇怪的网站:直 ...

  4. JavaScript之父Brendan Eich,Clojure 创建者Rich Hickey,Python创建者Van Rossum等编程大牛对程序员的职业建议

    软件开发是现时很火的职业.据美国劳动局发布的一项统计数据显示,从2014年至2024年,美国就业市场对开发人员的需求量将增长17%,而这个增长率比起所有职业的平均需求量高出了7%.很多人年轻人会选择编 ...

  5. 读书笔记:JavaScript DOM 编程艺术(第二版)

    读完还是能学到很多的基础知识,这里记录下,方便回顾与及时查阅. 内容也有自己的一些补充. JavaScript DOM 编程艺术(第二版) 1.JavaScript简史 JavaScript由Nets ...

  6. [ 高并发]Java高并发编程系列第二篇--线程同步

    高并发,听起来高大上的一个词汇,在身处于互联网潮的社会大趋势下,高并发赋予了更多的传奇色彩.首先,我们可以看到很多招聘中,会提到有高并发项目者优先.高并发,意味着,你的前雇主,有很大的业务层面的需求, ...

  7. C#异步编程(一)

    异步编程简介 前言 本人学习.Net两年有余,是第一次写博客,虽然写的很认真,当毕竟是第一次,肯定会有很多不足之处, 希望大家照顾照顾新人,有错误之处可以指出来,我会虚心接受的. 何谓异步 与同步相对 ...

  8. UE4新手之编程指南

    虚幻引擎4为程序员提供了两套工具集,可共同使用来加速开发的工作流程. 新的游戏类.Slate和Canvas用户接口元素以及编辑器功能可以使用C++语言来编写,并且在使用Visual Studio 或 ...

  9. C#与C++的发展历程第三 - C#5.0异步编程巅峰

    系列文章目录 1. C#与C++的发展历程第一 - 由C#3.0起 2. C#与C++的发展历程第二 - C#4.0再接再厉 3. C#与C++的发展历程第三 - C#5.0异步编程的巅峰 C#5.0 ...

随机推荐

  1. 【转】c++ 获取程序运行时间

    转自:http://blog.csdn.net/ghevinn/article/details/22800059 DWORD start_time=GetTickCount(); {...} DWOR ...

  2. VUE 框架

    一.什么是vue             它是一个构建用户界面的JAVASCRITPO框架 二.怎么使用VUE (1).引入vue.js 如:<script src='vue.js'>&l ...

  3. aop难点解析。

    静态织入和动态织入的区别? 需求示例:假设有一个包,一个包当中有一个方法,我们想在这个方法的前后,加上环绕. 那么怎么加呢? 把知道的都说一遍. 1.建立JsonService 2.建立JSONASP ...

  4. Selenium UI自动化解决iframe定位问题

      更多原创测试技术文章同步更新到微信公众号 :三国测,敬请扫码关注个人的微信号,感谢! 原文链接:http://www.cnblogs.com/zishi/p/6735116.html 一个阴雨霏霏 ...

  5. SpringMVC源码情操陶冶-AnnotationDrivenBeanDefinitionParser注解解析器

    mvc:annotation-driven节点的解析器,是springmvc的核心解析器 官方注释 Open Declaration org.springframework.web.servlet.c ...

  6. SpringMVC源码情操陶冶-HandlerAdapter适配器简析

    springmvc中对业务的具体处理是通过HandlerAdapter适配器操作的 HandlerAdapter接口方法 列表如下 /** * Given a handler instance, re ...

  7. MySQL操作的一些优化

    1.用于不要使用select * from table xxx. 需要查询哪些列就在语句中指明,一个表结构复杂时,可能会有上百列,使用*来查询时会造成很大的浪费. 2.选择合适的属性及大小    例如 ...

  8. Selenium+PhantomJS实现简易有道翻译爬虫

    Selenium一款自动化测试工具,当然用来写爬虫也是没有问题的.它支持Chrome.Safari.Firefox等主流界面式浏览器,另外它也支持多种语言开发,比如 Java,C,Ruby,Pytho ...

  9. hdu4149 Magic Potion

    Magic Potion Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65535/32768 K (Java/Others)Tota ...

  10. Maven中的pom.xml详解

    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/20 ...