Linux kist.c源码注释

/*
 * klist.c - Routines for manipulating klists.
 *
 * Copyright (C) 2005 Patrick Mochel
 *
 * This file is released under the GPL v2.
 *
 * This klist interface provides a couple of structures that wrap around
 * struct list_head to provide explicit list "head" (struct klist) and list
 * "node" (struct klist_node) objects. For struct klist, a spinlock is
 * included that protects access to the actual list itself. struct
 * klist_node provides a pointer to the klist that owns it and a kref
 * reference count that indicates the number of current users of that node
 * in the list.
 *
 * The entire point is to provide an interface for iterating over a list
 * that is safe and allows for modification of the list during the
 * iteration (e.g. insertion and removal), including modification of the
 * current node on the list.
 *
 * It works using a 3rd object type - struct klist_iter - that is declared
 * and initialized before an iteration. klist_next() is used to acquire the
 * next element in the list. It returns NULL if there are no more items.
 * Internally, that routine takes the klist's lock, decrements the
 * reference count of the previous klist_node and increments the count of
 * the next klist_node. It then drops the lock and returns.
 *
 * There are primitives for adding and removing nodes to/from a klist.
 * When deleting, klist_del() will simply decrement the reference count.
 * Only when the count goes to 0 is the node removed from the list.
 * klist_remove() will try to delete the node from the list and block until
 * it is actually removed. This is useful for objects (like devices) that
 * have been removed from the system and must be freed (but must wait until
 * all accessors have finished).
 */

#include <linux/klist.h>
#include <linux/export.h>
#include <linux/sched.h>

/*
 * Use the lowest bit of n_klist to mark deleted nodes and exclude
 * dead ones from iteration.
 */
#define KNODE_DEAD		1LU
#define KNODE_KLIST_MASK	~KNODE_DEAD

static struct klist *knode_klist(struct klist_node *knode)  //返回klist_node中的klist成员
{
	return (struct klist *)
		((unsigned long)knode->n_klist & KNODE_KLIST_MASK);//清零最低位  因为klist是4字节对齐,所以最低位为0
}

static bool knode_dead(struct klist_node *knode)      		//判断knode是否已经死亡(请求删除)
{
	return (unsigned long)knode->n_klist & KNODE_DEAD; 	   //判断knode中的n_klist的最低位是否为1,如果是1则已死亡
}

static void knode_set_klist(struct klist_node *knode, struct klist *klist)  //设置klist_node中的n_klist成员
{
	knode->n_klist = klist;													//将knode->n_klist设置为传入的参数klist
	/* no knode deserves to start its life dead */
	WARN_ON(knode_dead(knode));												//如果knode已经被请求删除,则发出警告,内核还是继续运行
}

static void knode_kill(struct klist_node *knode)							//将节点请求删除
{
	/* and no knode should die twice ever either, see we're very humane */
	WARN_ON(knode_dead(knode));												//如果节点已经被请求删除,则发出警告,内核继续运行
	*(unsigned long *)&knode->n_klist |= KNODE_DEAD;						//将knode->n_klist的最低位置1
}

/**
 * klist_init - Initialize a klist structure.
 * @k: The klist we're initializing.
 * @get: The get function for the embedding object (NULL if none)
 * @put: The put function for the embedding object (NULL if none)
 *
 * Initialises the klist structure.  If the klist_node structures are
 * going to be embedded in refcounted objects (necessary for safe
 * deletion) then the get/put arguments are used to initialise
 * functions that take and release references on the embedding
 * objects.
 */
void klist_init(struct klist *k, void (*get)(struct klist_node *),      //初始化一个klist
		void (*put)(struct klist_node *))
{
	INIT_LIST_HEAD(&k->k_list);											//将k->k_list初始化,即将k->k_list->prev,next均指向自身
	spin_lock_init(&k->k_lock);											//初始化k中的自旋锁成员
	k->get = get;														//初始化k中的get函数和put函数
	k->put = put;
}
EXPORT_SYMBOL_GPL(klist_init);

static void add_head(struct klist *k, struct klist_node *n)				//将n链接到k的头部
{
	spin_lock(&k->k_lock);												//上锁
	list_add(&n->n_node, &k->k_list);									//通过k,n中的list_head成员进行连接
	spin_unlock(&k->k_lock);											//解锁
}

static void add_tail(struct klist *k, struct klist_node *n)				//同上,只不过是将n链接到k的尾部
{
	spin_lock(&k->k_lock);
	list_add_tail(&n->n_node, &k->k_list);
	spin_unlock(&k->k_lock);
}

static void klist_node_init(struct klist *k, struct klist_node *n)	 //knode初始化
{
	INIT_LIST_HEAD(&n->n_node);										//将k中的list_head成员初始化,指向自身
	kref_init(&n->n_ref);											//初始化k中的n_ref成员,计数值置1
	knode_set_klist(n, k);											//将n中的n->n_klist设置为k
	if (k->get)				//搞清楚klist里面的get和put到底是干嘛的   //如果get成员存在,则执行get函数
		k->get(n);
}

/**
 * klist_add_head - Initialize a klist_node and add it to front.
 * @n: node we're adding.
 * @k: klist it's going on.
 */
void klist_add_head(struct klist_node *n, struct klist *k)		//1.调用klist_node_init将knode初始化(初始化knode中的n_node成员和n->n_ref成员)
{																//2.将knode插入到klist的头部
	klist_node_init(k, n);
	add_head(k, n);
}
EXPORT_SYMBOL_GPL(klist_add_head);

/**
 * klist_add_tail - Initialize a klist_node and add it to back.
 * @n: node we're adding.
 * @k: klist it's going on.
 */
void klist_add_tail(struct klist_node *n, struct klist *k)  //同上,只不过是加到尾部
{
	klist_node_init(k, n);
	add_tail(k, n);
}
EXPORT_SYMBOL_GPL(klist_add_tail);

/**
 * klist_add_behind - Init a klist_node and add it after an existing node
 * @n: node we're adding.
 * @pos: node to put @n after
 */
void klist_add_behind(struct klist_node *n, struct klist_node *pos)   //将n加到pos的后面
{
	struct klist *k = knode_klist(pos);								//获取pos所在的klist

	klist_node_init(k, n);											//初始化n
	spin_lock(&k->k_lock);											//上锁
	list_add(&n->n_node, &pos->n_node);								//将n中的n_node加入到pos中的n_node之后
	spin_unlock(&k->k_lock);										//解锁
}
EXPORT_SYMBOL_GPL(klist_add_behind);

/**
 * klist_add_before - Init a klist_node and add it before an existing node
 * @n: node we're adding.
 * @pos: node to put @n after
 */
void klist_add_before(struct klist_node *n, struct klist_node *pos) //同上  加到前面
{
	struct klist *k = knode_klist(pos);

	klist_node_init(k, n);
	spin_lock(&k->k_lock);
	list_add_tail(&n->n_node, &pos->n_node);
	spin_unlock(&k->k_lock);
}
EXPORT_SYMBOL_GPL(klist_add_before);

struct klist_waiter {
	struct list_head list;
	struct klist_node *node;
	struct task_struct *process;
	int woken;
};

static DEFINE_SPINLOCK(klist_remove_lock);
static LIST_HEAD(klist_remove_waiters);   //==>static struct list_head klist_remove_waiters = {&klist_remove_waiters,&klist_remove_waiters};

static void klist_release(struct kref *kref)
{
	struct klist_waiter *waiter, *tmp;					//定义两个klist_waiter结构体 waiter用做轮询,tmp用作list_for_each_entry_safe的安全检查
	struct klist_node *n = container_of(kref, struct klist_node, n_ref);	//获取kref所在的klist_node  n

	WARN_ON(!knode_dead(n));							//当节点已经被请求删除时,发出警告
	list_del(&n->n_node);								//首先把n->n_node从所在的链表删除
	spin_lock(&klist_remove_lock);						//上锁
	list_for_each_entry_safe(waiter, tmp, &klist_remove_waiters, list) {  //1.寻找knode所在klist_waiter结构体(之前已经被请求删除了,被加入了klist_waiter体中,请求删除的线程被阻塞)
		if (waiter->node != n)											  //2.如果找到了,就在该waiter从所在的链表中删除
			continue;													  //3.将waiter中的woken成员置1
																		  //4.保护
		list_del(&waiter->list);										  //5.唤醒被阻塞的线程
		waiter->woken = 1;
		mb();
		wake_up_process(waiter->process);
	}
	spin_unlock(&klist_remove_lock);								     //解锁
	knode_set_klist(n, NULL);										     //将n中的n->klist指向为空
}

static int klist_dec_and_del(struct klist_node *n)						// 调用kref_put将n的应用计数减一,如果为0,调用上面的klist_release
{
	return kref_put(&n->n_ref, klist_release);							
}

static void klist_put(struct klist_node *n, bool kill)
{
	struct klist *k = knode_klist(n);                                //获得n所在klist给k
	void (*put)(struct klist_node *) = k->put;						//获得k中的put函数给put

	spin_lock(&k->k_lock);											//上锁
	if (kill)														//如果kill为真
		knode_kill(n);												//将n杀死
	if (!klist_dec_and_del(n))										//将n->n_ref减1,如果已经减到0了(执行了klist_release)返回1,不然就是返回0
		put = NULL;													//case 1:返回0说明kref不为0,还有数据结构在使用它,将put=null,不执行k->put;
	spin_unlock(&k->k_lock);										//case 2: 返回1说明kref为0了,klist_release已经执行,这时候需要执行k->put;
	if (put)
		put(n);
}

/**
 * klist_del - Decrement the reference count of node and try to remove. //减少节点的应用次数,并且尝试删除
 * @n: node we're deleting.
 */
void klist_del(struct klist_node *n)                              //调用上面的函数 将kill == true
{
	klist_put(n, true);
}
EXPORT_SYMBOL_GPL(klist_del);

/**
 * klist_remove - Decrement the refcount of node and wait for it to go away.
 * @n: node we're removing.
 */
void klist_remove(struct klist_node *n)                         //klistremove,提供给外部的API(没有static)
{
	struct klist_waiter waiter;									//首先定义了一个klist_waiter结构体

	waiter.node = n;											//用要删除的n来给waiter中的node赋值
	waiter.process = current;									//用当前线程的tast_struct给process赋值
	waiter.woken = 0;											//woken == 0;
	spin_lock(&klist_remove_lock);
	list_add(&waiter.list, &klist_remove_waiters);				//将这个waiter加入到等待删除的waiter中
	spin_unlock(&klist_remove_lock);

	klist_del(n);												//尝试删除这个knode

	for (;;) {													//无限循环  
		set_current_state(TASK_UNINTERRUPTIBLE);				//设置当前线程为不可打断状态,阻塞
		if (waiter.woken)										//当线程被唤醒时检查woken是否为0;这句话是防止当前线程刚进入睡眠态之前,woken就已经变成1了
			break;
		schedule();												//调度
	} 
	__set_current_state(TASK_RUNNING);							//设置当前任务为运行态
}
EXPORT_SYMBOL_GPL(klist_remove);

/**
 * klist_node_attached - Say whether a node is bound to a list or not.
 * @n: Node that we're testing.
 */
int klist_node_attached(struct klist_node *n)  //返回knode是否被绑定到一个klist上
{
	return (n->n_klist != NULL);
}
EXPORT_SYMBOL_GPL(klist_node_attached);

/**
 * klist_iter_init_node - Initialize a klist_iter structure.  //初始化一个klist_iter结构体
 * @k: klist we're iterating.								  //我们要迭代的klist
 * @i: klist_iter we're filling.							  //我们要填充的klist_iter
 * @n: node to start with.									  //开始跌迭代的节点
 *
 * Similar to klist_iter_init(), but starts the action off with @n,
 * instead of with the list head.
 */
void klist_iter_init_node(struct klist *k, struct klist_iter *i,
			  struct klist_node *n)
{
	i->i_klist = k;											//用传入参数初始化klist_iter
	i->i_cur = n;
	if (n)													//如果n存在,把n的引用次数加一
		kref_get(&n->n_ref);
}
EXPORT_SYMBOL_GPL(klist_iter_init_node);

/**
 * klist_iter_init - Iniitalize a klist_iter structure.
 * @k: klist we're iterating.
 * @i: klist_iter structure we're filling.
 *
 * Similar to klist_iter_init_node(), but start with the list head.
 */
void klist_iter_init(struct klist *k, struct klist_iter *i) //和上面类似,不过这个函数是从链表头开始的
{
	klist_iter_init_node(k, i, NULL);
}
EXPORT_SYMBOL_GPL(klist_iter_init);

/**
 * klist_iter_exit - Finish a list iteration.
 * @i: Iterator structure.
 *
 * Must be called when done iterating over list, as it decrements the
 * refcount of the current node. Necessary in case iteration exited before
 * the end of the list was reached, and always good form.
 */
void klist_iter_exit(struct klist_iter *i)  //这个函数主要是在迭代结束时,将kref减一,如果没有迭代到链表末尾则一定要调用,如果到了链表末尾,则无所谓调不调用
{
	if (i->i_cur) {
		klist_put(i->i_cur, false);
		i->i_cur = NULL;
	}
}
EXPORT_SYMBOL_GPL(klist_iter_exit);

static struct klist_node *to_klist_node(struct list_head *n)
{
	return container_of(n, struct klist_node, n_node);
}

/**
 * klist_next - Ante up next node in list.
 * @i: Iterator structure.
 *
 * First grab list lock. Decrement the reference count of the previous
 * node, if there was one. Grab the next node, increment its reference
 * count, drop the lock, and return that next node.
 */
struct klist_node *klist_next(struct klist_iter *i)
{
	void (*put)(struct klist_node *) = i->i_klist->put;  //首先或者这个要迭代的knode所在的klist的put函数
	struct klist_node *last = i->i_cur;					//last指向当前跌代到的knode
	struct klist_node *next;							//next用来返回要访问的下一个knode

	spin_lock(&i->i_klist->k_lock);						//上锁

	if (last) {											//如果last存在,next就等于last所在klist的下一个knode
		next = to_klist_node(last->n_node.next);		//把last的kref减一
		if (!klist_dec_and_del(last))					//如果last的kref变成0即已经被删除了,put == NULL
			put = NULL;
	} else
		next = to_klist_node(i->i_klist->k_list.next);//如果last不存在,说明要从链表头开始遍历

	i->i_cur = NULL;									//把当前的klist_iter的i_cur置NULL
	while (next != to_klist_node(&i->i_klist->k_list)) {  //如果next knode不是没有被请求删除,把knode的ref加1,同时
		if (likely(!knode_dead(next))) {				 //将遍历结构体的i_cur设置为nest,跳出循环
			kref_get(&next->n_ref);
			i->i_cur = next;
			break;
		}
		next = to_klist_node(next->n_node.next);
	}

	spin_unlock(&i->i_klist->k_lock);				//解锁

	if (put && last)								//如果put和last同时存在,说明last已经已经被删除了,执行put
		put(last);
	return i->i_cur;
}
EXPORT_SYMBOL_GPL(klist_next);


/* likely()与unlikely()在2.6内核中,随处可见,那为什么要用它们?它们之间有什么区别呢?
首先明确:
 if (likely(value))等价于if (value)
 if (unlikely(value))等价于if (value)

也就是说likely()和unlikely()从阅读和理解的角度是一样的。
这两个宏在内核中定义如下:
#define likely(x) __builtin_expect(!!(x), 1)
#define unlikely(x) __builtin_expect(!!(x), 0)
这里的__built_expect()函数是gcc(version >= 2.96)的内建函数,提供给程序员使用的,目的是将"分支转移"的信息提供给编译器,这样编译器对代码进行优化,以减少指令跳转带来的性能下降。
__buildin_expect((x), 1)表示x的值为真的可能性更大.
__buildin_expect((x), 0)表示x的值为假的可能性更大.
也就是说,使用likely(),执行if后面的语句的机会更大,使用unlikely(),执行else后面的语句机会更大一些。通过这种方式,编译器在编译过程中,会将可能性更大的代 */

自己查资料写的注释,有大佬看到的话,欢迎指出里面的漏误

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值