Newsgroup: it.comp.os.linux.development
Titolo: processi zombie

Ho un processo padre che mantiene N figli, nel senso che appena uno termina
il padre ne crea subito un altro per rimpiazzarlo, in modo che il num di
processi attivi
sia costante N+1
Tuttavia controllando con il comando ps mi sono accorto che i processi
terminati rimangono in memoria fino a che il padre non ha terminato, e ache
se segnalati come <defunct> non è possibile (almeno per me) eliminarli; fino
a quando il padre non termina, abbandonando spontaneamnete la memoria
Tutto ciò è normale o dipende da un bug del mio programma ?
E se è un bug da cosa può dipendere ? Puo dipendere da evtuali descrittori
(di pipe e/o socket) rimasti aperti ?
Grazie a tutti.
--
Alessandro
alem...@libero.it
207. Il mio dottore dice che facendo le scale a piedi si guadagnano minuti
di vita. Rampa dopo rampa ho guadagnato due settimane, durante le quali
piovera' sempre...
--Woody Allen

 
Se non ricordo male, un processo che termina DEVE restituire al padre il
proprio stato di terminazione, e lo fa spedendo un SIGCHILD al padre.
Se il padre lo ignora, il processo rimane zombie (in attesa che qualcuno
ascolti il suo ultimo grido :-)). Quando il padre termina il "grido" lo
ascolta init e fa terminare correttamente il processo zombie.
Per evitare i processi zombie devi installare un gestore per SIGCHILD,
ma non ricordo cosa devi ficcarci dentro (forse solo un waitpid()): gli
anni dall'esame di calcolatori elettronici cominciano ad essere parecchi
:-).
Spero di esserti stato utile.
C:\>iao Angelo

Dalla man page di wait(2):
NOTES
       The Single Unix Specification describes a flag SA_NOCLDWAIT (not 
present under Linux) such that if either
       this  flag  is  set,  or  the  action for SIGCHLD is set to SIG_IGN 
(which, by the way, is not allowed by
       POSIX), then children that exit do not become zombies and a call to 
wait() or waitpid() will block  until
       all children have exited, and then fail with errno set to ECHILD.


MS Outlook : (noun) A newsreader with support for RAID 0.
MS Works   : (noun) An oxymoron.

 Spero di esserti stato utile.
Si i tuoi consigli mi sono stati veramente utili, grazie. Ma ho ancora un
piccolo problema; con il seguente gestore
void gestore(int signo){
wait(NULL);
return;
}
Non riesco a gestire i casi di contemporaneità. Se blocco il segnale
sigchild all'interno del gestore come posso gestire i segnali rimasti
pendenti ?
Anche se valuto con sigpending e sigismember come faccio a lanciare il
gesore per questi segnali ?
Grazie ancora
--
by Ale
alem...@libero.it
alem...@inwind.it
Sono un pessimista felice.  Le cose vanno peggio di ogni piu' rosea
previsione.
  -- Altan

 Tutto ciò è normale o dipende da un bug del mio programma ?
No, il processo rimane zombie finche' il padre non ne riceve lo stato di
terminazione. C'e' un trucco che si usa di solito:
- metti questa istruzione all'inizio del main:
signal(SIGCHLD, signalhandler);
- e definisci la funzione signalhandler cosi':
void signalhandler(int signum) {
	signal(SIGCHLD, signalhandler);
}
-- 
 Ciao, Bianco.
 Reply to luca.bianco (at) 
tiscalinet.it

 Tutto cio` e` normale o dipende da un bug del mio programma ?
No, e` normale. Spetta al genitore ripulire il child
Prima del fork inserisci un gestore per il signal SIGCHLD:
signal(SIGCHLD, cleanup);
la funzione cleanup sara` semplicemente:
void cleaup(int useless) {
	wait(NULL);
}
ciao
Kronos
-- 
Home: 
http://kronoz.cjb.net
La vasca da bagno fu inventata nel 1850, il telefono nel 1875.
Se fossi vissuto nel 1850, avrei potuto restare in vasca per 25 anni
senza sentir squillare il telefono

 pendenti ?
prova cosi`:
void sigchld(int useless)  {
	pid_t tmp;
 
	while(1) {
		tmp = waitpid(WAIT_MYPGRP, NULL, WNOHANG);
 
		if (tmp == -1) {
			fprintf(stderr, "%s\n", strerror(errno));
			break;
		}
 
		if (tmp == 0)
			break;
	}
}
non l'ho compilato ma dovrebbe funzionare
ciao
Kronos
-- 
Home: 
http://kronoz.cjb.net
Se il  destino di un uomo  e` annegare, anneghera` anche  in un bicchier
d'acqua.
Proverbio yddish

 }
 
Dai un occhiata a questo URL, negli esempi dovrebbe
esserci la soluzione al tuo problema.
 
http://www.faqs.org/faqs/unix-faq/programmer/faq/
 
 
C:\>iao Angelo.

 pendenti?
Non so se hai gia' risolto il problema, ma, controllando meglio
l'esempio che ti ho suggerito, mi sono accorto che in caso di
segnali contemporanei venivano comunque generati dei processi
zombie (in modo piu' o meno random sul mio sistema).
Il programma che ho usato come test e' quello riportato sotto,
dove vengono generati dei processi che terminano dopo un periodo
variabile dipendente dalla variabile idx.
----------------------------- Begin code -----------------------------
#include <sys/types.h>  /* include this before any other sys headers */
#include <sys/wait.h>   /* header for waitpid() and various macros */
#include <signal.h>     /* header for signal functions */
#include <stdio.h>      /* header for fprintf() */
#include <unistd.h>     /* header for fork() */
void sig_chld(int);     /* prototype for our SIGCHLD handler */
int main()
{
  int idx = 0;
    struct sigaction act;
    pid_t pid;
    /* Assign sig_chld as our SIGCHLD handler */
    act.sa_handler = sig_chld;
    /* We don't want to block any other signals in this example */
    sigemptyset(&act.sa_mask);
    /*
     * We're only interested in children that have terminated, not ones
     * which have been stopped (eg user pressing control-Z at terminal)
     */
    act.sa_flags = SA_NOCLDSTOP;
    /*
     * Make these values effective. If we were writing a real
     * application, we would probably save the old value instead of
     * passing NULL.
     */
    if (sigaction(SIGCHLD, &act, NULL) < 0)
    {
        fprintf(stderr, "sigaction failed\n");
        return 1;
    }
  for(idx = 0; idx < 10; idx++)
  {
     switch(fork())
     {
        case -1 : printf("Errore nella crazione del processo figlio\n");
                  exit(1);
                  break;
        case 0  : sleep(idx%4 * 5);
                  exit(0);
                  break;
        default : 
                  break;                 
     }
  }
  while(1)
    sleep(10);
    return 0;
}
 
/*
 * The signal handler function -- only gets called when a SIGCHLD
 * is received, ie when a child terminates
 */
void sig_chld(int signo)
{
    int status, child_val;
    /* Wait for any child without blocking */
    if (waitpid(-1, &status, WNOHANG) < 0)
    {
        /*
         * calling standard I/O functions like fprintf() in a
         * signal handler is not recommended, but probably OK
         * in toy programs like this one.
         */
        fprintf(stderr, "waitpid failed\n");
        return;
    }
    /*
     * We now have the info in 'status' and can manipulate it using
     * the macros in wait.h.
     */
    if (WIFEXITED(status))               /* did child exit normally?*/
    {
        child_val = WEXITSTATUS(status); /* get child's exit status */
        printf("child's exited normally with status %d\n", child_val);
    }
}
------------------------------- End code -------------------------------
Quello che ho ottenuto io e' un numero di zombie variabile tra
due e cinque.
Il problema e' dovuto al fatto che il gestore suggerito, nel caso
di segnali contemporanei ne prende uno a caso, lasciando gli altri
pendenti. Il modo corretto di gestire queste situazioni e' quello
riporato a pag. 475 di "The GNU C Library Reference Manual" scari-
cabile dal sito GNU.
Come spiegato, nel caso di piu' segnali contemporanei e' necessario
chiamare piu' volte waitpid(...) come riportato di seguito
void 
sigchld_handler (int signum) 
{
   int pid; 
   int status; 
   while (1) 
   {
      pid = waitpid (WAIT_ANY, &status, WNOHANG); 
      if (pid < 0)
      {
         perror ("waitpid"); 
         break; 
      }
      if (pid == 0) 
      break; 
   }
}
waitpid(...) restituisce 0 nel caso in cui non ci siano processi in
attesa di restituire lo stato, questo puo' essere sfruttato per
terminare il ciclo while.
Da test fatti (stesso codice precedente con modifica al signal handler)
non ho ottenuto piu' processi zombie.
ATTENZIONE! Quando anche l'ultimo processo ha segnalato la sua
            "dipartita" waitpid(...) restituisce -1 e viene
            stampato il messaggio di errore associato a ENOCHLD
            (??? mi sembra). Ovviamente l'uso di perror(...) non
            e' necesario.
Spero che la notizia ti sia utile (e di non aver postato due volte
il papiro). :-)
C:\>iao Angelo.

 zombie (in modo piu' o meno random sul mio sistema).
Si il problema lo ho già risolto grazie al tuo esempio e alle pagine del
man, cmq volevo ringraziare te e tutti quelli che hanno mi hanno aiutato,
senza il vostro aiuto non ce l'avrei fatta...
Grazie ancora
--
by Ale
alem...@libero.it
alem...@inwind.it
"L'uomo di Neanderthal e' stato scoperto molto tardi.  D'altronde lo stesso
Neanderthal non e' che ci tenesse a far sapere che stava con un uomo."
--Anatolj Balasz