netlib.narod.ru< Назад | Оглавление | Далее >

Идиомы кода ядра

Код ядра демонстрирует ряд выдающихся идиом, часть из которых обсуждаются в этом разделе. Во время чтения кода ядра важно не столько понимание собственно идиом, а только тот факт, что они существуют и непротиворечиво применяются. Во время написания кода для ядра необходимо знать, какие идиомы используются ядром, и применять их в собственном коде.

Я дал идиомам имена, поэтому мне теперь проще о них говорить. Однако имена эти мои, и даны они только в интересах обсуждения. На практике мало кто явно ссылается на идиомы. Они — суть способ, в соответствии с которым ядро выполняет свою работу.

Одна общая идиома — это та, которую я называю идиома накопления ресурсов (resource acquisition idiom). В соответствии с этой идиомой, некоторая функция должна получать последовательность ресурсов — память, блокировки и т.д. Функция перейдет к получению следующего ресурса только после того, как будет успешно получен текущий ресурс. В конечном итоге, функция должна освободить все накопленные ресурсы и не предпринимать попытки освобождать те, при получении которых возникшли ошибки.

Идиома накопления ресурсов была показана в композиции с идиомой переменной ошибки (error variable idiom), которая предполагает использование временной переменной для записи возвращаемого из функции значения. Разумеется, множество функций делают это — тем-то и известна идиома переменной ошибки, когда некая переменная ошибки приеняется для того, чтобы справиться с управлением потоком, усложненным ради достижения высокой скорости. Значение переменной ошибки — либо 0 (успешное выполнение), либо отрицательная величина (ошибка). Рассмотренные две идиомы переходят из рук в руки, естественно приводя к коду, шаблон которого показан ниже:

int f(void)
{
    int err;
    resource * r1, * r2;
    err = -ERR1;    /* Предположить ошибку */
    r1 = acquire_resource1();
    if (!r1)        /* Ресурс не получен */
        goto out;   /* Вернуть -ERR1 */
    /* Получили ресурс r1; запрашиваем r2 */
    err = -ERR2;    /* Предположить ошибку */
    if (!r2)        /* Ресурс не получен */
        goto out1;  /* Вернуть -ERR2 */
    /* Получили ресурсы r1 и r2 */
    err = 0;        /* Ошибок нет */

    /* . . . Используем r1 и r2 . . . */

out2:
    release_resource(r2);
out1:
    release_resource(r1);
out:
    return err;
}

Следует заметить, что уже само по себе существование переменной err указывает на присутствие идиомы переменной ошибки. Аналогично, имена меток out, out1, out2 непосредственно связаны с идиомой накопления ресурсов.

Всякий раз, когда достигается метка out2, r1 и r2 уже получены и должны быть освобождены. Всякий раз когда достигается метка out1 (либо строка за строкой, либо через goto), r2 — недоступен (возможно, r2 освобожден), но r1 — занят и должен быть освобожден. Аналогично, при достижении метки out, r1 и r2 освобождены, а err содержит код ошибки либо успешного завершения.

В рассмотренном примере не все присваивания err являются необходимыми. Реальный код следует приведенному шаблону, однако с некоторыми изменениями. Как показывают исследования, многие строки кода возвращают одно и то же значение ошибки, поэтому гораздо проще установить это значение один раз. В показанном выше примере преследовались чисто иллюстративные цели, реальный же пример кода подобного рода можно найти в функции sys_shmctl (строка 21654) в главе 9.


netlib.narod.ru< Назад | Оглавление | Далее >

Сайт управляется системой uCoz