1. 程式人生 > >linux核心之klist連結串列

linux核心之klist連結串列

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);
.........
}