Linux Notification 機制的分析

來源:互聯網
上載者:User


 

1. 基本機制
1)資料結構
struct notifier_block
{
int (*notifier_call)(struct notifier_block *self, unsigned long, void *);
struct notifier_block *next;
int priority; /*用於對註冊者進行優先順序排隊,高優先順序的處理常式將被優先執行,由註冊者自己指定 */
};
2)基本常式
extern int notifier_chain_register(struct notifier_block **list, struct notifier_block *n);
說明:註冊到某個notifier_block鏈;這時的n可以只要初始化(*notifier_call)指標;
extern int notifier_chain_unregister(struct notifier_block **nl, struct notifier_block *n);
說明:從某個notifier_block鏈中移去n;
extern int notifier_call_chain(struct notifier_block **n, unsigned long val, void *v);
說明:輪循執行某個notifier_block鏈中的所有notifier_block,對其(*notifier_call)傳入參數val和*v;
其中val應該是EVENT NUMBER,而*v是導致這個事件的資料結構,比如某個網路裝置UP,則val=NETDEV_UP,v=dev;
3)傳回值
#define NOTIFY_DONE 0x0000 /* Don't care */
#define NOTIFY_OK 0x0001 /* Suits me */
#define NOTIFY_STOP_MASK 0x8000 /* Don't call further */
#define NOTIFY_BAD (NOTIFY_STOP_MASK|0x0002) /* Bad/Veto action */

4)已定義事件
/*
* Declared notifiers so far. I can imagine quite a few more chains
* over time (eg laptop power reset chains, reboot chain (to clean
* device units up), device [un]mount chain, module load/unload chain,
* low memory chain, screenblank chain (for plug in modular screenblankers)
* VC switch chains (for loadable kernel svgalib VC switch helpers) etc...
*/

/* netdevice notifier chain */
#define NETDEV_UP 0x0001 /* For now you can't veto a device up/down */
#define NETDEV_DOWN 0x0002
#define NETDEV_REBOOT 0x0003 /* Tell a protocol stack a network interface
detected a hardware crash and restarted
- we can use this eg tocp sessions
once done */
#define NETDEV_CHANGE 0x0004 /* Notify device state change */
#define NETDEV_REGISTER 0x0005
#define NETDEV_UNREGISTER 0x0006
#define NETDEV_CHANGEMTU 0x0007
#define NETDEV_CHANGEADDR 0x0008
#define NETDEV_GOING_DOWN 0x0009
#define NETDEV_CHANGENAME 0x000A

#define SYS_DOWN 0x0001 /* Notify of system down */
#define SYS_RESTART SYS_DOWN
#define SYS_HALT 0x0002 /* Notify of system halt */
#define SYS_POWER_OFF 0x0003 /* Notify of system power off */

2. 舉例分析
以網路裝置的通知資訊塊netdev_chain為例來說明如何使用notification機制。
在net/core/dev.c中定義了netdev_chain鏈:
static struct notifier_block *netdev_chain=NULL;
提供別的模組的介面,以便它們使用netdev_chain鏈:
/*
* Device change register/unregister. These are not inline or static
* as we export them to the world.
*/

/**
* register_netdevice_notifier - register a network notifier block
* @nb: notifier
*
* Register a notifier to be called when network device events occur.
* The notifier passed is linked into the kernel structures and must
* not be reused until it has been unregistered. A negative errno code
* is returned on a failure.
*/

int register_netdevice_notifier(struct notifier_block *nb)
{
return notifier_chain_register(&netdev_chain, nb);
}

/**
* unregister_netdevice_notifier - unregister a network notifier block
* @nb: notifier
*
* Unregister a notifier previously registered by
* register_netdevice_notifier(). The notifier is unlinked into the
* kernel structures and may then be reused. A negative errno code
* is returned on a failure.
*/

int unregister_netdevice_notifier(struct notifier_block *nb)
{
return notifier_chain_unregister(&netdev_chain,nb);
}

以X25為例來說明使用者。
在af_x25.c中,定義了:
struct notifier_block x25_dev_notifier = {
notifier_call: x25_device_event,
};
然後模組初始化時向netdev_chain註冊:
static int __init x25_init(void)
{
... ...
register_netdevice_notifier(&x25_dev_notifier);
... ...
}
比如當NETDEV_UP事件發生時,調用到:
notifier_call_chain(&netdev_chain, NETDEV_UP, dev);
就會執行到x25_dev_notifier中註冊的處理常式:x25_device_event,至於對相應的事件(event number)是不是感興趣,
需要處理常式自己來判斷。
static int x25_device_event(struct notifier_block *this, unsigned long event, void *ptr)
{
struct net_device *dev = (struct net_device *)ptr;
struct x25_neigh *neigh;

if (dev->type == ARPHRD_X25
#if defined(CONFIG_LLC) || defined(CONFIG_LLC_MODULE)
|| dev->type == ARPHRD_ETHER
#endif
) {
switch (event) {
case NETDEV_UP:
x25_link_device_up(dev);
break;
case NETDEV_GOING_DOWN:
if ((neigh = x25_get_neigh(dev)))
x25_terminate_link(neigh);
break;
case NETDEV_DOWN:
x25_kill_by_device(dev);
x25_route_device_down(dev);
x25_link_device_down(dev);
break;
}
}

return NOTIFY_DONE;
}

所有關於網路裝置的事件全部在net/core/dev.c中發生,從而引發notifier_call_chain(&netdev_chain,val, dev)的調用:
Dev.c (linux/net/core): notifier_call_chain(&netdev_chain, NETDEV_CHANGE, dev);
Dev.c (linux/net/core): notifier_call_chain(&netdev_chain, NETDEV_UP, dev);
Dev.c (linux/net/core): notifier_call_chain(&netdev_chain, NETDEV_GOING_DOWN, dev);
Dev.c (linux/net/core): notifier_call_chain(&netdev_chain, NETDEV_DOWN, dev);
Dev.c (linux/net/core): notifier_call_chain(&netdev_chain, NETDEV_CHANGE, dev);
Dev.c (linux/net/core): notifier_call_chain(&netdev_chain, NETDEV_CHANGEMTU, dev);
Dev.c (linux/net/core): notifier_call_chain(&netdev_chain, NETDEV_CHANGEADDR, dev);
Dev.c (linux/net/core): notifier_call_chain(&netdev_chain, NETDEV_CHANGEADDR, dev);
Dev.c (linux/net/core): notifier_call_chain(&netdev_chain, NETDEV_CHANGENAME, dev);
Dev.c (linux/net/core): notifier_call_chain(&netdev_chain, NETDEV_REGISTER, dev);
Dev.c (linux/net/core): notifier_call_chain(&netdev_chain, NETDEV_UNREGISTER, dev);
Dev.c (linux/net/core): notifier_call_chain(&netdev_chain, NETDEV_UNREGISTER, dev);

3. 總結
從上面的分析可以看出,Linux下的Notification機制不是通過訊息的方式實現的,而是一旦外來事件發生,所以對這個事件感興趣的模組都會立即響應這個事件。但是,這個通知機制的效率不是很高,因為它的粒度不夠細,比如A對E1、E2事件感興趣,B對E2、E3感興趣,但是E1~E3 都是由N鏈來管理的,這樣當發生E1事件時,A、B的處理常式都會被調用一次。如果能夠區分對待不同模組感興趣的事件集,然後只把事件發送到感興趣的模組,效率會更高一些。另外,對優先順序的處理是必須得,但是如何利用這個優先順序似乎沒有很好的說明和例證。

 

 
 
相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.