In C, I would like to print the exit status of a child process when it finishes executing. I know how to do this in a foreground process (just use waitpid) but in a background process I want the command line access to be instantly given to the user when the child is forked.
In other words I can't wait around in the case of the parent and instead I have to return to the top and let the while loop execute again.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <dirent.h>
#include <limits.h>
#include <fcntl.h>
#include <unistd.h>
#include <signal.h>
#include <sys/wait.h>
#define MAX_JOBS 100 //max jobs that can go on at once
pid_t jobs[MAX_JOBS];
int job_count = 0;
int last_exit_status = 0;
char* last_termination = 0;
void addJob(pid_t pid) {// Function to add a job to the list
if (job_count < MAX_JOBS) {
jobs[job_count] = pid;
job_count++;
}
}
//main func
int main() {
int x = 0;
char *token;
char *argv[1024]; // Array to store command and arguments
char *argvSec[1024];
int i = 0;
while(x == 0) {
int pid = getpid();
char* command = prompt(); //get user input
if (command != NULL) {
int childExitMethod;
pid_t spwanPID = fork();
switch (spwanPID){
case -1:
last_exit_status = 1;
case 0:
execvp(argv[0], argv);
last_exit_status = 1;
exit(1);
default:
if (isForeGround){
waitpid(spwanPID, &childExitMethod, 0); // Wait for the child only if foreground
if (WIFEXITED(childExitMethod) && !WEXITSTATUS(childExitMethod)) {
last_exit_status = 0;
} else {
printf("bash: %s: command not found\n", command);
last_exit_status = 1;
}
} else if (isBackground){
}
}
}
}
return 0;
}
The problem I was expeirencing was because waitpid(spwanPID, &childExitMethod, 0); blocks and waits for the child to finish running, because of this I couldnt give the user command line access instantly after the fork. I was able to solve this by using waitpid(-1, ¤tStatus, WNOHANG); where WHOHANG stops waitpid from blocking. And I can check the child termination by doing so before the prompt function. Heres an example.
void check_background() {
if (backgroundChildrenRunning > 0) { //this function is to print the background process termination signal
int currentStatus;
int completedChild = waitpid(-1, ¤tStatus, WNOHANG); //use WHOHANG so it does not block
if (completedChild > 0) {
if (WIFEXITED(currentStatus)) {
printf("Background process with ID %d has been completed. Exit value: %d.\n", completedChild, WEXITSTATUS(currentStatus));
last_termination = WEXITSTATUS(currentStatus);
}
else {
if (completedChild == backgroundPid) {
printf("Background process with ID %d has been completed. Terminated by signal: %d.\n", completedChild, WTERMSIG(currentStatus));
last_termination = WTERMSIG(currentStatus);
}
}
backgroundPid = 0;
backgroundChildrenRunning -= 1;
}
}
}
int main() {
int x = 0;
char *token;
char *argv[1024];
char *argvSec[1024];
while(x == 0) {
check_background(); //check background here
int pid = getpid();
char* command = prompt(pid); //get user input
if (command != NULL) {
int childExitMethod;
pid_t spwanPID = fork();
switch (spwanPID){
case -1:
last_exit_status = 1;
case 0:
execvp(argv[0], argv);
last_exit_status = 1;
exit(1);
default:
if (hasSymbolEnd == 0){
waitpid(spwanPID, &childExitMethod, 0); // Wait for the child only if background
if (WIFEXITED(childExitMethod) && !WEXITSTATUS(childExitMethod)) {
last_exit_status = 0;
}
} else {
printf("background pid is %d\n", spwanPID); //print the child pid as requeste
backgroundChildrenRunning += 1;
}
}
}
}
return 0;
}