linux 内核辅助接口

本文介绍了Linux内核开发中常用的几种技术,包括链表、sysfs文件系统和工作队列。详细阐述了它们的数据结构、核心接口及使用技巧,并提供了实际代码示例。

       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");


 

      

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值