Why my atexit function not working in linux - c

I made processes with fork() and put exit(0) at the end and atexit(func) so I can get notice when process is exited or not to avoid zombie processes.
However, there are no output for atexit so I think maybe I have made zombie process. Can anyone tell me why my atexit output doesn't show?
//fork parent process (first process fork):
if ((pid = fork()) == 0) {
printf("parent1: %d in %d\n", getpid(), getpgid(pid));
atexit(endfunc);
char* argf[MAXARGS];
int a;
printf("buf: %s\n", buf);
if (strchr(cmdline, '|') != NULL) {
a = make_tokens(buf, 0, argf, "|");
printf("In pipe\n");
int fd[200][2];
pid_t pids[200];
for (int i = 0; i < a - 1; i++) {
pipe(fd[i]);
//somewhere in parent fork child:
if ((pids[0] = fork()) == 0) {
printf("child: %d in %d\n", getpid(), getpgid(pid));
atexit(endfunc);
close(fd[0][0]);
for (int i = 1; i < a - 1; i++) {
close(fd[i][0]);
close(fd[i][1]);
}
char* arg[MAXARGS];
parseline(argf[0], arg);
execvp(arg[0], arg);
exit(0);
}
//at the end of parent process wait for childrens
pid_t wpid;
for (int i = 0; i < a; i++) {
wpid = waitpid(pids[i], NULL, 0);
if (wpid < 0) {
perror("waitpids");
}
else if (wpid >= 0) {
printf("wait for %d\n", pids[i]);
}
exit(0);//parent process exit
//endfunc: function for atexit()
void endfunc(void) {
printf("process %d ended\n", getpid());
}
This is the output after I input ls -al | grep t:
mini> ls -al | grep t
parent1: 23154 in 23140
buf: ls -al | grep t
In pipe
child: 23155 in 23140
child: 23156 in 23140
//output for command
wait for 23155
wait for 23156
process 23154 ended
wait for 23154
As we can see, parent process has ended well and atexit printed. However, child processes has been made but atexit for child has not cameout.Has my child processes has not been exited?

From the atexit manual page:
Upon a successful call to one of the exec(3) functions, all registrations are removed.
Because a successful exec call will replace the process code, including the one you registered with atexit, your exit code can no longer be called and is thus "unregistered".

Related

Using fork() and execlp() to create process hierarchy in C

I MUST use fork() and execlp() to create and annotate the given process hierarchy:
I cannot wrap my head around when each process should be forked in order to reflect this hierarchy, add to that the non-negotiable use of execlp() which replaces the current process image.
Here is what I managed to come up with (please excuse the very non-DRY code, I'm new to these concepts):
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/wait.h>
#define oops(m) {perror(m); exit(EXIT_FAILURE);}
int main() {
pid_t pid1_1, pid1_2, pid1_1_1, pid1_1_2, pid1_2_1, pid1_2_2;
pid1_1 = fork();
if (pid1_1 < 0) {
oops("Fork Failed!");
}
// child 1.1
if (pid1_1 == 0) {
printf("I am the child %d\n", getpid());
if (execlp("./iam", "iam", "1.1", NULL) < 0)
oops("Execlp Failed!");
} else {
// grandchild 1.1.1
pid1_1_1 = fork();
if (pid1_1_1 < 0) {
oops("Fork Failed!");
}
if (pid1_1_1 == 0) {
printf("I am the grandchild %d\n", getpid());
if (execlp("./iam", "iam", "1.1.1", NULL) < 0)
oops("Execlp Failed!");
}
//grandchild 1.1.2
pid1_1_2 = fork();
if (pid1_1_2 < 0) {
oops("Fork Failed!");
}
if (pid1_1_2 == 0) {
printf("I am the grandchild %d\n", getpid());
if (execlp("./iam", "iam", "1.1.2", NULL) < 0)
oops("Execlp Failed!");
}
}
pid1_2 = fork();
if (pid1_2 < 0) {
oops("Fork Failed!");
}
// child 1.2
if (pid1_2 == 0) {
printf("I am the child %d\n", getpid());
if (execlp("./iam", "iam", "1.2", NULL) < 0)
oops("Execlp Failed!");
} else {
// grandchild 1.2.1
pid1_2_1 = fork();
if (pid1_2_1 < 0) {
oops("Fork Failed!");
}
if (pid1_2_1 == 0) {
printf("I am the grandchild %d\n", getpid());
if (execlp("./iam", "iam", "1.2.1", NULL) < 0)
oops("Execlp Failed!");
}
// grandchild 1.2.2
pid1_2_2 = fork();
if (pid1_2_2 < 0) {
oops("Fork Failed!");
}
if (pid1_2_2 == 0) {
printf("I am the grandchild %d\n", getpid());
if (execlp("./iam", "iam", "1.2.2", NULL) < 0)
oops("Execlp Failed!");
}
}
// pid > 0 ==> must be parent
printf("I am the parent %d\n", getpid());
/* parent will wait for the child to complete */
if (waitpid(-1, NULL, 0) < 0)
printf("-1 from wait() with errno = %d\n", errno);
printf("Child terminated; parent exiting\n");
exit(EXIT_SUCCESS);
}
My output shows that this hierarchy is not set up correctly. For example, manually stepping through with gdb and finishing the PID for 1.2 terminates the entire process tree (when 1.1 sub-tree should be left in tact).
Any suggestions for where I'm going wrong with logically replicating this process hierarchy would be really appreciated. Thanks!
Any suggestions for where I'm going wrong with logically replicating this process hierarchy would be really appreciated.
Check this part of code at start of your program:
pid1_1 = fork();
this will fork a child process. After this you are doing:
if (pid1_1 == 0) {
printf("I am the child %d\n", getpid());
if (execlp("./iam", "iam", "1.1", NULL) < 0)
......
That means, now the child process image will be replaced by another process image.
As per picture you have shown, a process is supposed to fork 2 child process before calling execlp(), if it is a parent process in the given process tree. Similar kind of problems are there in below part of your code.
I cannot wrap my head around when each process should be forked in order to reflect this hierarchy, .....
Look at the process tree closely and you will find it as a perfect binary tree where every internal node has 2 child and all leaf nodes are at same level.
That said, every process should create 2 child process and then call execlp() and as soon as you reach to the given height (which is 2 in your case), no child process should fork further.
I will show you how to create the process hierarchy and you can add the execlp() call to replace the current process image with some other process image.
add to that the non-negotiable use of execlp() which replaces the current process image.
I believe, here, the current process means the process which is forking of child processes and this includes the top most process (equivalent to root in tree) as well.
To create the hierarchy of process as perfect binary tree, you can do:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
int main (int argc, char *argv[]) {
int height;
if (argc != 2) {
printf ("Invalid number of arguments, exiting..\n");
exit (0);
}
height = atoi (argv[1]);
if (height < 0) {
printf ("Invalid input.\n"); // error handling can be better
exit (0);
}
printf ("Parent process, my pid = %d, height = %d\n", getpid(), height);
for (int i = 0; i < height; ++i) {
printf ("\nMy pid : %d, current height of tree : %d, forking..\n", getpid(), i);
pid_t pid = fork();
if (pid == -1) {
printf ("Fork failed\n");
} else if (pid == 0) {
printf ("My pid = %d, [my parent : %d], I am child 1..\n", getpid(), getppid());
// this sleep is for sequenced output, otherwise it's not needed
// sleeping for 1 second
sleep (1);
continue;
}
pid = fork();
if (pid == -1) {
printf ("Fork failed\n");
} else if (pid == 0) {
printf ("My pid = %d, [my parent : %d], I am child 2..\n", getpid(), getppid());
// this sleep is for sequenced output, otherwise it's not needed
// sleeping for 1 second
sleep (1);
continue;
}
// break the loop as the current process is done with forking 2 child process
break;
}
// ADD execlp call here
// This part of code is to just show you the hierarchy.
// If you add execlp call above then part is not needed.
while (wait(NULL) > 0);
printf ("pid %d : I am EXITING\n", getpid());
// added sleep for sequenced output, otherwise it's not needed
sleep (1);
return 0;
}
Usage: ./a.out <height_of_process_tree>
Output:
# ./a.out 0
Parent process, my pid = 50807, height = 0
pid 50807 : I am EXITING
# ./a.out 1
Parent process, my pid = 50808, height = 1
My pid : 50808, current height of tree : 0, forking..
My pid = 50809, [my parent : 50808], I am child 1..
My pid = 50810, [my parent : 50808], I am child 2..
pid 50810 : I am EXITING
pid 50809 : I am EXITING
pid 50808 : I am EXITING
# ./a.out 2
Parent process, my pid = 50811, height = 2
My pid : 50811, current height of tree : 0, forking..
My pid = 50812, [my parent : 50811], I am child 1..
My pid = 50813, [my parent : 50811], I am child 2..
My pid : 50812, current height of tree : 1, forking..
My pid : 50813, current height of tree : 1, forking..
My pid = 50814, [my parent : 50812], I am child 1..
My pid = 50815, [my parent : 50813], I am child 1..
My pid = 50816, [my parent : 50812], I am child 2..
My pid = 50817, [my parent : 50813], I am child 2..
pid 50814 : I am EXITING
pid 50815 : I am EXITING
pid 50816 : I am EXITING
pid 50817 : I am EXITING
pid 50812 : I am EXITING
pid 50813 : I am EXITING
pid 50811 : I am EXITING

execvp in C not going through ar

I'm trying to use exec to execute a list of commands given as arguments.
Example input when In run the program would be ./assn2 ls date.
When I do this only the first command is executed.
#include<stdio.h>
#include<stdlib.h>
#include<sys/wait.h>
#include<unistd.h>
int main(int argc, char *argv[])
{
int args = argc-1;
pid_t childpid = fork();
// error
if (childpid < 0)
{
perror("fork() error");
exit(-1);
}
// parent process
if (childpid != 0)
{
printf("Parent Process started, now waiting for ID: %d\n", childpid);
wait(NULL);
printf("Parent Process resumeed. Child exit code 0. Now terminating\n");
exit(0);
}
// child process
if (args > 0)
{
printf("Child process has begun. %d argument/s provided\n", args);
int i;
for (i = 1; i <= argc; i++)
{
execlp(argv[i], argv[i], NULL);
}
execvp(argv[1], argv);
}
else
{
printf("No arguments provided, terminating child\n");
}
return 0;
}
Once the first child process execs (and succeeds), the for loop no longer continues because the an execlp would just replace the current process image with the command being exec'ed.
What you want to do is to loop over the command line arguments in the parent process and exec once for each of the command. Something like is probably what you're after:
for(int i = 1; i < argc; i++) {
pid_t pid = fork();
if (pid == 0) {
execlp(argv[i] ,argv[i], (char*)0);
perror("exec");
} else if (pid > 0) {
wait(NULL);
} else {
perror("fork");
exit(1);
}
}
What are you trying to achieve with the sequential calls to execlp() and execvp()? These functions are not meant to return. I think you should read the ref:
The exec() family of functions replaces the current process image with a new process image. [..] The exec() functions only return if an error has occurred.
As a result you cannot execute them one after another in the same process.
Read about fork():
fork() creates a new process by duplicating the calling process.
Moreover, here:
for(i = 1; i <= argc; i++)
you go out of bounds, since argv starts indexing from 0, and ends at argc - 1.
Chnage it to:
for(i = 1; i < argc; i++)

how to not block parent with waitpid

I need to create a program that creates n number of processes and displays information. When each process ends, I am to print it's PID and the exit status. The way I am doing it, the parent program waits to create the next process until the current one ends. I need it so that it keeps creating the child processes and just displays the exit information when ever one process ends without blocking the parent from continuing. I can;t figure out where to put my wait to ensure this. Below is my code:
int main (int argc, char *argv[])
{
if (argc < 2)
{
printf("\n\nUsage: %s <enter a number (12 or less)>\n\n", argv[0]);
exit (-1);
}
else
{
int *processNum = (int *)malloc(sizeof(12));
int processNumTemp;
processNumTemp = atoi(argv[1]);
processNum = &processNumTemp;
if(*processNum > 12 || *processNum < 1)
{
printf("\n\nUsage: %s <enter a number (12 or lrss)>\n\n", argv[0]);
}
else
{
parentInfo(processNum);
createChildProcess(processNum);
}
}
return 0;
}
//Name: parentInfo
//Description: Displays information about the parent process
//Parameters: processNum - stores the number of child processes to create
// (entered at the command line).
//Return: none
void parentInfo(int *processNum)
{
printf("Parent process ID: %d\n", getppid());
printf("Number of processes to create: %d\n", *processNum);
}
//Name: createChildProcess
//Description: Creates n number of child processes.
// For each child process, it says its a child process and it
// displays its PID.
// After each child process closes, the parent displays info.
//Parameters: processNum - stores the number of child processes to create
// (entered at the command line).
//Return: none
void createChildProcess(int *processNum)
{
int i;
int childStatus;
pid_t childpid;
/*The for loop will create n number of processes based on the value of processNum.*/
for(i = 1; i <= *processNum; i++)
childpid = fork();
//Executes if fork didn't work
if(childpid < 0)
{
perror("fork");
exit(1);
}
//Executes if the fork worked
else if( childpid == 0)
{
int pid = getpid();
//Prints a message and the child processe's PID
printf("\nHello I am a child process.\n");
printf("My PID is %d. \n", getpid());
for(int x = 1; x <= pid; x ++);
exit(15);
}
}
//Executes after the child process has ended
//Checks the child process's exit status
waitpid(childpid, &childStatus, WUNTRACED);
printf("\nPID of the child process that was just created: %d.\n", childpid);
if(WIFEXITED(childStatus))
{
printf("PID %d exited normally. Exit number: %d\n", childpid, WEXITSTATUS(childStatus));
}
else if(WIFSTOPPED(childStatus))
{
printf("PID %d was stopped by %d\n", childpid, WSTOPSIG(childStatus));
}
else if(WIFSIGNALED(childStatus))
{
printf("PID %d exited due to signal %d\n.", childpid, WTERMSIG(childStatus));
}
else
{
perror("waitpid");
}
}
Before fork code
signal(SIGCHLD, childHandler);
In childHandler put your waitpid code.
void childHandler(int signum)
{
pid_t childpid;
int childstatus;
while ((childpid = waitpid( -1, &childstatus, WNOHANG)) > 0)
{
if (WIFEXITED(childStatus))
{
printf("PID %d exited normally. Exit number: %d\n", childpid, WEXITSTATUS(childStatus));
}
else
if (WIFSTOPPED(childStatus))
{
printf("PID %d was stopped by %d\n", childpid, WSTOPSIG(childStatus));
}
else
if (WIFSIGNALED(childStatus))
{
printf("PID %d exited due to signal %d\n.", childpid, WTERMSIG(childStatus));
}
else
{
perror("waitpid");
}
}
}
}
You should not use async-unsafe calls like printf inside a signal handler so alter your code to save the status in a global or heap allocated array - you know the size to create from processNum - and print the status info outside the handler.
Also, as currently structured, your parent could end before reaping all the children. Add a counter for the children so that you wait on all of them before the parent exits.
Look into signal SIGCHLD. If you have it blocked, you must unblock it or might instead explicitly check for it.
The purpose of wait is to, well, wait, so the way to solve your problem is to first create all the children, then start waiting for them to terminate.
Here is a program which does that:
// fork
#include <unistd.h>
// wait
#include <sys/types.h>
#include <sys/wait.h>
// exit
#include <stdlib.h>
//printf
#include <stdio.h>
void child( int id)
{
int seed= id;
int x= rand_r( &seed) % 10;
sleep( x);
exit( x);
}
int main( int argc, char *argv[])
{
const int n= 5;
int i;
printf( "creating %d children.\n", n);
for ( i= 0; i < n; ++i) {
pid_t pid= fork();
if ( !pid)
child( i); // does not return
else
printf( "child [0x%x] created.\n", pid);
}
// all the children are created now
// now we wait for them to terminate
printf( "waiting for children to terminate.\n", n);
for ( i= 0; i < n; ++i) {
int result;
pid_t pid= wait( &result);
printf( "child [0x%x] terminated with result [%u].\n", pid, WEXITSTATUS( result));
}
puts( "all children terminated.");
}

Interprocess Communication fork() - Timing wait() and/or sleep()

I've been asked to develop the consumer (client) side to a producer (server), where the producer creates processes, waits until the consumer has read shared memory and deleted processes, then passes control back to the producer for the killing of processes and the shutting down of the shared memory block.
I've researched the difference between sleep and wait, and realise that as soon as fork() is called, the child process begins running.
The below code is after the creation of processes and checks if they're parent processes. If they are, they wait(0). *Now for my question, how do I know where the code in the consumer starts to be executed, and how do I pass it back? *
else if(pid > 0)
{
wait(0);
}
Below can be seen the main loop the producer uses.
int noToCreate = atoi(argv[2]); // (user inputs on cmd line "./prod 20 10 5" - 20 size of shared mem, 10 process to be created, 5 processes to be deleted)
while(*memSig != 2)
{
while(*memSig == 1) // set memsignature to sleep while..
{
sleep(1);
}
for(B = 0; B < noToCreate; B++)
{
pid = fork();
if(pid == -1)
{
perror("Error forking");
exit(1);
}
else if(pid > 0)
{
wait(0);
}
else
{
srand(getpid());
while(x == 0)
{
if(*randNum == 101)
{
*randNum = rand() % (100 -
1) + 1;
*pidNum = getpid();
printf("priority: %d
Process ID: %d \n", *randNum, *pidNum);
x = 1;
}
else
{
*randNum++;
*pidNum++;
}
}
exit(0);
}
} /* Closes main for loop */
if(*memSig == 0)
{
*memSig = 1;
}
} /* Closes main while loop */
Thanks a bunch guys :)
wait make parent blocked until any child end .You can use waitpid let parent wait specific child.
When a child process end, it will set a signal SIG_CHILD.
The pid is zero for the child process after the fork, so you are in the child process at your call to the srand function.
The other pid is that for the child process which allows he original thread to wait for the child to finish. If you wish to pass data between the processes consider using a pipe. A popen call returns two file descriptors, one to write end and the other to the read end. Set this up before the fork and the two processes can communicate.
wait makes the parent wait for any child to terminate before going on (preferably use waitpid to wait for a certain child), whereas sleep puts the process to sleep and resumes it, as soon as the time passed as argument is over.
Both calls will make the process block.
And it is NOT said that the child will run immediately, this is indeterminate behavior!
If you want to pass data between producer and consumer, use pipes or *NIX sockets, or use the return-value of exit from the child if a single integer is sufficient.
See man wait, you can get the return value of the child with the macro WEXITSTATUS.
#include <sys/wait.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
int
main(int argc, char *argv[])
{
pid_t cpid, w;
int status;
cpid = fork();
if (cpid == -1) {
perror("fork");
exit(EXIT_FAILURE);
}
if (cpid == 0) { /* Code executed by child */
printf("Child PID is %ld\n", (long) getpid());
if (argc == 1)
pause(); /* Wait for signals */
_exit(atoi(argv[1]));
} else { /* Code executed by parent */
do {
w = waitpid(cpid, &status, WUNTRACED | WCONTINUED);
if (w == -1) {
perror("waitpid");
exit(EXIT_FAILURE);
}
if (WIFEXITED(status)) {
printf("exited, status=%d\n", WEXITSTATUS(status));
} else if (WIFSIGNALED(status)) {
printf("killed by signal %d\n", WTERMSIG(status));
} else if (WIFSTOPPED(status)) {
printf("stopped by signal %d\n", WSTOPSIG(status));
} else if (WIFCONTINUED(status)) {
printf("continued\n");
}
} while (!WIFEXITED(status) && !WIFSIGNALED(status));
exit(EXIT_SUCCESS);
}
}

Semaphores, processes and incrementing variables in shared memory

This is a homework question. I have to write a program forking itself 20 times. Each new process is adding +1 to a variable (integer) which is shared between all of them. The thing is, I have to use semaphores (IPC). This piece of code is 'working' - giving the value of 20 in the end.
*buf = 0;
for(i=1; i<=20; ++i)
{
if(fork()!=0)
{
*buf += 1;
exit(0);
}
}
EDIT:
Based on this code I am trying to get output like :
I am child 1...
I am child 2...
.
.
.
I am child 20...
It worked once (first time), and then the order became random. But I did not change any code. What am I doing wrong?
Well your major problem is this:
if (fork()!=0) //<-- this
fork() will return -1 on error, the parent pid, OR ZERO for the child. So you are actually doing everything in the parent. Change to (fork() ==0) and it does what you want.
Also you should wait on your children and detach shared memory. (I added some output of the process ids to make it a little clearer.)
printf("I AM THE PARENT pid = %d\n", getpid());
*buf = 0;
for(i=1; i<=20; ++i)
{
if((pid = fork()) == -1)
{
perror("fork");
exit(1);
}
if (pid == 0)
{
v(semid, 0);
*buf += 1;
p(semid, 0);
printf("I am child %d with pid = %d\n", i, getpid());
shmdt(buf);
exit(0);
}
}
for (i = 1; i <= 20; ++i)
{
pid = wait(&status);
printf("child pid = %d reaped\n", pid);
}
printf("buf: %p\n", buf);
printf("*buf: %d\n", *buf);
shmdt(buf);
return 0;

Resources