2嵌入式操作系统实验指导书更新文档格式.docx
《2嵌入式操作系统实验指导书更新文档格式.docx》由会员分享,可在线阅读,更多相关《2嵌入式操作系统实验指导书更新文档格式.docx(14页珍藏版)》请在冰豆网上搜索。
(17)插入模式下输入“Hello,thisisviworld!
”.
(18)返回命令行模式。
(19)向下查找字符串“0:
wait”。
(20)再向上查找字符串“halt”。
(21)强制退出vim,不存盘。
2、用gdb调试程序的bug
(1)使用vi编辑器,将以下代码输入到名为greet.c的文件中。
此代码的原意为输出倒序main函数中定义的字符串,但结果显示没有输出,代码如下所示。
#include<
stdio.h>
intdisplay1(char*string);
intdisplay2(char*string);
intmain()
{
charstring[]=”EmbeddedLinux”;
display1(string);
display2(string);
}
intdisplay1(char*string)
printf(“Theoriginalstringis%s\n”,string);
intdisplay2(char*string1)
char*string2;
intsize,i;
size=strlen(string1);
string2=(char*)malloc(size+1);
for(i=0,i<
size;
i++)
{
string2[size-i]=string[i];
}
string2[size+1]=’’;
printf(“Thestringafterwardis%s\n”,string2);
(2)使用gcc编译这段代码,注意要加上“-g”选项以方便之后的调试。
(3)运行生成的可执行文件,观察运行结果。
(4)使用gdb调试程序,通过设置断点、单步跟踪,一步步找出错误所在。
(5)纠正错误,更改源程序并得到正确的结果。
3、编写包含多文件的makefile
(1)用vi在同一目录下编辑两个简单的hello程序,如下所示。
#hello.c
#include“hello.h”
printf(“Helloeveryone!
\n”);
#hello.h
#include<
(2)仍在同一目录下用vim编辑makefile,且不使用变量替换,用一个目标体实现(即直接将hello.c和hello.h编译成hello目标体)。
然后用make验证所写的makefile是否正确。
(3)将上述makefile使用变量替换实现。
同样用make验证所编写的makefile是否正确。
(4)编辑另一个makefile,取名为makefile1,不使用变量替换,但用两个目标体实现(也就是首先将hello.c和hello.h编译为hello.o,再将hello.o编译为hello),再用make的“-f”选项验证这个makefile1的正确性。
(5)将上述makefile1使用变量替换实现。
三、实验步骤
根据实验内容要求完成实验。
实验2进程管理实验
2实验名称:
进程管理实验
计算机科学与技术(嵌入式系统)学时数:
1、通过编写多进程程序,使读者熟练掌握fork()、exec()、wait()和waitpid()等函数的使用,进一步理解在Linux中多进程编程的步骤。
2、通过编写经典的“生产者—消费者”问题的实验,进一步熟悉Linux中的多线程编程,掌握用信号量处理线程间的同步和互斥问题。
1、编写多进程程序
该实验有3个进程,其中一个为父进程,其余两个是该父进程创建的子进程,其中一个子进程运行“ls-l”指令,另一个子进程在暂停5s之后异常退出,父进程先用阻塞方式等待第一个子进程的结束,然后用非阻塞方式等待另一个子进程的退出,等待收集到第二个子进程结束的信息,父进程就返回。
参考流程图如图1所示。
图1多进程实验流程图
2、多线程实验
编写“生产者—消费者”问题的实验,熟悉Linux中的多线程编程。
“生产者—消费者”问题描述如下。
有一个有限缓冲区和两个线程:
生产者和消费者。
他们分别不停地把产品放入缓冲区和从缓冲区中拿走产品。
一个生产者在缓冲区满的时候必须等待,一个消费者在缓冲区空的时候也必须等待。
另外,因为缓冲区是临界资源,所以生产者和消费者之间必须互斥执行。
要求使用有名管道来模拟有限缓冲区,并且使用信号量来解决“生产者—消费者”问题中的同步和互斥问题。
使用3个信号量,其中两个信号量avail和full分别用于解决生产者和消费者线程之间的同步问题,mutex是用于这两个线程之间的互斥问题。
其中avail表示有界缓冲区中的空单元数,初始值为N;
full表示有界缓冲区中非空单元数,初始值为0;
mutex是互斥信号量,初始值为1。
参考流程图如图2所示。
图2多线程实验流程图
1、根据参考流程图编写程序;
2、编译和运行程序代码,并观察运行结果。
实验3模块编程实验
3实验名称:
模块编程实验
1、熟悉模块添加和删除的方法。
2、熟悉字符设备驱动的编写流程。
要求实现到虚拟设备(一段内存)的打开、关闭、读写的操作,并通过编写测试程序来测试虚拟设备及其驱动运行是否正常。
(1)编写代码。
这个简单的驱动程序的源代码如下所示:
/*test_drv.c*/
linux/module.h>
linux/init.h>
linux/fs.h>
linux/kernel.h>
#incldue<
linux/slab.h>
linux/types.h>
linux/errno.h>
linux/cdev.h>
asm/uaccess.h>
#defineTEST_DEVICE_NAME“test_dev”
#defineBUFF_SZ1024
/*全局变量*/
staticstructcdevtest_dev;
unsignedintmajor=0;
/*主设备号major=250*/
staticchar*data=NULL;
/*读函数*/
staticssize_ttest_read(structfile*file,char*buf,size_tcount,loff_t*f_pos)
{
intlen;
if(count<
0)
return–EINVAL;
}
len=strlen(data);
count=(len>
count)?
count:
len;
if*(copy_to_user(buf,data,count))/*将内核缓冲的数据复制到用户空间*/
{
return–EFAULT;
returncount;
/*写函数*/
staticssize_ttest_write(structfile*file,constchar*buffer,
size_tcount,loff_t*f_pos)
if(count<
memset(data,0,BUFF_SZ);
count=(BUFF_SZ>
BUFF_SZ;
if(copy_from_user(data,buffer,count))/*将用户缓冲的数据复制到内核空间*/
/*打开函数*/
staticinttest_open(structinode*inode,structfile*file)
printk(“Thisisopenoperation\n”);
/*分配并初始化缓冲区*/
data=(char*)kmalloc(sizeof(char)*BUFF_SZ,GFP_KERNEL);
if(!
data)
return–ENOMEM;
memset(data,0,BUFF_SZ);
return0;
/*关闭函数*/
staticinttest_release(structinode*inode,structfile*file)
printk(“Thisisreleaseoperation\n”);
if(data)
kfree(data);
/*释放缓冲区*/
data=NULL;
/*防止出现野指针*/
}
/*创建、初始化字符设备,并且注册到系统*/
staticvoidtest_setup_cdev(structcdev*dev,intminor,
structfile_operations*fops)
interr,devno=MKDEV(major,minor);
cdev_init(dev,fops);
dev->
owner=THIS_MODULE;
ops=fops;
err=cdev_add(dev,devno,1);
if(err)
printk(KERN_NOTICE"
Error%daddingtest%d"
err,minor);
/*虚拟设备的file_operations结构*/
staticstructfile_operationstest_fops=
.owner=THIS_MODULE,
.read=test_read,
.write=test_write,
.open=test_open,
.release=test_release,
};
/*模块注册入口*/
intinit_module(void)
intresult;
dev_tdev=MKDEV(major,0);
if(major)
{/*静态注册一个设备,设备号先前指定好,并设定设备名,用cat/proc/devices来查看*/
result=register_chrdev_region(dev,1,TEST_DEVICE_NAME);
else
result=alloc_chrdev_region(&
dev,0,1,TEST_DEVICE_NAME);
if(result<
printk(KERN_WARNING"
Testdevice:
unabletogetmajor%d\n"
major);
returnresult;
test_setup_cdev(&
test_dev,0,&
test_fops);
printk("
Themajorofthetestdeviceis%d\n"
major);
return0;
/*卸载模块*/
voidcleanup_module(void)
cdev_del(&
test_dev);
unregister_chrdev_region(MKDEV(major,0),1);
Testdeviceuninstalled\n"
);
(2)编译代码。
虚拟设备的驱动程序的Makefile如下所示:
ifeq($(KERNELRELEASE),)
KERNELDIR?
=/lib/modules/$(shelluname-r)/build/*内核代码编译路径*/
PWD:
=$(shellpwd)
modules:
$(MAKE)-C$(KERNELDIR)M=$(PWD)modules
modules_install:
$(MAKE)-C$(KERNELDIR)M=$(PWD)modules_install
clean:
rm-rf*.o*~core.depend.*.cmd*.ko*.mod.c.tmp_versions
.PHONY:
modulesmodules_installclean
obj-m:
=test_drv.o/*将生成的模块为test_drv.ko*/
endif
(3)加载和卸载模块。
通过下面两个脚本代码分别实现驱动模块的加载和卸载。
加载脚本test_drv_load如下所示:
#!
/bin/sh
#驱动模块名称
module="
test_drv"
#设备名称。
在/proc/devices中出现
device="
test_dev"
#设备文件的属性
mode="
664"
group="
david"
#删除已存在的设备节点
rm-f/dev/${device}
#加载驱动模块
/sbin/insmod-f./$module.ko$*||exit1
#查到创建设备的主设备号
major=`cat/proc/devices|awk"
\\$2==\"
$device\"
{print\\$1}"
`
#创建设备文件节点
mknod/dev/${device}c$major0
#设置设备文件属性
chgrp$group/dev/${device}
chmod$mode/dev/${device}
卸载脚本test_drv_unload如下所示:
#卸载驱动模块
/sbin/rmmod$module$*||exit1
#删除设备文件
exit0
(4)编写测试代码。
最后一步是编写测试代码,也就是用户空间的程序,该程序调用设备驱动来测试驱动的运行是否正常。
以下实例只实现了简单的读写功能,测试代码如下所示:
/*test.c*/
#include<
stdlib.h>
string.h>
sys/stat.h>
sys/types.h>
unistd.h>
fcntl.h>
#defineTEST_DEVICE_FILENAME"
/dev/test_dev"
/*设备文件名*/
#defineBUFF_SZ1024/*缓冲大小*/
intfd,nwrite,nread;
charbuff[BUFF_SZ];
/*缓冲区*/
/*打开设备文件*/
fd=open(TEST_DEVICE_FILENAME,O_RDWR);
if(fd<
0)
perror("
open"
exit
(1);
do
printf("
Inputsomewordstokernel(enter'
quit'
toexit):
"
memset(buff,0,BUFF_SZ);
if(fgets(buff,BUFF_SZ,stdin)==NULL)
fgets"
break;
buff[strlen(buff)-1]='
\0'
;
if(write(fd,buff,strlen(buff))<
0)/*向设备写入数据*/
write"
if(read(fd,buff,BUFF_SZ)<
0)/*从设备读取数据*/
read"
printf("
Thereadstringisfromkernel:
%s\n"
buff);
}while(strncmp(buff,"
quit"
4));
close(fd);
exit(0);
四、实验结果
首先在虚拟设备驱动源码目录下编译并加载驱动模块。
$makeclean;
make
$./test_drv_load;
加载模块直接运行脚本文件test_drv_load
接下来,编译并运行测试程序
$gcc–otesttest.c
$./test
测试程序运行效果如下:
Hello,everybody!
/*从内核读取的数据*/
Thisisasimpledriver
Thisisasimpledriver
quit
最后,卸载驱动程序
$./test_drv_unload卸载模块直接运行脚本文件test_drv_unload
通过dmesg命令可以查看内核打印的信息:
$dmesg|tail–n10
……
Themajorofthetestdeviceis250/*当加载模块时打印*/
Thisisopenoperation/*当打开设备时打印*/
Thisisreleaseoperation/*关闭设备时打印*/
Testdeviceuninstalled/*当卸载设备时打印*/