При помощи этого макроса код ядра переводит текущий выполняемый процесс в режим ожидания в очереди wq до тех пор, пока не будет удовлетворено заданное условие condition (которое может быть произвольным выражением).
Если условие истино, процесс не должен ожидать.
В противном случае процесс будет находиться в состоянии ожидания до тех пор, пока условие не станет истинным. Это завершается обращением к __wait_event (строка ). Поскольку __wait_event отделено от wait_event, фрагменты кода ядра, которым известно, что условие ожидания ложно, могут вызывать __wait_event напрямую, а не через макрос. В данном случае макрос выполняет избыточную проверку. Если условие истино, wait_event пропускает код, помещающий процесс в очередь ожидания.
Код wait_event заключен в несколько необычную конструкцию:
do { /* . . . */ } while (0)
Этот небольшой трюк не настолько хорошо известен, как он того заслуживает. Идея состоит в том, чтобы заставить помещенный внутрь конструкции код действовать подобно одному оператору. Рассмотрим следующий макрос, который вызывает free, если p является ненулевым указателем:
#define FREE1(p) if (p) free(p)
Все хорошо до тех пор, пока FREE1 не будет задействован в ситуации наподобие:
if (expression) FREE1(p); else printf ("expression ложно.\n");
После разворачивания макроса FREE1 конструкция else ассоциируется не с тем if (т.е. с if относящимся к FREE1).
Я наблюдал, как некоторые программисты так решали подобную проблему:
#define FREE2(p) if (p) { free(p); } #define FREE3(p) { if (p) { free(p); } }
Ни одно из вышеприведенных решений нельзя считать удовлетворительным— точка с запятой, которую программист естественно ставит после вызова макроса, портит разворачиваемый текст. Возьмите, к примеру, FREE2. После разворачивания макроса и добавления отступов для лучшего чтения компилятор получит такой текст:
if (expression) if (p) { free(p); } ; else printf("expression ложно.\n");
Результат — синтаксическая ошибка, поскольку else не связан ни с одним if. Аналогичная проблема имеет место и с FREE3. После некоторых размышлений становится ясно, что абсолютно неважно, есть ли if внутри тела макроса. Ту же проблему можно получить и в результате заключения тела макроса в скобки, причем неважно, что находится внутри макроса.
Вот почему применяется трюк с do/while(0). Посмотрите на макрос FREE4, свободный от описанных выше проблем: