LINUX.ORG.RU

[СИ] close и сигнал.

 


0

1

[СИ] close и сигнал.

Язык СИ
ОС UNIX

Кусок кода:


start:
      ....

    k=close(fd);
    if(k<0) goto ERR; //--- close() может быть прерван SIGALRM ---
    fd=-1;
      ....
    goto start;

ERR:

    alarm(0);  // выключить сигнал
    if(fd>=0) close(fd);
    fd=-1;
    goto start;

Т. к. процесс бесконечный, то файл обязательно нужно закрыть.
Я догадываюсь, что если close() обрамить масками сигнала, то было бы хорошо.
Сработает ли это повторное закрытие?
Или непременно маски сигнала в главной ветке?

Можно расширить вопрос. Если close возвращает ошибку, любую,
то как избавиться от файла?


Т. к. процесс бесконечный, то файл обязательно нужно закрыть.

Ну, если вы завершите приложение, файл все равно закроется. Правда, если оно завершится аварийно, буферы скорее всего не сбросятся.

Если close возвращает ошибку, любую,

то как избавиться от файла?

Сделать unlink и завершить процесс.

Eddy_Em ☆☆☆☆☆
()

Простой способ: на все сигналы поставить флажок SA_RESTART. Если важно, чтобы сигналы могли обрывать сисколлы, то все такие сисколлы заворачивай в циклы:

while (close(fd) == -1 && errno == EINTR);

const86 ★★★★★
()
Ответ на: комментарий от const86

Eddy_Em
В приведенном коде SIGALRM просто сигнализирует, что время работы
с одним файлом истекло. Там где точки, на самом деле есть подвисающие
вызовы read и write из pipe-канала и сокета. Завершать процесс из-за
такого пустяка не желательно. Нужно просто как то закрыть этот файл
и перейти к следующему.

И под словом «избавиться от файла» я имею ввиду закрыть файл, чтоб не
накапливать открытые файлы. Процесс завершать не желательно.

const86
SA_RESTART помоему не годится. read и write должны прерываться без рестарта.
Цикл такой выглядит опасным на зацикливание. Ну пусть. Но тогда Вы косвенно
подтверждаете, что приведенный код с повторным close сработает?

oleg_2
() автор топика
Ответ на: комментарий от oleg_2

Кстати, мне вот что интересно: вы когда-нибудь натыкались на ситуацию, когда close не мог закрыть файл (кроме случайного прерывания этой операции сигналом)? А уж тем более - повторно?

Просто я даже не представляю, что же такого должно случится для этого...

Ну, а ежели close не сработал из-за проблем с ФС, то и демону нет смысла работать дальше

Eddy_Em ☆☆☆☆☆
()
Ответ на: комментарий от oleg_2

Цикл такой выглядит опасным на зацикливание. Ну пусть. Но тогда Вы косвенно подтверждаете, что приведенный код с повторным close сработает?

Циклить будет ровно до тех пор, пока сигналы будут лететь в процесс из пулемёта. Ему всё равно не до полезных дел будет :)
Про повторный close:

man

If close() is interrupted by a signal that is to be caught, it shall return -1 with errno set to [EINTR] and the state of fildes is unspecified.

Ну то есть, чёрт его знает. Если закроется, повторный close выдаст EBADF. Если прога многопоточная, можешь закрыть чужой дескриптор. В таком случае надо либо всё-таки включать рестарт, либо обрамлять pthread_sigmask'ом. Либо убедить себя, что данивжистьтакогонебудетмамойклянусь!

const86 ★★★★★
()
Ответ на: комментарий от Eddy_Em

Eddy_Em
«вы когда-нибудь натыкались на ситуацию, когда close не мог закрыть файл».

Нет, ни разу.
Я не знаю как проверить, может быть в демоне есть несколько не закрытых.

Конкретизирую вопрос: если close прерван сигналом и вызвать его повторно,
то сработает ли это? Закроется? Возвратит при повторном вызове 0?

«Ну, а ежели close не сработал из-за проблем с ФС, то и демону нет смысла работать дальше».

Согласен. Пока всё работает. До поры - до времени.
Может прав const86 в том, что проверять errno, и разделить все ошибки на
фатальные и не фатальные?

oleg_2
() автор топика
Ответ на: комментарий от oleg_2

У close(2) всего 3 варианта ненормального завершения. При EINTR следует повторить вызов, при EBADF спешно валиться, а при EIO сам решай, я бы повалился.

again:
if (0 != close(fd))
    switch (errno) {
        case EINTR: goto again;
        case EIO:
        case EBADF:
        default: abort();
    }
fd = -1;
arturpub ★★
()
Ответ на: комментарий от oleg_2

const86 абсолютно прав. Системный вызов может быть прерван сигналом. Аномально высокая частота сигналов не должна влиять на работу программы.

arturpub ★★
()
Ответ на: комментарий от Eddy_Em

вы когда-нибудь натыкались на ситуацию, когда close не мог закрыть файл

Есть такая распределенная файловая система: AFS (http://www.openafs.org). У нее семантика отличается от POSIX тем, что изменения в файле становятся видны остальным клиентам не после каждой операции write, а только после close. При этом, насколько я помню, если связь с сервером пропала в момент отправки модификаций в файле на сервер (в момент выполнения close), то close возвратит ошибку, пруфлинка по быстрому найти не удалось, но если интересно можешь почитать доки на http://www.openafs.org

Сделано это (синхронизация по close) для увеличения производительности, поскольку эта ФС позиционируется как ФС для глобальных сетей в отличии от NFS, например.

anonymous
()
Ответ на: комментарий от oleg_2

Конкретизирую вопрос: если close прерван сигналом и вызвать его повторно, то сработает ли это? Закроется? Возвратит при повторном вызове 0?

Если не схлопочет какую-нибудь другую ошибку или опять не будет сигнала, то закроет. Но я даже не представляю, что должно делать приложение, чтобы так часто ловить сигналы.

Eddy_Em ☆☆☆☆☆
()
Ответ на: комментарий от const86

По идее ось не должна выдавать дескриптор, для которого state теперь unspecified, так что насчет потоков, думаю, можно не переживать. К тому же ничего не говорится об операциях над такими дескрипторами. Наверное при EBADF тут стоит забить на него и двигаться дальше.

arturpub ★★
()
Ответ на: комментарий от arturpub

Спасибо всем за разъяснения.
Конкретно, однопотоковый процесс, обычный местный файл, и кроме того
pipe и сокет TCP. fd я написал для примера.
close(pipe) и close(сокет) я пока вообще не проверяю, т. к. они не там,
где может придти сигнал.

oleg_2
() автор топика
Ответ на: комментарий от arturpub

по ссылке arturpub

while (1) {
    if (close(fd) == -1) {
        if (errno == EINTR) continue;
        printf("Barf\n");
        exit(1);
    }
    break;
}

Это точно похоже на цикл const86. Но с учетом его разъяснения
«Если закроется, повторный close выдаст EBADF»,
и что я внимательный и не допускаю случайных плохих fd, можно так

k=0;
while (1) {
    if(k++ > 20) exit(1); // страховка. не верю, что никогда не зациклится
    if (close(fd) == -1) {
        if (errno == EINTR) continue;
        if (errno == EBADF) break;
        exit(1);
    }
    break;
}

Как я понимаю EBADF значит, что нет такого открытого файла, а это и нужно.

oleg_2
() автор топика
Ответ на: комментарий от anonymous

А чо, fsync() перед close() не помогает от зависания/падения на close() ?

mmarkk
()
Ответ на: комментарий от geekless

А «вдруг» fd - дескриптор, полученный из fileno()?

Если же мы не буферизуем ввод-вывод, то, понятное дело - проблем не будет. Т.к. буферизация на уровне ФС выполняется прозрачно и ядро точно сбросит эти буферы (если, конечно, reset или poweroff не нажать).

Eddy_Em ☆☆☆☆☆
()
Ответ на: комментарий от Eddy_Em

А «вдруг» fd - дескриптор, полученный из fileno()?

Если «вдруг», то программист вообще не имеет права делать close(fd).

geekless ★★
()
10 августа 2012 г.
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.