klist接口提供了两个封装了list_head的结构体,链表头klist和链表节点klist_node
对于结构体klist包含一个spinlock来提供访问保护.klist_node包含一个klist指针指向
归属的klist和kref引用计数器指示该节点的引用次数.
链表头结构体定义如下:
struct klist {
spinlock_t k_lock; // 自旋锁,用于保护列表的访问
struct list_head k_list; // 双向列表
void (*get)(struct klist_node *);//两个函数指针,是用来操作链表中的节点接口
void (*put)(struct klist_node *);//两个函数指针,是用来操作链表中的节点接口
} __attribute__ ((aligned (sizeof(void *))));
链表节点结构体定义如下:
struct klist_node {
void *n_klist; /* never access directly */ //是一个空指针,随便用来指啥,但在我们的klist原语中是用来指向链表头的。另外其最低位用来做标志位
struct list_head n_node; //双向链表,用来联系各节点及链表头
struct kref n_ref;//引用计数,是个int型计数器
};
这两个结构体单独使用没什么意义,一般都是嵌入到更大的结构体来组成链表.在这里举例来说明.
1.subsys_private结构体用于bustype/class结构体来为驱动内核保存私有数据 (structure to hold the private to the driver core portions of the bus_type/class structure),其中struct klist klist_devices,struct klist klist_drivers成员就是两个klist内嵌链表
struct subsys_private {
struct kset subsys; // the struct kset that defines this subsystem
struct kset *devices_kset; // the list of devices associated
struct kset *drivers_kset; // the list of drivers associated
struct klist klist_devices;// the klist to iterate over the @devices_kset
struct klist klist_drivers;// the klist to iterate over the @drivers_kset
.......
};
2.device 结构体内嵌链表节点
struct device {
........
struct klist_node knode_class;
.........
};
3.内嵌链表头的初始化:
static void klist_class_dev_get(struct klist_node *n)
{
struct device *dev = container_of(n, struct device, knode_class);
get_device(dev);
}
static void klist_class_dev_put(struct klist_node *n)
{
struct device *dev = container_of(n, struct device, knode_class);
put_device(dev);
}
int __class_register(struct class *cls, struct lock_class_key *key)
{
struct subsys_private *cp;
.........
klist_init(&cp->klist_devices, klist_class_dev_get, klist_class_dev_put);
.........
}
4.内嵌链表添加节点
int device_add(struct device *dev)
{
........
if (dev->class) {
mutex_lock(&dev->class->p->class_mutex);
/* tie the class to the device */
klist_add_tail(&dev->knode_class,
&dev->class->p->klist_devices);
.........
}