История изменений
Исправление firkax, (текущая версия) :
shm_open это считай почти алиас в openat() с базой /dev/shm/
Так что обращайся как с обычным файлом. Вобщем-то это файл и есть (в tmpfs смонтированном в /dev/shm). Можешь даже не пользоваться shm_open а смонтировать своё tmpfs в любое другое место и там их создавать - будет ровно то же самое.
Как сказать ядру удалить shm
Соответственно, ядро вообще не знает что там какие-то shm, для него это обычные файлы.
Могу предложить такой вариант
int shm_open_clean(char const *path, int mode) {
int e;
struct stat sb, sbf;
off_t fsz;
again:
if((fd = open(path, O_RDWR|O_CREAT, mode))<0) return -1;
if(flock(fd, LOCK_EX|LOCK_NB)>=0) {
/* это новый файл или же старый у которого исчезли все клиенты */
if((fsz=lseek(fd, 0, SEEK_END))<0) { e=errno; goto fail; }
if(fsz) {
unlink(path);
close(fd);
goto again;
}
} else if((e=errno)!=EWOULDBLOCK) goto fail;
/* 1) EXLOCK удался, и это был пустой (новый или старый) файл
2) EXLOCK не удался т.к. кто-то держит EXLOCK или SHLOCK
=> подождём владельца EXLOCK (если он есть) и перепроверим что файл не удалили;
надо учитывать что переход EXLOCK->SHLOCK не atomic и в середине есть момент где EXLOCK могут украсть */
while(flock(fd, LOCK_SH)<0) if((e=errno)!=EINTR) goto fail;
if(stat(path, &sb)<0) {
if((e=errno)!=ENOENT) goto fail;
/* файл удалён, идём в race с другим процессом за создание нового */
close(fd);
goto again;
}
if(fstat(fd, &sbf)<0) { e=errno; goto fail; }
if(sb.st_ino!=sbf.st_ino) {
/* файл удалён и уже пересоздан */
close(fd);
goto again;
}
/* файл открыт, не удалён, и им либо кто-то пользуется, либо он пустой */
return fd;
fail:
/* все непредвиденные проблемы сюда */
close(fd); errno=e; return -1;
}
(компилировать не пробовал, корректную работу на практике тем более не проверял, но вроде всё норм)
Исправление firkax, :
shm_open это считай почти алиас в openat() с базой /dev/shm/
Так что обращайся как с обычным файлом. Вобщем-то это файл и есть (в tmpfs смонтированном в /dev/shm). Можешь даже не пользоваться shm_open а смонтировать своё tmpfs в любое другое место и там их создавать - будет ровно то же самое.
Как сказать ядру удалить shm
Соответственно, ядро вообще не знает что там какие-то shm, для него это обычные файлы.
Могу предложить такой вариант
int shm_open_clean(char const *path, int mode) {
int e;
struct stat sb, sbf;
off_t fsz;
again:
if((fd = open(path, O_RDWR|O_CREAT, mode))<0) return -1;
if(flock(fd, LOCK_EX|LOCK_NB)>=0) {
/* это новый файл или же старый у которого исчезли все клиенты */
if((fsz=lseek(fd, 0, SEEK_END))<0) { e=errno; goto fail; }
if(fsz) {
unlink(path);
close(fd);
goto again;
}
} else if((e=errno)!=EWOULDBLOCK) goto fail;
/* 1) EXLOCK удался, и это был пустой (новый или старый) файл
2) EXLOCK не удался т.к. кто-то держит EXLOCK или SHLOCK
=> подождём владельца EXLOCK (если он есть) и перепроверим что файл не удалили;
надо учитывать что переход EXLOCK->SHLOCK не atomic и в середине есть момент где EXLOCK могут украсть */
while(flock(fd, LOCK_SH)<0) if((e=errno)!=EINTR) goto fail;
if(stat(path, &sb)<0) {
if((e=errno)!=ENOENT) goto fail;
/* файл удалён, идём в race с другим процессом за создание нового */
close(fd);
goto again;
}
if(fstat(fd, &sbf)<0) { e=errno; goto fail; }
if(sb.st_ino!=sbf.st_ino) {
/* файл удалён и уже пересоздан */
close(fd);
goto again;
}
/* файл открыт, не удалён, и им либо кто-то пользуется, либо он пустой */
return fd;
fail:
/* все непредвиденные проблемы сюда */
close(fd); errno=e; return -1;
}
(компилировать не пробовал, корректную работу тем более на практике не проверял, но вроде всё норм)
Исходная версия firkax, :
shm_open это считай почти алиас в openat() с базой /dev/shm/
Так что обращайся как с обычным файлом. Вобщем-то это файл и есть (в tmpfs смонтированном в /dev/shm). Можешь даже не пользоваться shm_open а смонтировать своё tmpfs в любое другое место и там их создавать - будет ровно то же самое.
Как сказать ядру удалить shm
Соответственно, ядро вообще не знает что там какие-то shm, для него это обычные файлы.
Могу предложить такой вариант
int shm_open_clean(char const *path, int mode) {
int e;
struct stat sb, sbf;
off_t fsz;
again:
if((fd = open(path, O_RDWR|O_CREAT, mode))<0) return -1;
if(flock(fd, LOCK_EX|LOCK_NB)>=0) {
/* это новый файл или же старый у которого исчезли все клиенты */
if((fsz=lseek(fd, 0, SEEK_END))<0) { e=errno; goto fail; }
if(fsz) {
unlink(path);
close(fd);
goto again;
}
} else if((e=errno)!=EWOULDBLOCK) goto fail;
/* 1) EXLOCK удался, и это был пустой (новый или старый) файл
2) EXLOCK не удался т.к. кто-то держит EXLOCK или SHLOCK
=> подождём владельца EXLOCK (если он есть) и перепроверим что файл не удалили;
надо учитывать что переход EXLOCK->SHLOCK не atomic и в середине есть момент где EXLOCK могут украсть */
while(flock(fd, LOCK_SH)<0) if((e=errno)!=EINTR) goto fail;
if(stat(path, &sb)<0) {
if((e=errno)!=ENOENT) goto fail;
/* файл удалён, идём в race с другим процессом за создание нового */
close(fd);
goto again;
}
if(fstat(fd, &sbf)<0) { e=errno; goto fail; }
if(sb.st_ino!=sbf.st_ino) {
/* файл удалён и уже пересоздан */
close(fd);
goto again;
}
/* файл открыт, не удалён, и им либо кто-то пользуется, либо он пустой */
return fd;
fail:
/* все непредвиденные проблемы сюда */
close(fd); errno=e; return -1;
}