7

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

do{} while(0)in 宏在 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(). 那这个怎么锁?

4

3 回答 3

12

请参阅此链接以获得比我能给出的更好的解释。

于 2010-09-22T06:38:13.393 回答
5

@Kragen has answered what the do...while construct is for - it basically makes a macro much safer to use.

However, I don't think it answers the question of "how does this work?":

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

The macro is defined to do nothing. Why would you want to do nothing?

  • In some cases you want to use a macro as a placeholder for doing something. For example, you might write code on one system where "preempt" isn't an issue, but you know the code might be ported to a system where "preempt" needs some special handling. So you use a macro everywhere the second system needs it (so that the handling is easy to enable later), but for the first system you then define that macro as a blank macro.

  • In some cases you may want to do things like a task that is made up of different parts, (e.g. START_TABLE(); TABLE_ENTRY(1); TABLE_ENTRY(2); END_TABLE();). This makes a nice clean clear implementation of your table. But then you find that you don't actually need the END_TABLE() macro. To keep the client code tidy, you leave the macro defined, and simply define it to do nothing. That way, all your tables have an END_TABLE and the code is easier to read.

  • A similar case can occur with two states (enable/disable) where one state needs the macro to do something, but the other state just happens by default, so the implementation of one is "empty" - you still use the macro because it makes the client code easier to understand, because it explicitly states the places where things are enabled or disabled.

于 2010-09-22T07:25:49.243 回答
3

IIRC the use of the do-while in macros is to make them look more like a normal function invocation; there are some subtle syntax issues around unbraced if statements and things like that. Without the do-while the macro might look like a normal function invocation but would work differently.

I would guess that in this case those macros are being used so certain function calls compile away to nothing; it looks like that might be what you get if CONFIG_PREEMPT wasn't set, so certain parts of the kernel that are only necessary for preempt simply vanish without it. So those loops do not disable preempt or reschedule anything; there'll be another definition (probably a real function) elsewhere in the kernel source.

于 2010-09-22T06:41:57.440 回答