Perché i processi generati dalla fine cron fino defunta?
-
19-09-2019 - |
Domanda
Ho alcuni processi che mostrano come <defunct>
in top
(e ps
). Ho bollito le cose dagli script e programmi reali.
Nel mio crontab
:
* * * * * /tmp/launcher.sh /tmp/tester.sh
Il contenuto di launcher.sh
(che è ovviamente segnati eseguibile):
#!/bin/bash
# the real script does a little argument processing here
"$@"
Il contenuto di tester.sh
(che è ovviamente segnati eseguibile):
#!/bin/bash
sleep 27 & # the real script launches a compiled C program in the background
ps
mostra quanto segue:
user 24257 24256 0 18:32 ? 00:00:00 [launcher.sh] <defunct>
user 24259 1 0 18:32 ? 00:00:00 sleep 27
Si noti che tester.sh
non appare -. Che è uscito dopo il lancio del processo in background
Perché launcher.sh
restare, segnato <defunct>
? Sembra solo per fare questo quando lanciato da cron
-. Non quando l'eseguo io
Nota aggiuntiva: launcher.sh
è uno script comune nel sistema gira su questo, che non è facilmente modificabile. Le altre cose (crontab
, tester.sh
, anche il programma che ho eseguito, invece di sleep
) possono essere modiified molto più facilmente.
Soluzione
Perché non sono stati oggetto di una chiamata di sistema wait(2)
.
Dal momento che qualcuno potrebbe aspettare che questi processi in futuro, il kernel può non completamente sbarazzarsi di loro o non sarà in grado di eseguire la chiamata di sistema wait
perché non avrà lo stato di uscita o la prova della sua l'esistenza di più.
Quando si avvia uno dalla shell, la shell è intrappolando SIGCHLD e facendo varie operazioni di attesa comunque, quindi niente rimane defunta per lungo tempo.
Ma cron non è in uno stato di attesa, si sta dormendo, in modo che il bambino defunta può restare per un po 'fino a quando si sveglia cron.
Aggiornamento: In risposta a commentare ... Hmm. Sono riuscito a duplicare il problema:
PPID PID PGID SESS COMMAND
1 3562 3562 3562 cron
3562 1629 3562 3562 \_ cron
1629 1636 1636 1636 \_ sh <defunct>
1 1639 1636 1636 sleep
Quindi, quello che è successo è stato, penso:
- forchette cron e bambino cron avvia shell
- shell (1636) inizia a sid e pgid 1636 e comincia il sonno
- shell uscite, SIGCHLD inviati a cron 3562
- segnale viene ignorato o utilizzata in maniera impropria
- shell gira zombie. Si noti che il sonno è reparented a init, in modo che quando il sonno esce init ottenere il segnale e la pulizia. Sto ancora cercando di capire quando lo zombie viene raccolto. Probabilmente senza figli attivi cron 1629 figure out si può uscire, a quel punto lo zombie sarà reparented di init e ottenere raccolto. Così ora ci chiediamo circa il SIGCHLD mancante che avrebbe dovuto cron elaborati.
- Non è necessariamente colpa vixie di cron. Come si può vedere qui, libdaemon installa un gestore di SIGCHLD durante
daemon_fork()
, e questo potrebbe interferire con la consegna del segnale su una rapida uscita da intermedio 1629Ora, io non so nemmeno se vixie cron sul mio sistema Ubuntu è anche costruito con libdaemon, ma almeno ho una nuova teoria. :-)
- Non è necessariamente colpa vixie di cron. Come si può vedere qui, libdaemon installa un gestore di SIGCHLD durante
Altri suggerimenti
Ho il sospetto che cron è in attesa di tutti i sottoprocessi nella sessione per terminare. Vedere attendere (2) per quanto riguarda gli argomenti pid negativi. Si può vedere il SESS con:
ps faxo stat,euid,ruid,tty,tpgid,sess,pgrp,ppid,pid,pcpu,comm
Ecco quello che vedo (a cura):
STAT EUID RUID TT TPGID SESS PGRP PPID PID %CPU COMMAND
Ss 0 0 ? -1 3197 3197 1 3197 0.0 cron
S 0 0 ? -1 3197 3197 3197 18825 0.0 \_ cron
Zs 1000 1000 ? -1 18832 18832 18825 18832 0.0 \_ sh <defunct>
S 1000 1000 ? -1 18832 18832 1 18836 0.0 sleep
Si noti che il pesce e il sonno sono nella stessa Sess.
Utilizzare il comando setsid (1). Ecco tester.sh:
#!/bin/bash
setsid sleep 27 # the real script launches a compiled C program in the background
Si noti che non è necessario &
, setsid mette in background.
per il mio parere è causata da crond processo (generato da crond per ogni compito) in attesa di input su standard input che viene convogliata al output / error del comando nel crontab. Ciò avviene perché cron è in grado di inviare l'output risultante via posta per l'utente.
Quindi crond è in attesa di EOF fino al comando utente e processi figli tutto è generato hanno chiuso il tubo. Se questo è fatto crond prosegue con l'attesa-dichiarazione e poi il comando utente defunta scompare.
Quindi penso che si deve disconnettere in modo esplicito ogni sottoprocesso deposto le uova nello script formare il tubo (per esempio riorientando in un file o / dev / null.
in modo che la riga seguente dovrebbe funzionare in crontab:
* * * * * ( /tmp/launcher.sh /tmp/tester.sh &>/dev/null & )
Vorrei raccomandare che si risolve il problema semplicemente non avere due processi separati: Avere launcher.sh
fare questo sulla sua ultima riga:
exec "$@"
Ciò elimina il processo di superfluo.
Ho trovato questa domanda mentre ero alla ricerca di una soluzione con un problema simile. Purtroppo le risposte a questa domanda non ha risolto il mio problema.
Uccidere processo defunto non è un'opzione come è necessario trovare e uccidere il suo processo genitore. Ho finito per uccidere i processi defunti nel seguente modo:
ps -ef | grep '<defunct>' | grep -v grep | awk '{print "kill -9 ",$3}' | sh
In "grep ''" è possibile restringere la ricerca ad uno specifico processo defunta siete dopo.
Ho testato lo stesso problema così tante volte. E finalmente ho la soluzione. Basta specificare il '/ bin / bash' prima che lo script bash come illustrato di seguito.
* * * * * /bin/bash /tmp/launcher.sh /tmp/tester.sh