Notifier Chain 的分析和使用(1)

在分析PM时看到了notifier 相关的函数,这里记录一下学习内容.

 notifier_block的定义

 定义 了回调函数notifier_call , 当订阅者接受到消息后执行回调函数进行处理.

回调函数可以阻塞,并且运行在进程上下文,atomic 类型的chain 可以运行在中断上下文.

struct notifier_block;

定义了一种数据结构类型, notifier_fn_t  包含回调函数,对应的action,和携带的额外数据.
typedef	int (*notifier_fn_t)(struct notifier_block *nb,
			unsigned long action, void *data);

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

这里我们可以看到down_write 和up_write. 这就是读写信号量的获取和释放函数. 

读写信号量与信号量之间的关系,类似于读写自旋锁与自旋锁之间的关系;读写信号量可能会引起进程阻塞,但是它允许N个读执行单元同时访问共享资源,而最多只允许有一个写执行单元访问共享资.
 

 /*
 *	Blocking notifier chain routines.  All access to the chain is
 *	synchronized by an rwsem.
 */

/**
 *	blocking_notifier_chain_register - Add notifier to a blocking notifier chain
 *	@nh: Pointer to head of the blocking notifier chain
 *	@n: New entry in notifier chain
 *
 *	Adds a notifier to a blocking notifier chain.
 *	Must be called in process context.
 *
 *	Currently always returns zero.
 */
int blocking_notifier_chain_register(struct blocking_notifier_head *nh,
		struct notifier_block *n)
{
	int ret;

	/*
	 * This code gets used during boot-up, when task switching is
	 * not yet working and interrupts must remain disabled.  At
	 * such times we must not call down_write().
	 */
	if (unlikely(system_state == SYSTEM_BOOTING))
		return notifier_chain_register(&nh->head, n);

	//down_write(&nh->rwsem);// 可能有多个访问者尝试去获取 rwsem ,但是只会有一个获取锁然后执行后面的函数. 
	ret = notifier_chain_register(&nh->head, n);
	up_write(&nh->rwsem);

	return ret;
}
EXPORT_SYMBOL_GPL(blocking_notifier_chain_register);

fb_notify.c 里面实现了framebuffer 的notifier 

来看看怎么实现的.

1.fb_register_client  注册

2.fb_unregister_client 注销

3.fb_notifier_call_chain   调用

#include <linux/fb.h>
#include <linux/notifier.h>
#include <linux/export.h>

static BLOCKING_NOTIFIER_HEAD(fb_notifier_list);

/**
 *	fb_register_client - register a client notifier
 *	@nb: notifier block to callback on events
 */
int fb_register_client(struct notifier_block *nb)
{
	return blocking_notifier_chain_register(&fb_notifier_list, nb);
}
EXPORT_SYMBOL(fb_register_client);

/**
 *	fb_unregister_client - unregister a client notifier
 *	@nb: notifier block to callback on events
 */
int fb_unregister_client(struct notifier_block *nb)
{
	return blocking_notifier_chain_unregister(&fb_notifier_list, nb);
}
EXPORT_SYMBOL(fb_unregister_client);

/**
 * fb_notifier_call_chain - notify clients of fb_events
 *
 */
int fb_notifier_call_chain(unsigned long val, void *v)
{
	return blocking_notifier_call_chain(&fb_notifier_list, val, v);
}
EXPORT_SYMBOL_GPL(fb_notifier_call_chain);
H:\kernel-codes\linux-4.18.tar\linux-4.18\include\linux\backlight.h
中定义了背光的设备结构体,这是内核的一贯作风,先定义一个该设备的结构体,报需要用的内核变量成员都放进去,比如 他会注册framebuffer 的 notifier block,那就定义一个自己要注册的结构体在这里. 

struct backlight_device {
	/* Backlight properties */
	struct backlight_properties props;

	/* Serialise access to update_status method */
	struct mutex update_lock;

	/* This protects the 'ops' field. If 'ops' is NULL, the driver that
	   registered this device has been unloaded, and if class_get_devdata()
	   points to something in the body of that driver, it is also invalid. */
	struct mutex ops_lock;
	const struct backlight_ops *ops;

	/* The framebuffer notifier block */
	struct notifier_block fb_notif;

	/* list entry of all registered backlight devices */
	struct list_head entry;

	struct device dev;

	/* Multiple framebuffers may share one backlight device */
	bool fb_bl_on[FB_MAX];

	int use_count;
};

然后背光的实现中把自己的回调函数 bd->fb_notif.notifier_call = fb_notifier_callback;   通过公用接口 fb_register_client  进行注册!  看到了吗? 这里是调用fb_notify.c 里的函数进行注册, 那当然是注册到 fb_notifier_list   这个notifier 的链表上. 

因为在fb_notify.c 里面定义了全局的fb notifier 链表头.

static BLOCKING_NOTIFIER_HEAD(fb_notifier_list);

static int backlight_register_fb(struct backlight_device *bd)
{
	memset(&bd->fb_notif, 0, sizeof(bd->fb_notif));
	bd->fb_notif.notifier_call = fb_notifier_callback;

	return fb_register_client(&bd->fb_notif);
}

那是如何调用backlight 里面的回调函数的? 

fb_notify.c  会通过 fb_notifier_call_chain  按照优先级调用 注册到自己的fb_notifier_list 上面的回调函数.

所以这里就可以明白,为什么其他的driver 会注册自己的回调函数到公共的notifier chain 上面了吗?  

`

**
 * fb_notifier_call_chain - notify clients of fb_events
 *
 */
int fb_notifier_call_chain(unsigned long val, void *v)
{
	return blocking_notifier_call_chain(&fb_notifier_list, val, v);
}
EXPORT_SYMBOL_GPL(fb_notifier_call_chain);

猜你喜欢

转载自blog.csdn.net/yuzaipiaofei/article/details/81813063