How to send data from parent process to child process and signal - c

I got two processes run in parallel. I want that the parent will send some char to the child. I want to use pipe() and write from the parent and send signal to the child, then check from child if signal sent and read the char at the child process. How can i do that?
int run() {
pid_t pid;
int filds[2];
pipe(filds);
char *args[150] = {"./draw.out", NULL}; // child will run executable.
char buff = '\0';
if ((pid = fork()) < 0) { // fork a child process/
printf("*** ERROR: forking child process failed\n");
exit(1);
} else if (pid == 0) {
execvp(args[0], args); // run program from the child process.
} else { // for the parent
char btnPressed = getch();
while (btnPressed != 'q'){
btnPressed = getch(); // gets the char
write(filds[1],buff, BUFF_SIZE); //write to the pipe.
// how do i send safe signal to child?
}
}
}

First of all, you cannot use execvp and pipe together. Since execvp replaces the child process with another executable. It means that the parent and child process don't share the pipe anymore because the new process created by execvp has a different stack.
You can pass the data on shared memory and send a signal to the child. After the child reads the data, it can also send a signal to indicate that I got the data.

Related

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;
}

Interrupt a process calling the function popen

I need to implement a child process that will execute a file and send the execution result, the 2 process will communicate with a shared memory segment.
My problem is that i want to kill the child process calling popen after 10 seconds but the function popen ignores signals.
Here is my code (shared memory segment not included) :
void kill_child(int sig)
{
kill(child_pid,SIGKILL);
printf("processus killed \n");
}
/*code....*/
signal(SIGALRM,(void (*)(int))kill_child);
if(fork()==0){
res.buffer=true;
FILE * fd;
char cmd[BUFFER_SIZE],output[BUFFER_SIZE];
strcpy(cmd,"./");
strcat(cmd,res.filepath);
system(cmd);
if((fd=popen(cmd,"r"))== NULL)
exit(1);
else
res.status=200;
strcpy(output,"");
while(fgets(buf,sizeof(buf)-1,fd))
strcat(output,buf);
if(pclose(fd))
exit(1);
strcat(res.customHTML,output);
res.buffer=true;
int err = sendResponse(res,args->client_fd);
if (err < 0) on_error("failed!\r\n");
exit(0);
}
else{
int status;
alarm(10);
waitpid(-1,&status,0);
printf("status %d _n);
}
How can make the child process interruptible?
thanks
First off, you need to actually store the child PID into child_pid. It's returned from fork for the parent process so changing your fork call to
child_pid = fork();
if(child_pid == 0)
{
...
otherwise your call to kill is being passed a random value. Luckily it seems to be defaulting to 0, which kill takes to mean kill all processes in the same process group so your child process is being killed.
Secondly, rather than calling popen() call the executable yourself with (for example) execvp() and have the parent read the output using a pipe you create yourself...
int fds[2];
pipe(fds);
child_pid = fork();
if(child_pid == 0)
{
char *cmd[]={"mycmd",NULL};
/* Replace stdout with the output of the pipe and close the original */
dup2(fds[1],1);
close(fds[0]);
close(fds[1]);
execvp(cmd[0],cmd);
}
else
{
close(fds[1]);
alarm(10);
while(...)
{
read(fds[0],....);
if(waitpid(child_pid,&status,WNOHANG))
{
....
}
}
}
This way you've only got the one child process which is running your executable and you've got visibility on when and how it exits.

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.

how to correctly use fork, exec, wait

The shell i'm writing needs to execute a program given to it by the user. Here's the very shortened simplified version of my program
int main()
{
pid_t pid = getpid(); // this is the parents pid
char *user_input = NULL;
size_t line_sz = 0;
ssize_t line_ct = 0;
line_ct = getline(&user_input, &line_sz, stdin); //so get user input, store in user_input
for (;;)
{
pid_t child_pid = fork(); //fork a duplicate process
pid_t child_ppid = getppid(); //get the child's parent pid
if (child_ppid == pid) //if the current process is a child of the main process
{
exec(); //here I need to execute whatever program was given to user_input
exit(1); //making sure to avoid fork bomb
}
wait(); //so if it's the parent process we need to wait for the child process to finish, right?
}
}
Have I forked the new process & checked to see if it's a child process correctly
What exec could I use here for what I'm trying to do? What is the most simple way
What are my arguments to wait? the documentation I'm looking at isn't helping much
Assume the user might input something like ls, ps, pwd
Thanks.
Edit:
const char* hold = strdup(input_line);
char* argv[2];
argv[0] = input_line;
argv[1] = NULL;
char* envp[1];
envp[0] = NULL;
execve(hold, argv, envp);
Here's a simple, readable solution:
pid_t parent = getpid();
pid_t pid = fork();
if (pid == -1)
{
// error, failed to fork()
}
else if (pid > 0)
{
int status;
waitpid(pid, &status, 0);
}
else
{
// we are the child
execve(...);
_exit(EXIT_FAILURE); // exec never returns
}
The child can use the stored value parent if it needs to know the parent's PID (though I don't in this example). The parent simply waits for the child to finish. Effectively, the child runs "synchronously" inside the parent, and there is no parallelism. The parent can query status to see in what manner the child exited (successfully, unsuccessfully, or with a signal).

Killing a child process from a signal handler

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;
...
}
}

Resources