美文网首页
浅尝辄止70-内核那些“非显式定义”宏

浅尝辄止70-内核那些“非显式定义”宏

作者: 阿棍儿_Leon | 来源:发表于2019-01-07 13:03 被阅读0次

    如果你顺着上一篇的线索去读mark_buffer_dirty的实现会很困惑,因为很多“函数”的定义找不到。

    非显式定义宏

    有些函数、变量或类型的名字不是直接写出来的,而是用宏的##符号定义出来的,这意味着这些名字在定义的地方可以不出现,如果你不知道的话,就很难找到他们的定义。
    mark_buffer_dirty[kernel/fs/buffer.c]这个函数看起来不长,但是里面有好几个东西找不到的定义,包括buffer_uptodatebuffer_dirtytest_set_buffer_dirtyTestSetPageDirty

    void mark_buffer_dirty(struct buffer_head *bh)
    {
        WARN_ON_ONCE(!buffer_uptodate(bh));
    
        trace_block_dirty_buffer(bh);
    
        /*
         * Very *carefully* optimize the it-is-already-dirty case.
         *
         * Don't let the final "is it dirty" escape to before we
         * perhaps modified the buffer.
         */
        if (buffer_dirty(bh)) {
            smp_mb();
            if (buffer_dirty(bh))
                return;
        }
    
        if (!test_set_buffer_dirty(bh)) {
            struct page *page = bh->b_page;
            if (!TestSetPageDirty(page)) {
                struct address_space *mapping = page_mapping(page);
                if (mapping)
                    __set_page_dirty(page, mapping, 0);
            }
        }
    }
    

    buffer_uptodate

    事实上名字叫做buffer_uptodate的函数是存在的,它在kernel/include/linux/buffer_head.h里面

    #define BUFFER_FNS(bit, name)                       \
    static inline void set_buffer_##name(struct buffer_head *bh)        \
    {                                   \
        set_bit(BH_##bit, &(bh)->b_state);              \
    }                                   \
    static inline void clear_buffer_##name(struct buffer_head *bh)      \
    {                                   \
        clear_bit(BH_##bit, &(bh)->b_state);                \
    }                                   \
    static inline int buffer_##name(const struct buffer_head *bh)       \
    {                                   \
        return test_bit(BH_##bit, &(bh)->b_state);          \
    }
    //...
    BUFFER_FNS(Uptodate, uptodate)
    

    将宏展开就是

    static inline void set_buffer_uptodate(struct buffer_head *bh)
    {
        set_bit(BH_Uptodate, &(bh)->b_state);
    }
    static inline void clear_buffer_uptodate(struct buffer_head *bh)
    {
        clear_bit(BH_Uptodate, &(bh)->b_state);
    }
    static inline int buffer_uptodate(const struct buffer_head *bh)
    {
        return test_bit(BH_Uptodate, &(bh)->b_state);
    }
    

    buffer_dirty

    同上,将BUFFER_FNS(Dirty, dirty)展开

    static inline void set_buffer_dirty(struct buffer_head *bh)
    {
        set_bit(BH_Dirty, &(bh)->b_state);
    }
    static inline void clear_buffer_dirty(struct buffer_head *bh)
    {
        clear_bit(BH_Dirty, &(bh)->b_state);
    }
    static inline int buffer_dirty(const struct buffer_head *bh)
    {
        return test_bit(BH_Dirty, &(bh)->b_state);
    }
    

    test_set_buffer_dirty

    也是一样的

    #define TAS_BUFFER_FNS(bit, name)                   \
    static inline int test_set_buffer_##name(struct buffer_head *bh)    \
    {                                   \
        return test_and_set_bit(BH_##bit, &(bh)->b_state);      \
    }                                   \
    static inline int test_clear_buffer_##name(struct buffer_head *bh)  \
    {                                   \
        return test_and_clear_bit(BH_##bit, &(bh)->b_state);        \
    }
    //...
    TAS_BUFFER_FNS(Dirty, dirty)
    

    展开TAS_BUFFER_FNS(Dirty, dirty)

    static inline int test_set_buffer_dirty(struct buffer_head *bh)
    {
        return test_and_set_bit(BH_Dirty, &(bh)->b_state);
    }
    static inline int test_clear_buffer_dirty(struct buffer_head *bh)
    {
        return test_and_clear_bit(BH_Dirty, &(bh)->b_state);
    }
    

    TestSetPageDirty

    它的定义可以从kernel/include/linux/page-flags.h找到,线索如下

    #define TESTSETFLAG(uname, lname)                   \
    static inline int TestSetPage##uname(struct page *page)         \
            { return test_and_set_bit(PG_##lname, &page->flags); }
    //...
    TESTSETFLAG(Dirty, dirty)
    

    都是一个套路,我就不展开了。

    遇到这种情况,如果猜它是非显式定义的宏,还是有一点办法的,例如可以把名字拆开,然后搜索那个名字。例如TestSetPageDirty的形式是TestSetPagexxxx,前面的TestSetPage部分看起来是不变的,所以搜它就可以找到上面这个线索。

    相关文章

      网友评论

          本文标题:浅尝辄止70-内核那些“非显式定义”宏

          本文链接:https://www.haomeiwen.com/subject/wjqurqtx.html