Linux系统分析与应用实验指导书.doc_第1页
Linux系统分析与应用实验指导书.doc_第2页
Linux系统分析与应用实验指导书.doc_第3页
Linux系统分析与应用实验指导书.doc_第4页
Linux系统分析与应用实验指导书.doc_第5页
已阅读5页,还剩19页未读 继续免费阅读

下载本文档

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

文档简介

Linux系统分析与应用实验指导书及报告班 级_学 号_姓 名_实验地点_浙江科技学院信息与电子工程学院浙江科技学院信息与电子工程学院实验指导书实验一 Linux基础一、实验目的1熟悉Linux字符界面和窗口系统,掌握其常用命令。2学会运用Linux常用的编辑工具。3熟悉Linux的在线求助系统。4掌握在Linux操作系统环境上编辑.编译.调试.运行一个C语言程序的全过程。二、实验内容1熟悉开机后登录Linux系统和退出系统的过程;熟悉Linux字符界面虚拟终端窗口和shell,以及图形界面X-Window(如gnome或KDE);熟悉常用shell的提示符;熟悉字符窗口与图形界面之间的切换。2使用set命令查阅自己的shell环境,并根据需要修改,例如,在PATH变量中增加当前目录;学会使用passwd命令修改用户口令;学习使用Linux的在线求助系统,如man和help命令等。3学习使用常用的Linux操作命令,如ls.cat.ps.find.grep.cd.more.cp.rm.mv,at,whereis locate等。l 注销(退出)系统:logout 或exitl 练习使用命令ls(注意Linux命令区分大小写。)使用ls 查看当前目录内容;使用ls 查看指定目录内容,如/目录,/etc目录l 使用cd改变当前目录如cd . 回到上层目录 ;cd / 回到根目录l pwd 显示当前路径 l 建立目录mkdirmkdir 目录名 ; 如mkdir /home/s2001/newdir l 删除目录:rmdir;l 复制文件cp: 如 cp 文件名1 文件名2l 移动文件或目录: mv l 删除文件: rml 显示文件内容:more (分页显示); l 显示文件:cat 文件名 建立文件:cat 文件名,ctrl+d结束输入l 创建软件硬链接文件:lnl 观察文件的结点内容:请你在主目录下建立三个子目录:textdir,sh_script,c_exmaple,分别用来存放文本文件,shell脚本和c程序,并从其他目录中找到相应类型的文件拷贝到其中,完成后使用pstree命令列出你建立的目录树,并删除所有的文件和子目录。4使用编辑器vi 编辑文件。l 在linux的命令行键入vi filename 并回车。其中,vi命令是打开vi编辑器。后面的filename是用户即将编辑的文件名字;也可以直接用vi打开一个新的未命名的文件,当保存的时候再给它命名,只是这样做不很方便。l 最基本的命令i :当进入刚打开的文件时,不能写入信息,这时按一下键盘上的i键(insert),插入的意思,就可以进入编辑模式了。如下图所示: l a与i是相同的用法l 当文件编辑完后,需要保存退出,这时需要经过以下几个步骤:1)按一下键盘上的Esc 键,进入命令模式;2)键入冒号(:),表示即将输入的是ex命令。紧跟在冒号后面是wq(意思是保存并退出)。如果不想保存退出,则在第二步键入冒号之后,键入!q(不带w,即为不保存)。请使用vi编辑一个名字为vi_exercise文本文件,内容自定。5掌握一个简单c语言程序的编辑.编译链接以及执行的过程。l 可以使用vi.gedit.emacs等编辑器编辑源程序,注意扩展名为.c;l indent 文件名 使用该命令可以实现c程序的自动缩排。l 要对刚才编写的程序进行编译。编译的命令是:gcc filename.c -o outputfilename,其中gcc是c的编译器。参数:filename.c 是刚才编辑的c 文件(当然也可以是以前编写好的c文件);后面中括号里面的参数是可选的,它是一个输出文件。如果不选,默认的输出文件是a.out ,选了之后输出文件就是outputfilename.outl 运行程序,方法如下:./outputfilename.outl 练习编写makefile文件,使用make命令执行刚才的程序请编写一个打印“Hello,I am a C program”字串的C语言程序,然后编译并运行它,记下整个过程。熟悉gcc.gdb等编译器.调试器的使用。 三、实验过程请描述实验内容1中你所看到的现象,列出实验2,实验3和实验4的操作步骤,写出实验5中的c程序,并给出操作过程和执行结果。实验二 Shell编程一、.实验目的掌握Shell编程的一般方法,能运用常用的Shell命令编写简单的Shell程序,并能在LINUX系统所提供的bin/sh或bin/bash下正确的运行。二、实验内容1用Shell命令确定自己登录的是何种Shell。2创建一个Shell脚本,通常要注意以下几个问题:l 可以使用任何文本编辑器制作脚本,如emacs.vi.gedit等。l 程序通常以下面的行开始(必须在文件的第一行):#!/bin/bash l 改变文件属性为可读可执行 chmod +rx filename l ./filename 来执行编写的脚本请你创建一个shell脚本程序,输入圆半径值, 输出圆面积值,并在Linux下运行。#!/bin/bashPI=3.14159echo “请输入圆的半径:”read recho “圆的面积为:”echo $PI*$r*$r | bc 3. 在Shell中可以使用语句控制程序流程,请你阅读如下Shell脚本,并分析其执行结果:#!/bin/bashresult=0num=1while test $num -le 10doresult=expr $result + $numnum=expr $num + 1doneecho result=$result若将其功能扩展为:计算12.n(n作为文件名参数输入),应该如何实现?while test $num -le $14在shell中除了可以定义变量之外,还可以定义函数。通常,我们将函数看成是脚本中的一段代码,在使用函数之前必须先定义该函数,使用时利用函数名直接调用。请编写一个函数,求一个数的平方数:#!/bin/bashfunction square local sq # sq is local to the function let sq=$1 * $1 echo Number to be squared is $1. echo The result is $sq echo Give me a number to square. read number value_returned=$(square $number) # Command substitution echo $value_returned也可以用函数库来实现:(用source或. 来加载)如:source myfunction.sh注意若要在bash中直接调用自定义函数,则应该在bash中直接加载库函数。如:$ source myfunction.sh5熟练掌握Shell脚本程序的设计,对日常系统维护有很大帮助,例如,通过test命令可以实现对指定文件属性的检测,#!/bin/bashif test -d $1 then echo directoty else echo not directoryfiif test -f $1 then echo file else echo not filefiif test -x $1then echo excutebleelse echo Archive onlyfi . .请你编写一个Shell脚本程序,实现文件属性检测的功能。三、实验过程请写出每个实验的shell命令或脚本,并给出操作过程和执行结果。实验三 Linux编程接口一、实验目的 1.掌握LINUX下的编程方法,学会使用Linux下编译器gcc和调试工具gdb。 2.了解和熟悉文件系统中主要系统调用的使用方法,并能够利用它们进行编程。 3.掌握与进程管理有关的系统调用,加深对进程并发执行的理解,能够利用这些系统调用编程。二、实验原理 常用的进程管理类系统调用有:1.fork函数fork()函数用于创建一个新进程(子进程)。其调用格式为:int fork();正确返回:等于0,创建子程序,从子进程返回的ID值。 大于0,从父进程返回的子进程的进程ID值。错误返回:等于-1,创建失败。2.wait()函数wait()函数常用来控制父进程与子进程的同步。在父进程中调用wait()函数,则父进程被阻塞,进入等待队列,等待子程序结束。当子进程结束时,产生一个终止状态字,系统会向父进程发出SIGCHLD信号。当接到信号后,父进程提取子进程的终止状态字,从wait()函数返回继续执行原来的信号。其调用格式为:#include#include(pid_t) wait(int * statloc);正确返回:大于0,子进程的进程ID值。 等于0,其他。错误返回:等于-1,调用失败。3.exec()函数族可以使一个进程调用或引用一个新程序。引用的程序副本覆盖了进程的存储空间。原存在的用户级上下文的内容被覆盖而不存在。#include int execl(const char *path, const char *arg, .);int execlp(const char *file, const char *arg, .);int execle(const char *path, const char *arg, ., char *const envp);int execv(const char *path, char *const argv);int execvp(const char *file, char *const argv);int execve(const char *path, char *const argv, char *const envp);4.exit()函数exit()函数是进程结束时最常调用的函数,在main()函数中调用return,最终也是调用exit()函数。这些都是进程的正常终止,在正常终止时,exit()函数返回进程结束状态。其调用格式为:#includevoid exit(int status);其中,status为进程结束状态。常用的文件操作类系统调用有:5.creat()函数创建一个新文件或重写一个旧文件,并将文件描述符fd返回给用户程序。用户通过fd对文件进行读写。其调用格式为:#include int creat(char *path, int smode);返回值为文件描述符。path为创建的文件名(全路径),smode为文件实际的权限,用户的权限mode用三位8进制数mnk表示。若umask xyz,则smode=xyz & mnk。默认mode为777,则mode=mode。6.open()函数将文件打开之后才能对文件进行读/写操作。其调用格式为:#include int open(*path, int rwmode); path为全路径的打开文件名;rwmode为头文件fcntl.h定义的对打开文件的访问模式: rwmode=0 表示可读,O_RDONLY; rwmode=1表示可写,O_WRONLY; rwmode=2表示可读写,O_RDWR.返回值为打开文件的描述符。若打开成功返回文件描述符,否则返回-1。7.read()对文件进行读操作。其调用格式为:#include int read(int fd, char *buffer, unsigned count);fd是open返回的文件描述符;buffer是一个缓冲区,用于存放所读的数据;count是要读的字节数;若系统调用成功,则返回实际读取的字节数;在读时,若读指针已到末尾但还没有读够指定的count,也立即停止;若试图读一个已被加锁的文件,则read进程必须等到锁打开。若count缺省,则通常为1字节。8.write()从缓冲区buffer将指定字节的内容写到已打开的文件描述符所指定的文件中。格式为:#include int write(int fd, char *buffer, unsigned count);其中,fd是open返回的文件描述符,该文件存放由write写入的内容;buffer是一个缓冲区,用于存放要写的内容;count是要写的字节数;若系统调用成功则返回实际写的字节数;在写时,若写指针已经到达文件末尾但还没写够指定的count,立即停止;若试图写一个加锁的文件,则write进程必须等待直到锁打开。若count缺省,通常是1个字节。9.close()断开用户程序与文件之间的通路,关闭该文件。其调用格式为:#include int close(int fd);其中fd为文件描述符,根据fd从用户文件描述表中得到指向文件表项的指针fp;由fp得到文件表项中的f.count,并对f.count减1。操作结果如果不为0,表示还有进程在使用该文件,此时不能回收文件表项;若为0,表示无进程使用该文件,将此文件表项置空。三、实验内容1文件系统调用是Linux系统调用的重要部分,用户应用程序通过文件系统调用来使用文件资源,常用的文件系统调用有:creat,open,read,write,close等。请使用这些系统调用编写一段源程序,能够将当前目录下一个已经存在的文件拷贝到一个新建文件中。2阅读如下源程序:#includemain()int p1;if (p1=fork()=0) /*子进程创建成功*/ putchar(b);else putchar(a); /*父进程执行*/在程序中,系统调用fork()创建一个子进程,当此程序运行时,在系统中有一个父进程和一个子进程活动。父进程显示字符“a”,子进程分别显示字符“b”。请多次执行该程序,观察记录屏幕上的显示结果,并分析原因。3在上面的程序中,若用系统调用fork()创建两个子进程,让父进程显示字符“a”,子进程分别显示字符“b”和字符“c”。请用写出c语言程序,并分析执行结果。4.创建一个子进程中并利用execl系统调用,若成功,则去执行ls l 命令而不执行该子进程。四、实验过程请描述各个实验的算法思想,写出c程序,并给出操作过程和执行结果。实验四 内核定时器一、实验目的1理解Linux内核定时器2. 掌握定时器的设计和实现方法二、实验原理内核定时器是内核用来控制在未来某个时间点(基于jiffies)调度执行某个函数的一种机制,其实现位于和kernel/timer.c文件中。内核定时器的函数运行过一次后就不再被运行了(自动注销)但可以通过在被调度的函数中重新调度自己来周期运行。Linux 2.4内核中内核定时器的数据结构:#includestruct timer_list struct list_head list;unsigned long expires; /定时器到期时间unsigned long data; /作为参数被传入定时器处理函数void (*function)(unsigned long);/* */;利用这个结构我们可以在驱动中很方便的使用定时器。1. timer的API函数:初始化定时器:void init_timer(struct timer_list * timer); 增加(激活)定时器:void add_timer(struct timer_list * timer); 删除定时器:int del_timer(struct timer_list * timer); 修改定时器的expire:int mod_timer(struct timer_list *timer, unsigned long expires); 2. 使用定时器的一般流程为:(1)创建timer、编写超时定时器处理函数function;(2)为timer的expires、data、function赋值;(3)调用add_timer将timer加入列表;(4)在定时器到期时,function被执行;(5)在程序中涉及timer控制的地方适当地调用del_timer、mod_timer删除timer或修改timer的expires。3. 关于jiffies全局变量jiffies用来记录自系统启动以来产生的节拍的总数。启动时,内核将该变量初始化为0,此后,每次时钟中断处理程序都会增加该变量的值。一秒内时钟中断的次数等于Hz,所以jiffies一秒内增加的值也就是Hz。系统运行时间以秒为单位,等于jiffies/Hz。jiffies类型为无符号长整型(unsigned long)。jiffies定义于文件中:三、实验步骤 1. 设计实现一个定时器,定时1秒后输出 Mytimer is okn,并传递给超时函数一个数值。/*timer.c*/#include #include #include #include /jiffies在此头文件中定义 #include #include struct timer_list mytimer;/定义一个定时器void mytimer_ok(unsigned long arg) printk(Mytimer is okn); printk(receive data from timer: %dn,arg); static int _init hello_init (void) printk(hello,worldn); init_timer(&mytimer); /初始化定时器 mytimer.expires = jiffies+100;/设定超时时间,100代表1秒 mytimer.data = 250; /传递给定时器超时函数的值 mytimer.function = mytimer_ok;/设置定时器超时函数 add_timer(&mytimer); /添加定时器,定时器开始生效 return 0; static void _exit hello_exit (void) del_timer(&mytimer);/卸载模块时,删除定时器 printk(Hello module exitn);module_init(hello_init);module_exit(hello_exit); MODULE_AUTHOR(CXF);MODULE_LICENSE(Dual BSD/GPL);编译执行:#gcc c timer.c D_KERNEL_ -DMODULE Wall O2 -I/usr/src/linux-2.4/include #ls s /在当前目录下查看的目标文件timer.o#lsmod /显示当前系统中加载的模块的信息#insmod timer.o /加载模块方式添加定时器#rmmod timer /卸载模块方式删除定时器注:init_module是默认的模块的入口,如果你想指定其他的函数作为模块的入口就需要module_init函数来指定,比如 module_init(your_func);其中your_func是你编写的一个函数的名称。2.进一步理解定时器:在上面的定时器超时函数mytimer_ok(unsigned long arg)中,添加如下代码:mytimer.expires = jiffies+100;/设定超时时间,100代表1秒mytimer.function = mytimer_ok;/设置定时器超时函数add_timer(&mytimer); /添加定时器,定时器开始生效编译后执行:#insmod timer.o#rmmod timer3.扩展知识:间隔定时器(Interval Timer,itimer)四、实验结果 设计实现该定时器,并记录和分析实验结果。编写好程序后,在终端下编译程序,结果如下所示:按“ctrl+shift+alt+F1”切换至字符界面,登陆,重新加载该模块,运行结果如下将下列几句代码加入程序中后。mytimer.expires = jiffies+100;/设定超时时间,100代表1秒mytimer.function = mytimer_ok;/设置定时器超时函数add_timer(&mytimer); /添加定时器,定时器开始生效对程序进行编译,并加载该模块,在字符界面下显示结果如下:将模块进行卸载,结果如下:实验五 系统调用一、实验目的1理解Linux下系统调用的运行机制;2掌握创建系统调用的方法;3学习Linux内核编译的方法,初步了解操作系统的生成过程。二、实验原理系统调用是操作系统为程序设计人员提供的接口服务,通过系统调用,程序员可以更充分利用计算机资源,使编写的程序更加灵活,功能更加强大,程序员也可以对系统调用充分了解的情况下自己定做系统调用,系统调用工作的基本原理如图1所示:图 1. 使用中断方法的系统调用的简化流程1.每个系统调用都是通过一个单一的入口点多路传入内核。EAX 寄存器用来标识应当调用的某个系统调用,这在 C 库中做了指定(来自用户空间应用程序的每个调用)。2.当加载了系统的 C 库调用索引和参数时,就会调用一个软件中断(0x80 中断),它将执行 system_call 函数(通过中断处理程序),这个函数会按照 EAX 内容中的标识处理所有的系统调用。3.在经过几个简单测试之后,使用 system_call_table 和 eax 中包含的索引来执行真正的系统调用了。从系统调用中返回后,最终执行 syscall_exit,并调用 resume_userspace 返回用户空间。然后继续在 C 库中执行,它将返回到用户应用程序中。系统调用接口的核心是系统调用多路分解表。如图2所示,使用 eax 中提供的索引来确定要调用该表中的哪个系统调用(sys_call_table)。图 2. 系统调用表和各种链接printk函数内核中进行输出1.当函数在内核中运行时,只能使用内核空间的资源,不能使用用户态的资源,例如C库。所以在输入信息的时候使用printk。2.printk是printf的一个简化版本,不能输出像浮点数之类的复杂数据类型。3.printf不同的是,printk按照相关的记录级或优先级将消息严格分类。4.Printk输出到哪儿去了? 内核输出到终端console(字符模式下的终端,可直接显示在屏幕)中; 如果在X界面下,因为找不到console,送到/var/log/messages中,可以通过cat或dmesg查看。 注:Linux的字符界面称为虚拟终端,默认有7个:1-6是字符终端,7是图形化用户界面;Ctrl+shift+alt+F1切换到字符界面;Alt+F7回到图形界面。三、实验步骤1.添加新函数在/usr/src/linux-2.4/kernel/sys.c中,添加一个系统调用函数到内核,命名和代码如下:asmlinkage int sys_foo(int x)printk(“%dn”,x);return 0;2.更新头文件在/usr/src/linux-2.4/include/asm-i386/unistd.h中,添加一个系统调用函数号。#define _NR_foo 2593.针对这个新函数更新系统调用表在/usr/src/linux-2.4/arch/i386/kernel/entry.S中,添加一个系统调用表项。.long SYSMBOL_NAME(sys_foo)4.重新编译内核前的准备工作为了使新的系统调用生效,需要重建Linux内核,首先必须以root身份登录。在编译内核前,需要:(1)编译内核前,如果用的是VMWare,务必记住进行一下快照,以免将来内核编译失败,可以返回修改代码后的状态.(2)将/etc/modules.conf的scsi_hostAdapter BusLogic一行注释掉,避免将来的编译错误。(3)cd /usr/src/linux ;将Makefile中版本号里的custom去掉,防止内核版本冲突。5.编译内核(1)make mrproper;/*文件归位。清除上次编译内核的文件*/(2)make xconfig;必选的配置选项如下:/或者make menuconfig SCSI device support-SCSI low-level drivers- BusLogic SCSI support Fusion MPT device support- Fusion MPT (base + ScsiHost) drivers和Fusion MPT misc device (ioctl) driver(这个要用模块形式加载) Network devices support-Ethernet (10 or 100Mbit)- AMD PCnet32 PCI support block devices-RAM disk support 和Initial disk(initrd) support Filesystems-ext3 jourmalling systemsupport(3)make dep; /作用:配置内核代码前需要进行配置,可根据用户的配置设置源代码的相关性(4)make bzImage; /内核编译命令,可生成一个新内核映像文件bzImage,即编译好的可以被cpu直接执行的二进制机器码。(5)make modules;(6)make modules_install; /配置的内核有模块支持(7)make insall; /将内核安装在系统中这之后新内核已经安装在了系统中,我们只需重启一下系统.5.运行测试文件在重新启动并成功进入系统之后,我们需要对之前增加的系统调用进行测试,测试代码如下所示:#include #include #include #define _NR_foo 259_syscall1(long, foo, int, ret)main() int i,j; i=100; j=0; j=foo(i); printf(“This is the result of new kernel!n”); printf(“%d”,j);编译该测试文件,由于需要引入内核头文件unistd.h,应这样设置编译参数:gcc o test I /usr/src/linux-2.4 test.c 注:应查看自己操作系统相应的目录名对C语言程序进行编译,最终得到文件名为test的可执行文件,在终端中输入:./test请你查看运行结果,并与在没有加载内核时候的运行结果相比较。四、实验结果请你记录实验运行过程,查看结果,并与在没有加载内核时候的运行结果相比较。实验六 模块与设备驱动程序一、实验目的1.理解Linux模块的组织结构,理解操作系统“宏内核”的组织方式,2.掌握模块的编译方法.模块的加载与卸载;3.理解利用模块实现设备驱动程序的方法,学习如何编写一个简单的设备驱动程序。二、实验原理1.模块的组织结构模块作为一种抽象数据类型,它具有一个可以通过静态内核中断的接口。最小的模块结构必须包括两个函数:init_module()和cleanup_module(),它们在系统加载模块和卸载模块时被调用。由于模块可以实现相当复杂的功能,故可以在模块中加入很多新函数以实现所期望的功能。不过加入模块的每个新函数都必须在该模块加载到内核中时进行注册。若该模块是静态加载的,则该模块的所有函数都是在内核启动时进行注册;若该模块是动态加载的,则这些新函数必须在加载这个模块时动态注册。当然,如果该模块被动态卸载了,则该模块的函数都必须从系统中注销。通过这种方式,当这个模块不在系统中时,就不能调用该模块的函数。其中注册工作通常是在函数init_module()中完成的,而注销工作则是在函数cleanup_module()中完成。模块的格式如下:#include / 说明是个内核功能 #include / 声明是一个模块 / 其它header信息 int init_module( ) / 加载时,初始化模块的编码 / 期望该模块所能实现的一些功能函数,如open().release().write(). read().ioctl()等函数 void cleanup_module( ) / 卸载时,注销模块的编码 2.模块的编译一般编译模块文件的命令格式如下:#gcc -O2 g -Wall -DMODULE -D_KERNEL_ -c -I/usr/src/ linux-2.4/include filename.c /filename.c为自己编写的模块程序源代码文件其中:-O2 表示编译产生尽可能小和尽可能快的代码;-Wall 提示编译信息;-DMODULE确定其类型;-D_ _KERNEL_ _提示是对内核的编译;/usr/src/linux-2.4/include 其选项是你的计算机的内核的版本;执行命令后就会得到文件filename.o,该文件就是一个可加载的目标代码文件。3.模块的加载内核模块的加载方式有两种:一种是使用insmod命令手工加载模块;另一种是请求加载demand loading(在需要时加载模块),即当有必要加载某个模块时,如果安装了内核的核心并并不存在的文件系统时,核心将请求内核要求内核守护进程kerneld准备加载适当的模块。该内核守护进程是一个带有超级用户权限的普通用户进程。4.模块的卸载当一个模块不需要使用时,可以使用rmmod命令卸载该模块。由于无须链接,因此它的任务比加载模块要简单的多。但如果采用的是请求加载模块方式时,当其使用计数为0,kernel将自动从系统中卸载该模块。卸载时通过调用模块cleanup_module()释放分配给该模块的内核资料,并将其标志为DELETED(模块被卸载);同时断开内核模块链表中的连表中的链接,修改它所依赖的其他模块的引用,重新分配模块所占的内核内存。5.模块程序管理模块的几个文件操作(设备驱动程序事实上的接口)在内核是用一个file结构来识别模块,而且内核使用file_operations结构来访问模块程序中的函数。file_operations结构是一个定义在中的函数指针表。管理模块的文件操作,通常也称为“方法”,它们都为struct file_operations提供函数指针,一般它们返回0值时表示访问成功;发生错误时会返回一个负的错误值。struct file_operations int (*seek) (struct inode *, struct file *, off_t, int); int (*read) (struct inode *, struct file *, char, int); int (*write) (struct inode * , struct file *, off_t , int); int (*readdir) (struct inode * , struct file *, struct dirent * , int); int (*select) (struct inode * , struct file *, int , select_table *); int (*ioctl) (struct inode * , struct file *, unsined int , unsigned long);/*除读写外的其他控制设备的操作*/int (*mmap) (struct inode * , struct file *, struct vm_area_struct *); int (*open) (struct inode * , struct file *); int (*release) (struct inode * , struct file *); int (*fsync) (struct inode * , struct file *); int (*fasync) (struct inode * , struct file *, int); int (*check_media_change) (struct inode * , struct file *); int (*revalidate) (dev_t dev); 最基本的4个操作: int(*read)(struct inode*, struct file*,char*,int)该方法用来从模块中读取数据。当其为NULL指针时, 将引起read系统调用返回-EINVAL(即非法参数)。函数返回一个非负整数值, 则表示成功读取字节数。 int(*write)(struct inode*,struct file*,const char*,int)该方法用来向模块发送数据。当其为NULL指针时, 将导致write系统调用返回-EINVAL。如果函数返回一个非负整数值, 则表示成功写入的字节数。 int(*open)(struct inode*,struct file*)该方法是用来打开模块, 它是作为第一个操作在模块节点上进行的。即使这样, 该方法还是可以设置为NULL指针。如果为NULL指针, 则表示该模块的打开操作永远成功, 但系统不会通知你的模块程序。 void(*release)(struct inode*,struct file*)该方法是用来关闭模块。当节点需要被关闭时就调用这个操作。6. 内核模块与应用程序的区别:C语言程序模块运行用户空间内核空间入口main()init_module()出口无cleanup_module()编译gcc -cgcc -c D_ _KERNEL_ _ -DMODULE连接gccinsmod运行直接运行insmod调试gdbkdbug, kdb, kgdb等7.模块引用计数: module对象的uc.usecount域 当开始执行模块的操作时,递增计数器;在操作结束时,递减这个计数器。当计数为0时,可以卸载这个模块。 在linux/module.h中,定义了维护使用计数的三个宏:_ _MOD_INC_USE_COUNT当前模块计数加1_ _MOD_DEC_USE_COUNT当前模块计数减1_ _MOD_IN_USE计数非0时返回真 计数器的当前值可以在/proc/modules(或者使用lsmod命令)中每一项的第三个域 找到。8.设备驱动程序的组织结构用户进程利用系统调用在对设备文件进行诸如read/write操作时,系统调用通过设备文件的主设备号找到相应的设备驱动程序,然后读取这个数据结构相应的函数指针,接着把控制权交给该函数。设备驱动程序有一个比较标准的组织结构,一般可分为下面三个主要组成部分:(1)自动配置和初始化子程序这部分程序负责检测所要驱动的硬件设备是否存在以及是否能正常工作。如果该设备正常,则对其相关软件状态进行初始化。这部分程序仅在初始化时被调用一次。(2)服务于I/O请求的子程序这部分是驱动程序的上半部分,由系统调用对其操作。系统认为这部分程序在执行时的进程和进行调用的进程属于同一个进程,只是由用户态变成了内核态,而且具有相同的运行环境。故可以在其中调用与进程运行环境有关的函数。(3)中断服务子程序这部分是驱动程序的下半部分,设备在I/O请求结束时或其他状态改变时产生中断。中断可以产生在任何一个进程运行时,因此中断服务子程序被调用时并不依赖于任何进程状态,因而也就不能调用与进程运行环境有关的函数,因为设备驱动程序一般支持同一类型的若干设备,所以在系统调用中断服务子程序时都带有一个或多个参数,以唯一的标识并确定请求服务的设备。三、实验步骤1.编写一个简单的模块:/*testmodule.c*/#include / 在内核模块中共享#include / 一个模块/处理CONFIG_MODVERSIONS/#if CONFIG_MODVERSIONS = 1/#define MODVERSIONS/#include /#endifint init_module(void) /初始化模块printk(“Hello! This is a testing module! n”);return 0; void cleanup_module(void) /取消init_module()函数所做的打印功能操作 printk(“Sorry! The testing module is unloading now! n”); 模块的编译.加载.卸载:rootlocalhost root#gcc c testmodule.c D_KERNEL_ -DMODULE Wall O2 -I/usr/src/linux-2.4/include rootlocalhost root#ls s /在当前目录下查看的目标文件testmodule.orootlocalhost root#lsmod /显示当前系统中加载的模块的信息rootlocalhost root#cat /var/log/messages /可以看到输出结果,或者切换到字符界面下执

温馨提示

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

评论

0/150

提交评论