exit() or _exit()? - c

Consider this snippet of code:
void do_child(void);
int main(void){
int n;
pid_t child;
printf("Write a number: ");
scanf("%d", &n);
if(n != 1){
exit(1);
}
child = fork();
if(child >= 0){ /* fork ok */
if(child == 0){
printf("Child pid: %d\n", getpid());
do_child();
_exit(0);
}
else{ /* parent */
printf("Child parent: %d\n", getpid());
_exit(0);
}
}
else{ /* fallito */
perror("No fork");
return 1;
}
return EXIT_SUCCESS;
}
void do_child(void){
/* some code here */
if(1 != 1){
/* what to write here?? _exit or exit*/
}
}
When exiting from a child process it is best to write _exit instead of exit but if i need to call an external function and into this function i want to put an exit, what should i write? _exit or exit?

You can expect exit to call functions registered with atexit. _exit won't do that. Normally, each registered cleanup handler should be executed exactly once, usually in the process in which it was registered. This means that a child process should _exit() and the parent should exit(). If the child process does exec some other program, which is probably the most common case, then that new program will overwrite any registered handlers, which means that you are back to exit().
As to external functions: I'd say you should call exit but you should be prepared to encounter strange behaviour if the parent registers non-trivial stuff atexit before doing the fork. So try to fork early unless you mean to exec in the child. And have an eye on what exit handlers your own code and the libraries you use might install. I/O buffer flushing is one example.

exit() terminates after cleanup whereas _exit() terminates immediately.
I would suggest that under normal circumstances, exit() is the correct approach - although I am sure you will understand what you are doing if you chose _exit()?!
I'll cite MSDN online as it's in my favourites :)

Related

Child process not exiting with fork()

I am creating a simple Linux command shell in C. I am having trouble understanding where my code is having problems. "commands" is a list of strings of Linux commands that I want to be executed concurrently as the children processes of one parent. When all are done executing, I want the parent to exit the function. However, when I call exit(0), the for loop continues and parses the current command again, causing the args to be executed again in execvp. Am I using fork() and wait() correctly here? I have tried using waitpid() as well with no luck.
void executeShell(char** commands){
char **arr = commands;
char *c;
pid_t pid, wpid;
int status = 0;
for (c = *arr; c; c=*++arr){
// printf("%d-\n", strcmp(command, "exit"));
if (strcmp(c, "exit") == 0){
EXIT = 1;
return;
}
printf("Running command \'%s\'...\n", c);
char** args = parseStringToTokenArray(c, " ");
free(args);
/* fork and execute the command */
pid = fork();
if(pid < 0){
perror("fork() error\n");
return;
}
/* child process executes command */
else if (pid == 0){
/* 'cd' is not a part of /bin library so handle it manually */
if (strcmp(args[0], "cd") == 0){
changeDirectory(args[1]);
}
else if (strcmp(args[0], "sdir") == 0){
searchDirectory(args[1]);
}else{
/* parse commands with arguments */
execvp(args[0], args);//execute the command
}
exit(0);// <-----command is finished, so why no exit?
}
}
/* wait for children to complete */
while((wpid = wait(&status)) > 0);
}
If execvp succeeds, the entire child process address space is replaced by the program invoked by execvp(). This means that the exit(0) will only ever be invoked following your two special cases i.e. cd and sdir. As far as your code is concerned execvp() should never return, unless there is an error.
A further problem is that you free args immediately after allocating it and then go on to use it in your child processes. This is undefined behaviour.
The only problem I see with your wait code is that, if any of the children block waiting for user input, the parent will block waiting for the child to exit.
The cd code, has no effect on any process except the child in which it is executed. The parent's current directory is not affected. As you state in the comments, this can bet fixed by handling cd in the parent without forking.

Get returned value of a child process without holding parent execution

I need to be able to get the returned value from a child process without having to hold the execution of the parent for it.
Notice the a runtime error could happen in the child process.
Here is my program that I'm trying to make:
//In parent process:
do
{
read memory usage from /proc/ID/status
if(max_child_memory_usage > memory_limit)
{
kill(proc, SIGKILL);
puts("Memory limit exceeded");
return -5; // MLE
}
getrusage(RUSAGE_SELF,&r_usage);
check time and memory consumption
if(memory limit exceeded || time limit exceeded)
{
kill(proc, SIGKILL);
return fail;
}
/*
need to catch the returned value from the child somehow with
this loop working.
Notice the a runtime error could happen in the child process.
*/
while(child is alive);
The waitpid function has an option called WNOHANG which causes it to return immediately if the given child has not yet returned:
pid_t rval;
int status;
do {
...
rval = waitpid(proc, &status, WNOHANG);
} while (rval == 0);
if (rval == proc) {
if (WIFEXITED(status)) {
printf("%d exited normal with status %d\n", WEXITSTATUS(status));
} else {
printf("%d exited abnormally\n");
}
}
See the man page for waitpid for more details on checking various abnormal exit conditions.
The solutions using the WNOHANG flag would work only if you need to check just once for the exit status of the child. If however you would like to procure the exit status when the child exits, no matter how late that is, a better solution is to set a signal handler for the SIGCHLD signal.
When the child process terminates whether normally or abnormally, SIGCHLD will be sent to the parent process. Within this signal handler, you can call wait to reap the exit status of the child.
void child_exit_handler(int signo){
int exit_status;
int pid = wait(&exit_status);
// Do things ...
}
// later in the code, before forking and creating the child
signal(SIGCHLD, child_exit_handler);
Depending on other semantics of your program, you may want to use waitpid instead. (SIGCHLD may also be called if the program was stopped, not terminated. The man page for wait(2) describes macros to check for this.)

Waitpid and fork/exec's non-blocking advantage over a syscall?

I always hear that you should never use system() and instead fork/exec because system() blocks the parent process.
If so, am I doing something wrong by calling waitpid(), which also blocks the parent process when I do a fork/exec? Is there a way around calling waitpid...I always thought it was necessary when doing a fork/exec.
pid_t pid = fork();
if (pid == -1)
{
// failed to fork
}
else if (pid > 0)
{
int status;
waitpid(pid, &status, 0);
}
else
{
execve(...);
}
The WNOHANG flag (set in the options argument) will make the call to waitpid() non-blocking.
You'll have to call it periodically to check if the child is finished yet.
Or you could setup SIGCHLD to take care of the children.
If you want to do other stuff whilst the child process is off doing it's thing, you can set up a trap for SIGCHLD that handles the child finishing/exiting. Like in this very simple example.
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
pid_t pid;
int finished=0;
void zombie_hunter(int sig)
{
int status;
waitpid(pid, &status, 0);
printf("Got status %d from child\n",status);
finished=1;
}
int main(void)
{
signal(SIGCHLD,zombie_hunter);
pid = fork();
if (pid == -1)
{
exit(1);
}
else if (pid == 0)
{
sleep(10);
exit(0);
}
while(!finished)
{
printf("waiting...\n");
sleep(1);
}
}
I always hear that you should never use system() and instead fork/exec because system() blocks the parent process.
Never say never. If system() has the semantics you want, including, but not limited to, blocking the calling process, then by all means, use it! Do be sure that you understand all those semantics, though.
If your objective is to avoid blocking the parent process, then it is important to understand that the parent can perform an unbounded amount of work between forking a child and collecting it via one of the wait() family of functions. This is very much analogous to starting a new thread, proceeding on with other work, and then eventually joining the thread.
Moreover, if the parent doesn't need to know or care when the child terminates, then it is possible to avoid any need to wait for it at all, ever.

fork + wait gets EINTR on OSX

I fail at fork 101. I expect this to fork a child process, and output both child and parent printfs:
pid_t fpid;
if ((fpid = fork()) < 0)
{
printf("fork: %s\n", strerror(errno));
exit(-1);
}
if (0 == fpid) // child
{
printf("\nI am the child\n");
}
else
{
printf("\nI am the parent\n");
pid_t wpid;
while ((wpid = waitpid(WAIT_ANY, NULL, 0)))
{
if (errno == ECHILD)
break;
else if (wpid < 0)
printf("wait: %s\n", strerror(errno));
}
}
Instead, I get this output:
I am the parent
wait: Interrupted system call
So my question is: why doesn't the child get a chance to live and run? Won't someone please think of the children! Also, where does the EINTR come from? Obviously, this is somehow related to my first question.
Furthermore, when I run that code in a standalone program, it works correctly, but not when inside a larger program of mine; what could the larger program do to upset waitpid?
FWIW this is on OSX 10.9.
On OSX, it's not legal to do much on the child side of a fork before/without execing. See the caveat at the bottom of the fork man page. The list of safe functions is on the sigaction(2) man page. printf() is not among them.
Also, stdout is likely buffered. The results of the printf() may not be being flushed. It would be flushed if you called exit(), but that's also not legal on the child side of a fork. (It's appropriate to use _exit() but that doesn't flush open streams.) As it is, you don't appear to be exiting your child process, which means flow of execution continues to the caller of the code you've shown, presumably returning to the rest of your program. It may be getting stuck there because of the limitations on the child side of a fork.
You may have more luck if you do something like this in the child:
const char msg[] = "\nI am the child\n";
write(STDOUT_FILENO, msg, sizeof(msg) - 1);
_exit(0);
Finally, I think you should pass fpid rather than WAIT_ANY to waitpid(). You have a specific child process you want to wait for. In the context of a larger program, you don't want to steal the notification of the termination of a child spawned by some other subcomponent. And you always need to loop around interruptible syscalls until they return something other than EINTR.
Only check errno if a failure was indicated, for example by a system call returning -1.
The code should look like this:
pid_t fpid;
if ((fpid = fork()) < 0)
{
printf("fork: %s\n", strerror(errno));
exit(-1);
}
if (0 == fpid) // child
{
printf("\nI am the child\n");
}
else
{
printf("\nI am the parent\n");
pid_t wpid;
while ((wpid = waitpid(WAIT_ANY, NULL, 0)))
{
if (-1 == wpid)
{
perror("waitpid() failed");
}
else if (wpid == fpid)
{
/* My child ended, so stop waiting for it. */
break;
}
}
}

fork() function will never return 0

I am currently trying to run a fork function in C where in the child section of the code,
I am trying to execute a command using exacvp, but before the execution I am trying a printf function which never executes. I ran this in debug and I have noticed that the pid is never assigned 0. I did try a simple fork example on a separate project and it worked smoothly. Does anyone have an idea why the child section never executes?
int startProcesses(int background) {
int i = 0;
while(*(lineArray+i) != NULL) {
int pid;
int status;
char *processName;
pid = fork();
if (pid == 0) {
printf("I am child");
// Child Process
processName = strtok(lineArray[i], " ");
execvp(processName, lineArray[i]);
i++;
continue;
} else if (!background) {
// Parent Process
waitpid(pid, &status, 0);
i++;
if(WEXITSTATUS(status)) {
printf(CANNOT_RUN_ERROR);
return 1;
}
} else {
i++;
continue;
}
}
return 0;
}
stdio files are flushed on program's exit, but execvp directly replaces the process with another image, bypassing the flush-at-exit mechanism and leaving the I am child message in memory never to be sent to the screen. Add an explicit fflush(stdout) before execvp, or end your string with \n so that it is automatically flushed when running on a TTY.
Note that execvp never exits, and if it does, it is because it has failed to execute the new process. At that point, the only thing the child can do is to report an error and call _exit(127) (or similar exit status). If the child continues, an incorrectly configured command name will cause it to execute the rest of the parent's loop in parallel with the parent. This process will continue for other descendants, effectively creating a fork bomb that can grind your system to a halt.

Resources