当前位置:   article > 正文

DO_ONCE 和 printk_once

printk_once
DO_ONCE 这个宏是是kernel 为避免一个函数被调用两次而定义的宏
#define DO_ONCE(func, ...)                             \
    ({                                     \
        bool ___ret = false;                         \
        static bool ___done = false;                     \
        static struct static_key ___once_key = STATIC_KEY_INIT_TRUE; \
        if (static_key_true(&___once_key)) {                 \
            unsigned long ___flags;                     \
            ___ret = __do_once_start(&___done, &___flags);         \
            if (unlikely(___ret)) {                     \
                func(__VA_ARGS__);                 \
                __do_once_done(&___done, &___once_key,         \
                           &___flags);             \
            }                             \
        }                                 \
        ___ret;                                 \
    })

如果有一个func 只能被调用一次,例如初始化函数的话,则可以用这个宏,如下例所示foo这个函数即使被调用两次,也只会运行一次
 *   void foo(void)
 *   {
 *     DO_ONCE(func, arg);
 *   }
 *
 *   foo();
 *   foo();


例如netdev_rss_key_fill 函数可能没调用多次,但是应该除了第一次外,后面的几次直接返回就行了
void netdev_rss_key_fill(void *buffer, size_t len)
{
    BUG_ON(len > sizeof(netdev_rss_key));
    net_get_random_once(netdev_rss_key, sizeof(netdev_rss_key));
    memcpy(buffer, netdev_rss_key, len);
}

#define net_get_random_once(buf, nbytes)            \
    get_random_once((buf), (nbytes))
#define get_random_once(buf, nbytes)                         \
    DO_ONCE(get_random_bytes, (buf), (nbytes))


对于printk 也有一个once的函数,只会被调用一次,但是必须定义CONFIG_PRINTK
#ifdef CONFIG_PRINTK
#define printk_once(fmt, ...)                    \
({                                \
    static bool __print_once __read_mostly;            \
    bool __ret_print_once = !__print_once;            \
                                \
    if (!__print_once) {                    \
        __print_once = true;                \
        printk(fmt, ##__VA_ARGS__);            \
    }                            \
    unlikely(__ret_print_once);                \
})
}
而且kernel 已经帮我们定义好了不同log level的printk_once,一般推荐直接使用下面的函数.
#define pr_emerg_once(fmt, ...)                    \
    printk_once(KERN_EMERG pr_fmt(fmt), ##__VA_ARGS__)
#define pr_alert_once(fmt, ...)                    \
    printk_once(KERN_ALERT pr_fmt(fmt), ##__VA_ARGS__)
#define pr_crit_once(fmt, ...)                    \
    printk_once(KERN_CRIT pr_fmt(fmt), ##__VA_ARGS__)
#define pr_err_once(fmt, ...)                    \
    printk_once(KERN_ERR pr_fmt(fmt), ##__VA_ARGS__)
#define pr_warn_once(fmt, ...)                    \
    printk_once(KERN_WARNING pr_fmt(fmt), ##__VA_ARGS__)
#define pr_notice_once(fmt, ...)                \
    printk_once(KERN_NOTICE pr_fmt(fmt), ##__VA_ARGS__)
#define pr_info_once(fmt, ...)                    \
    printk_once(KERN_INFO pr_fmt(fmt), ##__VA_ARGS__)
#define pr_cont_once(fmt, ...)                    \
    printk_once(KERN_CONT pr_fmt(fmt), ##__VA_ARGS__)


声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小蓝xlanll/article/detail/482170
推荐阅读
相关标签
  

闽ICP备14008679号