zh-cn yz rbdQNXNeutrino实时操作系统移植指南_第1页
zh-cn yz rbdQNXNeutrino实时操作系统移植指南_第2页
zh-cn yz rbdQNXNeutrino实时操作系统移植指南_第3页
zh-cn yz rbdQNXNeutrino实时操作系统移植指南_第4页
zh-cn yz rbdQNXNeutrino实时操作系统移植指南_第5页
免费预览已结束,剩余85页可下载查看

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

页次页次iiQNX简 架构概 架构对 首要移植问 移植策 建议移植路 详细对 内核可 QNX 可移植操作系统接口(POSIX)支 内存可 QNX 任务间/进程间通 VxWorks信息队列实 QNXNeutrino版本(信息队列 使用单独进程的QNXNeutrino版 VxWorks共享内存实 QNXNeutrino版本(共享内存 使用单独进程的QNXNeutrino版 VxWorks监视程序计时器的实 QNXNeutrino版本(监视程序计时器 异常处 QNX 结 移植元 启动代 VxWorks启 结 硬件输入/输出设 中断服务例程 输入/输 设备驱动程 网 VxWorks网络架 QNXNeutrino网络架 结 网络应用程序编 应用程序的移 vx2qnx.lib概 构建环 生成文 应用程序内存的使 附 移植参 运行区 参考文 图 图2:QNXNEUTRINO架构提供全内存保护 图3:QNXNEUTRINO中单独的多线程进程 图4:QNXNEUTRINO中的多个多线程进程 图7:QNXNEUTRINO中的内存管理 图8:QNXNeutrino中的函数mmap() 图10:QNXNEUTRINO的启动顺序 图11:VXWORKS的输入/输出系统 QNX软件系统公 页次iii页次页次ivQNX图12:QNXNEUTRINO中的设备输入/输出 图13:QNXNEUTRINO中的文件系统分层 图14:VXWORKS的网络架构 图15:QNXNEUTRINO的网络架构 图15:IO-PKT架构 图16:VXWORKS遗留程序 简WindRiverVxWorks系统是过去十年来非常成功的一款实时操作系统。与桌面/服务器操作系统的复杂性相比,VxWorks操作系统结构的相QNX®Nti®开发未来平台软件的途径。嵌入式系统的开发人员现在能使其产品具有与高级操作系统一样的复杂功能,同时又能精确响应嵌入式系统环境的独特NXNuoMSS-4与x6传统意义上,从实时操作系统(VxWorks)向高级操作系统(QNX的各种选择可能对移植过程产生深远的影响。认识到这种情况后,QNX开发了功能全面的迁移工具(包括本文件)Library库,帮助客户以更VxWorksQNXNeutrino实时操作VxWorks向QNXNeutrino移植是仅使用所有重要,但无法对这一复杂的专题进行详尽论述。必要时,您可参考其它QNX文件以深入了解该专题。本文涉及到应用程序开发/移植的各个阶段,并对两种操作系统进行了对比。它阐述了移植策略并了两种操作系统之间的主要异同点。概括介绍移植要求之外,本文还对QNXNeutrino与VxWorks的应用程序接最后,本文还介绍vx2qnx移植库QNXNeutrino移植VxWorks应移植到QNXNeutrino系统中,但该移植库实现了VxWorks的关键功能,因注意:本文中的“VxWorks”在所有情况下均指WindRiver公司5.x版产品组合,而不是指其AE产品。架构概架构图1:VxWorks系统的架构DeviceVxWorksDeviceI/OInterruptIntertaskMemory1显示的是系统架构示意图。VxWorks内核很小,除含有调度程序外,操作系统通过使用和同步技术监视任务的执行情况。可抢占式内(MMU),但在执行指令和数据高速缓存(如需要)时可能需要使用它()。内存管理单元是以任务内存时使用物理内存地址的方式建立的。也就是说,无需内存地址转换以从任务内使用的内存地址中获取物理地址。需要重视的是,尽管VxWorks可启用内存管理单元,但它不提供任何内存保护功能。任务与操作系统内核之间的通信是通过一个简单的函数调用接口完成的,(也可能不会中断服务例程(ISR)与设备驱动器(由WindRiver或用户提供)是通过调用口可确保使用标准的输入/输出调用(打开、、写入等)设备。设QNXNeutrinoQNXNeutrino是一种基于微内核且具有微内核结构的操作系统,它能提供如可通过QNXNeutrino微内核管理的基元与同步基元互相通信,这种架构与传统的实时执行程序和单核nx式系统有本质的区别。NXNuro(IC)服务,并通过附加的服务进程扩展内核功能方面有显著区别。由于操作系统是以微内核管理的一组协作进程的形式实现的,因此用户编写的进程可同时用作(针对与用户有关的程序因此,操作系统本身就变为“开放”式的,而且易于扩展。QNXNeutrino充分利用处理器的内存管理单元在受保护的运行环境中提供完整的可移植操作系统接口(POSIX)进程模型。微内核可为用户应用程序为嵌入式应用程序,特别是任务关键型系统增加内存保护功能能实现的主要优势是提高系统的稳定性。如果在多任务处理环境中运行的某个进程试图未明确或分配用于其类型的内存资源,内存管理单元硬件就能利用内存保护功能通知操作系统,由其(通过失败/指令中止线程。这样可以在进程地址空间之间提供“保护”,防止一个进程中出现的线程编码错误“损坏”其他进程(或操作系统)中的线程使用的内存。这盖的内存,那么调试会十分。启用内存管理单元后,操作系统就能在出现内存时立即中止进程,为程序员提供即时反馈,而不是一段时间之后莫名其妙地导致系统。操作系统还能提供失败进程中错误指图2:QNXNeutrino架构提供全内存保护。UserUserDevice在宏内核架有许乎相当于整个操作系统,而QNX基本的系统服务,包括处理线程、信号、、同步、调度、计时器和进程。与线程不同,QNXNeutrino本身不会被安排执行任务。只有个操作系统都是在这些调用的基础上构建的。QNXNeutrino是一种完全可QNXNeutrino微内核的最小复杂性可为通过内核的不可抢占的最长代码路径设置上限,其紧凑的代码大小允许对复杂的多处理器问题进行。加系统进程与用户编写的程序在本质上很难区分——因为它们都使用相同的公共用序接和何(有适当的户进使用内服QNXNtrno操作系统本身很简单:只需编写新程序提供新的操作系统服务即可。VxWorks中的基本运行单元是任务。QNXNeutrino中的基本运行单元是线程。QNXNeutrino中的线程会集中进入名为“进程”的容器内,并通过操作系统进行控制和调度。VxWorksQNXNeutrino的线程是一样的。VxWorks中的任务控制taskLib函数实现的,而QNXNeutrino中的线程控制是通过pthread_函数族实现的。VxWorks中只有一个“任务容器”,即操作系统本身。在QNXNeutrino中, 共享内存区,但进程必须使用函数shm_*明确指明其想要共享的内存区。QNXNeutrino中的操作系统和应用程序之间有非常清楚的界限。进入操作系统的调用是通过能完全用户应用程序和操作系统的系统调用接口实VxWorks提供的基于函数的操作系统接口形成了鲜明对比,因为其中的参数错误或内存指针会导致操作系统内部结构的损坏。是显而易见的。在VxWorks中,操作系统组件必须到应用程序中,以的方式建立的,并单独在文件系统中以便随后执行。用户无法修改QNXNeutrino内核,由于其具有可扩展的架构,因此也无需修QNXNeutrino中,用户可通过向其他协作进程发送信息来扩展内核的功能。Vrs中的内存几乎总是按照“一对一”映射的方式进行的,其中的物理内存地址与应用程序的地址完全相同。QNXNtrno启用了虚拟内存;内存管理单元会将应用程序地址转换成对应的物理内存地址,同时将适当的内存保护标准用于被的内存。如果需要一个特殊的物理内用_*将内存空“映射”到进存空间。如果需要知道应用程序的物理地址(如要将缓冲库位输入硬件设备),就(e_offse()_ece_eoy()_ee_())转换地址。QNXNeutrino程中加入了“”和“权”概念。这在本质上提供了一种可限制线程使用的功能的机制。例如,在x86架构中,线程必须具有输入/输出(通过使用函数ThreadCtl()取得)和根权(通过在应用他处理器族中也提供了类似的级别。首要移植VxWorksQNXNeutrino的程序库应用程序接口有很大差异。虽然两QNXNeutrino例程中。必须将应用程序地址转换成物理内存地址QNXNeutrino中,不同进程中的线程之间不会自动共享内存。必须移植策QNXNeutrinoVxWorksvx2qnx移植库,以最少量的修改将大部分应用程序代码从VxWorks迁移到QNX使用适QNXNeutrino调用VxWorks私有函数。这种替换可通过手动方式完成,或通过使用代码分析工具自动完成。由于某些因此需要对一部分应用程序代码进行重新架构和修改,以适应QNXNeutrino提供的架构与服务。rsQNXNtrno。最理想的是,能使这种迁移像“重建并运行”一样简单。但在实际中,多数应用程序都很复杂,而且操作系统架构存在很大差异,因此无法在实际操作中实现完全模拟。同时,常见的操作系统中还有数百种应用程序接口功能。因此,正确地模拟所有应用程序接口功能不仅而且容易出错。第二种方案要求从VxWorks向QNXNeutrino移植应用程序,这涉及到修改一部分代码以体QNXNeutrino提供的新架构与服务。这样您就不必再通过VxWorks进行编码就能不断取得进展,以开发能使用QNXNeutrino中和冗长的转换过程是明显的不利因为充分利QNXNeutrino的功能两种方案都需要VxWorks私有函数到QNXNeutrino私有函数调用的适当映函数语法更改(一对一映射能以模拟VxWorks功能)vx2qnxVxWorks功能(如任务库功能、信号量、信息队列等)。由于开源移植库已经指明并且其他第提供的资源也已确认,因POSIX操作系统(QNXNeutrino)上开VxWorks应用能无法处理需要直接硬件的代码(因为这种代码依赖于相同的物理和代码进行手动移植,以确保将其正确集成到QNXNeutrino架构中。VxWorksVxSim产品可识别能以这种方式移植的应用程序部分和需要的应用程序在两种目标硬件和VxSim上运行,因此您应该使vx2qnx移植层在QNXNeutrino上“重建并运行”应用程序。vx2qnx移植库完成大应引入一种规划策略,以尽快使用本QNXNeutrino代码,这样就能实现QNXNeutrino的全部功能集并在必要时进行优化。图3:QNXNeutrino中单独的多线程进程。ProtectedmemoryDeviceQNXNeutrino4所示。可QNXNeutrino进程间通信(IPC)调用或共享内存区,以便进程图4:QNXNeutrino中的多个多线程进程。ProtectedProtectedmemoryDeviceProtectedmemoryProtectedmemoryProtectedmemoryProtectedmemoryVxWorks运行模式的方方案二更令人满意,但其需完成的工作量更大。它能实QNXNeutrino提供的完全保护和功能。但除了重新编写之外,很可能还需要对代码进行逐步完成移植。可使用QNXNeutrino或针对进程间通信的vx2qnx移VxWorks任务,并将其放入单独的进程中。清晰的进程间通口就是为松散耦合的任务设分离机制提供的附加模块化和功能,能在针对某些问题进行故障排解时大显身手,例如解决“内存”(一个任务覆写另一个任务拥有的内机QNXNeutrino函数调用。程序并完全实现QNXNeutrino的增强功能。建议移植VxWorks线程的单独进程。这样就能在最短时识别任何有性能问题的区域,并使用本机QNXNeutrino调用对这部分析代码库并引入使用本机QNXNeutrino进程间通信机制(针对松QNXNeutrino函数启用这些功能,内核可图5:在VxWorks中,所有内容都是在“内核空间”内运行的KernelKernelFunctionFunctionDeviceVxWorks中的内核在许多层上都是可完全的,包括任务对它的无意任务通过VxWorks程序库提供的直接函数调用获得对内核的权限。操作系统内所有可执行组件都能所有数据区任务管理是通过VxWorks调度程序进taskHook例程(位于taskLib内)修改任务执行的一些特征。这些包括taskSwitchHookAdd()、控制块(TCB)结构与任务有关的操作系统信息。虽然可以进行这种访问,但由于用于信息的C结构在不同的释放之间会发生变化,因此建议您不要采用这种。这些结构的损坏(可在显示所有任务信息时检测VxWorks中的任务调度是基于优先级的,而且可通过两种调度模式实现完全抢占:即先入先出(FIFO)调度和循环调度。任务控制是通过taskLib库完成的。可通过调用延迟任务的调度期(taskDelay)、防止任务被抢占(taskLock/intLock)、更改任务的优先级(taskPrioritySet)等。QNXQNXNeutrino微内核与进程管理器在单独的模(to)内配对。所有运能包含多个POSIX线程)。用户进程可直接通过内核调用微内核功能,并通过向to发送信息()需要重视的是,在to内执行的线程调用微内核的方式与其他进的味着有“特殊”或“”接口。系统内的所有线程均共享相同一致的内核接口,而且所有线会在调用微内核时进行转换。可移植操作系统接口(POSIX)支持VxWorks为多种工具(包括调度、信号量、信息队列、信号和计时器)提POSIX接口。QNXNeutrino包含所有这些接口,而且还提供了完全符POSIX标准。POSIX与QNXNeutrino都采用相反的方式:数值越大的优先级越重要。QNXNeutrino256种不同的优先级(VxWorks类似)用于线程(FIFO的策略之允许有偶发CPU利用需求的应用程序线程分配其所需的执行预算。VxWorksQNXNeutrinoPOSIX的功能进行了并列对比。请注意,在VxWorks中,大部分不同的功能都是由独立库提QNXNeutrino中,大部分POSIX功能都是通过libc程序库内的函数实现的。VxWorks程序QNXNeutrino程RR,互斥体(POSIX1003.1线程256,High=Low256,High=HighPOSIX1003.1(系统接口POSIX1003.1(系统接口扩展POSIX1003.1b(实时扩展POSIX1003.1c(线程POSIX1003.1b(附加实时扩展POSIXPOSIXPOSIX1003.1f(透明文件POSIX1003.1j(高级实时扩展POSIX1003.1-200x(草稿POSIX1003.4-200x(草稿QNXNeutrinoPOSIX1003.1-2001规范(1003.1-1996规范修改P1003.1a、1003.1d-、.1g-、.1j-2000)的要求,以及现行POSIX1003.13文件(PSE51、5253)定义的功能要求。QNXNeutrino已获得PSE52实时控制器1003.13-2003系统的符合性认证。内存可如前所述,VxWorks中的内存空间对所有任务都是开放的,内存时可它只会在提供指令和数据缓存功能时启动。可使用标准的库分配例程(malloc()、calloc等),或使用满足指定内存池(在启动顺序的内存初始化内存的设备提供缓存保护内存。尽管有时需要将“虚拟”内存转换成“物理内存”(cacheDrvVirtToPhys()/cacheDrvPhysToVirt函数),但根据图6:VxWorks中的内存分配。MemoryMemoryMemPartAlloc(SystemWasblockof sufficientsizefound(firstSplittheblockFreeListtotaskReturnunusedportiontotheglobalfreelistQNXQNXNeutrino(MMU)实现的功能全面的虚拟内存来运行。处理器内的硬件会利用在系统内存中定义虚拟地址(如在应用程序内使用的内存地址)CPU发出地址的映射的一组页表,以物理内存。程执行时,操作系统管理的页表会控制线程使用的内存地QNXNeutrino提供了全面的内存保护模式,它能将系统映像内的所有代码表。在该模式下,会为每个进程分配由CPU的内存管理单元控制的虚任务进行的内存分配是使用POSIX标准mmap()函数调用实现的,QNX内存碎片并对性能进行优化。由于进程管理器是以4KB为单位管理内存QNXNeutrino(first-fit分配策略的。每个进同进的线程堆。分配器的运行原理如下。内存(使malloc()、calloc()realloc()调用)时,系统会搜索空闲列表,寻找注意:QNXNeutrino中的空闲列表是使向链表的。因此,可同图7:QNXNeutrino中的内存管理。 QNXNeutrino系统架构指南提供了有关操作系统如何管理内存的详细任务间/进程间通信VxWorks提供了几种不同的任务间通信机制。可使用的不同方法包括:信号量是VxWorks中的任务间进行同步的主要。它提供了三种不同当建立信号量时,程序还能为等待信号量(即将可用)s对X。信息队列与管道Vrs了间。留量可变的信息,每种信息都有不同的长度。应用程序信息会使用sgend函(信息在发送时会被存放在队列开头)VxWorks还提供了具有32种优先级的POSIX信息队列(mq_*)。任务等待来自任何一组文件描述符(输入/输出设备)的数据。QNXNeutrino提供了符合POSIX1003.1接口规范要求的管道接口实现。VxWorks信息队列VxWorks中的任务之间实现同步和进行#include<stdio.h>#include<sysLib.h>#include<string.h>#defineMAX_NUM_MSG#defineMAX_MSG_LEN100#defineNUM_MSGS2*MAX_NUM_MSG void{staticcharbuf[MAX_MSG_LEN];inti;for(i=0;i<NUM_MSGS;i++)/*Yieldtoallowothertaskstorun.OtherwiseFIFOmeansthatthistaskwillrununtilblocked.*//*Writeandsendamessage.*/sprintf(buf,"Send1%d",i);ifMSG_PRI_NORMAL)==ERROR)printf("Send1msgQSendfailed!\n");}if(i==3)/*Sendanurgentmessage.*/sprintf(buf,"Send1URG%d",i);if(msgQSend(msgQId,MSG_PRI_URGENT)==ERROR)printf("Send1msgQSendfailed!\n");}}}}void{staticcharbuf[MAX_MSG_LEN];inti;for(i=0;i<NUM_MSGS;i++)sprintf(buf,"Send2%d",i);if(msgQSend(msgQId,MSG_PRI_NORMAL)==ERROR)printf("Send2msgQSendfailed!\n");}if(i==5)sprintf(buf,"Send2URG%d",i);if(msgQSend(msgQId,MSG_PRI_URGENT)==ERROR)printf("Send2msgQSendfailed!\n");}}}}void{charbuf[MAX_MSG_LEN];inti;for(i=0;i<NUM_MSGS;i++)ifWAIT_FOREVER)==ERROR)printf("Rxtask1msgQReceive}elseprintf("Task1received%s\n",}}}void{charbuf[MAX_MSG_LEN];inti;for(i=0;i<10;{ifWAIT_FOREVER)==ERROR)printf("Rxtask2msgQReceive}elseprintf("Task2received%s\n",}}}void{int /*Priorityislessthaninit’spriority,soinitcanruntocompletion.*/if((msgQId=MSG_Q_FIFO))==NULL){}if(0,0,0,0,0,0,0,0,0,0)==ERROR){printf("taskSpawnTx1}if0,0,0,0,0,0,0,0,0,0)==ERROR){printf("taskSpawnTx2}if0,0,0,0,0,0,0,0,0,0)==ERROR){printf("taskSpawnRx1}if0,0,0,0,0,0,0,0,0,0)==ERROR){printf("taskSpawnRx2}}QNXNeutrino版本(信息队列QNXNeutrino中实现同样的功能,我们有两种不同的选择方案。我们可以将VxWorks中的原始任务映射成相同进的线程,或使其成为不同的#include<stdio.h>#include<stdlib.h>#include#include<sys/QNXNeutrino.h>#include<sys/types.h>#include<pthread.h>#include<mqueue.h>#include#defineMAX_NUM_MSG#defineMAX_MSG_LEN100#defineNUM_MSGS2*MAX_NUM_MSG#defineMSG_PRI_NORMAL#defineMSG_PRI_URGENT20#defineMQ_NAME"simple_queue"mqd_tmsgQId;void*sendTask1(void{staticcharbuf[MAX_MSG_LEN];inti;for(i=0;i<NUM_MSGS;i++)/*Yieldtoallowothertaskstorun.OtherwiseFIFOmeansthatthistaskwillrununtilblocked.*//*Writeandsendamessage.*/sprintf(buf,"Send1%d",i);if(mq_send(msgQId,buf,strlen(buf)+1,MSG_PRI_NORMAL)<{printf("Send1msgQSendfailed!\n");}if(i==3)/*Sendanurgentmessage.*/sprintf(buf,"Send1URG%d",i);if(mq_send(msgQId,buf,strlen(buf)+1,MSG_PRI_URGENT)<{printf("Send1msgQSendfailed!\n");}}}}void*sendTask2(void{staticcharbuf[MAX_MSG_LEN];inti;for(i=0;i<NUM_MSGS;i++)sprintf(buf,"Send2%d",i);if(mq_send(msgQId,buf,strlen(buf)+1,MSG_PRI_NORMAL)<{printf("Send2msgQSendfailed!\n");}if(i==5)sprintf(buf,"Send2URG%d",if(mq_send(msgQId,buf,strlen(buf)+1,MSG_PRI_URGENT)<{printf("Send2msgQSendfailed!\n");}}}}void*receiveTask1(void{charbuf[MAX_MSG_LEN];inti;unsignedfor(i=0;i<NUM_MSGS;i++)if(mq_receive(msgQId,buf,MAX_MSG_LEN,&prio)<{printf("Rxtask1msgQReceive}elseprintf("Task1received%s\n",}}}void*receiveTask2(void{charbuf[MAX_MSG_LEN];inti;unsignedfor(i=0;i<10;i++)if(mq_receive(msgQId,buf,MAX_MSG_LEN,&prio)<0{printf("Rxtask2msgQReceive}elseprintf("Task2received%s\n",}}}void{intpri;pthread_attr_tattrib;structsched_paramparam;structsched_paramour_param;inti;structmq_attrpthread_attr_setinheritsched(&attrib,PTHREAD_EXPLICIT_SCHED);pthread_attr_setschedpolicy(&attrib,SCHED_FIFO);sched_getparam(0,&our_param);param.sched_priority=our_param.sched_priority-1;pthread_attr_setschedparam(&attrib,¶m);memset(&mqattr,0,sizeof(mqattr));mqattr.mq_maxmsg=MAX_NUM_MSG;mqattr.mq_msgsize=MAX_MSG_LEN;if((msgQId=mq_open(MQ_NAME,O_RDWR|O_CREAT,S_IRUSR|S_IWUSR,&mqattr))<0){}if(pthread_create(&tid[0],&attrib,sendTask1,NULL)<{printf("taskSpawnTx1}if(pthread_create(&tid[1],&attrib,sendTask2,NULL)<{printf("taskSpawnTx2}if(pthread_create(&tid[2],&attrib,receiveTask1,NULL)<{printf("taskSpawnRx1}if(pthread_create(&tid[3],&attrib,receiveTask2,NULL)<{printf("taskSpawnRx2}for(i=0;i<3;i++)}intmain(intargc,char{}使用单独进程的QNXNeutrino版#include<stdio.h>#include<stdlib.h>#include#include<sys/QNXNeutrino.h>#include<sys/types.h>#include<pthread.h>#include<mqueue.h>#include<sched.h>#include<unistd.h>#include<spawn.h>#include<fcntl.h>#include#defineMAX_NUM_MSG#defineMAX_MSG_LEN100#defineNUM_MSGS2*MAX_NUM_MSG#defineMSG_PRI_NORMAL#defineMSG_PRI_URGENT20#defineMQ_NAME"simple_queue"mqd_tmsgQId;void{staticcharbuf[MAX_MSG_LEN];inti;for(i=0;i<NUM_MSGS;i++)/*Yieldtoallowothertaskstorun.OtherwiseFIFOmeansthatthistaskwillrununtilblocked.*//*Writeandsendamessage.*/sprintf(buf,"Send1%d",i);if(mq_send(msgQId,buf,strlen(buf)+1,MSG_PRI_NORMAL)<{printf("Send1msgQSendfailed!\n");}if(i==3)/*Sendanurgentmessage.*/sprintf(buf,"Send1URG%d",i);if(mq_send(msgQId,buf,strlen(buf)+1,MSG_PRI_URGENT)<0)printf("Send1msgQSendfailed!\n");}}}}void{staticcharbuf[MAX_MSG_LEN];inti;for(i=0;i<NUM_MSGS;i++)sprintf(buf,"Send2%d",i);if(mq_send(msgQId,buf,strlen(buf)+1,MSG_PRI_NORMAL)<{printf("Send2msgQSendfailed!\n");}if(i==5)sprintf(buf,"Send2URG%d",if(mq_send(msgQId,buf,strlen(buf)+1,MSG_PRI_URGENT)<{printf("Send2msgQSendfailed!\n");}}}}void{charbuf[MAX_MSG_LEN];inti;unsignedfor(i=0;i<NUM_MSGS;i++)if(mq_receive(msgQId,buf,MAX_MSG_LEN,&prio)<{printf("Rxtask1msgQReceive}elseprintf("Task1received%s\n",}}}void{charbuf[MAX_MSG_LEN];inti;unsignedfor(i=0;i<10;i++)if(mq_receive(msgQId,buf,MAX_MSG_LEN,&prio)<0)printf("Rxtask2msgQReceive}elseprintf("Task2received%s\n",}}}voidmsgQ_init(int{intif(first)structmq_attrmemset(&mqattr,0,sizeof(mqattr));mqattr.mq_maxmsg=MAX_NUM_MSG;mqattr.mq_msgsize=MAX_MSG_LEN;if((msgQId=mq_open(MQ_NAME,O_RDWR|O_CREAT,S_IRUSR|S_IWUSR,&mqattr))<0){}}elseif((msgQId=mq_open(MQ_NAME,O_RDWR))<{printf("msgQOpenfailed!\n");}}}intmain(intargc,char{if(argc=={pid_tpid[3];charbuf[10];inti;for(i=0;i<3;{sprintf(buf,"%d",i+2);argv[1]=buf;argv[2]=pid[i]=spawnv(P_NOWAIT,argv[0],}for(i=0;i<3;i++)waitpid(pid[i],NULL,WEXITED);}elseintnum=atoi(argv[1]);switch(num){case2:case3:case4:}}}共享内存QNXNetro准IXhm_*调用提供对共享内存的,样能使不同进程(不共享同一地址空间)中的线程互相通信。与在xor中(可使用在不同上下文中运行的直接代码指针法据的同。shm_openopen相同的参数,然后它会将文件描述符退回对象。与ftruncateshm_ctl()函数。请注意,ftruncate()与设置文件大小的函mmap()将对象(或其一部分)映射到进程的地址空间内。函数mmap()是QNXNeutrino中内mmap()是按下列方式定void*mmap(void*where_i_want_it,size_tintmemory_protections,intmap_flags,intfd,off_toffset_within_shared_memory);长度(位于共享内存对象中oft_wthshe_eoy)fd有关。”图8:QNXNeutrino中的函数mmap()len,prot,flags,len,prot,flags,fd,offset

mmapMAP_ANON标志连用时,用户能轻松实现专用的页级分配器/mprotect更改对内存映射区的保护。VxWorks共享内存 #include<stdio.h>#include<sysLib.h>#include<string.h>struct{char}void{intfor(i=0;i<10;i++)/*Sharedareaismutex-protected.*/semTake(mSem,WAIT_FOREVER);/*Delayfor2seconds*//*Printandthenchangethesharedmemory.*/sprintf(shareThis.writeArea,"Thisisshared1/*Releasethemutex.*/}}void{int/*Delayforonesecondtolettheshared1taskgrabthemutex.*/for(i=0;i<10;i++)/*Sharedareaismutex-protected.*/semTake(mSem,WAIT_FOREVER);printf("Shared2reads%s",shareThis.writeArea);}}void{int/*Prioritylessthaninit’spriority,sotasksstartandwaitforinittocomplete.*/mSem=semMCreate(SEM_Q_PRIORITY);if(mSem==NULL){}if(0,0,0,0,0,0,0,0,0,0)==ERROR){printf("taskSpawn1}if0,0,0,0,0,0,0,0,0,0)==ERROR){printf("taskSpawn2}}QNXNeutrino版本(共享内存程实例中,同一进的线程会自动共享内存。为防止对共享区的同时访#include<stdio.h>#include<stdlib.h>#include<string.h>#include<sys/QNX#include<unistd.h>struct{char}void*shared1(void{intfor(i=0;i<10;i++)/*Sharedareaismutex-protected.*//*Printandthenchangethesharedmemory.*/sprintf(shareThis.writeArea,"Thread1Writes:Thisisshared1/*Releasemutex.*//*Delayfor2seconds*/}}void*shared2(void{int/*Delayforonesecondtolettheshared1taskgrabthemutex.*/for(i=0;i<10;i++)/*Sharedareaismutex-protected.*/printf("Thread2reads:%s",shareThis.writeArea);/*Delayfor1seconds*/}}void{intpri;pthread_attr_tattrib;structsched_paramparam;structsched_paramour_param;inti;pthread_attr_setinheritsched(&attrib,PTHREAD_EXPLICIT_SCHED);pthread_attr_setschedpolicy(&attrib,SCHED_RR);sched_getparam(0,&our_param);param.sched_priority=our_param.sched_priority-1;pthread_attr_setschedparam(&attrib,¶m);mmutex=malloc(sizeof(pthread_mutex_t));pthread_mutex_init(mmutex,NULL);if(pthread_create(&tid[0],&attrib,shared1,NULL)<{printf("taskSpawn1}if(pthread_create(&tid[1],&attrib,shared2,NULL)<{printf("taskSpawn2}for(i=0;i<2;{pthread_join(tid[i],}}intmain(intargc,char{}使用单独进程的QNXNeutrino版适当的共享内存区,因此两个进能该内存区。定义一个互斥体并#include<stdio.h>#include<stdlib.h>#include<string.h>#include<sys/QNXNeutrino.h>#include<pthread.h>#include<unistd.h>#include<spawn.h>#include<fcntl.h>#include<sys/wait.h>#include#defineroundup(x,y)((((x)+((y)-1))/(y))*(y))#defineSHAREDNAME"/shared_test"struct{pthread_mutex_tmmutex;charwriteArea[128];structsharedarea*sharedThis;voidshared1(void){intfor(i=0;i<10;i++)/*Sharedareaismutex-protected.*//*Printthesharedmemorybeforechangingit.*/printf("%s",sharedThis->writeArea);"Proc1Writes:Thisisshared1/*Releasethemutex.*//*Delayfor2seconds*/}}void{int/*Delayforonesecondtolettheshared1taskgrabthemutex.*/for(i=0;i<10;i++)/*Sharedareaismutex-protected.*/printf("Proc2reads:%s",sharedThis->writeArea);/*Delayfor1seconds*/}}voidshare_init(int{intsize;intfd;if(first){fd=shm_open(SHAREDNAME,O_CREAT|O_RDWR,}elsefd=shm_open(SHAREDNAME,O_RDWR,}size=size=roundup(size,4096);//roundtopageaddr=(void*)mmap(0,size,PROT_READ|PROT_WRITE,MAP_SHARED,fd,sharedThis=(structsharedarea*)addr;}intmain(intargc,char{pid_tpid;if(argc=={shm_unlink(SHAREDNAME);pthread_mutex_init(&(sharedThis->mmutex),&attr);strcpy(sharedThis->writeArea,"Initialstartingstring\n");argv[1]="1";argv[2]=pid=spawnv(P_NOWAIT,argv[0],argv);waitpid(pid,NULL,WEXITED);}else}}套接字与过程调用进行的。在建立套接字时,您还要指定协议(UDPTCP)。TCP套接字为套接字的两端之间提供了可靠的双向通信。VxWorksBSD套接字接口实现代码兼容。QNXNeutrino提供的套接字接口也是基于BSD模式的。两种操作系统都提供了过程调用(RPC)工具。信适当的信号,就会调用这些处理程序。VxWorksPOSIX1003.1信号BSD信号接口。QNXNeutrinoPOSIX信号工具和基于语义的BSD信号工具。监视程序计时器监视程序计时器的函数是在系统时钟的中断服务例程(ISR)的上下文中执行的。这就限制了在回调例程中可实现的功能。用户还能使用POSIX1003.1b时钟和计时器接口。QNXNeutrinoPOSIX1003.1b时钟和计时器接口,从而允许线程将来在特定时间内自行发送信号。QNXNeutrino提供了功能全面的事件发 监视程序计时器的#include<stdio.h>#include<sysLib.h>#include<string.h>#include#include<wdLib.h>WDOG_IDwDog;SEM_IDbSem;void{}void{intfor(i=0;i<10;i++)/*Waitforsignalfromwdogtogoahead.*/semTake(bSem,WAIT_FOREVER);printf("Taskreceivedwatchdog/*Fireoffthewatchdogagaininonesecond.*/if(wdStart(wDog,sysClkRateGet(),(FUNCPTR)wDogRoutine,0)=={printf("wdStartfailedin}}}void{bSem=semBCreate(SEM_Q_PRIORITY,SEM_EMPTY);if(bSem==NULL){}wDog=wdCreate();if(wDog==NULL)printf("wdCreatefailed\n");}/*Fireoffthewatchdoginonesecond.*/if(taskSpawn("watchDog",0,0,0,0,0,0,0,0,0,0)==ERROR){printf("watchDogtaskspawn}if(wdStart(wDog,(FUNCPTR)wDogRoutine,0)=={printf("wdStart}}QNXNeutrino版本(监视程序计时器#include<stdio.h>#include<stdlib.h>#include<string.h>#include<sys/QNXNeutrino.h>#include<pthread.h>pthread_mutex_twd_mutex=PTHREAD_MUTEX_INITIALIZER;pthread_cond_twd_cond=PTHREAD_COND_INITIALIZER;structsigeventevent;inttimer_chid;structitimerspec#define void*wDogRoutine(void{intstruct_pulsemsg;while(1){rcvid=MsgReceive(timer_chid,&msg,sizeof(msg),NULL);if(rcvid==0){/*wegotapulse*/if(msg.code=={printf("\nwDogfired!\n");}}}}void*watchDogTask(void{intfor(i=0;i<10;i++)/*Waitforasignalfromwdogtogoahead.*/pthread_cond_wait(&wd_cond,&wd_mutex);printf("Taskreceivedwatchdogsem:%d.\n",i);itime.it_value.tv_sec=1;itime.it_value.tv_nsec=0;timer_settime(timer_id,0,&itime,NULL);}}void{pthread_ttid[2];pthread_attr_tattrib;structsched_paramparam;structsched_paramour_param;inti;setbuf(stdout,NULL);timer_chid=ChannelCreate(0);event.sigev_notify=SIGEV_PULSE;event.sigev_coid=ConnectAttach(0,0,timer_chid,event.sigev_priority=getprio(0);event.sigev_code=TIMER_PULSE_CODE;timer_create(CLOCK_REALTIME,&event,&timer_id);itime.it_value.tv_sec=itime.it_value.tv_nsec=0;timer_settime(timer_id,0,&itime,NULL);pthread_attr_setinheritsched(&attrib,PTHREAD_EXPLICIT_SCHED);pthread_attr_setschedpolicy(&attrib,SCHED_RR);sched_getparam(0,&our_param);param.sched_priority=our_param.sched_priority;pthread_attr_setschedparam(&attrib,¶m);if(pthread_create(&tid[0],&attrib,wDogRoutine,NULL)<{printf("watchDogroutinespawn}if(pthread_create(&tid[1],&attrib,watchDogTask,NULL)<{printf("watchDogtaskspawn}}intmain(intargc,char{}异常处CPU架构有关的库调用对异常中断向量表进行初始化。内核启动后,excInitexk()、可使用函数excHookAdd()增加用户异常代码,以增加默认动作。该代码是在正还可使用信号库sigLib(一种与Unix兼容的接口)处理硬件异常,在这种情况下,使用了sigvec()对单独的异常向量进行初始化。这种信号库同时提供了BSD4.3POSIX接口,但是这两种应用程序接口(API)不能混插。信号确QNX针对异常处理和异常恢复,QNXNeutrino提供了多种不同的机制。例如,然后在现场的所有其他设备遇到同样的前,为它们准备可的修复(SPOF)。此时真正需要的是一系统进程间完全支持内存管理单元(MMU)的内存保护功能可轻松并保护单独进程。QNXNeutrino的进程模型还具备动态创建和析构功能,这对结植工作的难度取决于VxWorks应用程序中使用了何种异常库。在QNXNeutrino中,可通过重启进程为显示应用程序出现严重故障VxWorks应用程序(常常需要进行系统完全重设)通常无1节中所述,代码移植的简易性与要移植的代码和硬件的关联程度密通常,进行移植时首先要在硬件平台上建立操作系统(本质上即板级支持启动代VxWorks启VxWorks针对嵌入式应用的基本启动顺序是先执行重设的汇编代码,这可通过_romInit代码或BIOS完成,具体取决于使用的硬件。该代码可执行建立CPU和内存所需的最基本功能,以便将VxWorks应用程序加载到随(RAM图9:VxWorks的启动顺序。 ImageismovedintoRAM

机器(RAM)中,而且通常还要进行解压缩和。必要时,可在此时当映像进入随机器(RAM)后,会从只读器(ROM)跳转执行随机存(RAM)内建立处理器和堆栈帧的少量程序集(_sysInit),以便启动服务等级(COS)初始化例程usrInit()。usrInit(会处理其余必要的设置,以对内核进行初始化(包括初始化异常向量、缓存库、中断和任何附加的硬件初始化)kernelInit()呼叫建立内核。内核初始化会导致执行usrRoot()。文件系统和其他支持的硬件,最后它会启动userAppInit(),其中包含用户提#define进行配置的,以在建立阶段确定应包含的prjConfig.c内QNXNeutrino启QNXNeutrino(to)to程序(IPL)完成的。IPL的初始任务是对硬件进行最低限度的配置以建立一种运行环境,便于启动程序以及随后的QNXNeutrino微内核运行。具体说来,(包括配置选择与/或PCI控制器)、配置时钟,以及建立能使IPL库 图10:QNXNeutrino的启动顺序。ROM OSboot

Boot软件执行的第二步是配置处理器和硬件、检测系统资源并启动操作系统。启动IL在进行必要的最低限度的配置,以使系统进入启动程序可以运行的状态时,启动程序L检测到各种资源,它会就该信息与启动程序进行通信(这样它就不必重新检测相同的资源)。为尽量确保QNXNuro些代码段必须能清除中断源。注意,启动程序不会配置串行端口的波特率。查看的一段内存)后,启动代码会负责将控制权转至QNXNeutrino内核与进程管理器(to),由其完成最后的载入步骤。要建立操作系统,需使用一个单独的映像文件。该映像至少应包含操作系但它们通常在单独的文件系统中(如闪存或磁盘),并由映像文件中包含的启动。有参考驻留文件(应用程序映像、程序库、操作系统映像、启动等)所需的mkifs(建立映像文件系统)的程序会使用命令结QNXNeutrinoVxWorksromStart/usrInit代码QNXNeutrinoVxWorksusrRoot类似的无需配置QNXNeutrino的内核。内核是作为生成文件可容纳的独立QNXNeutrino中的操作系统与应用程序能以不同格式在不同区VxWorks不同,VxWorks中的应用程序和操作系统必须硬件输入/输出设备系统中,这样就能使用一致的应用程序接口(API)硬件。在低层级,可使用标准输入/输出命令(开启、、写入、关闭等)设备。中断服务例程进行处理的。该例程库提供的例程可用于锁定/、启用/中断、为CPU产品系列。中断服务功说DRV_CTRL_SdrvCtrl;SEM_IDpacketSem;LOCALvoidmotFccISR(DRV_CTRL_S{structfcc_regs*fcc_regs;unsignedint *pQ=(PQ2IMM*)vxImmrGet();fcc_regs=&pQ->fcc_regs[pDrvCtrl-> um-1];/*Savetheeventregister.*/events=fcc_regs->fcc_fcce;/*Cleartheeventthat’scausingtheinterrupt.*/fcc_regs->fcc_fcce=0xffff0000;/*Otherprocessing/*Signaltotask.*/}DRV_CTRL_SdrvCtrl;...packetSem=semBCreate(SEM_Q_PRIORITY,SEM_EMPTY);um=1;(VOIDFUNCPTR)motFccISR,...}{while(1)/*Processpacket...}}在处理程序内部,可(QIMM结构与传递数据结构内包含的信息直接内内存射,确要的当存器清中。还可进行其他处理以应对中断问题。当完成中断处理后,会指定一个信号量以向任务通知出现的中断。semTake、malloc、printf、QNX望中断服务例程与特定的中断源产生关联。线程会使用InterruptAttach()或InterruptAttachEvent()函数调用指定它希望哪个中断源与哪个中断服务例程产生关联。当软件希望解除中断服务例程与中断源的关联时,它可以调用//ExampletoshowattachinganISR#defineIRQ33externconstsigevent*handle_int3(void*,//ObtainI/OPrivilegesThreadCtl(_NTO_TCTL_IO,0);//AssociateaninterrupthandlerwithIRQid=InterruptAttach(IRQ3,handle_int3,NULL,0,//Performsome//Done;detachtheinterruptsource.试图依附中断的线程必须具有输入/输出——即有关控制输入/输出端口和影响处理器允许中断标志的。只有根账户能获得输入/输出,handle_int3()是中断服务例程。中断服务例程通常负责特性产生影响。str*mem*()(strcpymemcpy())在中断服务例程中非常有用,所strdup()分配内存并使用互斥体。QNXNeutrino库参考可识别您能从中断服务例程调用的功能。InterruptDisableInterruptEnable()呼叫。由于这些呼叫能有效关闭中断,因此线程应该能使数据操作运行保持(如非全部)真正的线程级“维修”操作。您可以决定一些需要在中断服务例程中实现的时序要求严格的功能,然后稍后调度线程去做“实际”的工作,或者,您也可以决定无需在中断服务例程中实现任何功能;仅需调tA()Itettchet()(structsigevent)之间的明显区别。中断服务例程从硬件中一些寄存器后,或者完成进行维修所需的任何conststructsigevent结构即可;内线程,它仅需返回一个空(NULL)值即可。和迅速的方法是专门安排一个线程进行中断处理。线程(通过保持阻塞,直到中断服务例程返回SIGEV_INTR事件。#include<errno.h>#include<fcntl.h>#include<stdarg.h>#include<stdio.h>#include<stdlib.h>#include<string.h>#include<unistd.h>#include<sys/iofunc.h>#include<sys/resmgr.h>#include<sys/stat.h>#include<sys/syspage.h>#define void*interrupt_thread(void*data);structsigeventintr_event; #defineNUM_DATA_BYTES1unsignedintinterrupt_num=intmain(intargc,char{intwhile((i=getopt(argc,argv,"i:"))!=-{switch{caseinterrupt_num=atoi(optarg);printf("Unknownarg\n");return(EXIT_FAILURE);}}fprintf(stderr,"UsingInterrupt%u\n",interrupt_num);pthread_create(0,NULL,interrupt_thread,//Nowourmain()threadjustwaitstillwegetkilledreturn}conststructsigevent*interrupt_handler(void*event,int{structsigevent*return_event=(structsigevent*) mentthefollowinglinestopulse//NUM_DATA_BYTES'thinterrupt.Wearepretendingwe//onebyteofdataperinterruptandonlywakeup//threadafterNUM_DATA_BYTES//Whydotheworkofgettingthebytesofdatafrom//thethread?Becausewearepretendingthatifwe//doitathandlertime,thenwe'llmissthedata(e.g.//bufferingonthe//staticunsignedinterrupt_counter=////if(interrupt_counter==NUM_DATA_BYTES) interrupt_counter=0;returnreturn_event;//}else return//}void*interrupt_thread(void{unsignedcounter=0;structsched_paramparam;param.sched_priority=if(sched_setscheduler(0,SCHED_FIFO,¶m)==-1{fprintf(stderr,"Unabletochangepriority:%s\n",exit(EXIT_FAILURE}//WeneedI/OprivilegessowecancallInterruptAttach()if(ThreadCtl(_NTO_TCTL_IO,0)==-1){fprintf(stderr,"UnabletogetI/Oprivileges:%s\n",exit(EXIT_FAILURE}//SetupasigeventthatwillwakeupInterruptWait()SIGEV_INTR_INIT(&intr_event);if(interrupt_num==0)//Setinterrupt_numtothetimerinterrupt.On//thisis0.Wedothisjusttoshowhowtopull//fromtheinterrupt_num=SYSPAGE_ENTRY(qtime)-}intr_id=InterruptAttach(interrupt_num,interrupt_handler,&intr_event,sizeof(intr_event),_NTO_INTR_FLAGS_TRK_MSK);if(intr_id==-1)fprintf(stderr,"Unabletoattachtoirq%u:%s\n",interrupt_num,strerror(errno));exit(EXIT_FAILURE}for(;;)if(InterruptWait(NULL,NULL)==-1{fprintf(stderr,"\nInterruptWaitinterrupted:%s\n",}else//Theinterruptwentoff,andtheinterrupt//wascalled,andtheinterrupthandlerthen//usupfromInterruptWait()byreturningwith//SIGEV_INTRfprintf(stderr,"%u",counter);}}}正确设置QNXNeutrino中断服务例程中的硬件,然后才能使用程中能进行的函数调用的类型。QNXNeutrino进一步限制了在中断相对而言,将可清除硬件中断根源并执行semGive(启动一个执行剩Neutrino中并不。输入/接口(API),这就为硬件提供了一致的接口(如图11所示)。图11:VxWorks的输入/输出系统。EnhancedI/O(e.g.buffered,BasicI/OOSinfrastructure(e.g.filesystems,Device输入/输出函数说操作系统库中还包括更高级的标准功能(如套接字调用、printf、scanf等)。合”中分配/VxWorks5.4255个文件描述文件描述符可在open()或creat()调用过程中分配,并通过close()解除分配,而0分配给标准输入、1分配给标准输出、2块设备(如磁盘驱动器VxWorks中的文件系统位于块设备驱动程序的顶部。块设备驱动程序可充文件系统说ISO9660CD-ROM可通过您熟悉的stdio库调用(建立、打

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论