Killing a child process from a signal handler - c

I'm writing a simple shell, and I have to fork a child process an external program using execv. I have to send the signal TSTP(Cntl+Z) to the signal handler, and then kill the currently running child process. My problem is I can't find a way to pass the Child pid into the signal handler. If i do a getpid() in the handler, it just returns the parent pid. I also tried setting the child pid as getpid() inside the child process, and having that variable as a global variable, but that also didn't work. Here is some of the code I have so far.
void handler(int);
//in main
if (!built_in_cmd(myArgc,myArgs)) {
pid_t pid;
char *x = myArgs[0];
if((pid=fork())<0)
printf("Parent: fork() process failed");
else {
if (pid == 0) {
y=getpid();
printf("Parent: My child has been spawned. %d %d\n",y,getppid());
execv(x, myArgs);
exit(0);
}
else {
signal(SIGTSTP,handler);
wait(0);
printf("Parent: My child has terminated.\n");
}
}
}
return;
//outside main
void handler(int signo){
kill(idk,SIGKILL);
}

Signals are asynchronous in nature, there's no way to pass any extra state to them except through global variables. Assuming that you only ever have one thread waiting for a child, it's safe to use a global, but otherwise there's no multithread-safe way of doing so:
// At global scope
pid_t child_pid = (pid_t)-1;
...
void myfunc()
{
pid_t pid;
if((pid = fork()) < 0)
...
else if(pid == 0)
...
else
{
child_pid = pid;
...
}
}

Related

How to restart a child process from parent process in c

How to restart the child process from parent process when child process terminates. In one application I have created a child process which has an infinite while loop. The application runs in a router. When some event happens my child process terminates. But after rebooting the router everything works fine. Is it possible to restart my child process from parent process(parent process always works).
int main()
{
pid_t pid;
pid = fork();
if (pid == 0)
{
while(1)
{
printf("Child process\n");
sleep(1);
}
}
else
{
while(1)
{
printf("parrent process\n");
}
}
return 0;
}
Assuming you only start one process and it's another executable:
pid_t pid = 0;
void sigchld(int unused)
{
if (pid) {
int status = 0;
waitpid(pid, &status, WNOHANG);
if (WIFSTOPPED(status) || WIFCONTINUED(status)) return;
if (!WIFSIGNALED(status)) return; // It exited rather than terminated
pid = 0;
}
if ((pid = vfork() == 0) {
/* fork() isn't really signal safe anymore but vfork() still is! */
execle(...);
_exit(0);
}
}
int main()
{
pid = 0;
struct sigaction sa;
memset(&sa, 0, sizeof(sa));
sa.sa_handler = sigchld;
sa.sa_flags = SA_NODEFER;
sigaction(SIGCHLD, &sa, NULL);
kill(SIGCHLD, getpid());
while(1)
{
printf("parrent process\n");
}
}
Trivially adaptable to more than one, but if it's not another executable you have your work cut out from you. Attempting to fork() and run more code inside the signal handler is fraught with pearl. fork() itself is only safe if you haven't installed any pthread_atfork() handlers (which don't run in vfork()). You cannot call malloc() in a signal handler, and stdio is unreasonably tricky and best to assume it just doesn't work.

How to determine a child process is a a background process or foreground process by looking at code?

we know that if a parents process wait for the termnination of its child processes first, then the child processes are called foreground process, for example:
int main() {
int status;
...
if ((pid = fork()) == 0){
...// Child runs
exit(0);
}
waitpid(pid, &status, 0); //parent wait for its child to reap it
}
since the parent process uses waitpid to wait and reap its child, so the child process is foreground process.
But what if I use signal handler to reap child processes as:
void sigchld_handler(int s){
int olderrno = errno;
pid = waitpid(-1, NULL, 0);
errno = olderrno;
}
volatile sig_atomic_t pid;
int main() {
sigset_t mask, prev;
signal(SIGCHLD, sigchld_handler);
sigemptyset(&mask);
while(1) {
sigprocmask(SIG_BLOCK, &mask, &prev); // Block SIGCHLD
if ((pid = Fork()) == 0){
...// Child runs
exit(0);
}
// Wait for SIGCHLD to be received
pid = 0;
while (!pid)
sigsuspend(&prev);
...//Do some work after receiving SIGCHLD
}
exit(0);
}
then can I say the child process in latter is a foreground process, because the parent wait for it using while (!pid) sigsuspend(&prev);?
But my understanding is that a child can be a foreground process only if the parents explicitly the child's process id in waitpid like waitpid(pid, &status, 0);, bu in the latter example, the parents doesn't specify child process's id to reap (use -1 in waitpid)?

Setting parent to child process group with setpgid fails

I'm trying to change the pgrp of the processes to that of the child's so i can setsid on the parent process. The only thing is I keep getting an EPERM error code. Both processes have the same session group, according to htop.
I'm basing this off of this blog post, so I can change which terminal output gets directed to.
void sig_exit(int signum)
{
_Exit(0);
}
pid_t change_process_group()
{
pid_t child_pid;
if ((child_pid = fork()) < 0)
{
perror("fork failed while attaching to term");
exit(1);
}
if (child_pid == 0)
{
pid_t parent = getppid();
setpgid(0, getpid());
signal(SIGUSR1, sig_exit); // wait till parent tells child to exit
//sleep(5);
//kill(parent, SIGUSR2);
pause();
printf("Shouldn't reach this\n");
}
//sleep(5);
//signal(SIGUSR2, sig_wait);
//pause();
int parent_pid = getpid();
int code = setpgid(parent_pid, child_pid); // need child process group
printf("%s\n", strerror(errno));
setsid();
return child_pid;
}
main()
{
pid_t child = change_process_group();
kill(child, SIGUSR1);
}
The commented out lines were from me thinking the processes might not be executing in the correct order, but those don't appear to fix the problem.
How may I correctly use setpgid to change the pgrp of the parent process to the child's?
This is a race condition and it works if you uncomment the sleep(5) line in the parent. When you call setpgid(parent_pid, child_pid), the child_pid process group must exist. It isn't enough that there exists a process with the PID child_pid: setpgid needs an existing process group unless the process is putting itself into its own group. If setpgid(parent_pid, child_pid) in the parent runs after setpgid(0, getpid()) in the child, it works.
Sleeping is both inefficient and fragile, so instead of that the parent should wait for a notification from the child. Signals are fragile because there aren't many different signals and they could come from anywhere. A good way to communicate between related processes is a pipe. Since all you need here is a one-time notification, you can set up a pipe and read from it in the parent (with the write end closed in the parent). The parent will wait until the child writes to the pipe or closes it. In the child, just close the write end of the pipe when you've finished the preparations. The parent's read call (or select if you need to do other things at the same time) will return.
Proof-of-concept code:
pid_t change_process_group()
{
pid_t child_pid;
int child_ready_pipe[2];
if (pipe(child_ready_pipe) < 0)
{
perror("pipe");
exit(1);
}
if ((child_pid = fork()) < 0)
{
perror("fork failed while attaching to term");
exit(1);
}
if (child_pid == 0)
{
close(child_ready_pipe[0]);
sleep(1); // mimic slow start of the child
if (setpgid(0, 0))
perror("child setpgid to create group");
close(child_ready_pipe[1]);
signal(SIGUSR1, sig_exit); // wait till parent tells child to exit
pause();
printf("Shouldn't reach this\n");
}
close(child_ready_pipe[1]);
int parent_pid = getpid();
char ignored;
read(child_ready_pipe[0], &ignored, 1);
close(child_ready_pipe[0]);
if (setpgid(parent_pid, child_pid) < 0) // need child process group
perror("parent setpgid");
if (setsid() < 0)
perror("parent setsid");
return child_pid;
}

Create new process in separate function [c]

I wanna create spare process (child?) in specific function called eg. void process(). I want just to create that child process and do nothing with it. I just wanna it alive and do nothing while main() of my app will be working as I want.
In some point of my app's main() I will be killing child process and then respawn it again. Any ideas how to do that ?
I have something like that but when I'm using this function to create process I get everything twice. Its like after initiation of process() every statement is done twice and i dont want it. After adding sleep(100) after getpid() in child section seems working fine but I cannot kill it.
int process(int case){
if(case==1){
status=1;
childpid = fork();
if (childpid >= 0) /* fork succeeded */
{
if (childpid == 0) /* fork() returns 0 to the child process */
{
printf("CHILD PID: %d\n", getpid());
}
/* fork() returns new pid to the parent process *//* else
{
}*/
}
else
{
perror("fork");
exit(0);
}
}
else{
if(status!=0){
status=0;
//kill!!!!
system(a); //getting kill -9 PID ; but PID is equal 0 here...
printf("\nkilling child");
}
}
}
how to just spawn new child process and let it just exist, like some sort of worker in C#?
Assuming you are in Linux, here's an example that might clarify your view: parent process spawns a child, the child calls pause() which suspends it until a signal is delivered, and finally parent process kill's the child with SIGKILL.
#include <unistd.h>
#include <signal.h>
#include <stdio.h>
int main()
{
pid_t pid;
pid = fork();
if (pid < 0) { perror("fork"); exit(0); }
if (pid == 0) {
printf("Child process created and will now wait for signal...\n");
pause(); //waits for signal
}
else {
//do some other work in parent process here
printf("Killing child (%ld) from parent process!", (long) pid);
kill(pid, SIGKILL);
}
return 0;
}
Please note that fork() returns:
<0 on failure
0 in child process
the child's pid in parent process.

How to make parent wait for all child processes to finish?

I'm hoping someone could shed some light on how to make the parent wait for ALL child processes to finish before continuing after the fork. I have cleanup code which I want to run but the child processes need to have returned before this can happen.
for (int id=0; id<n; id++) {
if (fork()==0) {
// Child
exit(0);
} else {
// Parent
...
}
...
}
pid_t child_pid, wpid;
int status = 0;
//Father code (before child processes start)
for (int id=0; id<n; id++) {
if ((child_pid = fork()) == 0) {
//child code
exit(0);
}
}
while ((wpid = wait(&status)) > 0); // this way, the father waits for all the child processes
//Father code (After all child processes end)
wait waits for a child process to terminate, and returns that child process's pid. On error (eg when there are no child processes), -1 is returned. So, basically, the code keeps waiting for child processes to finish, until the waiting errors out, and then you know they are all finished.
POSIX defines a function: wait(NULL);. It's the shorthand for waitpid(-1, NULL, 0);, which will suspends the execution of the calling process until any one child process exits.
Here, 1st argument of waitpid indicates wait for any child process to end.
In your case, have the parent call it from within your else branch.
Use waitpid() like this:
pid_t childPid; // the child process that the execution will soon run inside of.
childPid = fork();
if(childPid == 0) // fork succeeded
{
// Do something
exit(0);
}
else if(childPid < 0) // fork failed
{
// log the error
}
else // Main (parent) process after fork succeeds
{
int returnStatus;
waitpid(childPid, &returnStatus, 0); // Parent process waits here for child to terminate.
if (returnStatus == 0) // Verify child process terminated without error.
{
printf("The child process terminated normally.");
}
if (returnStatus == 1)
{
printf("The child process terminated with an error!.");
}
}
Just use:
while(wait(NULL) > 0);
This ensures that you wait for ALL the child processes and only when all have returned, you move to the next instruction.

Resources