第一篇:2-嵌入式操作系統(tǒng)實驗指導書(2018年5月更新)
《嵌入式操作系統(tǒng)》實驗指導書
實驗1 Linux編程基礎(chǔ)
實驗序號:1 適用專業(yè):計算機科學與技術(shù)
一、實驗目的
1、熟悉Vim的工作模式,熟練使用vim中的常見操作。
2、熟練掌握gcc編譯命令及gdb的調(diào)試命令,通過對有問題程序的跟蹤調(diào)試,進一步提高發(fā)現(xiàn)問題和解決問題的能力。
3、熟悉多文件的makefile的編寫,熟悉各種形式的makefile,并且進一步加深對makefile中用戶自定義變量、自動變量的理解。
4、使用autotools生成多文件的makefile,進一步掌握autotools的使用方法。
二、實驗內(nèi)容
1、vim使用練習
(1)在“/root”目錄下建一個名為“vim”的目錄。(2)進入“vim”目錄。
(3)將文件“/etc/inittab”復制到“vim”目錄下。(4)使用vim打開“vim”目錄下的inittab.(5)設(shè)定行號,指出設(shè)定initdefault(類似于“id:5:initdefault”)的所在行號。(6)將光標移到該行。(7)復制該行內(nèi)容。
(8)將光標移到最后一行行首。(9)粘貼復制行的內(nèi)容。(10)撤銷第9步的動作。
(11)將光標移動到最后一行的行尾。(12)粘貼復制行的內(nèi)容。
(13)光標移到“si::sysinit:/etc/rc.d/rc.sysinit”。(14)刪除該行。(15)存盤但不退出。(16)將光標移到首行。
(17)插入模式下輸入“Hello,this is vi world!”.(18)返回命令行模式。
(19)向下查找字符串“0:wait”。(20)再向上查找字符串“halt”。
實驗名稱:Linux編程基礎(chǔ)
學 時 數(shù):4學時
(21)強制退出vim,不存盤。
2、用gdb調(diào)試程序的bug(1)使用vi編輯器,將以下代碼輸入到名為greet.c的文件中。此代碼的原意為輸出倒序main函數(shù)中定義的字符串,但結(jié)果顯示沒有輸出,代碼如下所示。
#include
int main(){
} int display1(char *string){
} int display2(char *string1){
char *string2;int size,i;size=strlen(string1);string2=(char *)malloc(size+1);for(i=0,i (4)使用gdb調(diào)試程序,通過設(shè)置斷點、單步跟蹤,一步步找出錯誤所在。 (5)糾正錯誤,更改源程序并得到正確的結(jié)果。 3、編寫包含多文件的makefile(1)用vi在同一目錄下編輯兩個簡單的hello程序,如下所示。#hello.c #include“hello.h” int main(){ } #hello.h #include (3)將上述makefile使用變量替換實現(xiàn)。同樣用make驗證所編寫的makefile是否正確。 (4)編輯另一個makefile,取名為makefile1,不使用變量替換,但用兩個目標體實現(xiàn)(也就是首先將hello.c和hello.h編譯為hello.o,再將hello.o編譯為hello),再用make的“-f”選項驗證這個makefile1的正確性。 (5)將上述makefile1使用變量替換實現(xiàn)。 三、實驗步驟 根據(jù)實驗內(nèi)容要求完成實驗。printf(“Hello everyone!n”); 實驗2 進程管理實驗 實驗序號:2 實驗名稱:進程管理實驗 適用專業(yè):計算機科學與技術(shù)(嵌入式系統(tǒng))學 時 數(shù):4學時 一、實驗目的 1、通過編寫多進程程序,使讀者熟練掌握fork()、exec()、wait()和waitpid()等函數(shù)的使用,進一步理解在Linux中多進程編程的步驟。 2、通過編寫經(jīng)典的“生產(chǎn)者—消費者”問題的實驗,進一步熟悉Linux中的多線程編程,掌握用信號量處理線程間的同步和互斥問題。 二、實驗內(nèi)容 1、編寫多進程程序 該實驗有3個進程,其中一個為父進程,其余兩個是該父進程創(chuàng)建的子進程,其中一個子進程運行“l(fā)s-l”指令,另一個子進程在暫停5s之后異常退出,父進程先用阻塞方式等待第一個子進程的結(jié)束,然后用非阻塞方式等待另一個子進程的退出,等待收集到第二個子進程結(jié)束的信息,父進程就返回。參考流程圖如圖1所示。 開始 fork()創(chuàng)建兩個子進程子進程1父進程阻塞式等待子進程1的結(jié)束等待1s子進程2是否結(jié)束?運行(調(diào)用execlp()執(zhí)行“l(fā)s-l”命令)是子進程2運行(調(diào)用sleep函數(shù))結(jié)束 圖1 多進程實驗流程圖 2、多線程實驗 編寫“生產(chǎn)者—消費者”問題的實驗,熟悉Linux中的多線程編程。 “生產(chǎn)者—消費者”問題描述如下。有一個有限緩沖區(qū)和兩個線程:生產(chǎn)者和消費者。他們分別不停地把產(chǎn)品放入緩沖區(qū)和從緩沖區(qū)中拿走產(chǎn)品。一個生產(chǎn)者在緩沖區(qū)滿的時候必須等待,一個消費者在 緩沖區(qū)空的時候也必須等待。另外,因為緩沖區(qū)是臨界資源,所以生產(chǎn)者和消費者之間必須互斥執(zhí)行。 要求使用有名管道來模擬有限緩沖區(qū),并且使用信號量來解決“生產(chǎn)者—消費者”問題中的同步和互斥問題。 使用3 個信號量,其中兩個信號量 avail 和 full 分別用于解決生產(chǎn)者和消費者線程 之間的同步問題,mutex 是用于這兩個線程之間的互斥問題。其中 avail 表示有界緩沖區(qū)中 的空單元數(shù),初始值為 N;full 表示有界緩沖區(qū)中非空單元數(shù),初始值為 0;mutex是互斥 信號量,初始值為 1。參考流程圖如圖2所示。 開始 建立有名管道 打開有名管道 初始化三個信號量 創(chuàng)建消費者和生 產(chǎn)者兩個線程 生產(chǎn)者線程 P操作(avail)P操作(mutex)讀管道消費者線程 P操作(full)P操作(mutex)寫管道 V操作(full)V操作(mutex)結(jié)束 V操作(avail)V操作)(mutex 圖2 多線程實驗流程圖 三、實驗步驟 1、根據(jù)參考流程圖編寫程序; 2、編譯和運行程序代碼,并觀察運行結(jié)果。 實驗3 模塊編程實驗 實驗序號:3 實驗名稱:模塊編程實驗 適用專業(yè):計算機科學與技術(shù)(嵌入式系統(tǒng))學 時 數(shù):4學時 一、實驗目的 1、熟悉模塊添加和刪除的方法。 2、熟悉字符設(shè)備驅(qū)動的編寫流程。 二、實驗內(nèi)容 要求實現(xiàn)到虛擬設(shè)備(一段內(nèi)存)的打開、關(guān)閉、讀寫的操作,并通過編寫測試程序來測試虛擬設(shè)備及其驅(qū)動運行是否正常。 三、實驗步驟 (1)編寫代碼。 這個簡單的驅(qū)動程序的源代碼如下所示: /*test_drv.c*/ #include { int len;if(count<0) } { } len=strlen(data);count=(len>count)?count:len;if *(copy_to_user(buf,data,count))/*將內(nèi)核緩沖的數(shù)據(jù)復制到用戶空間*/ { } return count;return –EFAULT;return –EINVAL;/*寫函數(shù)*/ static ssize_t test_write(struct file *file,const char *buffer,size_t count,loff_t *f_pos){ if(count<0){ } memset(data,0,BUFF_SZ); } /*打開函數(shù)*/ static int test_open(struct inode *inode,struct file *file){ printk(“This is open operationn”);/*分配并初始化緩沖區(qū)*/ data=(char*)kmalloc(sizeof(char)* BUFF_SZ,GFP_KERNEL);if(!data)count=(BUFF_SZ>count)?count:BUFF_SZ;if(copy_from_user(data,buffer,count))/*將用戶緩沖的數(shù)據(jù)復制到內(nèi)核空間*/ { } return count;return –EFAULT;return –EINVAL; } { } memset(data,0,BUFF_SZ);return 0;return –ENOMEM;/*關(guān)閉函數(shù)*/ static int test_release(struct inode *inode,struct file *file){ } /* 創(chuàng)建、初始化字符設(shè)備,并且注冊到系統(tǒng)*/ static void test_setup_cdev(struct cdev *dev, int minor, struct file_operations *fops) { int err, devno = MKDEV(major, minor);cdev_init(dev, fops);dev->owner = THIS_MODULE;dev->ops = fops; err = cdev_add(dev, devno, 1); if(err){ printk(KERN_NOTICE “Error %d adding test %d”, err, minor);} } /* 虛擬設(shè)備的 file_operations 結(jié)構(gòu) */ static struct file_operations test_fops = { .owner = THIS_MODULE,.read.open }; /*模塊注冊入口*/ = test_read, = test_open,.write = test_write,.release = test_release, printk(“This is release operationn”);if(data){ } return 0;kfree(data);data=NULL; /*釋放緩沖區(qū)*/ /*防止出現(xiàn)野指針*/ int init_module(void){ int result;dev_t dev = MKDEV(major, 0);if(major) {/* 靜態(tài)注冊一個設(shè)備,設(shè)備號先前指定好,并設(shè)定設(shè)備名,用 cat /proc/devices 來查看*/ } else { } if(result<0){ printk(KERN_WARNING“Test device:unable to get major %dn”,major);return result; } test_setup_cdev(&test_dev, 0, &test_fops);printk(“The major of the test device is %dn”, major);return 0;} /*卸載模塊*/ void cleanup_module(void){ cdev_del(&test_dev);unregister_chrdev_region(MKDEV(major, 0), 1);printk(“Test device uninstalledn”);} result=alloc_chrdev_region(&dev,0,1,TEST_DEVICE_NAME);result=register_chrdev_region(dev,1,TEST_DEVICE_NAME); (2)編譯代碼。 虛擬設(shè)備的驅(qū)動程序的 Makefile 如下所示: ifeq($(KERNELRELEASE),) KERNELDIR ?= /lib/modules/$(shell uname-r)/build /*內(nèi)核代碼編譯路徑*/ PWD := $(shell pwd)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: modules modules_install clean else obj-m := test_drv.o /* 將生成的模塊為 test_drv.ko*/ endif (3)加載和卸載模塊。通過下面兩個腳本代碼分別實現(xiàn)驅(qū)動模塊的加載和卸載。加載腳本 test_drv_load 如下所示: #!/bin/sh # 驅(qū)動模塊名稱 module=“test_drv” # 設(shè)備名稱。在/proc/devices 中出現(xiàn) device=“test_dev” # 設(shè)備文件的屬性 mode=“664” group=“david” # 刪除已存在的設(shè)備節(jié)點 rm-f /dev/${device} # 加載驅(qū)動模塊 /sbin/insmod-f./$module.ko $* || exit 1 # 查到創(chuàng)建設(shè)備的主設(shè)備號 major=`cat /proc/devices | awk “$2==”$device“ {print $1}”` # 創(chuàng)建設(shè)備文件節(jié)點 mknod /dev/${device} c $major 0 # 設(shè)置設(shè)備文件屬性 chgrp $group /dev/${device} chmod $mode /dev/${device} 卸載腳本 test_drv_unload 如下所示: #!/bin/sh module=“test_drv” device=“test_dev” # 卸載驅(qū)動模塊 /sbin/rmmod $module $* || exit 1 # 刪除設(shè)備文件 rm-f /dev/${device} exit 0(4)編寫測試代碼。 最后一步是編寫測試代碼,也就是用戶空間的程序,該程序調(diào)用設(shè)備驅(qū)動來測試驅(qū)動的運行是否正常。以下實例只實現(xiàn)了簡單的讀寫功能,測試代碼如下所示: /* test.c */ #include #include int fd, nwrite, nread;char buff[BUFF_SZ];/* 打開設(shè)備文件 */ fd = open(TEST_DEVICE_FILENAME, O_RDWR);if(fd < 0){ perror(“open”);exit(1);} do { printf(“Input some words to kernel(enter 'quit' to exit):”);memset(buff, 0, BUFF_SZ);if(fgets(buff, BUFF_SZ, stdin)== NULL){ perror(“fgets”);break;} buff[strlen(buff)-1] = '