include/linux/notifier.h Kernel

struct notifier_block Kernel

可以理解为一个注册进来的需要 notify 的 entry。

struct notifier_block {
	notifier_fn_t notifier_call;
	struct notifier_block __rcu *next;
	int priority;
};

struct atomic_notifier_head / struct blocking_notifier_head / struct raw_notifier_head / struct srcu_notifier_head / Kernel

尽管 entry 只有一种,但是 list(或者叫 chain)有四种:

  • Atomic: Chain callbacks run in interrupt/atomic context. 里面的每一个函数不允许阻塞。
  • Blocking: 跑在进程上下文,允许阻塞,应该用的比较多。
  • Raw: 只提供基础功能,锁和保护要使用者来保证
  • Srcu: Blocking 的一个变种(可能实现的方式不同?),其他性质和 Blocking 是一样的。
struct atomic_notifier_head {
	spinlock_t lock;
	struct notifier_block __rcu *head;
};

struct blocking_notifier_head {
	struct rw_semaphore rwsem;
	struct notifier_block __rcu *head;
};

struct raw_notifier_head {
	struct notifier_block __rcu *head;
};

struct srcu_notifier_head {
	struct mutex mutex;
	struct srcu_usage srcuu;
	struct srcu_struct srcu;
	struct notifier_block __rcu *head;
};

`

kernel/notifier.c Kernel

notifier_chain_register() / Kernel

// 如果不允许有重复优先级,发现了重复优先级就返回一个 error
// 如果允许,这个链表的优先级是从大到小的。
static int notifier_chain_register(struct notifier_block **nl, struct notifier_block *n, bool unique_priority)
{
	while ((*nl) != NULL) {
        //...
		if (n->priority > (*nl)->priority)
			break;
		if (n->priority == (*nl)->priority && unique_priority)
			return -EBUSY;
		nl = &((*nl)->next);
	}
	n->next = *nl;
    //...
	*nl = n;
    //...
}

Blocking notifier

blocking_notifier_chain_register() / __blocking_notifier_chain_register() Kernel

static int __blocking_notifier_chain_register(struct blocking_notifier_head *nh,
					      struct notifier_block *n,
					      bool unique_priority)
{
    //...
	down_write(&nh->rwsem);
	ret = notifier_chain_register(&nh->head, n, unique_priority);
	up_write(&nh->rwsem);
    //...
}