RTLinux编程总结
做过一个有关RTLinux的项目,时间一长,差不多忘光了,现在尽量把原来做过的东西总结一下,以备后用,同时正在做类似项目的一个借鉴
平台
主机:redhat 8.0
目标机:PC104模块、ISA总线脉冲输出、实时串口通信
linux-2.4.18.tar.bz2 +rtlinux-3.2-pre1.tar.bz2
简述
Linux是典型的分时应用系统,对于实时性要求很高的应用,必须对内核本身动手术。而RTLinux则采取了一种比较聪明也比较折中的办法:他们实现一个最底层的精简的调度器,用于调度实时线程,原来的内核本身则成为实时调度器的一个优先级最低的任务。这样,当有实时任务时,普通内核已经建立于其上的普通进程被强制中断,实时线程被强制执行;只有当若有实时线程都让出cpu之后,普通内核才被运行,再由普通内核去调度执行普通的应用程序……
实例
- #include <rtl_fifo.h>
- #include <rtl.h>
- #include <rtl_sched.h>
- #include <time.h>
- #include <pthread.h>
- #include <rtl_time.h>
- #include <signal.h>
- #include "rt_com.h"
- #include <linux/kernel.h>
- #include <linux/module.h>
- MODULE_LICENSE("GPL v2");
- MODULE_AUTHOR("Wind-Son");
- MODULE_DESCRIPTION("Pulse-Control system");
- typedef unsigned short __u16;
- void io_bit_on(__u16 port, unsigned int pos, __u16 *status)
- {
- __asm__ __volatile__(
- "movl %1,%?x\n\t"
- "movl %0,%?x\n\t"
- "btsl %2,(%?x)\n\t"
- "mov (%?x),%%al\n\t"
- "out %%al,(%%dx)\n\t"
- "out %%al,$0x80\n\t"
- :
- :"m"(status), "rm"(port), "Ir"(pos)
- );
- }
- void io_bit_off(__u16 port, unsigned int pos, __u16 *status)
- {
- __asm__ __volatile__(
- "movl %1,%?x\n\t"
- "movl %0,%?x\n\t"
- "btrl %2,(%?x)\n\t"
- "mov (%?x),%%al\n\t"
- "out %%al,(%%dx)\n\t"
- "out %%al,$0x80\n\t"
- :
- :"m"(status), "rm"(port), "Ir"(pos)
- );
- }
- #define dbg_print rtl_printf
- #define MIN_TIME 5000
- static void get_time_interval(void)
- {
- }
- void* pulse_generate_thread(void *arg)
- {
- static __u16 io_status = 0;
- struct sched_param p;
- hrtime_t current_time;
- REAL_TIME_GET_ENABLE;
- int intrrupt_sched_period = 180000;
- p.sched_priority = 1;
- struct timespec resolution;
- rtl_setclockmode(CLOCK_REALTIME, RTL_CLOCK_MODE_PERIODIC,
- intrrupt_sched_period);
- clock_getres(rtl_getschedclock(), &resolution);
- intrrupt_sched_period = timespec_to_ns(&resolution);
- pthread_make_periodic_np(pthread_self(), clock_gethrtime(rtl_getschedclock()),
- intrrupt_sched_period);
- pthread_setschedparam (pthread_self(), SCHED_FIFO, &p);
- for (;;) {
- dbg_print("debug entry\n");
- while (!ready)
- pthread_wait_np();
- dbg_print("debug exit\n");
- if (!init_rt_clock) {
- init_rt_clock = 1;
- pthread_wait_np();
- current_time = clock_gethrtime(CLOCK_REALTIME);
- } else {
- if (intrrupt_sched_period < MIN_TIME)
- intrrupt_sched_period = MIN_TIME;
- current_time += intrrupt_sched_period;
- clock_nanosleep(CLOCK_REALTIME, TIMER_ABSTIME, hrt2ts(current_time), NULL);
- }
- io_bit_on(IO_PORT_OUT, XPULSE, &io_status);
- intrrupt_sched_period = get_time_interval();
- }
- return 0;
- }
- static void init_for_rt_mm(void)
- {
- }
- static void rt_alloc_mm(void)
- {
- thread_wait_np();
- buf = kmalloc(size, GFP_ATOMIC);
- }
- static int kmalloc_thread(void * kthread_arg)
- {
- unsigned long timeout = HZ;
- init_for_rt_mm();
- for (;;) {
- while (!get_flag(MM_ALLOC_FLAG)) {
- if( signal_pending(current))
- return 0;
- timeout = interruptible_sleep_on_timeout(&wq, timeout);
- }
- rt_alloc_mm();
- clear_flag(MM_ALLOC_FLAG);
- }
- return -1;
- }
- wait_queue_head_t wq;
- static pid_t kmalloc_kthread_id;
- static int kmalloc_kthread_state = 1;
- static int pulse_generate_thread_created = 0;
- static int main_ctrl_thread_created = 0;
- static pthread_t pulse_generate_pthread;
- static pthread_t main_ctrl_pthread;
- static pthread_mutex_t cache_mutex;
- void rt_mm_request(void)
- {
- set_flag(MM_ALLOC_FLAG);
- while(get_flag(MM_ALLOC_FLAG))
- pthread_wait_np();
- }
- void* main_ctrl_thread(void *arg)
- {
- int work_sched_period = 160000;
- struct timespec resolution;
- int ret1 = rtl_setclockmode(rtl_getschedclock(), RTL_CLOCK_MODE_PERIODIC,
- work_sched_period);
- if (ret1) {
- dbg_print("seting periodic mode failed\n");
- clear_flag(WORK_SCHED_MODE);
- }
- clock_getres(rtl_getschedclock(), &resolution);
- work_sched_period = timespec_to_ns(&resolution);
- pthread_make_periodic_np(pthread_self(), clock_gethrtime(rtl_getschedclock()),
- work_sched_period);
- init_task();
- for (;;) {
- if (work) {
- dbg_print("work\n");
- rt_mm_request();
- calc_time_interval();
- if (exit)
- break;
- } else
- pthread_wait_np();
- }
- exit_task();
- return 0;
- }
- int init_module(void)
- {
- pthread_attr_t attr;
- struct sched_param p;
- int ret;
- rtf_destroy(0);
- rtf_destroy(1);
- rt_com_clr_in(0);
- rt_com_clr_out(0);
- int fifo_status = rtf_create(0,100);
- if(fifo_status)
- dbg_print("FIFO Create failed!");
- fifo_status = rtf_create(1, 4000);
- if(fifo_status)
- dbg_print("FIFO Create failed!");
- rt_com_setup(0, 9600, RT_COM_PARITY_NONE, 1, 8);
- hrtime_t now = gethrtime();
- pthread_attr_init(&attr);
- pthread_mutex_init(&cache_mutex, NULL);
- pthread_attr_setfp_np(&attr, 1);
- ret = pthread_create(&pulse_generate_pthread, &attr,
- pulse_generate_thread, (void *)0);
- if (!ret)
- pulse_generate_thread_created = 1;
- pthread_make_periodic_np (pulse_generate_pthread, now + 2 * 240000, 80000);
- p . sched_priority = 1;
- pthread_setschedparam (pulse_generate_pthread, SCHED_FIFO, &p);
- ret = pthread_create(&main_ctrl_pthread, &attr, main_ctrl_thread, (void *)1);
- if (!ret)
- main_ctrl_thread_created=1;
- pthread_make_periodic_np (main_ctrl_pthread, now + 2 * 160000, 30000);
- p . sched_priority = 2;
- pthread_setschedparam (main_ctrl_pthread, SCHED_FIFO, &p);
- init_waitqueue_head(&wq);
- kmalloc_kthread_id = kernel_thread(kmalloc_thread, NULL, 0);
- if (kmalloc_kthread_id < 0) {
- printk(KERN_ERR "fork failed, errno %d\n", -kmalloc_kthread_id);
- return kmalloc_kthread_id;
- }
- return ret;
- }
- void cleanup_module(void)
- {
- int ret = kill_proc(kmalloc_kthread_id, SIGKILL, 1);
- if (!ret) {
- int count = 10 * HZ;
- while (kmalloc_kthread_state && --count) {
- current->state = TASK_INTERRUPTIBLE;
- schedule_timeout(1);
- }
- }
- if (main_ctrl_thread_created) {
- pthread_cancel(main_ctrl_pthread);
- pthread_join(main_ctrl_pthread, NULL);
- pthread_delete_np(main_ctrl_pthread);
- }
- if (pulse_generate_thread_created) {
- pthread_cancel(pulse_generate_pthread);
- pthread_join(pulse_generate_pthread, NULL);
- pthread_delete_np(pulse_generate_pthread);
- }
- rt_com_setup(0, -1, 0, 0, 0);
- rtf_destroy(0);
- rtf_destroy(1);
- pthread_mutex_destroy (&cache_mutex);
- }
复制代码
其实现在有关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编程总结的更多相关文章
- Linux下的C编程实战
Linux下的C编程实战(一) ――开发平台搭建 1.引言 Linux操作系统在服务器领域的应用和普及已经有较长的历史,这源于它的开源特点以及其超越Windows的安全性和稳定性.而近年来, Linu ...
- Linux下的编程实战【转】
一篇比较不错的文章, 降到了 makefile make , gcc编译器,GDB调试器, Linux文件系统,Linux文件API,.C语言库函数(C库函数的文件操作实际上是独立于具体的操作系统平台 ...
- 从直播编程到直播教育:LiveEdu.tv开启多元化的在线学习直播时代
2015年9月,一个叫Livecoding.tv的网站在互联网上引起了编程界的注意.缘于Pingwest品玩的一位编辑在上网时无意中发现了这个网站,并写了一篇文章<一个比直播睡觉更奇怪的网站:直 ...
- JavaScript之父Brendan Eich,Clojure 创建者Rich Hickey,Python创建者Van Rossum等编程大牛对程序员的职业建议
软件开发是现时很火的职业.据美国劳动局发布的一项统计数据显示,从2014年至2024年,美国就业市场对开发人员的需求量将增长17%,而这个增长率比起所有职业的平均需求量高出了7%.很多人年轻人会选择编 ...
- 读书笔记:JavaScript DOM 编程艺术(第二版)
读完还是能学到很多的基础知识,这里记录下,方便回顾与及时查阅. 内容也有自己的一些补充. JavaScript DOM 编程艺术(第二版) 1.JavaScript简史 JavaScript由Nets ...
- [ 高并发]Java高并发编程系列第二篇--线程同步
高并发,听起来高大上的一个词汇,在身处于互联网潮的社会大趋势下,高并发赋予了更多的传奇色彩.首先,我们可以看到很多招聘中,会提到有高并发项目者优先.高并发,意味着,你的前雇主,有很大的业务层面的需求, ...
- C#异步编程(一)
异步编程简介 前言 本人学习.Net两年有余,是第一次写博客,虽然写的很认真,当毕竟是第一次,肯定会有很多不足之处, 希望大家照顾照顾新人,有错误之处可以指出来,我会虚心接受的. 何谓异步 与同步相对 ...
- UE4新手之编程指南
虚幻引擎4为程序员提供了两套工具集,可共同使用来加速开发的工作流程. 新的游戏类.Slate和Canvas用户接口元素以及编辑器功能可以使用C++语言来编写,并且在使用Visual Studio 或 ...
- 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 ...
随机推荐
- java foreach遍历的前提条件
自我总结,欢迎拍砖,不胜感激! 目的: 加深foreach遍历的影响 证明:foreach遍历的前提条件是:list !=null ,而不是:list !=null && list.s ...
- debug时ClassNotFound可能出现的原因
自我总结,欢迎拍砖! 目的:总结ClassNotFound可能出现的原因,方便以后定位该类问题. 原因:当项目中加了新类,debug或run时,报classnotfound,说明没有找到该类的clas ...
- PHP 第3方评论系统
这段时间,无觅 评论也下线不能使用了. 客户好几个网站使用了.无觅 评论,前面也是用的是多说还是什么,总之也是第3方评论,没想到没过多久,又停止使用了. 没办法,网站还是需要评论系统,一气之下,自己做 ...
- 结合Nginx以cgi方式安装php5.5.4
新建用户及用户组 groupadd webuser useradd -g webuser webuser 下载php-5.5 下载链接:http://pan.baidu.com/s/1i3CBshv ...
- iOS-电子书开发 笔记
前言 刚接手电子书项目时,和安卓开发者pt Cai老师[aipiti Cai,一个我很敬佩很资深的开发工程师,设计领域:c++.Java.安卓.QT等]共同商议了一下,因为项目要做要同步,移动端[手机 ...
- ABP官方文档翻译 4.2 数据传输对象
数据传输对象 DTOs的必要性 领域层的抽象 数据隐藏 序列化和懒加载问题 DTO转换和验证 示例 DTOs和实体间的自动映射 辅助接口和类 数据传输对象用来在应用层和展示层之间传输数据. 展示层调用 ...
- xBIM 基本的模型操作
目录 xBIM 应用与学习 (一) xBIM 应用与学习 (二) xBIM 基本的模型操作 xBIM 日志操作 XBIM 3D 墙壁案例 xBIM 格式之间转换 xBIM 使用Linq 来优化查询 x ...
- 洛谷 [P1220] 关路灯
本题是一道区间DP,很容易设计出状态, dp[i][j]代表关掉i到j的路灯所耗的电量,但是对于新到一个路灯来说,可以是原来直接来的,也可以是掉头来的,于是还需要添加一维 0代表在区间的左端,1代表在 ...
- 洛谷 [P1314] 聪明的质检员(NOIP2011 D2T2)
###一道二分答案加前缀和### 题目中已经暗示的很明显了 "尽可能靠近" " 最小值" 本题的主要坑点在于 long long 的使用 ##abs函数不支持l ...
- SSE图像算法优化系列十七:一些图像处理中常用小过程的SSE实现。
在做图像处理的SSE优化时,也会经常遇到一些小的过程.数值优化等代码,本文分享一些个人收藏或实现的代码片段给大家. 一.快速求对数运算 对数运算在图像处理中也是个经常会遇到的过程,特备是在一些数据压缩 ...