二.掌握系统调用的实现过程,通过编译内核方法,增加一个新的系统调用。
另编写一个应用程序,调用新增加的系统调用。
(1) 实现的功能是:文件拷贝;
操作步骤:
1。
先在/usr/src/linux-2.4.18-3/kernel/sys.c文件末尾添加mycopy_s.c里的代码。
2。
修改文件 /usr/src/linux-2.4.18-3/include/asm-i386/unistd.h文件在文件中相应位置加上:
#define __NR_mycopy 239
3.修改文件 /usr/src/linux-2.
4.18-3/arch/i386/kernel/entry.S文件
在文件中相应位置加上:
.long SYMBOL_NAME(sys_mycopy)
编译内核:(过程中要先后使用的命令如下,其中后两步操作为非必要,若不执行,则新内核下某些系统功能将无法实现)
make mrproper
make oldconfig
make dep
make clean
make bzImage
make modules
make modules_install
maek install
这几步均成功完成后,新内核已经生成,执行如下步骤:
cp /usr/src/linux-2.4.18-3/arch/i386/boot/bzImage /boot/bzImage-new cp /usr/src/linux-2.4.18-3/System.map /boot/System.map-new
ln –sf /boot/System.map-new /boot/System.map
然后进入 /etc/lilo.conf(本机采用Lilo配置),添加如下代码:
image=/boot/bzImage-new
label=linux-new
root=/dev/hda1 /* hda1为安装linux的分区 */
然后进入 /sbin,运行lilo,完成配置。
重启系统后选择标签为linux-new的新内核进入。
在新内核下测试系统调用,其运行结果如下:
[YAKUZA$root] ls
copy.c test.c
[YAKUZA$root] gcc mycopy_test.c –o mycopy_test
[YAKUZA$root] ls
mycopy_test mycopy_test.c test.c
[YAKUZA$root] cat test.c
#include <stdio.h>
main()
{
printf(“This is a test!!”);
}
[YAKUZA$root] ./mycopy_test test.c test1.c
[YAKUZA$root] ls
mycopy_test mycopy_test.c test.c test1.c
[YAKUZA$root] cat test1.c
#include <stdio.h>
main()
{
printf(“This is a test!!”);
}
(2) 实现的功能是:P、V操作。
1。
在/usr/src/linux-2.4.18-3/kernel/sys.c末尾添加pv_s.c代码:
2。
修改文件 /usr/src/linux-2.4.18-3/include/asm-i386/unistd.h文件在文件相关位置加上:
#define __NR_creatsem 240
#define __NR_deletesem 241
#define __NR_myp 242
#define __NR_myv 243
3.修改文件 /usr/src/linux-2.
4.18-3/arch/i386/kernel/entry.S文件
在文件相关位置加上:
.long SYMBOL_NAME(sys_creatsem)
.long SYMBOL_NAME(sys_deletesem)
.long SYMBOL_NAME(sys_myp)
.long SYMBOL_NAME(sys_myv)
按照上题的方法编译产生新内核,在新内核下测试该系统调用
测试pv操作的程序:
算法思想:
通过创建进程的方法,申请一块共享内存(大小为一个字节),一个进程往里写数据,另外一个进程往外读数据,写数据的进程每往共享内存中写入一个数据后睡眠一段时间,而读数据的进程不采用睡眠机制,观察程序运行结果,如果读数据的进程也会同样跟随写数据进程的睡眠而等待,则说明PV机制得已实现。
运行结果:
[YAKUZA$root] ls
pv_test.c
[YAKUZA$root] gcc pv_test.c -o pv_test
[YAKUZA$root] ./pv_test
Father pid put 0 into memory!
Kid pid get 0 from memory!
Father pid put 1 into memory!
Kid pid get 1 from memory!
Father pid put 2 into memory!
Kid pid get 2 from memory!
Father pid put 3 into memory!
Kid pid get 3 from memory!
Father pid put 4 into memory!
Kid pid get 4 from memory!
Father pid put 5 into memory!
Kid pid get 5 from memory!
Father pid put 6 into memory!
Kid pid get 6 from memory!
Father pid put 7 into memory!
Kid pid get 7 from memory!
Father pid put 8 into memory!
Kid pid get 8 from memory!
Father pid put 9 into memory!
Kid pid get 9 from memory!
The members for the program are:
Shi Xiaolei :2001011830691
Zhang Rui :2001011830689
Xu Faqiang :2001011830690
Yang Yaxi :2001011830705
Li Fengming :2001011830703
调试过程:
本题主要让我们了解了如何在Linux下增加新的系统调用。
首先,Linux下的系统调用函数都有一定的标准格式,并且增加新的系统调用需要修改Linux 中不同地方的几个文件。
开始将系统调用加到内核里面去了以后,运行copy的测试程序时,发现拷贝出了一个空的文件,令人百思不得其解。
后面请教了老师,才知道系统调用时,需要现将用户态下的文件内容拷贝到核态下,再由核态拷贝回用户态下,这其中涉及到段的操作,于是在系统调用函数中加入了段操作的语句,重新编译内核,终于实现了增加新的copy系统调用。
但是,不知为什么PV就是不能实现,编译内核,和测试程序编译是都没有出现错误,就是读写进程不相互等待,输出是先执行完一个进程后再执行另一个进程,开始想不明白为什么,并且发现其他组也遇到类似的问题,在此郁闷了相当长一段时间。
后来与其他组的同学相互协作,查了些相关资料,才发现我们对函数semget ()的理解有误,此函数是建立一个信号灯集,而不是建立一个信号灯,struct sembuf 应该是对应于信号灯集的一个数组,建立信号灯时,需要指定信号灯集重信号灯的个数,再通过数组sembuf的下标对每一个信号灯操作。
根据上述思想修改后,实现了PV功能。
真可谓好事多磨!
体会与心得:
通过这次操作系统课程设计,我收获颇丰:对世界上最优秀的操作系统的内核有了一定了解,加深了对pv操作的理解,知道了怎么写设备驱动;而且增强了克服困难的能力。
刚看到课程设计内容时就懵了,linux根本就不太熟系,而且设备驱动程序从来没看过,感觉无从下手;后来寒假回去看了两本有关linux 方面的书,终于是找到一点头绪了;等到开学经老师讲解后,就有信心了。
但是在编程中还是遇到很多困难,我们大家一起查资料、讨论、分析、交流经验,最后终于搞定了。