Hi,
The EVBACKEND_EPOLL part of libev manual said:
The biggest issue is fork races, however - if
a program forks then *both* parent and child process have to
recreate the epoll set, which can take considerable time (one
syscall per file descriptor) and is of course hard to detect.
I want to know why?
After did some google, this site said, if the child close fds, it will lead
the fds clear form the epoll set in the parents.
https://lkml.org/lkml/2007/10/27/25
But my example code show that closing fds in child wouldn't clear the
parents epoll set.
So I want to know why the parents and child should has to recreate the
epoll set after fork.
Thank you.
this is my example code:
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<errno.h>
#include<netdb.h>
#include<fcntl.h>
#include<string.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<sys/un.h>
#include<netinet/in.h>
#include<netinet/in.h>
#include<netinet/tcp.h>
#include<arpa/inet.h>
#include<sys/epoll.h>
int StartTCPListener(const char* ip, const char* port)
{
int server_sockfd;
socklen_t server_len;
struct sockaddr_in server_address;
int flag;
int reuse = 1;
server_sockfd = socket(AF_INET,SOCK_STREAM,0);
if(server_sockfd==-1) return -1;
setsockopt(server_sockfd,SOL_SOCKET,SO_REUSEADDR,&reuse,sizeof(reuse));
server_address.sin_family = AF_INET;
server_address.sin_addr.s_addr = inet_addr(ip);
server_address.sin_port = htons(atoi(port));
server_len = sizeof(server_address);
if( bind(server_sockfd,(struct sockaddr*)&server_address,server_len) )
return -1;
if( listen(server_sockfd,SOMAXCONN) ) return -1;
flag = fcntl(server_sockfd,F_GETFL);
fcntl(server_sockfd,F_SETFL,flag|O_NONBLOCK);
fcntl(server_sockfd, F_SETFD, FD_CLOEXEC);
return server_sockfd;
}
int AcceptTCP(int server_fd)
{
int client_fd;
socklen_t client_len;
struct sockaddr_in client_address;
client_len = sizeof(client_address);
int flag;
client_fd = accept(server_fd,(struct sockaddr
*)&client_address,&client_len);
if(client_fd>0)
{
flag = fcntl(client_fd,F_GETFL);
fcntl(client_fd,F_SETFL,flag|O_NONBLOCK|O_DSYNC);
fcntl(client_fd, F_SETFD, FD_CLOEXEC);
}
return client_fd;
}
static int AddToEpollSet (int efd, int fd, int events)
{
struct epoll_event e;
memset(&e, 0, sizeof(e));
e.events = events;
e.data.fd = fd;
if (epoll_ctl(efd, EPOLL_CTL_ADD, fd, &e) == -1)
{
int err = errno;
fprintf(stderr, "epoll_ctl(ADD) failed : %s\n", strerror(errno));
return -1;
}
return 0;
}
int main(const int argc,const char* argv[])
{
int cpid;
int efd;
int sfd = StartTCPListener(argv[1],argv[2]);
struct epoll_event listener_evetn;
int n;
int cfd;
const char *msg="Hello world!\n";
if(sfd<0)
{
fprintf(stderr,"set socket listening error : %s\n",strerror(errno));
return -1;
}
efd=epoll_create(8);
if(efd<0)
{
fprintf(stderr,"epoll_create error : %s\n",strerror(errno));
return -1;
}
if(AddToEpollSet(efd,sfd,EPOLLIN)<0)
{
fprintf(stderr,"add socket to epoll set error :
%s\n",strerror(errno));
return -1;
}
cpid=fork();
if(cpid<0)
{
fprintf(stderr,"fork error : %s\n",strerror(errno));
return -1;
}
if(cpid==0)
{
printf("child progress %d\n",getpid());
close(sfd);
exit(0);
}
waitpid(cpid,NULL,0);
printf("%d fork %d\n",getpid(),cpid);
n=epoll_wait(efd,&listener_evetn,1,-1);
if(n>0)
{
if(listener_evetn.events & EPOLLIN)
{
cfd=AcceptTCP(listener_evetn.data.fd);
if(cfd>0)
{
write(cfd,msg,strlen(msg));
close(cfd);
}
}
}
close(sfd);
close(efd);
}
_______________________________________________
libev mailing list
[email protected]
http://lists.schmorp.de/mailman/listinfo/libev