Реализация перезапускаемого системного вызова
Если у меня есть часть кода драйвера 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;
}