linux内核事件通知,linux内核中的通知链机制

由起

内核中许多自系统之间关系密切,因此在一个子系统发生或者检测到的事件信息很可能对其他子系统来说也很有价值。为了满足其他子系统对这些事件信息的需求(内核子系统之间),内核提供了notification chain机制。

notification chain的实现使用publish-subscribe模型,当事件发生时,检测或者产生时间的子系统作为主动一方通过通知函数来告知作为被动一方的订阅者(需要该信息的子系统)。subscriber提供callback函数给publisher调用。subscriber必须知道其他子系统提供了哪些事件通知支持,以选择可以订阅的事件通知。subscriber本身也可以具有信息发布的功能。当事件发生时,publisher通知subscriber,但是publisher对于谁subscribe事件通知和为何需要此事件信息,不关心。

实现

内核实现主要在~/include/linux/notifer.h和~/kernel/notifer.c中实现了该机制。

notification chain由单链表实现(没有使用内核通用的循环链表),每个链表项是notifier_block结构体。

struct notifier_block {

int (*notifier_call)(struct notifier_block *, unsigned long, void *);

struct notifier_block __rcu *next;

int priority;

};

notifier_call,subscriber提供给publisher的回调函数。第一个参数为notifer_block本身,第二个参数表示时间发生的类型,因为一个chain可能支持多个事件,在该文件中设置了一些时间常量,第三个参数存放私有信息,与具体的事件相关。

priority:表示该回调函数的优先级,事件发生时,高优先级的回调函数先得到调用。具体作用在notifier_chain_register函数中可以得到体现。

static int notifier_chain_register(struct notifier_block **nl,

struct notifier_block *n)

{

while ((*nl) != NULL) {

if (n->priority > (*nl)->priority)

break;

nl = &((*nl)->next);

}

n->next = *nl;

rcu_assign_pointer(*nl, n);

return 0;

}

该函数的意义就十分明显了,根据block的优先级顺序,将其插入到指定的链中。

与之对应的,notifier_chain_unregister

static int notifier_chain_unregister(struct notifier_block **nl,

struct notifier_block *n)

{

while ((*nl) != NULL) {

if ((*nl) == n) {

rcu_assign_pointer(*nl, n->next);

return 0;

}

nl = &((*nl)->next);

}

return -ENOENT;

}

当指定的时间发生时,调用相应的通知链,告知subscriber事件的发生。

static int __kprobes notifier_call_chain(struct notifier_block **nl,

unsigned long val, void *v,

int nr_to_call,int *nr_calls)

{

int ret = NOTIFY_DONE;

struct notifier_block *nb, *next_nb;

nb = rcu_dereference_raw(*nl);

while (nb && nr_to_call) {

next_nb = rcu_dereference_raw(nb->next);

#ifdef CONFIG_DEBUG_NOTIFIERS

if (unlikely(!func_ptr_is_kernel_text(nb->notifier_call))) {

WARN(1, "Invalid notifier called!");

nb = next_nb;

continue;

}

#endif

//基本上所有的回调函数里面都会使用switch语句,通过判断不同的event值来执行不同的操作。

ret = nb->notifier_call(nb, val, v);

if (nr_calls)

(*nr_calls)++;

///回调函数可能中断对其他低优先级subscriber的通知

if ((ret & NOTIFY_STOP_MASK) == NOTIFY_STOP_MASK)

break;

nb = next_nb;

nr_to_call--;

}

///返回值为最后一个回调函数执行的返回值

return ret;

}

多数子系统都定义了这些基本例程的封装函数,因此很少看到对这些函数的直接调用。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值