Системный вызов
close. Раньше я думал, что для прикладной программы файл закрывается мгновенно, а далее система потихоньку освобождает системный буфер файлов, но выяснилось, что это не так. Минимальный пример. В качестве аргумента указать имя файла для копирования, он будет скопирован под именем "
test". Файл у меня 374 кб.
// gcc test.c -o test.cgi -Wall -Werror -O3
// ./test.cgi
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/time.h>
//------------------- gettime_dt_msek ----------------------
// разность двух временных меток в миллисекундах
int gettime_dt_msek(struct timeval *tv1, struct timeval *tv2)
{
return((tv2->tv_sec - tv1->tv_sec)*1000 +
(tv2->tv_usec - tv1->tv_usec + 500)/1000);
}
//--------- time_metka --------
// печатает метку времени. tv0 -начало отсчета времени.
void time_metka(struct timeval *tv0, const char *metka)
{
int t;
struct timeval tv1;
gettimeofday(&tv1, NULL);
t = gettime_dt_msek(tv0, &tv1);
printf("%s=%d.%03d sec\n", metka, t/1000, t%1000);
return;
}
//------------ main --------------
int main(int argc, char **argv)
{
struct timeval tv0[1];
int fd1, fd2, k, n;
char buf[8192];
if(argc<2){ printf("Err-arg\n"); exit(0);}
gettimeofday(tv0, NULL); // начало отсчета времени
fd1=open(argv[1], O_RDONLY);
if(fd1<0){ printf("fd1=open(%s)<0\n", argv[1]); exit(0);};
//unlink("test");
time_metka(tv0, "t1");
fd2=open("test", O_CREAT|O_TRUNC|O_WRONLY, 00644);
if(fd2<0){ printf("fd2=open()<0\n"); exit(0);};
time_metka(tv0, "t2");
while(1){
k=read(fd1, buf, sizeof(buf));
if(k<0){ printf("Error read\n"); exit(0);}
if(k==0) break;
n=write(fd2, buf, k);
if(n != k){ printf("Error write\n"); exit(0);}
}
time_metka(tv0, "t3");
close(fd1);
time_metka(tv0, "t4");
close(fd2);
time_metka(tv0, "t5");
exit(0);
}
/*
Тестовый файл для копирования 374 кб
Распечатка с закомментированным unlink.
Первый запуск, когда ещё нет выходного файла.
t1=0.000 sec
t2=0.000 sec
t3=1.182 sec
t4=1.182 sec
t5=1.182 sec
Следующие запуски.
t1=0.000 sec
t2=0.196 sec
t3=1.308 sec
t4=1.308 sec
t5=9.448 sec
Распечатка с раскомментированным unlink.
Первый запуск, когда ещё нет выходного файла.
t1=0.000 sec
t2=0.000 sec
t3=1.221 sec
t4=1.221 sec
t5=1.221 sec
Следующие запуски.
t1=0.208 sec
t2=0.209 sec
t3=1.395 sec
t4=1.395 sec
t5=1.395 sec
*/
В программе есть закомментированная строка
unlink, она существенно влияет. Имею пять меток времени. При распечатке отсчет от нулевой метки (
tv0).
Вопрос 1. Есть ли какое-нибудь объяснение этому явлению, почему так надолго подвисает
close, если файл уже существует и открыт с флагом
O_TRUNC, т. е. с опустошением? И зачем система его подвешивает?
Вопрос 2. Вызов
close может быть прерван сигналом с ошибкой
EINTR. Что при этом происходит? Немедленный возврат? А что с файлом, закрыт он или открыт? Или открыт наполовину? Не может же система так на половине всё бросить. Казалось бы, она должна тогда дозакрыть файл в фоновом режиме. Или же прикладная программа при получении
EINTR может дальше пользоваться этим файлом как открытым, включая повторный вызов
close?
Прошу ответить. Если можно, в общих чертах словами. Ссылки на английские тексты мне не прочитать.