The OpenNET Project / Index page

[ новости /+++ | форум | теги | ]




Версия для распечатки Пред. тема | След. тема
Новые ответы [ Отслеживать ]
Завершение дочерних процессов 2 уровня, !*! Аноним, 13-Май-20, 01:56  [смотреть все]
Подскажите, как лучше его организовать? Ситуация следующая: дети запускаются фоном, после чего они рождают ещё детей. Мне нужно всех их вырезать, потому что, если их не прибить собственноручно, они остаются жить навсегда. Добился нужного через pkill -g $$ в конце (повесил на выход), но возникают определённые подозрения (в частности в связи с тем, что при самоубийстве в баше не появляется приглашение, видимо фишка баша для провисших дескрипторов) или же вообще ломается любой ввод (он не отображается). Я так понял, это вообще проблема, в линуксе нельзя просто взять и узнать, кого мы родили. Мне только pstree -p $bgjobpid показывает, что там кто-то где-то висит во внучках (он обходит всех на предмет родителей?), разбирать выхлоп pstree чёт видится извратом. Вообще, в интернете обещали и что pkill -P $$ будет достаточно, да только дети детей то остаются!

Суть дела: мне нужно убить всех детей вместе с их детьми средствами, доступными родителю, в идеале получить перечень пидов и их перебить. Я могу получить пид мейна, скажем, через ppid/pgrp/tpgid, или даже того, кто запускал (баш) из sid, но я не могу получить перечень порождённых процессов и желательно перебить их всех по цепочке? Если не останавливать фоновый процесс через прямое убийство (что я делал изначально, поскольку я прекрасно вижу его в мейне), он вместе со всеми порождёнными (уже не видимыми мне) им переходит под инит при завершении. Если останавливать, порождённые им процессы остаются висеть (под инитом). Пробовал уже по-всякому, и kill, и pkill, и всё остальное, но внучки остаются недосягаемыми.

Из информации, полученной со стаковерфлоу, я сделал вывод, что единственный выход тут, это использовать неймспейс (и грохать его). Так ли это? Как же живут пользователи других систем?

И я смотрю unshare с --kill-child=sigkill как-то странно реагирует на ^C -- я так понимаю ему прилетает kill и sigint не доходит до приложения, в следствии чего я не могу обработать этот кейс в коде -- всё слишком быстро умирает. Или даже не так, но умирает всё равно раньше, чем я успеваю почистить файлы в перехватчике int. А с другими сигналами kill-child (term,int), всё умирает, но приглашение не появляется. Т.е. неймспейсы тут не подходят.

Это конечно хорошо, что мой код работает, но плохо, что я его не понимаю. Чем мне грозит pkill -g $$ на практике? Видимых проблем я не вижу, всё в полном порядке, вот только провисшие дескрипторы меня пугают.

  • Завершение дочерних процессов, !*! Аноним, 03:02 , 13-Май-20 (1)
    Что-то не то с порядком исполнения, или же временем? Если на exit повешено несколько действий, прилетает sigterm. Если там один pkill -g $$, всё нормально завершается. повесил новую ловушку на выход в ловушке на выход. Что-то странное, я всё чаще начинаю замечать, что не понимаю, почему мой баш работает и как он это делает.
  • Завершение дочерних процессов, !*! Аноним, 07:19 , 13-Май-20 (2) +1
    Да тебе бы сценарии к триллерам писать, а не вот это вот всё) ))
  • Завершение дочерних процессов, !*! eRIC, 13:32 , 13-Май-20 (3) +1
    предлагаю название темы поменять, потому-что по таким словам как: "убийство внучек", "суицид" ресурс OpenNet не забанили
  • Завершение дочерних процессов 2 уровня, !*! Аноним, 14:39 , 13-Май-20 (4)
    > Ситуация следующая: дети запускаются фоном, после чего они рождают ещё детей.

    Породив внуков, дети завершаются или остаются жить? Тут нужно либо обучить детей передавать прилетающие SIGTERM'ы и SIGINT'ы внукам (см. встроенные в bash команды trap и jobs), либо как-то передавать список внуков родителю.

    > что единственный выход тут, это использовать неймспейс (и грохать его).

    В Linux ещё control groups, и они, как мне представляется, более подходят к данному случаю.

    • Завершение дочерних процессов 2 уровня, !*! Аноним, 17:22 , 13-Май-20 (5)
      Они живут пока мамка жива, если мейн сворачивается по любой из причин внучки должны быть завершены сразу после детей (чтобы детям от них данные не попали и не было гонки). С внучками ещё проблема в том, что они даже не баш и не могут реагировать на изменения предка.

      Я попробовал навесить трапов на фоновый жоб, так я всё равно не могу узнать кого мы родили и там! И начинается вообще какая-то дичь, которую я не могу контролировать (сейчас хотя бы порядок срабатывания обработчиков не нарушается, всё разруливается в мейне имеющем все необходимые данные). У меня нет доступа в детях к внучкам, потому что дети ждут пока внуки завершатся или умрут (это даже не важно, что из двух) и это событие тригеррит детей, которые после этого обрабатывают полученные данные и взаимодействуют с мейном (через файл на диске, угу).

      Я так понимаю для работы с cgroups мне понадобится модификация системы и суидные рутовые бинарники? Потому что неймспейсы могут быть пользовательскими (чем весь софт вроде браузеров пользуется и суидные песочницы это вроде как уже не модно), а cgroups от пользователя можно как-то управлять исключительно через systemd,

      • Завершение дочерних процессов 2 уровня, !*! Аноним, 20:38 , 13-Май-20 (6)
        > У меня нет доступа в детях к внучкам, потому что дети ждут пока внуки завершатся или умрут

        Дети — bash? Внуков можно запускать в фоновом режиме (команда &), тогда доступ к ним остаётся. Также можно ждать завершения фоновых процессов встроенной командой wait.

        Bash, кстати, при получении SIGTERM'а автоматически передаёт его всем фоновым потомкам.

        > Я попробовал навесить трапов на фоновый жоб, так я всё равно не могу узнать кого мы родили и там!

        jobs выдаёт список фоновых процессов, не?

        > Я так понимаю для работы с cgroups мне понадобится модификация системы и суидные рутовые бинарники?

        Достаточно systemd-run или пользовательской сессии systemd. Возможно, эту всю скриптоту удобнее писать не на bash'е, а на юнитах systemd.

        • Завершение дочерних процессов 2 уровня, !*! Аноним, 21:19 , 13-Май-20 (7)
          Вот пример кода:

          EXBGFILE=$(mktemp -p /dev/shm/ --suffix=wdfile)

          sendvalue() {
            echo "${1}">${EXBGFILE}
          }
          readvalue() {
            echo "$(<${EXBGFILE})"
          }
          sendvalue 0

          bgloop() {
            while sleep 9 & wait; do
              echo "exec"
              var=$(readvalue)
              echo "${FUNCNAME} read:${var}"
            done
          }

          bgloop &
          bgjob=$!
          trap "kill '$bgjob'; rm -v -- '${EXBGFILE}'" EXIT

          echo `jobs -l`
          echo `jobs -p`
          sendvalue 2
          sleep 10
          sendvalue 5
          sleep 10
          sendvalue 9
          sleep 10
          sendvalue 11
          echo done

          Если я посылаю ^C скрипту, sleep 9 переходит под инит до завершения (kill останавливает только фоновый жоб и sleep никак не остановить). Сейчас я вешаю такую конструкцию на завершение мейна, чтобы убить себя, и при этом прилетало и внучке. У меня есть ощущение, что лучше обойтись без самоубийства (остановки группы процессов, к которой принадлежат все порождённые процессы включая мейн).

          trap "kill '$bgjob'; rm -v -- ${EXBGFILE}; trap 'pkill -g $$' EXIT;" EXIT;

          При этом kill '$bgjob' (как и jobs -p в мейне) вообще не надёжная тема, процесса может и не оказаться, если мы дёргаем sigint, и тогда килл жалуется, мол, но сач процесс. Однако, pkill -g $$ всегда завершает всех без эксцессов (при таком использовании -- если в trap exit что-то постороннее, прилетает terminated).

          • Завершение дочерних процессов 2 уровня, !*! Аноним, 21:24 , 13-Май-20 (8)
            Ой я имел в виду у меня конечно sigint отдельно, всё равно после завершения остаются висеть под мейном. Я запустил этот пример, и у меня слипы плодятся несколько раз, но последний переходит под инит и висит до завершения и вот он-то мне и нужен исчезнувшим сразу.
          • Завершение дочерних процессов 2 уровня, !*! Аноним, 21:55 , 13-Май-20 (10)
            Нужно сделать ещё один trap в bgloop():

            #!/usr/bin/env bash
            trap 'kill %' EXIT

            bgloop() {
                trap 'kill %' EXIT
                while sleep 10 & wait; do
                    :
                done
            }
            bgloop &
            wait


            Так при прибитии родителя прибиваются также все дети.
            • Завершение дочерних процессов 2 уровня, !*! Аноним, 22:25 , 13-Май-20 (11)
              Похоже, то что нужно, спасибо. Только всё ещё не понятно, почему $bgjob и jobs -p сообщают о процессе, который не существует с точки зрения kill при sigint. Он исчезает из-за sigint? И как мне его останавливать тогда, если для мейна его уже нет из-за sigint? Он может и быть, а может и не быть. Неприятненько, куда лучше, когда код без плавающих багов.
              • Завершение дочерних процессов 2 уровня, !*! Аноним, 12:11 , 14-Май-20 (13)
                > почему $bgjob и jobs -p сообщают о процессе, который не существует с точки зрения kill при sigint.
                > Он может и быть, а может и не быть..

                Сейчас проверил, своим потомкам, если это не внешние программы, bash пересылает сигналы завершения сам автоматически, т.е. в коде #10 первый trap излишен, а $bgjob из #7, видимо, был прибит до вызова kill.

                > Если отправлять pkill -g $$ в мейне, то bgloop получает только int (не term) и до обработчика exit дело не доходит.

                trap ... EXIT срабатывает и на INT (который также прилетает по ctrl+c), и на TERM.

                > смерть не мгновенная?

                Естественно: используемые сигналы можно перехватить и обработать. Нельзя обработать KILL, SEGV и некоторые другие.

                • Завершение дочерних процессов 2 уровня, !*! Аноним, 17:14 , 14-Май-20 (14)
                  > Сейчас проверил, своим потомкам, если это не внешние программы, bash пересылает сигналы
                  > завершения сам автоматически, т.е. в коде #10 первый trap излишен, а
                  > $bgjob из #7, видимо, был прибит до вызова kill.

                  1 trap там не излишен, он вообще не работает -- bgloop переходит под инит и остаётся висеть. Он должен быть заменён на

                  bgloop &
                  trap "kill $!" EXIT

                  Тогда работает, но только если bgloop остановлен kill (sigterm) в мейне. Если bgloop прерывается sigint (что происходит не каждый раз)

                  >> Если отправлять pkill -g $$ в мейне, то bgloop получает только int (не term) и до обработчика exit дело не доходит.
                  > trap ... EXIT срабатывает и на INT (который также прилетает по ctrl+c),
                  > и на TERM.

                  срабатывает, только exit отдельно стрелял после int при нажатии ^C, теперь только на int. Я уже сталкивался с тем, что простые примеры ведут себя не так, как чуть более сложные (из-за разного времени реакции системы надо полагать)

                  >> смерть не мгновенная?
                  > Естественно: используемые сигналы можно перехватить и обработать. Нельзя обработать KILL,
                  > SEGV и некоторые другие.

                  Дело не в обработке, я опасаюсь, что возникнет гонка из-за задержки между отправкой сигнала и реакцией на него. В примере из #10 bgloop дети переходят под мейн и продолжают работать бесконечно . И мне не надо bgloop& wait, мне надо чтобы он работал параллельно, в #10 мы в мейне ждём завершения фонового процесса, которое не случится пока мы не прервём. Мейн должен работать и передавать данные в bgloop, я ведь не зря привёл такой пример в #7.

                  • Завершение дочерних процессов 2 уровня, !*! Аноним, 20:25 , 14-Май-20 (15)
                    > И мне не надо bgloop& wait, мне надо чтобы он работал параллельно, в #10 мы в мейне ждём завершения фонового процесса, которое не случится пока мы не прервём.

                    В #10 главный скрипт завершается до завершения bgloop'а, в этом проблема. Мэйн должен либо что-то делать, либо ждать завершения детей, но не завершаться сам. Можно запихнуть wait в конец, после кормёжки детей данными, это спасёт от состояния гонки.

                    • Завершение дочерних процессов 2 уровня, !*! Аноним, 20:05 , 15-Май-20 (16)
                      Поэтому я и пытаюсь их прибить до выхода, но я даже не знаю кого. Думал на тему того, чтобы передавать пиды внучек через диск. но что-то и так уже слишком много файлов генерирую. Попробовал повесить wait на sigexit в мейне, что-то эксперименты не увенчались успехом и bgloop замечательно продолжает жить отдельно после нормального завершения мейна. Но sigint останавливает, это да.
                      • Завершение дочерних процессов 2 уровня, !*! Licha Morada, 21:19 , 15-Май-20 (17)
                        > Поэтому я и пытаюсь их прибить до выхода, но я даже не
                        > знаю кого.

                        Можно поддержиавать в актуальном состоянии список всех детей.
                        После каждого порождения, добавлять его PID в список:
                        CHILDERN_PIDS="$CHILDERN_PIDS $!"
                        https://stackoverflow.com/questions/2618403/how-to-kill-all-...

                        Можно узнавать список "всех детей" непосредственно перед прибиванием.
                        CHILDERN_PIDS=$(ps -o pid= --ppid $$)

                        Потом по CHILDERN_PIDS можно итерировать в простом цикле for.
                        Делать отдельно в каждом поколении в отношении непосредственных детей, либо рекурсивно из "дедушки".
                        Тут хорошо описанно:
                        https://unix.stackexchange.com/questions/124127/kill-all-des...

                        Должно работать если:
                        1. Дети есть строго дети, в терминах иерархии процессов, а не демонизированные сироты.
                        2. Дети успевают сделать что-то осмысленное после того как их прибивают и до, собственно, умирания.
                        Рекурсия из дедушки, в отличии от отдельной итерации в каждом поколении, смягчает ограничение 2.


                        > Думал на тему того, чтобы передавать пиды внучек через
                        > диск. но что-то и так уже слишком много файлов генерирую.

                        Не такой уж и порочный путь. Если написать некий диспетчер для отслеживания всего дерева, то можно будет отличать служебные файлы от временных данных и бардак станет более контролируемым.


                      • Завершение дочерних процессов 2 уровня, !*! Аноним, 02:11 , 19-Май-20 (18)
                        > sigexit

                        Нет такого сигнала. EXIT — это обобщение bash'а для обработки сигналов, по которым он должен завершаться, а также нормального его завершения.

                        Но я не пойму, зачем вешать wait в trap, когда его можно разместить в конце программы.

            • Завершение дочерних процессов 2 уровня, !*! Аноним, 22:57 , 13-Май-20 (12)
              Заметил что при таком использовании работает корректно, только если в bgloop прилетают оба сигнала (sigint и sigkill), если kill $bgpid не отправлять из мейна (выходе), то фоновый процесс останется висеть и вместе с внучками перейдёт под инит. Или он может остановится sigint, и тогда из мейна его уже не убить на выходе. Если отправлять pkill -g $$ в мейне, то bgloop получает только int (не term) и до обработчика exit дело не доходит. Кроме того, 1 раз я успел заметить, что внучка перед смертью переходит под инит (в принципе это не плохо), это значит смерть не мгновенная?
  • Завершение дочерних процессов 2 уровня, !*! user user, 15:24 , 20-Май-20 (19)
    чисто из любопытства, какой сценарий привел победе fork на pthread_create?



Партнёры:
PostgresPro
Inferno Solutions
Hosting by Hoster.ru
Хостинг:

Закладки на сайте
Проследить за страницей
Created 1996-2024 by Maxim Chirkov
Добавить, Поддержать, Вебмастеру