linux内核开发者为为我们提供丰富的接口,使用这些接口可以简化代码,减少错误和方便开发等好处。我用的比较多的是链表、sysfs、proc、和工作队列。
一、链表:
链表是linux内核开发最常用的数据结构之一,
1、数据结构
struct list_head {
struct list_head *next, *prev;
};
2、 两种初始化方式如下:
#define LIST_HEAD_INIT(name) { &(name), &(name) }
#define LIST_HEAD(name) \
struct list_head name = LIST_HEAD_INIT(name)
static inline void INIT_LIST_HEAD(struct list_head *list)
{
list->next = list;
list->prev = list;
}
3、常用接口
void list_add(struct list_head *new, struct list_head *head) 在head后增加一个一个元素new
void list_add_tail(struct list_head *new, struct list_head *head) 在head的尾部增加一个元素new
void list_del(struct list_head *entry) 删掉entry
list_entry(ptr, type, member) 返回ptr所在结构体,用container_of实现
list_for_each_entry(pos, head, member) 遍历链表中的所有节点
int list_empty(const struct list_head *head) 检查链表是否为空,是则为0 否则返回非零
4、使用技巧,
1、使用者应将struct head 嵌入其中
2、应该保留一个头部,以便增删改查
3、在多线程换件应该有互斥量和信号量等保护
5、简单示例
#include <linux/init.h>
#include <linux/module.h>
#include <linux/list.h>
#include <linux/kernel.h>
#include <linux/random.h>
struct number {
struct list_head list;
int num;
};
struct list_head number_head;
int dup_list(struct list_head *head)
{
struct number *elem = NULL;
list_for_each_entry(elem,head,list)
{
printk("num is %d\n",elem->num);
}
return 0;
}
static int list_test_free_all(struct list_head *head)
{
struct number *elem = NULL;
struct number *n = NULL;
list_for_each_entry_safe(elem,n,head,list)
{
list_del(&elem->list);
printk("del elem list num %d\n",elem->num);
kfree(elem);
}
return 0;
}
static int list_test_init(void)
{
int i;
int random;
struct number *elem = NULL;
INIT_LIST_HEAD(&number_head);
for(i = 0; i < 3;i++)
{
get_random_bytes(&random,sizeof(int));
printk("random is %d\n",random);
elem = kzalloc(sizeof(struct number), GFP_KERNEL);
if(NULL == elem)
{
printk("kmalloc is fail\n");
goto error;
}
elem->num = random%100;
list_add(&elem->list,&number_head);
}
dup_list(&number_head);
return 0;
error:
list_test_free_all(&number_head);
return -1;
}
static void list_test_exit(void)
{
list_test_free_all(&number_head);
}
module_init(list_test_init);
module_exit(list_test_exit);
MODULE_LICENSE("GPL");
二、sysfs :
sysfs 是内核和用户空间交互数据一个主要通道之一,在动态配置内核参数方便有着很大的又是
1、主要数据结构
struct kobj_attribute {
struct attribute attr;//name and mode
ssize_t (*show)(struct kobject *kobj, struct kobj_attribute *attr,
char *buf);// buf output buffer
ssize_t (*store)(struct kobject *kobj, struct kobj_attribute *attr,
const char *buf, size_t count);//buf input buffer
};
2、主要接口
int sysfs_create_group(struct kobject *kobj,const struct attribute_group *grp) 创建sysfs; kobj parent kobject group 要创建的sysfs组
void sysfs_remove_group(struct kobject *kobj, const struct attribute_group *grp) 移除sysfs
3、实例代码:
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/module.h>
#include <linux/sysfs.h>
#include <linux/list.h>
#include <linux/slab.h>
#define NAME_MAX_LENGTH 16
struct city {
struct list_head list;
char name[NAME_MAX_LENGTH];
int temp;
};
static struct list_head head;
static ssize_t city_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
{
struct city *elem = NULL;
char tem[32];
list_for_each_entry(elem, &head, list)
{
memset(tem, 0, sizeof(tem));
sprintf(tem, "%s temprature %d\n",elem->name, elem->temp);
strcat(buf,tem);
}
return strlen(buf);
}
static ssize_t city_store(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t count)
{
struct city *elem = NULL;
elem = (struct city *)kzalloc(sizeof(struct city), GFP_KERNEL);
if(NULL == elem)
{
printk("malloc failed\n");
return 0;
}
sscanf(buf,"%s%d",elem->name, &elem->temp);
printk("buf is %s name %s temp %d\n",buf, elem->name, elem->temp);
list_add(&elem->list, &head);
return count;
}
static struct kobj_attribute city_attribute =
__ATTR(city, 0666, city_show, city_store);
static struct attribute *attrs[] = {
&city_attribute.attr,
NULL,
};
static struct attribute_group attr_group = {
.attrs = attrs,
};
static int __init city_init(void)
{
int retval;
INIT_LIST_HEAD(&head);
retval = sysfs_create_group(kernel_kobj, &attr_group);
if(retval)
{
printk("sysfs create group is failed\n");
return -1;
}
printk("sysfs create group is success\n");
return 0;
}
static void __exit city_exit(void)
{
sysfs_remove_group(kernel_kobj,&attr_group);
}
module_init(city_init);
module_exit(city_exit);
MODULE_LICENSE("GPL");
三、work queue
工作队列是linux中建工作推后执行的一种方式之一,它将工作放在别的线程中执行,允许休眠。是中断下半部分的理想选择
1、主要数据结构
struct work_struct {
atomic_long_t data; //用来存放私人数据
struct list_head entry; //链表头部
work_func_t func; //工作队列要执行的工作
#ifdef CONFIG_LOCKDEP
struct lockdep_map lockdep_map;
#endif
};
2、主要接口
INIT_WORK(_work, _func) //初始化工作队列
int schedule_work(struct work_struct *work) //调度工作队列work执行函数
bool flush_work_sync(struct work_struct *work) //等待一个工作队列直到他完成
bool cancel_work_sync(struct work_struct *work) //在work执行完后结束他
3、示例代码
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/module.h>
#include <linux/sysfs.h>
#include <linux/list.h>
#include <linux/slab.h>
#include <linux/workqueue.h>
#define NAME_MAX_LENGTH 16
struct city {
struct list_head list;
char name[NAME_MAX_LENGTH];
int temp;
};
static struct list_head head;
static struct work_struct city_work;
static ssize_t city_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
{
/*struct city *elem = NULL;
char tem[32];
list_for_each_entry(elem, &head, list)
{
memset(tem, 0, sizeof(tem));
sprintf(tem, "%s temprature %d\n",elem->name, elem->temp);
strcat(buf,tem);
}*/
schedule_work(&city_work);
return strlen(buf);
}
static ssize_t city_store(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t count)
{
struct city *elem = NULL;
elem = (struct city *)kzalloc(sizeof(struct city), GFP_KERNEL);
if(NULL == elem)
{
printk("malloc failed\n");
return 0;
}
sscanf(buf,"%s%d",elem->name, &elem->temp);
printk("buf is %s name %s temp %d\n",buf, elem->name, elem->temp);
list_add(&elem->list, &head);
return count;
}
static struct kobj_attribute city_attribute =
__ATTR(city, 0666, city_show, city_store);
static struct attribute *attrs[] = {
&city_attribute.attr,
NULL,
};
static struct attribute_group attr_group = {
.attrs = attrs,
};
static void dup_city(struct work_struct *work)
{
struct city *elem = NULL;
list_for_each_entry(elem, &head, list)
{
printk("%s temprature %d\n",elem->name, elem->temp);
}
}
static int __init city_init(void)
{
int retval;
INIT_LIST_HEAD(&head);
INIT_WORK(&city_work, dup_city);
retval = sysfs_create_group(kernel_kobj, &attr_group);
if(retval)
{
printk("sysfs create group is failed\n");
return -1;
}
printk("sysfs create group is success\n");
return 0;
}
static void __exit city_exit(void)
{
sysfs_remove_group(kernel_kobj,&attr_group);
cancel_work_sync(&city_work);
}
module_init(city_init);
module_exit(city_exit);
MODULE_LICENSE("GPL");
本文介绍了Linux内核开发中常用的几种技术,包括链表、sysfs文件系统和工作队列。详细阐述了它们的数据结构、核心接口及使用技巧,并提供了实际代码示例。
1052

被折叠的 条评论
为什么被折叠?



