本科实验报告
课程名称: OS 实验报告
姓 名:
学 院: 计算机科学与技术
系:
计算机科学与技术
专 业: 计算机科学与技术
年 级:
学 号:
指导教师:
2007 年 4 月 15 日
一.实验目的
1.掌握 Linux 操作系统的使用方法;
2.了解 Linux 系统内核代码结构;
3.掌握实例操作系统的实现方法。
二. 实验环境
Linux-2.6.20.1(旧内核为 2.6.18.1)
三. 实验内容
1.编写一个 C 程序实现文件拷贝
2.编写一个 C 程序实现三个程序并发执行
3.通过系统调用实现文件拷贝
4.通过增加设备驱动的方法实现字符设备的驱动
5.利用 GTK 做一个任务管理器
四. 实验具体过程
1.编写一个 C 程序实现文件拷贝.
a.程序说明
通过循环每次使用 fgetc 读取一个字符,直到文件末尾结束.
b.程序源码
#include
#include
#include
int main()
{
FILE *f1,*f2;
f1=fopen("./source.txt","r");
f2=fopen("./source2.txt","w");
int s=0;
while(!feof(f1))
{
s=fgetc(f1);
if(s==EOF) break;
fputc(s,f2);
}
fclose(f1);
fclose(f2);
printf("Copy complete!!\n");
}
2. 编写一个 C 程序实现三个程序并发执行
a.程序说明
首先是主程序通过 fork 函数创建新进程,然后通过调用 execv 打开新文件以
到并发执行三个程序的目的.
2
子程序则使用了 GTK 编程,在一个窗体中放置了一个滚动条,加了个文字标签以改善视
觉效果.
b.程序源码
子程序代码:
#include
typedef struct _ProgressData {
GtkWidget *window;
GtkWidget *pbar;
int timer;
gboolean activity_mode;
} ProgressData;
itoa(int i,char* string)
{
int power,j;
j=i;
for(power=1;j>=10;j/=10)
power*=10;
for(;power>0;power/=10)
{
*string++='0'+i/power;
i%=power;
}
*string++='%';
*string='\0';
}//将整数转换成字符串
(GTK_PROGRESS_BAR (pdata->pbar)) +
0.005;
if (new_val > 1.0)
new_val = 0.0;
/* 设置进度条的新值 */
itoa(new_val*100,s);
gtk_progress_bar_set_fraction
(GTK_PROGRESS_BAR
new_val);
gtk_progress_bar_set_text
(pdata->pbar),
(GTK_PROGRESS_BAR (pdata->pbar),s);
/* 这是一个 timeout 函数,返回 TRUE,
这样它就能够继续被调用 */
return TRUE;
}
/* 清除分配的内存,删除定时器(timer) */
void
*widget,
destroy_progress(
GtkWidget
/* 更新进度条,这样就能够看到进度条的
移动 */
gint progress_timeout( gpointer data )
{
ProgressData
*pdata
=
(ProgressData
*)data;
gdouble new_val;
char s[10];
ProgressData *pdata)
gtk_timeout_remove (pdata->timer);
pdata->timer = 0;
pdata->window = NULL;
g_free (pdata);
gtk_main_quit ();
{
}
/* 使用在调整对象中设置的取值范
char *argv[])
int main( int
argc,
围计算进度条的值 */
new_val
gtk_progress_bar_get_fraction
{
=
ProgressData *pdata;
GtkWidget *align;
GtkWidget *separator;
3
GtkWidget *table;
GtkWidget *button;
GtkWidget *vbox;
gtk_init (&argc, &argv);
/* 为传递到回调函数中的数据分配内
存 */
pdata
=
g_malloc
(sizeof
(ProgressData));
pdata->activity_mode
= !pdata->activity_mode;
gtk_progress_bar_pulse
(GTK_PROGRESS_BAR (pdata->pbar));
gtk_progress_bar_set_fraction
(GTK_PROGRESS_BAR
(pdata->pbar),0.00);
gtk_progress_bar_set_text
(GTK_PROGRESS_BAR
"0.00");
(pdata->pbar),
pdata->window =
gtk_window_new
gtk_container_add (GTK_CONTAINER
(GTK_WINDOW_TOPLEVEL);
gtk_window_set_resizable
(GTK_WINDOW (pdata->window), TRUE);
(align), pdata->pbar);
gtk_widget_show (pdata->pbar);
/* 加一个定时器(timer),以更新进度条
g_signal_connect
(G_OBJECT
的值 */
(pdata->window), "destroy",
pdata->timer = gtk_timeout_add (100,
G_CALLBACK
progress_timeout, pdata);
(destroy_progress),
pdata);
gtk_window_set_title (GTK_WINDOW
(pdata->window), "这是窗口一");
gtk_container_set_border_width
(GTK_CONTAINER (pdata->window), 0);
vbox = gtk_vbox_new (FALSE, 5);
gtk_container_set_border_width
separator = gtk_hseparator_new ();
gtk_box_pack_start (GTK_BOX (vbox),
separator, FALSE, FALSE, 0);
gtk_widget_show (separator);
/* 行数、列数、同质性(homogeneous) */
table = gtk_table_new (2, 2, FALSE);
gtk_box_pack_start (GTK_BOX (vbox),
(GTK_CONTAINER (vbox), 10);
table, FALSE, TRUE, 0);
gtk_container_add (GTK_CONTAINER
gtk_widget_show (table);
(pdata->window), vbox);
gtk_widget_show (vbox);
/* 创建一个居中对齐的对象 */
align = gtk_alignment_new (0.5, 0.5, 0,
*/
/* 添加一个按钮,用来退出应用程序
button
=
gtk_button_new_with_label
0);
("close");
gtk_box_pack_start (GTK_BOX (vbox),
g_signal_connect_swapped (G_OBJECT
align, FALSE, FALSE, 5);
gtk_widget_show (align);
(button), "clicked",
G_CALLBACK (gtk_widget_destroy),
/* 创建进度条 */
pdata->pbar = gtk_progress_bar_new ();
pdata->window);
gtk_box_pack_start (GTK_BOX (vbox),
button, FALSE, FALSE, 0);
4
/* 将按钮设置为能缺省的构件 */
GTK_WIDGET_SET_FLAGS
(button,
gtk_widget_grab_default (button);
gtk_widget_show (button);
GTK_CAN_DEFAULT);
gtk_widget_show (pdata->window);
/* 将缺省焦点设置到这个按钮上,使
gtk_main ();
之成为缺省按钮,只要按回车键
* 就相当于点击了这个按钮 */
return 0;
主程序代码:
#include
#include
#include
#include
#include
int semid;
char *finish;
int p1,p2;
int main (void)
{
if((p1=fork())==0)//创建新进程
{
execv("./gtk1",NULL);
}
else
{
c.程序截图
}
if((p2=fork())==0)
{
execv("./gtk2",NULL);
}
else
{
if (fork()==0)
{
execv("./gtk3",NULL);//
打开文件执行
}
}
}
return;
}
3. 通过系统调用实现文件拷贝
a.程序说明:
5
要在 linux 下实现系统调用,首先修改内核中的三个文件,分别是 unistd.h,sys.c 和
syscalltable.s(这个是 2.6 版本和 2.4 版本的区别所在,2.4 版本要改的文件是 entry.s),
然后需要重新编译内核,具体步骤如下:
Make clean
Make bzImage
Make modules
Make modules_install
Make install
最后一步最为关键,2.6 版本不需要手动修改 grub,只需要执行 make install 就会自动
修改 grub,然后只要在启动时选择新内核即可,完全不需要手工操作.
此外还需要一个测试文件,文件拷贝的代码当然是原先写在内核里,这里是 sys.c 文
件.编译后的内核下通过系统调用同样实现了程序一文件拷贝的效果.
b.程序源码
测试程序:
#include
#include
#include
int mysyscall(char *f1,char *f2)
{
f1=sys_open(f1,"r");
f2=sys_open(f2,"w");
int s=0;
Sys.c 里的文件拷贝代码:
while(!feof(f1))
{
s=fgetc(f1);
if(s==EOF) break;
fputc(s,f2);
}
sys_close(f1);
sys_close(f2);
printk("Copy complete!!\n");
}
6
c.程序补充说明
在原先使用 2.6.18.1 的系统上编译 2.6.20.1 的内核,编程不受影响,因为编译后我们
使用的是新内核,编译需要漫长的时间,我还发现第一次编译需要 make modules 和 make
modules_install,而以后的重新编译则可以省略这两步,原因还有待进一步研究.
4.通过增加设备驱动的方法实现字符设备的驱动
a.程序说明
对于实现字符设备的驱动,首先要挂载字符设备,然后加载设备的驱动程序,然后再调
用测试程序进行测试.我们使用 mknod c 设备名称 设备号,这里 c 表示是字符设备.然后
我们可以通过 dmesg 查看每一步的进展情况.挂载设备成功后,通过分配的设备号,加载
设备的驱动,命令是 insmod 设备号.通过 lsmod 来查看所有挂载的设备,卸载设备则使
用 rmmod 设备号.所有这些完成后便可以开始测试了,编写测试程序 test.c 包含读设备
和写设备.
b.程序源码
驱动的编译命令(包含在 makefile 里):
ifneq ($(KERNELRELEASE),)
obj-m := ljian.o
else
KERNELDIR ?= /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)
default:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
endif
这里表示设备目标文件为 ljian.o
设备代码:
#include
#include
#include
#include
#include
#include
#include
#include
#define SUCCESS 0
#define
DEVICE_NAME
"cdev"
#define BUF_LEN 50
MODULE_LICENSE("GPL");
static int Device_Open=0;
static int test_major=0;//设备号
static
char
Message[BUF_L
EN]="test
only!";// 测 试 文
本
static char *Message_Ptr;
static
int
ljian_open(struct
7
inode *ind,struct
file *fip)
{
printk("<1>device
open:%d,%d\n",i
nd->i_rdev>>8,i
nd->i_rdev&0xF
F);
if(Device_Open)
return -EBUSY;
Device_Open++;
Message_Ptr=Message;
try_module_get(
THIS_MODUL
E);
return SUCCESS;
}
static
int
ljian_release(struct
inode *ind,struct
file *fip)
printk("<1>device
release:%d,%d.\
n",ind->i_rdev>
>8,ind->i_rdev&
0xFF);
Device_Open--;
module_put(THI
S_MODULE);
return 0;
{
}
static ssize_t
ljian_read(struct
file
*fip,char
*buffer,
size_t
length,loff_t
*offset)
{
int bytes_read=0;
if(*Message_Ptr==0)
return 0;
printk("<1>The message is
\"%s\"\n",Messa
ge);
while(length&&
*Message_Ptr){
put_user(*(Mess
age_Ptr++),buffe
r++);
length--;
bytes_read++;
}
return bytes_read;
}
static ssize_t
ljian_write(struct
file
*fip,const
char *buffer,
size_t
length,loff_t
*offset)
{
int i;
printk("<1>Befor
write
test,the message
is
\"%s\"\n",Messa
ge);
8