gyerek szigna'l

Fórumok

Sziasztok!
Kovetkezo" a problema. Van egy program, forkolja magat jo sok peldanyban es a szulo oldalon a SIGCHLD elkapa'sa'val szeretnek tudomast venni a child processzek leallasarol. Ugy tunik azonban, hogyha masszivabb a terheles (sok prosszesz, sok peldanyban), akkor random modon egy-egy (neha tobb) gyerek leallasakor nem jon meg a szigna'l. A gyerekek teljesen termeszetes modon allnak le. Tovabba ugy tunik, hogy minel tobb a jarulekos i/o (file muvelet, file-ba iras) a parent reszerol, annal nagyobb a valoszinusege, hogy nem jon meg a szignal.
Amit eddig neztem, az a sigaction()-nak a finomhangolasa, SA_NOCLDSTOP|SA_SIGINFO|SA_RESTART|SA_NODEFER-t adok meg a SIGCHLD esetere, mikozben a sa_mask ures (semmi extra egyeb szignal nem kavar be). Ami me'g megbolondithatja a dolgot, hogy a parent signal handler egy FIFO-ba (pipe()) irkal, amit a parent mas ponton kiolvas (igy gyk. select()-tel azonnal meg tudom kapni hogy ki mikor allt le). A waitpid()-et sima blokking uzemben hasznalom (nincs WNOHANG), probaltam a handler-be magaba betenni (igy abban lenyegeben ez a waitpid() es a FIFO-ba valo irkalas, egy write() az osszes rendszerhivas); illetve ugy is, hogy a FIFO-ba a handler beleirja a pid-et, es a select() utan, amennyiben errol a FIFO-rol jott valami, kiolvassa a pid-et, es bevarja a gyereket. Igy viszont, hogy a sigchld neha nem jon be, el se jut a waitpid()-ig, igy nehany processz zombikent beragad, ami hatarozottan nem jo...
Valakinek hasonlo tapasztalata/otlete/izeje?
Koszi, A.

Hozzászólások

Valószínűleg nem segít neked, sőt, lehet, hogy totál baromság:

FIFO-val kínlódtam sokat, mire rájöttem (doksik alapján nekem nem volt világos), hogy csak 1 helyről lehet olvasni. Ha több progi is olvassa a fájlt, akkor véletlenszerűen kapják meg az egyes programok a beírt adatot. És pont, amikor néztem, hogy miért nem megy, akkor nem ment.

On the
other hand, BSD does not reset the handler, but blocks new instances
of this signal from occurring during a call of the handler. The
glibc2 library follows the BSD behavior.

Itt azt irja, hogy mikozben handler dolgozik nem jon ujabb signal.
Honan tudja mikor vegeztt ? Hivasi lancba kerul ugy vegeztem hivas is ? longjmp kor mi lesz vele ,ha igen ?


#include <signal.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
int pipefd[2];

int cnt=0;
int errors=0;
int neintr=0;
int handler(int kuka)
{
  if (-1==write(pipefd[1],&cnt,sizeof(int)))
  {
  	errors++; //ha nem atomikus utasitas furakat lathatsz  :)
	if (errno==EINTR)
	{
		neintr++;		
	}
  }
  cnt++;
}

int main()
{
int a;
pipe(pipefd);
signal(SIGCHLD,(void*) handler);
for (a=0;a<100;a++)
 if (!fork()) 
 {
 	sleep(1); // probald e nelkul is
 	exit(0);
 }
sleep(1);
printf("rcv: %d errors:%d EINTR:%d\n",cnt,errors,neintr);
for (a=0;a<100;a++)
{
 int i,r;
 r=read(pipefd[0],&i,sizeof(int));
 printf("read: %d cnt: %d error:%d EINTR:%d ret:%d\n",i,cnt,errors,neintr,r);
}
printf("readed\n");
	getchar();
}

Letrehoztaam egy progit ami reprodukalni tudja a jelenseget.
(ha childek nem sleepeznek rendesen lefut.)


#include <signal.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/types.h>         
#include <sys/socket.h>
#include <string.h>
#include <sys/un.h>
#include <sys/ioctl.h>
int pipefd[2];

int cnt=0;
int errors=0;
int neintr=0;

int unix_socket;
struct sockaddr_un unix_addr;

int handler(int kuka)
{
 int pid;
 int r;
while (ioctl(unix_socket,TIOCINQ,&r),r)
{
if (0>recv(unix_socket,&pid,sizeof(int),0)) 
  {
  	errors++;
  }

  if (-1==write(pipefd[1],&pid,sizeof(int)))
  {
  	errors++; // nem atomikus utasitas furakat lathatsz  :)
	if (errno==EINTR)
	{
		neintr++;		
	}
  }
 }
  cnt++;
}
int main()
{
int a;
pipe(pipefd);
unix_socket=socket(PF_UNIX,SOCK_DGRAM,0);
memset(&unix_addr,0,sizeof(struct sockaddr_un));
unix_addr.sun_family=AF_UNIX;
strcpy(unix_addr.sun_path,"unix-socket");
unlink(unix_addr.sun_path);
bind(unix_socket,(const struct sockaddr*)&unix_addr,sizeof(struct sockaddr_un));

signal(SIGCHLD,(void*) handler);
for (a=0;a<100;a++)
 if (!fork()) 
 {	int pid;
 	int e;
 	sleep(1);
	pid=getpid();
	e=sendto(unix_socket,&pid,sizeof(int),0,(const struct sockaddr*)&unix_addr,sizeof(struct sockaddr_un));
	printf("haldoklom pid: %d sendto: %d\n",pid,e);
	if (e<0)
	{
		perror("sendto");
	}
 	exit(0);
 }
sleep(1);
printf("rcv: %d errors:%d EINTR:%d\n",cnt,errors,neintr);
for (a=0;a<100;a++)
{
 int i;
 int r;
 r=read(pipefd[0],&i,sizeof(int));
 printf("** read: %d cnt: %d error:%d EINTR:%d,ret:%d \n",i,cnt,errors,neintr,r);
}
printf("readed\n");
	getchar();
}

pipe igazabol nem kell. unix-domain rulz :)

De talan meg jobb, ha minden SIGCLHLD nel elenorzod az osszes gyerkocot.

> egy-egy (neha tobb) gyerek leallasakor nem jon meg a szigna'l.

Emlékeim szerint ha rövid időn belül több gyerek áll le, akkor csak egy SIGCHLD jön. Én a handler-ben a waitpid-et ciklusba tenném, WNOHANG-el, hogy így összeszedjem az összes már leállt gyereket. Ezenfelül adott időközönként (pld 30 másodpercenként) lefuttatnám a waitpid-es ciklust.

Szerintem így nem maradna ki egy gyerek se.

Emlékeim szerint ha rövid időn belül több gyerek áll le, akkor csak egy SIGCHLD jön
Koszi, ez volt.

Igy mar fasza, raadasul egyszerubb handlerrel is meg lehetett oldani (ti. waitpid(-1,&status,WNOHANG)-bol kijon a pid, oszt nem kell a handlerbol kiszedni).

Hat, ma sem lettem butabb...