how can i avoide zombie proccess - linux

I have this code:
server
while(1){ //loop the child
bzero(buffer, 256);
n = recv(newsockfd, buffer, 255,0);
printf("read %d ",n);
printf("pid %d\n",getpid());
if (n < 0) error("ERROR reading from socket");{
printf("Here is the message: %s\n", buffer);
}
if (strcmp(buffer,"quit") == 0){
printf("Disconnect from %s:%d\n",str,portno);
exit(EXIT_SUCCESS);
}else{
n = send(newsockfd, "message received\n", 19,0);
if (n < 0) error("ERROR writing to socket");
bzero(buffer, 256);
}
}
}else{ //parent
recv(newsockfd,gepid,10,0); //get the child pid
endID = waitpid(gepid,&status,WNOHANG|WUNTRACED); //get the exit code gepid want to be the child pid
if (endID==-1){
error("waitpid");
}else if (endID==0){
printf("Child still running!");
}else if(endID==childpid){
check_child_exit(status);
}
}
}
close(newsockfd);
return 0;
}
client
while(1){ //while after connect
printf(inet_ntoa(serv_addr.sin_addr));
printf(" :>");
bzero(buffer, 256);
printf("pid: %d",&getpid);
//fgets(buffer,255,stdin);
scanf("%s",&buffer[0]);
if ( send(sockfd, buffer, strlen(buffer),0)< 0)
error("ERROR writing to socket");
if(strcmp(buffer,"quit") == 0){
close(sockfd);
printf("Client: %s Disconnect \n",inet_ntoa(serv_addr.sin_addr));
gepid[0]=getpid(); //there is the error i want to get the pid of child
send(sockfd,gepid,10,0); //and send to server
exit(1);
}
if (recv(sockfd, buffer, 255,0)< 0){
error("ERROR reading from socket");
}else{
printf("%s\n %d", buffer,n);
}
}
return 0;
}
I have a server that can serve multy client and response to each one when the client write quit or stop with a signal[CTR-C] i want the server get that and avoid zombie proccess so to avoid zombie proccess i thought
to send from client to server the getpid so the client get the pid of the kid proccess when the proccess finish with quit or stop by signal parent get the exit with waitpaid
so the programm not have zombie proccess i dont know if this logic is good to stop the zombie proccess but i try to send pid from client to server and i get segmentation fault
Any help is appreciate

There are numerous problems with your code, but to focus on your question:
Don't try sending the pid to the server. It's unnecessary, and wouldn't work if the child crashes before it can send it anyway.
The usual way is to catch the SIGCHLD signal, and do any necessary waitpid stuff from inside the signal handler. But if your only concern is avoiding zombies, then just install a default signal handler with signal(SIGCHLD, SIG_IGN);, and don't use waitpid at all.

fork() returns 0 in the child and the child pid in the parent, so there is no need to send pid from child to parent. If you are forking multiple times, then you need to store each child pid for collection later.
You are not showing the type of gepid. Is it pid_t gepid2 or something? The len parameter to recv() is in bytes, so it would be more appropriate to recv(sock, gepid, sizeof(gepid[0]), 0);
Also if you pass -1 to waitpid(), it waits for any child.

Related

How can I print a message from a signal handler

I have small project for practice in system calls. The idea is to create a Rock paper scissors game. The controller need to create two child processes and when two processes are created they are supposed to send ready command to the controller (parent process) using SIGUSR1 signal. I have created the two children processes and the signal sent the signal to the controller but the problem message does not print out. what am I wrong?
Here is my code.
#include<stdio.h>
#include<unistd.h> // fork(); for creating processes and pipe()s
#include<signal.h>
#include<sys/signal.h>
#include<stdlib.h>
void handle_sigusr1(int sig){
printf("Sending ready command...\n");
}
int x = 0;
int main(int args, char* argv[]){
int player0, player1;
player0 = fork();
if(player0 != 0){
player1 = fork();
}
if( player0 == 0){
kill(getppid(), SIGUSR1);
sleep(2);
}else if(player1 == 0){
sleep(3);
kill(getppid(), SIGUSR1);
}else{
wait(NULL);
struct sigaction sa = { 0 };
sa.sa_flags = SA_RESTART;
sa.sa_handler = &handle_sigusr1;
sigaction(SIGUSR1, &sa, NULL);
if(signal(SIGUSR1, handle_sigusr1)){
x++;
printf("Controller: Received ready command. Total %d\n", x);
}
}
return 0;
}
In your code, there are 2 major issues to modify.
First of all, move the signal handler above the wait() function, otherwise you are defining how to handle the signal after receiving it
signal(SIGUSR1, handle_sigusr1);
wait();
Then, the parent process is waiting for only 1 child to receive the signal. You should add a loop to wait both the child processes in the parent statement branch

About Inter-process communication in C, Using pipe()

I'm trying to write sort function.
This function may fork many children to help itself to sort the given input.
When my function has only one child it is easy to use pipe(). I just create
int fd[2];
then everything is fine but I don't know what to do when there are many children. Should I create fd[Children*2] pipes or fd[2] is enough?
And how can i use these pipes to communicate with the child that I want (since there are many children)?
My main process will fork children, this is just one part of the code, I'm forking children and getting their pids into pid array
pid_t main = getpid();
int N = 30;
pid_t* children = (pid_t*) malloc(sizeof(pid_t) * N);
for(i = 0; i < N; i++){
pid_t child = fork();
if ( child == 0){
pid_t me = getpid();
printf("I'm a child and my pid is: %d\n", me);
sleep(1);
// exit(4);
return me * 2;
} else if ( child < 0){
// printf("Could not create child\n");
} else {
children[i] = child;
// printf("I have created a child and its pid %d\n", child);
}
}
If only the main process needs to create and communicate with children, and the children don't need to communicate with each other, create a separate pipe for each child in the main process before forking the child. The call to pipe() could be placed in your loop, before calling fork(). You could use a 2-dimensional array like fd[NUM_CHILDREN][2] to keep track of the file descriptors. If the data will be arriving asynchronously, poll() or select() can be used to find out when something is available to be read.

How to run child processes concurrently

I want child processes run concurrently. Is it OK to write as to achieve this:
for(p = 0; p < N; p++){ //there will be N child processes
pidOfChild = fork();
if(pidOfChild == -1){
printf("fork() failed.\n");
exit(1);
}
else if(pidOfChild == 0){
//do sth
printf("I am a child and my PID is %d.\n", getpid());
exit(0);
}
}
It is okay, and if your parent process exits, you don't need to wait.

second call prctl() dont work

I try write program, which realize next idea:
After start, program using fork() and:
parent process stopped on function wait() (for waiting death child process);
child process use prctl(PR_SET_PDEATHSIG, SIGHUP), and setup signal handler (It's helps detect parent death);
After death any process, program use fork() again.
void forking_process() {
pid_t id;
printf("forking_process is called!\n");
if (id = fork()) {
parent_process_operation();
} else {
child_process_operation();
}
}
void parent_process_operation() {
int status = 0;
printf("It's parent process! Pid = %d\n", (int)getpid());
pid_t chid = wait(&status);
printf("Terminated child process with PID = %d\n", chid);
inform_about_parent_death(status);
}
void child_process_operation() {
printf("It's child process! pid = %d, ppid = %d\n",
(int)getpid(), (int)getppid());
struct sigaction sa;
memset(&sa, 0, sizeof(sa));
sa.sa_handler = inform_about_parent_death;
if (sigaction(SIGHUP, &sa, NULL))
fprintf(stderr, "sigaction error\n");
prctl(PR_SET_PDEATHSIG, SIGHUP);
while(1) {
printf("."); fflush(stdout);
sleep(1);
}
}
void inform_about_parent_death(int i) {
printf("Process is dead. Restart!\n");
forking_process();
}
int main (void) {
forking_process();
return EXIT_SUCCESS;
}
If I run this application, and in another terminal kill child process - then will create child process.
If I kill the parent process once, - signal handler started and call fork().
If I again kill the parent process, - signal handler not responded.
That is - prctl() in first process work, but prctl() in second child process don't work.
Why it is happen? How I can correct it's program?

socket() returns 0 in C client server application

I'm working on an application that contains several server sockets that each run in a unique thread.
An external utility (script) is called by one of the threads. This script calls a utility (client) that sends a message to one of the server sockets.
Initially, I was using system() to execute this external script, but we couldn't use that because we had to make sure the server sockets were closed in the child that was forked to execute the external script.
I now call fork() and execvp() myself. I fork() and then in the child I close all the server sockets and then call execvp() to execute the script.
Now, all of that works fine. The problem is that at times the script reports errors to the server app. The script sends these errors by calling another application (client) which opens a TCP socket and sends the appropriate data. My issue is that the client app gets a value of 0 returned by the socket() system call.
NOTE: This ONLY occurs when the script/client app is called using my forkExec() function. If the script/client app is called manually the socket() call performs appropriately and things work fine.
Based on that information I suspect it's something in my fork() execvp() code below... Any ideas?
void forkExec()
{
int stat;
stat = fork();
if (stat < 0)
{
printf("Error forking child: %s", strerror(errno));
}
else if (stat == 0)
{
char *progArgs[3];
/*
* First, close the file descriptors that the child
* shouldn't keep open
*/
close(ServerFd);
close(XMLSocket);
close(ClientFd);
close(EventSocket);
close(monitorSocket);
/* build the arguments for script */
progArgs[0] = calloc(1, strlen("/path_to_script")+1);
strcpy(progArgs[0], "/path_to_script");
progArgs[1] = calloc(1, strlen(arg)+1);
strcpy(progArgs[1], arg);
progArgs[2] = NULL; /* Array of args must be NULL terminated for execvp() */
/* launch the script */
stat = execvp(progArgs[0], progArgs);
if (stat != 0)
{
printf("Error executing script: '%s' '%s' : %s", progArgs[0], progArgs[1], strerror(errno));
}
free(progArgs[0]);
free(progArgs[1]);
exit(0);
}
return;
}
Client app code:
static int connectToServer(void)
{
int socketFD = 0;
int status;
struct sockaddr_in address;
struct hostent* hostAddr = gethostbyname("localhost");
socketFD = socket(PF_INET, SOCK_STREAM, 0);
The above call returns 0.
if (socketFD < 0)
{
fprintf(stderr, "%s-%d: Failed to create socket: %s",
__func__, __LINE__, strerror(errno));
return (-1);
}
memset(&address, 0, sizeof(struct sockaddr));
address.sin_family = AF_INET;
memcpy(&(address.sin_addr.s_addr), hostAddr->h_addr, hostAddr->h_length);
address.sin_port = htons(POLLING_SERVER_PORT);
status = connect(socketFD, (struct sockaddr *)&address, sizeof(address));
if (status < 0)
{
if (errno != ECONNREFUSED)
{
fprintf(stderr, "%s-%d: Failed to connect to server socket: %s",
__func__, __LINE__, strerror(errno));
}
else
{
fprintf(stderr, "%s-%d: Server not yet available...%s",
__func__, __LINE__, strerror(errno));
close(socketFD);
socketFD = 0;
}
}
return socketFD;
}
FYI
OS: Linux
Arch: ARM32
Kernel: 2.6.26
socket() returns -1 on error.
A return of 0 means socket() succeeded and gave you file descriptor 0. I suspect that one of the file descriptors that you close has file descriptor 0 and once it's closed the next call to a function that allocated a file descriptor will return fd 0 as it's available.
A socket with value 0 is fine, it means stdin was closed which will make fd 0 available for reuse - such as by a socket.
chances are one of the filedescriptors you close in the forkExec() child path(XMLSocket/ServerFd) etc.) was fd 0 . That'll start the child with fd 0 closed, which won't happen when you run the app from a command line, as fd 0 will be already open as the stdin of the shell.
If you want your socket to not be 0,1 or 2 (stdin/out/err) call the following in your forkExec() function after all the close() calls
void reserve_tty()
{
int fd;
for(fd=0; fd < 3; fd++)
int nfd;
nfd = open("/dev/null", O_RDWR);
if(nfd<0) /* We're screwed. */
continue;
if(nfd==fd)
continue;
dup2(nfd, fd);
if(nfd > 2)
close(nfd);
}
Check for socket returning -1 which means an error occured.
Don't forget a call to
waitpid()
End of "obvious question mode". I'm assuming a bit here but you're not doing anything with the pid returned by the fork() call. (-:
As it is mentioned in another comment, you really should not close 0,1 or 2 (stdin/out/err), you can put a check to make sure you do not close those and so it will not be assigned as new fd`s when you request for a new socket

Resources