LINUX.ORG.RU

История изменений

Исправление 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;
}