做过一个有关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. scala 小结(一)

    Scala 是什么?(What is scala?)   引用百度百科对于scala的定义: Scala是一门多范式的编程语言,一种类似java的编程语言,设计初衷是实现可伸缩的语言.并集成面向对象编 ...

  2. 面试中的Java链表

    链表作为常考的面试题,并且本身比较灵活,对指针的应用较多.本文对常见的链表面试题Java实现做了整理. 链表节点定义如下: static class Node { int num; Node next ...

  3. 禁掉或启用firefox 的 javascript 脚本

    老版本的firefox可以直接在“选项”页设置启用或禁用javascript 脚本 新版的Firefox中,我找了半天,没有找到,看来是没法直接设置了 于是在 地址栏键入 about:config 搜 ...

  4. ABP官方文档翻译 5.4 SwaggerUI集成

    SwaggerUI集成 介绍 ASP.NET Core 安装Nuget包 配置 测试 ASP.NET 5.x 安装Nuget包 配置 测试 介绍 在它的网站上:“...使用Swagger可用的API, ...

  5. ABP官方文档翻译 3.1 实体

    实体 实体类 聚合根类 领域事件 常规接口 审计 软删除 激活/失活实体 实体改变事件 IEntity接口 实体是DDD(领域驱动设计)的核心概念之一.Eric Evans描述它为"An o ...

  6. linux 基础信息查询

    Linux下如何查看版本信息   Linux下如何查看版本信息, 包括位数.版本信息以及CPU内核信息.CPU具体型号等等,整个CPU信息一目了然.   1.# uname -a   (Linux查看 ...

  7. git的一些常见命令

    一.新建代码库 # 在当前目录新建一个Git代码库 $ git init # 新建一个目录,将其初始化为Git代码库 $ git init [project-name] # 下载一个项目和它的整个代码 ...

  8. BZOJ 4517: [Sdoi2016]排列计数 [容斥原理]

    4517: [Sdoi2016]排列计数 题意:多组询问,n的全排列中恰好m个不是错排的有多少个 容斥原理强行推♂倒她 $恰好m个不是错排 $ \[ =\ \ge m个不是错排 - \ge m+1个不 ...

  9. 运行所选代码生成器时出错:“预期具有协定名称 "NuGet.VisualStudio.IVsPackageInstallerServices" 的1导出 ——VS2015错误记录

    在编写ASP.NET MVC控制器后,右键添加视图时,VS2015报出错误: 运行所选代码生成器时出错:“预期具有协定名称 "NuGet.VisualStudio.IVsPackageIns ...

  10. 【IT人】如何提高阅读源代码的效率

    1.最近刚到公司,公司就发一架构代码自己看,看了几天看的想吐,也在网上找了下相关的技巧吧,不是有句话叫做:成功必有方法,失败总是借口! 2.借鉴别人的方法来看看如下: 记得在开源流行之前,我看过的代码 ...