LINUX.ORG.RU

Как сказать ядру удалить shm, если ВСЕ замапившие его процессы сдохли (SIGKILL)?

 ,


0

2

…причём сдохли ДО того как вызвали shm_unlink(). В этом случае мне нужно чтобы вновь запущенная куча процессов получила новую чистую память, а не старое состояние.

НЯП вызывать shm_unlink() сразу после mmap() нельзя: если после shm_unlink() другой процесс вызовет shm_open() с этим же именем, он получит другую область памяти.

Пишут, что в старом API (shmget(), …) это делается через shmctl(). Причём по дефолту там как раз нужное мне поведение, что есть правильно с т.з. защиты от race: SIGKILL может прилететь до shmctl(). …Хотя как-то мутно, в соседнем же каменте пишут наоборот, а по man shmctl вообще ни хрена не понятно.

А в новом API походу никак?

★★★★★

Последнее исправление: dimgel (всего исправлений: 4)
Ответ на: комментарий от utf8nowhere

Не, изолированные деревья процессов – это перебор, в моём случае это из пушки по воробьям. И для разработчика, и для юзера. Тем более что я вообще .so-шку пишу для чужого процесса.

dimgel ★★★★★
() автор топика
Последнее исправление: dimgel (всего исправлений: 1)

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 ★★★★★
()
Последнее исправление: firkax (всего исправлений: 2)

А в новом API походу никак?

Оно конечно хронологически новее, но что-то с этой фразой не так. Скорее «альтернативное».

Хотя как-то мутно, в соседнем же каменте пишут наоборот, а по man shmctl вообще ни хрена не понятно.

Там вообще всё мутно, что в sysv shm что в posix shm. Сплошные утечки данных/race/невозможность адекватной координации. Без костылей (как см. выше) не обойтись. Ну или можно забить на это (как все и делают) и просить юзера вручную фиксить при проблемах или перезапускать комп.

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

Ну или можно забить на это (как все и делают) и просить юзера вручную фиксить при проблемах или перезапускать комп.

Соответствующая инструкция для юзера уже написана. :) Но мечталось как-то по-людски. :(

Вообще, как вспоминаю, что в лялихе нету даже банального атомарного open+lock, так и хочется выйти на улицу и крикнуть на всю округу: что ж вы, тридварасы, виндовс-то ругаете?!

dimgel ★★★★★
() автор топика
Последнее исправление: dimgel (всего исправлений: 1)
Ответ на: комментарий от dimgel

Не, изолированные деревья процессов – это перебор, в моём случае это из пушки по воробьям.

Не знаю, насколько Вам это поможет (или подходит): мы тупо SHM чистим раз в неделю во время «глобального» рестарта. Решает кучу проблем, включая left-overs after resize. И в целом я не уверен что Вы реально хотите грохать SHM segments по последнему detach: там вполне себе могут быть ещё незапроцешенные данные.

bugfixer ★★★★★
()
Последнее исправление: bugfixer (всего исправлений: 2)
Ответ на: комментарий от bugfixer

Не знаю, насколько Вам это поможет (или подходит): мы тупо SHM чистим раз в неделю во время «глобального» рестарта.

В принципе, это то же самое, что @firkax сказал: «Ну или можно забить на это (как все и делают) и просить юзера вручную фиксить при проблемах или перезапускать комп.» Иногда самое дурацкое решение – самое правильное. По совокупности, так сказать, факторов.

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

В принципе, это то же самое, что @firkax сказал: «Ну или можно забить на это (как все и делают) и просить юзера вручную фиксить при проблемах или перезапускать комп.»

Не совсем. Речь идёт о полностью автоматизированном scheduled weekly maintenance, вмешательства «ручками» извне (а также наличия «проблем» как таковых) не предполагающем, ровно как и reboot’а машинок.

Иногда самое дурацкое решение – самое правильное.

Я бы сказал - самое простое, и как следствие - самое надёжное.

bugfixer ★★★★★
()
Последнее исправление: bugfixer (всего исправлений: 1)
9 января 2024 г.
Ответ на: комментарий от timdorohin

Делать unlink в момент запуска чтоб гарантированно потереть старое?

В общем, в итоге к этому и пришёл: чищу в мастер-процессе перед форками воркеров.

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

Запишу себе TODO поизучать, но на ближайшее обозримое будущее – поздняк метаться. В любом случае, спасибо.

dimgel ★★★★★
() автор топика
Последнее исправление: dimgel (всего исправлений: 1)