Estou usando bloqueios de propriedade da Open File Description (OFD) no Linux ( fcntl
com o comando F_OFD_SETLK
). Depois de bloquear um arquivo, mapeei-o na memória e fechei o descritor de arquivo. Outro processo tentou bloquear o mesmo arquivo e não conseguiu até que o primeiro processo desmapeou a memória. Parece que o Linux, pelo menos, mantém uma referência à descrição do arquivo aberto quando um mapeamento ainda está ativo.
Documentos POSIX.1-2024 que mmap
adicionam uma referência ao "arquivo associado ao descritor de arquivo".
A função mmap() deve adicionar uma referência extra ao arquivo associado ao descritor de arquivo fildes que não é removido por um close() subsequente naquele descritor de arquivo. Essa referência deve ser removida quando não houver mais mapeamentos para o arquivo.
Uma interpretação literal aqui significaria que a referência é ao arquivo em si, mas não sei se essa era a intenção quando a documentação foi escrita.
Gostaria de poder confiar nesse comportamento. Há algum lugar no POSIX onde está especificado que estou faltando? Isso pode ser um relatório de defeito? Se for exclusivo do Linux, há alguma referência em algum lugar de que esse era o comportamento pretendido (e, possivelmente, sua interpretação do padrão POSIX)?
Programa de teste (pode exigir macros de teste de recursos diferentes em outras plataformas):
#define _GNU_SOURCE
#include <fcntl.h>
#include <sys/mman.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main()
{
char filename[] = "/tmp/ofd-test.XXXXXX";
int fd = mkstemp(filename);
if (fd < 0) {
perror("mkstemp");
return 1;
}
fprintf(stderr, "created file '%s'\n", filename);
struct flock lock = {
.l_len = 0,
.l_pid = 0,
.l_whence = SEEK_SET,
.l_start = 0,
.l_type = F_WRLCK,
};
if (fcntl(fd, F_OFD_SETLK, &lock) < 0) {
perror("first lock");
return 1;
}
void *ptr = mmap(0, 1024, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
if (ptr == MAP_FAILED) {
perror("mmap");
return 1;
}
close(fd);
int newfd = open(filename, O_RDWR);
if (newfd < 0) {
perror("re-open");
return 1;
}
lock.l_pid = 0;
if (fcntl(newfd, F_OFD_SETLK, &lock) == 0) {
fputs("locking after mmap worked\n", stderr);
return 1;
}
perror("locking after mmap");
munmap(ptr, 1024);
lock.l_pid = 0;
if (fcntl(newfd, F_OFD_SETLK, &lock) < 0) {
perror("locking after munmap");
return 1;
}
fputs("locking after munmap worked\n", stderr);
if (unlink(filename) < 0) {
perror("unlink");
return 1;
}
return 0;
}
Para mim, isso resulta em:
created file '/tmp/ofd-test.Pyf3oj'
locking after mmap: Resource temporarily unavailable
locking after munmap worked
Um descritor de arquivo é uma referência a um arquivo aberto.
A contagem de referências é mantida no próprio arquivo, não nos descritores.
Ele
mmap
gera outra referência, mas ela não precisa ser anexada a um descritor — basicamente, o único estado que um descritor tem é seu número e o sinalizador close-on-exec, e nenhum dos dois é necessário para uma área mapeada.A
dup(2)
página do manual dizEntão sim, esse comportamento é esperado.