7

Though this topic has been discussed many times in this forum and all other forums, still I have doubts. Please help.

How does the do{} while(0) in macro work in Linux kernel? For example,

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

How does it disable preempt?

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

How does it reschedule?

Similarly I have seen macros for mutex locks and other also. How does this help? I understand for following problem but not for the examples above.

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

Edit:

What about the following code for 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);
        }
}

I am confused because rt_mutex_deadlock_account_lock is define at two places in the kernel:

In kernel/rtmutex-debug.c:

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

In kernel/rtmutex.h:

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

In new kernel 2.6.35.4 in the i2c driver rt_mutex_lock(&adap->bus_lock); has replaced the mutex_lock(). How does this lock then?

RBerteig
  • 41,948
  • 7
  • 88
  • 128
iSegFault
  • 947
  • 2
  • 9
  • 18
  • looks to me like it redefines that function to do nothing. – mpen Sep 22 '10 at 06:34
  • @Mark: Sounds convincing. ravspratapsingh: Have we got it right that for the two upper statements, there is really nothing between the braces? Or have you just simplified the code this way? – chiccodoro Sep 22 '10 at 06:44
  • possible duplicate of [What's the use of do while(0) when we define a macro?](http://stackoverflow.com/questions/923822/whats-the-use-of-do-while0-when-we-define-a-macro) – paxdiablo Sep 22 '10 at 07:02
  • 2
    @paxdiablo: the 'possible duplicate' isn't all that close; it discusses the `do ... while (0)`, but there the code has actions inside the loop body - unlike here. So this is somewhat different. – Jonathan Leffler Sep 22 '10 at 07:17
  • 3
    Its pretty clear to me that the kernel authors had some reason to want the macro to expand to more than just a completely empty expression, but making it expand to nothing or just a comment seems just as useful at first glance. In any case, it has caused the OP to question it when reading the kernel sources, and so I'd agree with @Jonathan that it is more about the lack of body then what the `do{}while(0)` means. – RBerteig Sep 22 '10 at 07:26
  • 1
    @chiccodoro : This is the original code piece from the kernel and nothing has been modified. My concern here is that when do-while(0) does nothing then how does it actually lock. – iSegFault Sep 22 '10 at 08:09
  • Actually, the duplicate _is_ close (in my opinion but I'm just one cell in the swarm). The idea is to be able to put `preempt_disable()` at any point in the code to provide a statement that does nothing. – paxdiablo Sep 22 '10 at 08:24

3 Answers3

12

See this link for a better explanation than I could give.

Justin
  • 84,773
  • 49
  • 224
  • 367
  • 2
    +1 Just to pop up one level of indirection, the first citation there answers the question: (from Dave Miller) Empty statements give a warning from the compiler so this is why you see `#define FOO do { } while(0)`. – Jens Gustedt Sep 22 '10 at 07:41
  • @justin and... the link is dead. If you can dig up mirror, please add the relevant information to your answer. – dandan78 Feb 08 '19 at 09:33
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.

Jason Williams
  • 56,972
  • 11
  • 108
  • 137
  • if `do {} while (0)` does nothing. Does the compiler generate garbage instructions because of it or the loop will be optimized out? – Zingam Jan 21 '16 at 11:00
  • 1
    Compilers have very good optimizers these days, so you are extremely unlikely to find one that wastes time on an obvious empty case like this. – Jason Williams Jan 21 '16 at 22:01
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.

Peter
  • 7,216
  • 2
  • 34
  • 46
  • Thanks, I understood how this preempt thing works but still confused about the mutex lock. Please see my reply about rt_mutex_lock – iSegFault Sep 22 '10 at 06:55
  • 1
    I assume the mutex lock is something similar - there is a "real" implementation and a "dummy" one that does nothing. Presumably in some cases the dummy one is used if the kernel is configured such that there's never any need for it - maybe if CONFIG_SMP is not enabled? – Peter Sep 23 '10 at 21:46