怎么做{} while(0)在宏中工作?

时间:2010-09-22 06:29:17

标签: c do-while

虽然本论坛和所有其他论坛已经多次讨论过这个话题,但我还是有疑问。请帮忙。

宏内的do{} while(0)如何在Linux内核中运行? 例如,

#define preempt_disable()    do { } while (0)

如何禁用抢占?

#define might_resched()    do { } while (0)

如何重新安排?

同样地,我也看到了互斥锁和其他宏的宏。这有什么用?我理解以下问题,但不是上面的例子。

#define foo(x)    do { do something } while(0)

修改

rt_mutex_lock的以下代码如何?

/**
 * rt_mutex_lock - lock a rt_mutex
 *
 * @lock: the rt_mutex to be locked
 */
void __sched rt_mutex_lock(struct rt_mutex *lock)
{
        might_sleep();
        rt_mutex_fastlock(lock, TASK_UNINTERRUPTIBLE, 0, rt_mutex_slowlock);
}
EXPORT_SYMBOL_GPL(rt_mutex_lock);


/*
 * debug aware fast / slowpath lock,trylock,unlock
 *
 * The atomic acquire/release ops are compiled away, when either the
 * architecture does not support cmpxchg or when debugging is enabled.
 */

static inline int rt_mutex_fastlock(struct rt_mutex *lock, 
    int state, int detect_deadlock, int (*slowfn)(struct rt_mutex *lock, 
    int state, struct hrtimer_sleeper *timeout, int detect_deadlock))
{
        if (!detect_deadlock && likely(rt_mutex_cmpxchg(lock, NULL, current))) {
                rt_mutex_deadlock_account_lock(lock, current);
                return 0;
        } else{
                return slowfn(lock, state, NULL, detect_deadlock);
        }
}

我感到困惑,因为rt_mutex_deadlock_account_lock是在内核的两个位置定义的:

kernel/rtmutex-debug.c

void rt_mutex_deadlock_account_lock(struct rt_mutex *lock, 
    struct task_struct *task)
{
    //....
}

kernel/rtmutex.h

#define rt_mutex_deadlock_account_lock(m, t) do { } while (0)

在新的内核2.6.35.4中,i2c驱动程序rt_mutex_lock(&adap->bus_lock);已替换mutex_lock()。这怎么锁定呢?

3 个答案:

答案 0 :(得分:11)

请参阅this link以获得比我能给出的更好的解释。

答案 1 :(得分:5)

@Kragen回答了做什么......虽然构造是为了 - 它基本上使宏更安全使用。

但是,我不认为它回答了“这是如何工作的?”的问题:

#define preempt_disable()    do { } while (0)

宏定义为不执行任何操作。你为什么什么都不想做?

  • 在某些情况下,您希望使用宏作为占位符来执行某些操作。例如,您可以在一个系统上编写代码,其中“抢占”不是问题,但您知道代码可能被移植到“抢占”需要一些特殊处理的系统。所以你在第二个系统需要它的地方使用一个宏(以便稍后可以轻松启用),但是对于第一个系统,你可以将该宏定义为空白宏。

  • 在某些情况下,您可能希望执行由不同部分组成的任务,(例如START_TABLE(); TABLE_ENTRY(1); TABLE_ENTRY(2); END_TABLE();)。这样可以很好地清理表格。但是你发现你实际上并不需要END_TABLE()宏。为了保持客户端代码整洁,您可以保留定义的宏,并将其定义为不执行任何操作。这样,所有表都有一个END_TABLE,代码更容易阅读。

  • 类似的情况可能发生在两个状态(启用/禁用),其中一个状态需要宏来执行某些操作,但另一个状态只是默认情况下发生,因此一个状态的实现是“空的” - 你仍然使用宏因为它使客户端代码更容易理解,因为它明确说明了启用或禁用事物的位置。

答案 2 :(得分:3)

IIRC在宏中使用do-while是为了使它们看起来更像是一个正常的函数调用;关于unbraced if语句和类似的东西,有一些微妙的语法问题。如果没有这样做,宏可能看起来像一个正常的函数调用,但会以不同的方式工作。

我想在这种情况下会使用那些宏,因此某些函数调用会编译为空;如果没有设置CONFIG_PREEMPT,它看起来可能就是你得到的东西,所以内核中只有先发制人必需的部分才会在没有它的情况下消失。所以这些循环不会禁用抢占或重新安排任何东西;在内核源代码的其他地方会有另一个定义(可能是一个真正的函数)。