Реализация перезапускаемого системного вызова

Если у меня есть часть кода драйвера likethis:

down_interruptible(&semA); //success
if(down_interruptible(&semB)) { //wait
   return -ERESTARTSYS;
}
up(&semA);
up(&semB);

Я прочитал, что если код драйвера возвращается -ERESTARTSYSУровень VFS может обрабатывать перезапуск системного вызова, не зная об этом пользователя. Но как насчет освобождения ресурсов, таких как блокировки, память и т. Д.? мы должны отменить их, прежде чем вернуться -ERESTARTSYS или ядро ​​справится с этим волшебно?

Например: должен ли выглядеть приведенный выше код?

down_interruptible(&semA); //success
if(down_interruptible(&semB)) { //wait
   up(&semA);
   return -ERESTARTSYS;
}
up(&semA);
up(&semB);

Я не уверен, что использование двух семафоров, как это нормально, но я упомянул это, чтобы понять концепцию. Если возможно, пожалуйста, укажите также реальный код в ядре Linux, где обрабатывается такой сценарий.

1 ответ

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

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


Распространенной схемой обработки ошибок является освобождение ресурсов в обратном порядке и использование ряда goto операторы, которые позволяют комбинировать нормальный и ошибочный пути выхода, что уменьшает количество ошибок:

int my_function(...)
{
    char *temp_buf;
    int err;

    err = -ENOMEM;
    temp_buf = kmalloc(123, GFP_KERNEL);
    if (!temp_buf)
        goto err_exit;

    err = -ERESTARTSYS;
    if (down_interruptible(&semA))
        goto err_free_temp;

    if (down_interruptible(&semB))
        goto err_unlock_A;

    strcpy(temp_buf, "do the needful ...");
    err = 0;

    up(&semB);
err_unlock_A:
    up(&semA);
err_free_temp:
    free(temp_buf);
err_exit:
    return err;
}
Другие вопросы по тегам