Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 6 years ago.
Improve this question
GOAL: Make parent process counters correct, counter1 = 5, counter2 =8.
Program is supposed to create 2 subprocesses. Each one of them will send set number of respectively SIGUSR1 and SIGUSR2 to parent. 5 and 8 times respectively.
To simplify, after many crashes causing my system to log out, closing all programs and forcing me to log in, i'm printing information about parent process instead. The goal is to replace those prints by
kill(getppid(),SIGUSR1) // and SIGUSR2 for second child process.
Current child work function:
void childWork(int loopCounter, int sigNum)
{
for(; loopCounter>0; loopCounter--)
{
if(SIGUSR1==sigNum) //kill(getppid(),SIGUSR1);
printf("[%d] sending SIGUSR1 to %d\n", getpid(),getppid());
else if(SIGUSR2 == sigNum) //kill(getppid(), SIGUSR2);
printf("[%d] sending SIGUSR2 to %d\n", getpid(),getppid());
}
}
Here is the zombie handling function for cleanup:
void handleZombie(int sig) {
while (1) {
pid_t pid = waitpid(0, NULL, WNOHANG);
if (pid < 0) {
if (errno == ECHILD)
return;
printf("Error, cleaning\n");
}
if (pid == 0)
return;
}
And finally main:
int main(int argc, char** argv)
{
printf("[%d] PARENT started! My parent: %d\n", getpid(), getppid());
childrenLeft=2;
setHandler(handleZombie,SIGCHLD);
setHandler(sigHandler1, SIGUSR1);
setHandler(sigHandler2, SIGUSR2);
int i;
for(i=1;i<=childrenLeft;i++)
{
pid_t pid = fork();
if(pid < 0)
printf("Error - fork\n");
if(pid==0)
if(i==1)
{
printf("[%d] child created!\n", getpid());
childWork(5,SIGUSR1);
}
if(i==2)
{
childWork(8, SIGUSR2);
printf("[%d] child created!\n", getpid());
}
exit(EXIT_SUCCESS);
}
printf("Work finished, final numbers:\nSIGUSR1 received: %d\nSIGUSR2 received: %d\n",sig1Count,sig2Count);
while (wait(NULL) > 0)
continue;
printf("[PARENT=%d] terminates\n", getpid());
return EXIT_SUCCESS;
}
Current issue is actually handling the parent process. For reason i do not understand, my second child isn't created. What more, the parent being printed is out of the blue.
[6025] PARENT started! My parent: 1300
[6026] child created!
[6026] sending SIGUSR1 to 6025
[6026] sending SIGUSR1 to 6025
[6026] sending SIGUSR1 to 6025
[6026] sending SIGUSR1 to 30404
[6026] sending SIGUSR1 to 30404
This is the complete output. Please help me understand what is going on here...
Note that you don't report that child 2 is created until after childWork() returns.
However, your fundamental problem is the lack of statement grouping braces after if (pid == 0) which means that the exit(EXIT_SUCCESS): after the two tests if (i == 1) and if (i == 2); causes the parent to exit immediately after launching the first child.
int main(int argc, char** argv)
{
printf("[%d] PARENT started! My parent: %d\n", getpid(), getppid());
childrenLeft=2;
setHandler(handleZombie,SIGCHLD);
setHandler(sigHandler1, SIGUSR1);
setHandler(sigHandler2, SIGUSR2);
int i;
for(i=1;i<=childrenLeft;i++)
{
pid_t pid = fork();
if(pid < 0)
printf("Error - fork\n");
if(pid==0)
{ // Primary bug: braces missing
if(i==1)
{
printf("[%d] child created!\n", getpid());
childWork(5,SIGUSR1);
}
if(i==2)
{
printf("[%d] child created!\n", getpid()); // Moved before childWork()
childWork(8, SIGUSR2);
}
exit(EXIT_SUCCESS); // Only executed by children
} // Primary bug: missing braces
}
printf("Work finished, final numbers:\nSIGUSR1 received: %d\nSIGUSR2 received: %d\n",sig1Count,sig2Count);
while (wait(NULL) > 0)
continue;
printf("[PARENT=%d] terminates\n", getpid());
return EXIT_SUCCESS;
}
This is the bare minimum fixing needed; there are many other changes that could and perhaps should be made.
Related
I have the following code in my main function
pid_t pid;
pid = fork(); //Two processes are made
if (pid > 0 && runBGflag==0) //Parent process. Waits for child termination and prints exit status
{
int status;
if (waitpid(pid, &status, 0) == pid && WIFEXITED(status))
{
printf("Exitstatus [");
for (int i = 0; i < noOfTokens; i++)
{
printf("%s ", commands[i]);
}
printf("\b] = %d\n", WEXITSTATUS(status));
}
}
else if (pid == 0) //Child process. Executes commands and prints error if something unexpected happened
{
if (runBGflag==1) insertElement(getpid(),ptr);
execvp(commands[0], commands);
printf ("exec: %s\n", strerror(errno));
exit(1);
}
In a nutshell, a child process is made and if the runBackGround flag is set, the parent process will not wait for the child process to exit, but rather continue running. If a background process is made, the PID of the background process is stored in a list. At a later point, this function is called
void delete_zombies(void)
{
pid_t kidpid;
int status;
char buffer[1337];
while ((kidpid = waitpid(-1, &status, WNOHANG)) > 0)
{
removeElement(kidpid,buffer,1337);
printf("Child %ld terminated\n", kidpid);
printf("its command was %s\n",buffer);
}
}
This function simply checks if any child processes have died and in that case deletes them. It will then search for the childs PID in the list, remove it and print it out.
The problem is, the delete_zombies function will find that a child has died and will then try to remove it from the list, but it only finds an empty list, as if the child process never inserted its PID into the list.
This is really strange, because delete_zombies only finds a dead child process, when there was one created with the background flag set, so we know insertElement must have been called, but strangely when the parent checks in the list nothing is there
Is the cause for that, that child process and parent process have seperate lists, or is the PID maybe wrong?
I am new in using signals on C programming.
I wrote two simple source codes child.c and parent.c in order to demonstrate my issue.
child.c
void errorHandler(char* message);
void sigterm_handler(int signum, siginfo_t* info, void* ptr);
int main(){
struct sigaction action1;
memset(&action1, 0, sizeof(action1));
action1.sa_sigaction = sigterm_handler;
action1.sa_flags = SA_SIGINFO;
if(sigaction(SIGTERM, &action1, NULL) != 0)
errorHandler("Signal sigterm_handler registration failed");
for(int i = 0; i < 10; i++){
printf("%d\n", i);
if(i == 5){
if(raise(SIGSTOP)!= 0)
errorHandler("Raise SIGSTOP failed");
}
}
return EXIT_SUCCESS;
}
void errorHandler(char* message){
printf("Error: %s: %s\n", message, strerror(errno));
exit(EXIT_FAILURE);
}
void sigterm_handler(int signum, siginfo_t* info, void* ptr){
printf("Child: Process %d finishes\n", getpid());
exit(EXIT_SUCCESS);
}
parent.c
int main(int argc, char* argv[]){
int status;
pid_t mem;
pid_t child = fork();
if(child == 0){
char* arr[] = {"./child", NULL};
execv(arr[0], arr);
}
else if(child > 0){
mem = child;
waitpid(mem, &status, WUNTRACED);
}
if(WSTOPSIG(status)){
printf("Sending SIGTERM to child\n");
kill(mem, SIGTERM);
waitpid(mem, &status, 0);
}
return 0;
}
When I run parent.c, the program print into stdout:
1
2
3
4
5
Sending SIGTERM to child
but then the program get stuck, probably because sigterm_handler don't invoke, instead of printing "Child: Process *** finishes".
I tried to read on the linux manual page but I still can't to figure it out.
Can anyone please explain to me what is causing this issue?
Any answer would be appreciated!
The problem is, that the child process, that calls
if(raise(SIGSTOP) != 0)
is still stopped, when the parent here
kill(mem, SIGTERM);
sends the signal SIGTERM. The signal is not lost, but is still pending at the child's process and will be delivered, as soon as the process continues to run. You can achieve that by issuing
kill(mem, SIGCONT);
directly after sending the SIGTERM. Then, the child will resume to run, the signal will be delivered and the handler will be executed, printing the diagnostic message and exiting the process.
I have a C server. This server has to handle multiple connections and user's input (through a simple ncurses GUI). So I created two childs.
My problem comes when from the main menu of the user interface, I need to exit the program (then terminate the second child process -which handles the connections- from the first child process).
I'll try to explain myself with a little example:
int main(){
pid_t pid;
int status1, status2;
if((pid = fork()) < 0){
perror("main fork failure:");
exit(1);
}
if(pid == 0){
pid = fork();
if(pid == 0){
/*
some stuff the second child does while
the first child is already running
*/
}
/* this is the first child */
int choice;
choice = menu();
switch(choice){
case 1:
break;
case 2:
/*
HERE I have to exit (from the first child first,
and from the program then): how can I kill the
second child that is running to prevent
zombie processes?
*/
// kill() which pid?
exit(2);
break;
}
wait(&status2);
}
wait(&status1);
return 0;
}
So, how can I kill it if I don't know the second child pid from the first child?
In your code, you reuse the variable pid, but fortunately, the non-zero pid is the one you need to signal.
Hence:
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <unistd.h>
extern int menu(void);
static void wait_for_pid(int pid)
{
int status;
int corpse;
while ((corpse = wait(&status)) >= 0 && corpse != pid)
printf("Unexpected child %d exited with status 0x%.4X\n", corpse, status);
if (corpse == pid)
printf("Child %d exited with status 0x%.4X\n", corpse, status);
else
printf("Child %d died without its death being tracked\n", pid);
}
int main(void)
{
pid_t pid;
if ((pid = fork()) < 0)
{
perror("main fork failure:");
exit(1);
}
if (pid == 0)
{
if ((pid = fork()) < 0)
{
perror("child fork failure:");
exit(1);
}
if (pid == 0)
{
pause(); /* Do nothing until signalled */
exit(0);
}
/* this is the first child */
int choice = menu();
switch (choice)
{
case 1:
/* action 1 */
break;
case 2:
kill(pid, SIGTERM);
exit(2);
/*NOTREACHED*/
}
wait_for_pid(pid);
exit(0);
}
wait_for_pid(pid);
return 0;
}
The loop in the wait_for_pid() function should be overkill for the child, but the parent process could have children it doesn't know about under some circumstances — unlikely but not impossible circumstances.
The use of pause() in the second child is simply writing some code; it is not useful and would not therefore be what you'd write there. Writing the comment /* action 1 */ is likewise dummy code; you'd replace it with code that does something useful. I'd probably have functions to call for the first child and the second child, rather than embedding much code in main(). I assume that it's written as shown to create an MCVE (Minimal, Complete, Verifiable Example); thank you for keeping the code small.
The code above was untested because there was no menu() function. The code below has a menu function — not that it is very interactive.
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <unistd.h>
extern int menu(void);
int menu(void)
{
printf("Dozing...\n");
sleep(1);
printf("Menu option 2 chosen\n");
return 2;
}
static void wait_for_pid(int pid)
{
int status;
int corpse;
int curpid = getpid();
printf("%d: waiting for children to die\n", curpid);
while ((corpse = wait(&status)) >= 0 && corpse != pid)
printf("%d: Unexpected child %d exited with status 0x%.4X\n", curpid, corpse, status);
if (corpse == pid)
printf("%d: Child %d exited with status 0x%.4X\n", curpid, corpse, status);
else
printf("%d: Child %d died without its death being tracked\n", curpid, pid);
}
int main(void)
{
pid_t pid;
if ((pid = fork()) < 0)
{
perror("main fork failure:");
exit(1);
}
if (pid == 0)
{
if ((pid = fork()) < 0)
{
perror("child fork failure:");
exit(1);
}
if (pid == 0)
{
printf("Second child (%d) - pausing\n", (int)getpid());
pause(); /* Do nothing until signalled */
printf("Second child (%d) - awake despite no signal handling\n", (int)getpid());
exit(0);
}
/* this is the first child */
printf("First child (%d) - menuing\n", (int)getpid());
int choice = menu();
switch (choice)
{
case 1:
/* action 1 */
break;
case 2:
printf("kill(%d, SIGTERM)\n", pid);
kill(pid, SIGTERM);
wait_for_pid(pid);
exit(2);
/*NOTREACHED*/
}
/* Reached on menu choices != 2 */
/* Probably needs a loop around the menu() - end loop before wait_for_pid() */
wait_for_pid(pid);
exit(0);
}
wait_for_pid(pid);
return 0;
}
When run, a sample output sequence was:
19489: waiting for children to die
First child (19490) - menuing
Dozing...
Second child (19491) - pausing
Menu option 2 chosen
kill(19491, SIGTERM)
19490: waiting for children to die
19490: Child 19491 exited with status 0x000F
19489: Child 19490 exited with status 0x0200
All of which looks as would be expected. You can see the death from SIGTERM in the status 0x000F (SIGTERM is normally 15, and is 15 on macOS Sierra, though AFAIK no standard demands that it is 15). You can see the first child exited normally with status 2 from the 0x0200. You can see that the parent started waiting before the children did anything. And you can see the debugging techniques — copious printing and including the PID most of the time.
I have to insert an odd number by terminal. After this, it generates two processes, A and B.
Then it sends SIGUSR2 signal to B, and his handler prints the reciprocal of the argv[1]. Then, B sleeps for argv[1] seconds and sends SIGUSR1 signal to A process before terminating. The SIGUSR1 handler for process A prints something and then terminates.
The problem is that SIGUSR1 handler for process A doesnt' work because the signal couldn't be sent by SIGUSR2 handler for process B. In fact, the kill(A,SIGUSR1) tells that there is no such process (for process A). After setting the signal handler in process A, it is in pause().
Can anyone help me to solve? Thank you.
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
int arg;
int pid1 = 11, pid2 = 12;
void sigusr2Handler1(int);
void sigusr1Handler2(int);
int main(int argc, char* argv[])
{
if(argc != 2){
printf("Usage: %s num(int)\n", argv[0]);
exit(1);
}
arg = atoi(argv[1]);
pid1 = fork();
if (pid1 != 0)
pid2 = fork();
if (arg%2 != 0) {
if (pid1 == 0) {
if (signal(SIGUSR1, sigusr1Handler2) == SIG_ERR) {
printf("PID %d can't catch SIGUSR1\n", getpid());
exit(1);
}
printf("PID1 %d sigusr1 handler2 installation\n", getpid());
pause();
}
if (pid2 == 0) {
signal(SIGUSR2, sigusr2Handler1);
printf("PID2 %d sigusr2 handler installation\n", getpid());
kill(0, SIGUSR2);
}
}
return 0;
}
void sigusr2Handler1(int sig)
{
printf("PID %d Received SIGUSR2. 1/%d = %f.\n", getpid(), arg, (float)1 / arg);
sleep(arg);
if (kill(pid1, SIGUSR1) < 0) {
perror("Kill error");
exit(1);
}
printf("PID %d. Sent SIGUSR1 to %d. Closing\n", getpid(), pid1);
exit(0);
}
void sigusr1Handler2(int sig)
{
printf("PID %d Received SIGUSR1. Closing.\n", getpid());
exit(0);
}
pid1 has been killed by the time pid2 attempts to send a it a SIGUSR1. pid2 is the killer.
When pid2 issues a kill(0, SIGUSR2), this sends SIGUSR2 to the entire process group, including pid1. This kills pid1, which is unprepared to receive a SIGUSR2.
I'm doing a homework assigment (the regular "write your own unix shell in c" assigment)
and cant make my child process run in the background properly, the are KILLED right before calling execvp
my intuition tells me the problem is in the signal handler or the usage of return in the parent process after fork().
This is how I've implemented it (just for the background process) :
void ExeExternal(char *args[MAX], char* cmd,ExecutionMode ExeMode) {
int pID;
switch(pID = fork())
{
case -1:
// Add your code here (error)
/*
your code
*/
perror("fail to fork in : ExeExternal(...)\n");
exit(-1);
case 0 :
// Child Process
signal(SIGTSTP, SIG_DFL);
signal(SIGINT, SIG_DFL);
signal(SIGCONT, SIG_DFL);
usleep(20000);
setpgrp();
printf("trying to execvp\n");
int run_result=execvp(args[0],args);
if(run_result==-1)
{
perror("execvp(...) result in execvp\n");
exit(-1);
}
break; //wont reach this part ever!
default://the parent. pID holds child's pID
setpgid(pID, pID); //note, this is also done in the child
if(ExeMode==BACKGROUND) //no need to WAIT()
{
return;
}
}
}
and this is my signal handler (registered in my main() with signal(SIGCHLD,handle_sigchld)
void handle_sigchld(int sig) {
pid_t pid;
int status;
pid=waitpid(WAIT_ANY,&status,WUNTRACED | WNOHANG);
if (pid >0)
{
if(WIFEXITED(status)) //if terminated normally, return or exit
{
printf("\n[%d] %d Done \n", ID, pid); //[1] a.out : 12340 214 secs
}
else if (WIFSIGNALED(status)) //killed with SIGINT
{
printf("handle_sigchld:[%d] pid %d KILLED\n",ID,pid);
}
else if (WIFSTOPPED(status)) //suspended with SIGCONT
{
printf("\n[%d] %s %d %d secs (stopped)\n", ID, value,pid,time);
}
}
}
I've tried to plant some prinft's and my child seems to be killed right before executing execvp(...)
Ive tried to print the args[0] and args[1] and it exited there, so it looks like it falls upon accessing them,
also - is that the right way to use return ? ive tried to replace it with waitpid(pid,status,WNOHANG) but it didnt helped
ANY help is greatly appreciated! even just a hint in the right direction