篇一:linux环境编程
福建农林大学金山学院
课程名称:姓 名:系: 专 业:年 级:学 号:指导教师:职 称:实验报告
Linux环境编程
信息与机电工程 计算机科学与技术
2009级
讲师
2012年 5 月 26 日
实验项目列表
福建农林大学金山学院实验报告
系: 信息与机电工程系 专业:计算机科学与技术年级:2009姓名: 学号: 实验室号_ _607_____ 计算机号实验时间:指导教师签字:成绩:
实验一: gcc编译器(验证性、2学时)
一、实验目的:
1)熟悉Shell操作环境。
2)掌握在Linux下的C语言代码编译运行的方法。 3)初步了解C语言库函数与Linux系统调用。
二、实验内容
1、编写能输出“Hello world!”问候语的C程序,并在终端中编译、执行。要求记录所使用的命令及结果。 #include <stdio.h> #include<stdlib.h> int main() {
printf("Hello World\n"); exit(0); }
2、编写程序p.c,其功能是从键盘输入两个实数,输出这两个实数的平方和,生成可执行文件为pow。 #include"stdio.h" main() {
float x,y;
scanf("%f %f",&x,&y); printf("%6.3f",x*x+y*y); }
3、教材第9页静态库实验,记录操作步骤与结果。分析所出现的问题及如何解决的? 4、编写一个C程序并设置其在后台执行,其功能是在一段时间后(可自行设置),在屏幕上显示信息:Time for play!,写出相应的程序、命令及结果。 #include <stdio.h> main() {
sleep(6);
printf("Time for Play!\n");
}
5、编制一段程序,使用系统调用fork( )创建两个子进程,这样在此程序运行时,在系统中就有一个父进程和两个子进程在活动。让每一个进程在屏幕上显示一个字符:父进程显示字符a,子进程分别显示字符 b和字符c。试观察、记录并分析屏幕上,进程调度的情况。 #include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include <unistd.h> main()
{
if ( fork() == 0 ) // 子进程1 {
printf("b\n");exit(0); } else
{
if ( fork() == 0 )// 子进程2{
printf("c\n"); exit(0);
}
printf("a\n");// 父进程exit(0); }
}
三、实验结果与讨论(根据实验结果回答下列问题)
1、 你所使用的实验环境是什么?请写出Linux的平台、内核版本号。
VMware Workstation
2、 在Linux中,标准设备文件有哪些?这些设备文件在哪个目录? Devfsudevmdev
3、 对于上述各编程题目中所用到了的各个头文件,请找到它们的位置。 /user/include 四、总结
篇二:设备文件系统剖析与使用
设备文件系统剖析与使用 设备文件系统剖析与使用
嵌入式Linux之我行,主要讲述和总结了本人在学习嵌入式linux中的每个步骤。一为总结经验,二希望能给想入门嵌入式Linux的朋友提供方便。如有错误之处,谢请指正。
? 共享资源,欢迎转载:http://hbhuanggang.cublog.cn
一、什么是Linux设备文件系统
首先我们不看定义,定义总是太抽象很难理解,我们先看现象。当我们往开发板上移植了一个新的文件系统之后(假如各种设备驱动也移植好了),启动开发板,我们用串口工具进入开发板,查看系统/dev目录,往往里面没有或者就只有null、console等几个系统必须的设备文件在这儿外,没有任何设备文件了。那我们移植好的各种设备驱动的设备文件怎么没有啊?如果要使用这些设备,那不是要一个一个的去手动的创建这些设备的设备文件节点,这给我们使用设备带来了极为的不便(在之前篇幅中讲的各种设备驱动的移植都是这样)。
设备文件系统就是给我们解决这一问题的关键,他能够在系统设备初始化时动态的在/dev目录下创建好各种设备的设备文件节点(也就是说,系统启动后/dev目录下就有了各种设备的设备文件,直接就可使用了)。除此之外,他还可以在设备卸载后自动的删除/dev下对应的设备文件节点(这对于一些热插拔设备很有用,插上的时候自动创建,拔掉的时候又自动删除)。还有一个好处就是,在我们编写设备驱动的时候,不必再去为设备指定主设备号,在设备注册时用0来动态的获取可用的主设备号,然后在驱动中来实现创建和销毁设备文件(一般在驱动模块加载和卸载函数中来实现)。
二、设备文件系统的种类
设备文件系统有:devfs、udev、mdev等。
mdev是udev的简化版本,是busybox中所带的程序,最适合用在嵌入式系统,而udev一般都用在PC上的Linux中,相对mdev来说要复杂些;devfs是2.4内核引入的,而在2.6内核中却被udev所替代,他们有着共同的优点,只是devfs中存在着一些未修复的bug,作者也停止了对他的维护,最显著的一个区别是:采用devfs时,当一个并不存在的设备节点被打开时,他却还能自动加载对应的驱动,而udev则不能,udev认为当打开并不存在的设备节点时不应该加载对应的驱动模块,因为加载了也没用,浪费系统资源。
三、udev或者mdev设备文件系统的使用
1. 首先让大家明白一个问题就是,不管是udev还是mdev,他们就是一个应用程序,就跟其他应用程序一样(比如:Boa服务),配置了就可以使用了。为了方便起见,我们就使用busybox自带的一个mdev,这样在配置编译busybox时,只要将mdev的支持选项选上,编译后就包含了mdev设备文件系统的应用(当然你也可以不使用busybox自带的,去下载udev的源码进行编译移植)
#cd busybox-1.13.0/
#make menuconfig
Linux System Utilities --->
[*] mdev
[*] Support /etc/mdev.conf
[*] Support subdirs/symlinks
[*] Support regular expressions substitutions when renaming device
[*] Support command execution at device addition/removal
2. udev或者mdev需要内核sysfs和tmpfs虚拟文件系统的支持,sysfs为udev提供设备入口和uevent通道,tmpfs为udev设备文件提供存放空间。所以在/etc/fstab配置文件中添加如下内容(红色部分):
# device mount-point type options dump fsck order
#----------------------------------------------------------------
procfs /proc proc defaults 0 0
sysfs /sys sysfs defaults 0 0
tmpfs /dev/shm tmpfs defaults 0 0
usbfs /proc/bus/usb usbfs defaults 0 0
ramfs /dev ramfs defaults 0 0
none /dev/pts devpts mode=0622 0 0
3. 在系统初始化配置文件/etc/init.d/rcS中挂载mdev要用到的sysfs文件系统和tmpfs文件系统,然后启动/sbin目录下的mdev应用对系统的设备进行搜索(红色部分)。
# Mount virtual filesystem
/bin/mount -t proc procfs /proc
/bin/mount -n -t sysfs sysfs /sys
/bin/mount -n -t usbfs usbfs /proc/bus/usb
/bin/mount -t ramfs ramfs /dev
# Make dir
/bin/mkdir -p /dev/pts
/bin/mkdir -p /dev/shm
/bin/mkdir -p /var/log
/bin/mount -n -t devpts none /dev/pts -o mode=0622
/bin/mount -n -t tmpfs tmpfs /dev/shm
# Make device node
echo /sbin/mdev > /proc/sys/kernel/hotplug
/sbin/mdev -s
4. 在设备驱动程序中加上对类设备接口的支持,即在驱动程序加载和卸载函数中实现设备文件的创建与销毁,例如在之前篇幅的按键驱动中添加(红色部分):
#include <linux/device.h> //设备类用到的头文件
static int device_major = DEVICE_MAJOR; //用于保存系统动态生成的主设备号
static struct class *button_class; //定义一个类
static int __init button_init(void)
{
//注册字符设备,这里定义DEVICE_MAJOR=0,让系统去分配,注册成功后将返回动态分配的主设备号 device_major = register_chrdev(DEVICE_MAJOR, DEVICE_NAME, &buttons_fops);
if(device_major < 0)
{
printk(DEVICE_NAME " register faild!\n");
return device_major;
}
//注册一个设备类,使mdev可以在/dev/目录下建立设备节点
button_class = class_create(THIS_MODULE, DEVICE_NAME);
if(IS_ERR(button_class))
{
printk(DEVICE_NAME " create class faild!\n");
return -1;
}
//创建一个设备节点,取名为DEVICE_NAME(即my2440_buttons)
//注意2.6内核较早版本的函数名是class_device_create,现该为device_create
device_create(button_class, NULL, MKDEV(device_major, 0), NULL, DEVICE_NAME);
return 0;
}
static void __exit button_exit(void)
{
//注销字符设备
uegister_chrdev(device_major, DEVICE_NAME);
//删除设备节点,注意2.6内核较早版本的函数名是class_device_destroy,现该为device_destroy
device_destroy(button_class, MKDEV(device_major, 0));
//注销类
class_destroy(button_class);
}
4. 至于mdev的配置文件/etc/mdev.conf,这个可有可无,只是设定设备文件的一些规则。我这里就不管他了,让他为空好了。
5. 完成以上步骤后,重新编译文件系统,下载到开发板上,启动开发板后进入开发板的/dev目录查看,就会有很多系统设备节点在这里产生了,我们就可以直接使用这些设备节点了。
篇三:设备模型(上)底层模型
Linux设备驱动工程师之路
——设备模型(上)底层模型
一、重要知识点
1. Sysfs文件系统
Sysfs文件系统是一种类似于proc文件系统的特殊文件系统,它存在于内存当中,当系统启动时由内核挂载于内存当中。用于将系统中的设备组织成层次结构,并向用户模式程序提供详细的数据结构信息。
2. Linux设备底层模型
1)为什么要使用设备模型
随着系统的拓扑结构越来越复杂,以及要支持诸如电源管理等新特性的要求,于是在
2.6的内核中出现了设备模型。设备模型其实就是一套数据结构建立起来的模型。内核使用该模型支持了多种不同的任务,包括:
a.电源管理和系统关机
设备模型使操作系统能够以正确的顺序遍历系统硬件。
b.与用户空间通信
Sysfs文件系统向用户空间提供系统信息以及改变操作参数的结构。 c.热插拔事件
d.设备类型
系统中许多部分对设备如何连接不感兴趣,但是他们需要知道哪些类型设备时可用的。设备模型提供了将设备分类的机制。
e.对象的生命周期
上述的许多功能,包括热插拔支持和sysfs,使得内核中管理对象的工作更为复杂。设备模型需要创造一套机制管理对象的生命周期。
2)Kobject
如果说设备模型是一套房子的话,Kobject就是构造房子的砖块。每个注册的Kobject的都对应于Sysfs文件系统中的一个目录。Kobject是组成设备模型的基本结构。类似于C++的基类,它潜入于更大的对象中——所谓的容器,用来描述设备模型的组件。如bus,device,drivers都是典型的容器。这些容器就是通过kobject连接起来,形成一个树状结构。这个树状结构就与/sys文件系统对应。不过kobject只能建立单层结构,也就是只能建立一级目录,要建立多级目录,还要使用后面要介绍的Kset。
Kobject结构定义为:
struct kobject {
const char *name; //指向设备名称的指针
struct list_head entry; // struct list_head entry; 挂接到所在kset中去的单元 struct kobject *parent; // 指向父对象的指针
struct kset *kset; //所属kset的指针
struct kobj_type *ktype; //指向其对象类型描述符的指针
struct sysfs_dirent *sd; // sysfs文件系统中与该对象对应的文件节点路径指针 struct kref kref; // 对象引用计数
unsigned int state_initialized:1;
unsigned int state_in_sysfs:1;
unsigned int state_add_uevent_sent:1;
unsigned int state_remove_uevent_sent:1;
unsigned int uevent_suppress:1;
};
struct kobj_type {
void (*release)(struct kobject *kobj);
struct sysfs_ops *sysfs_ops;
struct attribute **default_attrs;
};
相关操作函数:
void kobjet_init(struct kobject*kobj)
初始化Kobject
int kobject_add(struct kobject*kobj)
将Kobject对象注册到linux系统,如果失败则返回一个错误码.
int kobject_init_and_add(structkobject *kobj, kobj_type *ktype, struct kobject *parent, const *fmt…)
初始化并注册kobject,kobject传入要初始化的Kobject对象,ktype将在后面介绍到,parent指向上级的kobject对象,如果指定为NULL,将在/sys的顶层创建一个目录。*fmt为kobject对象的名字。
kobject的ktype对象是一个指向kobject_type结构的指针,该结构记录了kobject对象的一些属性。每个kobject都需要对应一个相应的kobj_type结构。
struct kobj_type{
void (*release)(struct kobject *kobj);
structsysfs_ops *sysfs_ops;
struct attribute **default_attrs;
};
release方法用于释放kobject占用的资源,当kobject引用计数为0时被调用。
kobje_type的attribute成员:
struct attribute{
char*name;//属性文件名
structmodule *owner;
mode_tmode;
}
struct attribute(属性):对应于kobject的目录下一个文件, name就是文件名。
kobje_type的struct sysfs_ops成员:
struct sysfs_ops
{
ssize_t (*show)(structkobejct *,
struct attribute *, char *name);ssize_t (*store)(structkobejct *, struct attribute *, char *name);
}
show:当用户读属性文件时,该函数被调用,该函数将属性值存入buffer中返回给用户态;
store:当用户写属性文件时,该函数被调用,用于存储用户存入的属性值。
Kobject测试模块:
#include <linux/device.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/string.h>
#include <linux/sysfs.h>
#include <linux/stat.h>
MODULE_AUTHOR("David Xie");
MODULE_LICENSE("Dual BSD/GPL");
void obj_test_release(struct kobject *kobject);
ssize_t kobj_test_show(struct kobject *kobject, struct attribute *attr,char *buf);
ssize_t kobj_test_store(struct kobject *kobject,struct attribute *attr,const char *buf, size_t count);
struct attribute test_attr = {
.name = "kobj_config",
.mode = S_IRWXUGO,
};
static struct attribute *def_attrs[] = {
&test_attr,
NULL,
};
struct sysfs_ops obj_test_sysops =
{
.show = kobj_test_show,
.store = kobj_test_store,
};
struct kobj_type ktype =
{
.release = obj_test_release,
.sysfs_ops=&obj_test_sysops,
.default_attrs=def_attrs,
};
void obj_test_release(struct kobject *kobject)
{
printk("eric_test: release .\n");
}
ssize_t kobj_test_show(struct kobject *kobject, struct attribute *attr,char *buf)
{
printk("have show.\n");
printk("attrname:%s.\n", attr->name);
sprintf(buf,"%s\n",attr->name);
return strlen(attr->name)+2;
}
ssize_t kobj_test_store(struct kobject *kobject,struct attribute *attr,const char *buf, size_t count) {
printk("havestore\n");
printk("write: %s\n",buf);
return count;
}
struct kobject kobj;
static int kobj_test_init()
{
printk("kboject test init.\n");
kobject_init_and_add(&kobj,&ktype,NULL,"kobject_test");
return 0;
}
static int kobj_test_exit()
{
printk("kobject test exit.\n");
kobject_del(&kobj);
return 0;
}
module_init(kobj_test_init);
module_exit(kobj_test_exit);
测试结果:
在/sys目录下创建了kobject_test目录
在kobject_test目录下有kobj_config文件
读kobject_config文件则调用了show函数。并在用户空间显示了show返回的kobject对象名字。
写kobject_config文件调用了store函数。
3)Kset
kset的主要功能是包容;我们可以认为它是kobject的顶层容器。实际上,在每个kset对象的内部,包含了自己的kobject,并且可以用多种处理kobject的方法处理kset。如果说kobject是基类的话,那么kset就是派生类。kobject通过kset组织成层次化的结构,kset是相同类型的组合。通俗的讲,kobject建立一级的子目录,kset可以为kobject建立多级的层次性的父目录。
struct kset {
struct list_head list; //用于连接该kset中所有kobject的链表头
spinlock_t list_lock;
struct kobject kobj; //嵌入的kobject
struct kset_uevent_ops *uevent_ops; //指向热插拔操作表的指针
};
struct kset {
struct subsystem * subsys; //所在的subsystem的指针
struct kobj type * ktype; //指向该kset对象类型描述符的指针
struct list head list;
struct kobject kobj;
struct kset_uevent_ops * uevent_ops;
};
包含在kset中的所有kobject被组织成一个双向循环链表,list域正是该链表的头。Ktype域指向一个kobj_type 结构,被该kset中的所有kobject共享,表示这些对象的类型。Kset数据结构还内嵌了一个kobject对象(由kobj域表示),所有属于这个kset 的kobject对象的parent域均指向这个内嵌的对象。此外,kset还依赖于kobj维护引用计数:kset的引用计数实际上就是内嵌的kobject对象的引用计数。