как работает {} while (0) в макросе?

Хотя эта тема много раз обсуждалась на этом форуме и на всех других форумах, все же у меня есть сомнения. Пожалуйста помоги.

Как работает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 в драйвере i2crt_mutex_lock(&adap->bus_lock); заменилmutex_lock(), Как это заблокировать тогда?

 paxdiablo22 сент. 2010 г., 09:02
 mpen22 сент. 2010 г., 08:34
мне кажется, что он переопределяет эту функцию, чтобы ничего не делать.
 Jonathan Leffler22 сент. 2010 г., 09:17
@paxdiablo: «возможный дубликат» не так уж и близок; это обсуждаетdo ... while (0), но там код имеет действия внутри тела цикла - в отличие от здесь. Так что это несколько другое.
 paxdiablo22 сент. 2010 г., 10:24
На самом деле, дубликатявляется близко (по-моему, но я всего лишь одна клетка в рое). Идея состоит в том, чтобы иметь возможность поставитьpreempt_disable() в любой точке кода, чтобы обеспечить утверждение, которое ничего не делает.
 RBerteig22 сент. 2010 г., 09:26
Мне совершенно ясно, что у авторов ядра были некоторые причины хотеть, чтобы макрос расширялся до большего, чем просто полностью пустое выражение, но на первый взгляд кажется, что его расширение ни к чему не приводит, или просто комментарий. В любом случае, это вызвало у ОП вопрос к нему при чтении исходных текстов ядра, и поэтому я согласен с @Jonathan, что речь идет скорее об отсутствии тела, чем о том, чтоdo{}while(0) средства.
 chiccodoro22 сент. 2010 г., 08:44
@Mark: звучит убедительно. ravspratapsingh: Правильно ли мы поняли, что для двух верхних утверждений между скобками действительно ничего нет? Или вы просто упростили код таким образом?
 iSegFault22 сент. 2010 г., 10:09
@chiccodoro: это оригинальный фрагмент кода из ядра, и ничего не было изменено. Меня беспокоит то, что когда do-while (0) ничего не делает, то как оно на самом деле блокируется.

Ответы на вопрос(3)

Решение Вопроса

для чего нужна конструкция do ... в то время как она делает макрос более безопасным в использовании.

Тем не менее, я не думаю, что это отвечает на вопрос «как это работает?»:

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

Макрос определен какничего не делать, Почему ты хочешь ничего не делать?

В некоторых случаях вы хотите использовать макрос в качестве заполнителя для выполнения каких-либо действий. Например, вы можете написать код в одной системе, где «preempt» не является проблемой, но вы знаете, что код может быть перенесен в систему, где «preempt» нуждается в особой обработке. Таким образом, вы используете макрос везде, где это требуется второй системе (чтобы потом было легко включить обработку), но для первой системы вы определяете этот макрос как пустой макрос.

В некоторых случаях вы можете захотеть сделать что-то вроде задачи, состоящей из разных частей (например, START_TABLE (); TABLE_ENTRY (1); TABLE_ENTRY (2); END_TABLE ();). Это делает хорошую чистую четкую реализацию вашего стола. Но затем вы обнаружите, что вам на самом деле не нужен макрос END_TABLE (). Чтобы сохранить клиентский код в чистоте, вы оставляете макрос определенным и просто определяете, что он ничего не делает. Таким образом, все ваши таблицы имеют END_TABLE, и код легче читать.

Подобный случай может возникнуть с двумя состояниями (включить / отключить), когда одному состоянию нужен макрос, чтобы что-то сделать, но другое состояние просто происходит по умолчанию, поэтому реализация одного состояния «пуста» - вы все равно используете макрос, потому что он делает клиентский код легче понять, потому что он явно указывает места, где все включено или отключено.

 Jason Williams21 янв. 2016 г., 23:01
В наши дни компиляторы имеют очень хорошие оптимизаторы, поэтому вы вряд ли найдете тот, который будет тратить время на очевидный пустой случай, подобный этому.
 Zingam21 янв. 2016 г., 12:00
еслиdo {} while (0) ничего не делает. Генерирует ли компилятор инструкции из-за этого или цикл будет оптимизирован?

чтобы они выглядели как обычные вызовы функций; Есть некоторые тонкие синтаксические проблемы вокруг несвязанных операторов if и тому подобного. Без do-while макрос может выглядеть как обычный вызов функции, но будет работать по-другому.

Я предполагаю, что в этом случае эти макросы используются, поэтому определенные вызовы функций компилируются в ничто; похоже, что это может быть то, что вы получите, еслиCONFIG_PREEMPT не был установлен, поэтому определенные части ядра, которые необходимы только для выгрузки, просто исчезают без него. Таким образом, эти циклы не отключают preempt или перепланировать что-либо; в другом месте исходного кода ядра будет другое определение (возможно, настоящая функция).

 iSegFault22 сент. 2010 г., 08:55
Спасибо, я понял, как работает эта упреждающая вещь, но все еще не понимал, что такое блокировка мьютекса. Пожалуйста, смотрите мой ответ о rt_mutex_lock
 Peter23 сент. 2010 г., 23:46
Я предполагаю, что мьютексная блокировка - нечто похожее - есть «реальная» реализация и «фиктивная», которая ничего не делает. Предположительно, в некоторых случаях используется фиктивный, если ядро ​​настроено так, что в этом нет необходимости - может быть, если CONFIG_SMP не включен?

эта ссылка для лучшего объяснения, чем я мог бы дать.

 Jens Gustedt22 сент. 2010 г., 09:41
+1 Просто для того, чтобы вызвать один уровень косвенности, первая цитата отвечает на вопрос: (от Дейва Миллера) Пустые операторы выдают предупреждение от компилятора, поэтому вы видите#define FOO do { } while(0).
 dandan7808 февр. 2019 г., 10:33
@ просто и ... ссылка мертва. Если вы можете выкопать зеркало, пожалуйста, добавьте соответствующую информацию в свой ответ.

Ваш ответ на вопрос