分享

项目经验杂记

 心不留意外尘 2016-05-03

http://blog.sina.com.cn/s/blog_6a1837e90100onsb.html
2011
static spinlock_t RequestResponseLock = SPIN_LOCK_UNLOCKED;
spin_lock_bh(&RequestResponseLock); //spin_lock_bh 在获取锁之前禁止软件中断, 但是硬件中断留作打开的.
spin_unlock_bh(&RequestResponseLock);
spin_lock(&RequestResponseLock);
spin_unlock(&RequestResponseLock);
//上层调用函数内包含自旋锁时使用spin_lock_bh,而内核层底半步调用时使用spin_lock。bh指bottom_half,即底半。
--------------------------------------------------------------------------------------------------
create_proc_info_entry( REQUEST_RESPONSE_STATUS_NAME, 0, proc_dir, RequestResponseCacheStatus );
remove_proc_entry(REQUEST_RESPONSE_STATUS_NAME, proc_dir);
--------------------------------------------------------------------------------------------------
init_timer(&m->timer);
m->timer.function = &RequestResponseEntryExpired;
m->timer.data = (unsigned long)m;
mod_timer(&m->timer, jiffies + GetRadiusResponseTimeout());
del_timer(&m->timer);
--------------------------------------------------------------------------------------------------
struct list_head e;
list_add(&m->e, &RequestResponseCache.hash_list[h].head);
while (!list_empty(&RequestResponseCache.hash_list[i].head))
m = list_entry(RequestResponseCache.hash_list[i].head.next, struct RequestResponseEntry, e);
list_for_each_entry(m, &RequestResponseCache.hash_list[h].head, e)
list_del(&m->e);
--------------------------------------------------------------------------------------------------
insmod /lib/modules/2.6.18-8.el5/kernel/drivers/rtc/rtc-lib.ko 
insmod monitor.ko
mknod /dev/mapdrv0 c 250 0
rmmod monitor
--------------------------------------------------------------------------------------------------
内核编程中:
#include <ctype.h>
存在错误,而
#include <linux/ctype.h>
正常
--------------------------------------------------------------------------------------------------
#ifdef __KERNEL__
#include <linux/ctype.h>
#else
#include <ctype.h>
#endif

宏__KERNEL__能够区别当前程序是在用户层还是内核层。
上述代码包含在.h中,此头文件可以被用户层和内核层的程序包含。
--------------------------------------------------------------------------------------------------
在strnpcy之后,需在目标字符串的结尾加上'\0',即
strncpy(dest, src, size);
dest[size] = '\0'
--------------------------------------------------------------------------------------------------
2的n次方使用(1 << n)的形式
--------------------------------------------------------------------------------------------------
kmalloc只能申请128K的内存,建议使用vmalloc
vfree()不能放在spin_lock_bh和spin_unlock_bh之间;
--------------------------------------------------------------------------------------------------
module_init()
module_exit()

函数module_init()和module_exit()是模块编程中最基本也是必须的两个函数。
module_init()向内核注册模块所提供的新功能,
而module_exit()注销由模块提供的所有功能。

MODULE_LICENSE("GPL")用于声明模块的许可证
--------------------------------------------------------------------------------------------------
Linux内核模块的编译需要给gcc指示-D__KERNEL__ -DMODULE -DLINUX参数
--------------------------------------------------------------------------------------------------
void *kmalloc(unsigned int len, int priority);
void kfree(void *__ptr);

priority:
GFP_KERNEL
GFP_ATOMIC
--------------------------------------------------------------------------------------------------
unsigned long copy_from_user(void *to, const void *from, unsigned long n);
unsigned long copy_to_user (void * to, void * from, unsigned long len);

put_user
get_user
--------------------------------------------------------------------------------------------------
内核编程用printk替代printf

内核一共有8个优先级.如果优先级数字比int console_loglevel变量小的话,消息就会打印到控制台上。如果syslogd和klogd守护进程在运行的话,则不管是否向控制台输出,消息都会被追加进/var/log/messages文件。klogd 只处理内核消息,syslogd 处理其他系统消息,比如应用程序。
--------------------------------------------------------------------------------------------------
include/linux/module.h中定义的宏MODULE_PARM(var,type) 用于向模块传递命令行参数。var为接受参数值的变量名,type为采取如下格式的字符串[min[-max]]{b,h,i,l,s}。min及max用于表示当参数为数组类型时,允许输入的数组元素的个数范围;
b:byte;h:short;i:int;l:long;s:string。

有了MODULE_PARM,在装载内核模块时,用户可以向模块传递一些参数,如:
insmod modname var=value
--------------------------------------------------------------------------------------------------
# Makefile2.6
obj-m += hellomod.o        # 产生hellomod 模块的目标文件
CURRENT_PATH := $(shell pwd)   #模块所在的当前路径
LINUX_KERNEL := $(shell uname -r)    #Linux内核源代码的当前版本
LINUX_KERNEL_PATH := /usr/src/linux-headers-$(LINUX_KERNEL) #Linux内核源代码的绝对路径
all:
make -C $(LINUX_KERNEL_PATH) M=$(CURRENT_PATH) modules   #编译模块了
clean:
make -C $(LINUX_KERNEL_PATH) M=$(CURRENT_PATH) clean    #清理

有了Makefile,执行make命令,会自动形成相关的后缀为.o和.ko文件。
--------------------------------------------------------------------------------------------------
模块和内核都在内核空间运行,模块编程在一定意义上说就是内核编程
模块是具有独立功能的程序,它可以被单独编译,但不能独立运行。
模块通常由一组函数和数据结构组成,用来实现一种文件系统、一个驱动程序或其他内核上层的功能。
因为内核版本的每次变化,其中的某些函数名也会相应地发生变化,因此模块编程与内核版本密切相关
内置模块:可加载模块
--------------------------------------------------------------------------------------------------
这些变量和函数就统称为符号。
其中宏定义EXPORT_SYMBOL()本身的含义是“移出符号”。为什么说是“移出”呢?因为这些符号本来是内核内部的符号,通过这个宏放在一个公开的地方,使得装入到内核中的其他模块可以引用它们。
在模块编程中,可以根据符号名从这个文件中检索出其对应的地址,然后直接访问该地址从而获得内核数据。
第三列“所属模块”指符号所在的模块名,对于从内核这一母模块移出的符号,这一列为空。
模块加载后,2.4内核下可通过 /proc/ksyms、 2.6 内核下可通过/proc/kallsyms查看模块输出的内核符号
--------------------------------------------------------------------------------------------------
模块依赖

为了确保模块安全地卸载,每个模块都有一个引用计数器
--------------------------------------------------------------------------------------------------
1.Insmod命令:
2. rmmod命令:
3.lsmod命令:读取/proc文件系统中的文件/proc/modules中的信息
4.ksyms命令:读取/proc文件系统中的文件/proc/kallsyms。
--------------------------------------------------------------------------------------------------
//MODULE_PARM_DESC(interface,”A network interface”);  2.4内核中该宏的用法
molule_parm(interface,charp,0644) //2.6内核中的宏
//MODULE_PARM_DESC(irq,”The IRQ of the network interface”);
module_param(irq,int,0644);

insmod myirq.ko interface=eth0 irq=9

if (request_irq(irq, &myinterrupt, SA_SHIRQ,interface, &irq)) //注册中断,中断值为irq,中断函数myinterrupt
free_irq(irq, &irq);

具体网卡 irq的值可以查看 cat /proc/interrupts

可动态更改
--------------------------------------------------------------------------------------------------
insmod(安装 LKM),
rmmod (删除 LKM),
modprobe(insmod 和 rmmod 的包装器),加载当前当前模块与其相关联的其他模块,单一模块无关联时,必须使用insmod,否则会报错,当自写编写模块时,建议不要使用。
depmod(用于创建模块依赖项),
modinfo(用于为模块宏查找值)。

LKM 只不过是一个特殊的可执行可链接格式(Executable and Linkable Format,ELF)对象文件。

在模块的加载和卸载期间,模块子系统维护了一组简单的状态变量,用于表示模块的操作。
--------------------------------------------------------------------------------------------------
内核中有一个叫做 HZ 的频率变量,它表示每秒的时钟节拍数。一般的,在某种平台上它会有一个固定值,这个固定值是人为设定的,
也就是可编程的(对系统定时器编程)。设定 HZ 的大小需要权衡。这个值设大了,带来的好处是定时器间隔变小,
从而使进程(任务)的调度的精确性得以提高,但带来的缺点是导致开销过大,让系统变得耗电,
这样在一些经常使用电池的设备来说(比如笔记本,平板电脑)是难以接受的。
在现在一般的 x86 平台,2.6 内核的 linux 下,这个值会被设为 100 。也就是说,一个时钟节拍为 1/100 = 0.01s = 10ms 。
一个时钟节拍也称为 1 个 jiffy 。
内核中还有一个重要的变量叫 jiffies 。它记录了系统从启动到当前所触发定时器的次数。jiffies 每秒钟增加 HZ 个计数,
实际上就是 N 个 jiffy 。
--------------------------------------------------------------------------------------------------
中断服务程序一般都是在中断请求关闭的条件下执行的,以避免嵌套而使中断控制复杂化。

下半部运行时是允许中断请求的,而上半部运行时是关中断的,这是二者之间的主要区别。 
--------------------------------------------------------------------------------------------------
小任务(Tasklet)机制

Count域是小任务的引用计数器。如果它不为0,则小任务被禁止,不允许执行;只有当它为零,小任务才被激活,并且在被设置为挂起时,小任务才能够执行。

DECLARE_TASKLET(name, func, data)
DECLARE_TASKLET_DISABLED(name, func, data)

DECLARE_TASKLET(my_tasklet, my_tasklet_handler, dev);
这行代码其实等价于
struct tasklet_struct my_tasklet = { NULL, 0, ATOMIC_INIT(0), tasklet_handler, dev};

static void tasklet_handler (unsigned long data)
tasklet_init(&my_tasklet, tasklet_handler, 0);
tasklet_schedule(&my_tasklet);
tasklet_kill(&my_tasklet);
--------------------------------------------------------------------------------------------------
如果推后执行的任务需要睡眠,那么就选择工作队列。如果推后执行的任务不需要睡眠,那么就选择tasklet。
另外,如果需要用一个可以重新调度的实体来执行你的下半部处理,也应该使用工作队列。

void work_handler(void *data); //工作队列待执行的函数

DECLARE_WORK(name, void (*func) (void *), void *data); //这样就会静态地创建一个名为name,待执行函数为func,参数为data的work_struct结构。
INIT_WORK(struct work_struct *work, woid(*func) (void *), void *data); //这会动态地初始化一个由work指向的工作。

queue = create_singlethread_workqueue(“helloworld”);
if (!queue)
goto err;
destroy_workqueue(queue);

schedule_work(&work);//把给定工作的待处理函数提交给缺省的events工作线程
schedule_delayed_work(&work, delay); //&work指向的work_struct直到delay指定的时钟节拍用完以后才会执行。
--------------------------------------------------------------------------------------------------

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多