I wrote a program which stops the time of a child process calling execvp(). The next task is to occasionally stop the child process for a given time and continue it.
pid_t child = fork();
if(child == 0){
// In child process
execvp(); // e.g. sleep 10
} else {
// In parent process
kill(child, SIGSTOP);
// Do stuff
kill(child, SIGCONT);
}
What i think is happening here is, that kill(child, SIGSTOP) is pausing the child process but not the execvp() process within it. Is there a way to get the pid of the execvp() process and stop it directly?
Edit example:
int main(int argsc, char *argv[]) {
int status;
// Fork for processB
pid_t processB = fork();
if (processB == 0) {
system("~/loop.sh");
} else {
for (;;) {
sleep(5);
kill(processB, SIGSTOP);
std::cout << "Should have stopped counting" << std::endl;
sleep(3);
kill(processB, SIGCONT);
// If loop process ended, exit watchDog
if (waitpid(processB, &status, WNOHANG) == processB)
_exit(1);
}
}
return 0;
}
Loop.sh
counter=0;
while :;
counter=$((counter+1));
do echo $counter;
sleep 1;
done
return 0;
Related
I know wait(NULL) waits for all child process to terminate. But while working with fork(),execv()/execvp() and wait(), it seems wait(NULL) is not waiting for all the child processed to terminate.
I was trying to understand the unexpected behaviour of the wait(NULL) system call in my code.
I tried to recreate the same situation with a different but smaller code, it is shown below.
#include <unistd.h>
#include <filesystem>
#include <sys/wait.h>
#include <bits/stdc++.h>
#include <fcntl.h>
using namespace std;
int main ()
{
int pid;
int fd[2];
char command[] = "square";
//constructing a pipe
if(pipe(fd)==-1)
cout<<"Pipe1 Failed";
//first fork
pid = fork();
if(pid<0)
{
cout<<"fork failed";
}
else if(pid == 0)
{
cout<<"inside child 1\n";
close(0);
//opening input file at fd = 0
if(open("input",O_RDONLY) != 0)
cerr<<"Failed input open\n";
//connecting write end of pipe to first child process
dup2(fd[1],1);
close(fd[1]);
close(fd[0]);
char *args[] = {command,NULL};
//calling exec system call
execv(command,args);
cerr<<"execv1 failed\n";
exit(0);
}
//second fork
pid = fork();
if(pid<0)
{
cout<<"fork failed";
}
else if(pid == 0)
{
cout<<"inside child 2\n";
//connecting read end of the pipe to second child process
dup2(fd[0],0);
close(fd[0]);
close(fd[1]);
char *args[] = {command,NULL};
//calling exec system call
execv(command,args);
cerr<<"execv2 failed\n";
exit(0);
}
wait(NULL);
cout<<"After wait\n";
return 0;
}
What this code effectively tries to do is something like ./square < input | ./square in bash. input is a file that contains a number (it was 5 when I ran the code), square is a function that takes an integer input and prints its square (n*n).
The code of square is
#include<stdio.h>
int main()
{
int n;
scanf("%d",&n);
printf("%d",n*n);
return 0;
}
The final output I was expecting is (with input file containing number 5)
inside child 1
inside child 2
625
After wait
But the final output I am getting is
inside child 1
inside child 2
After wait
625
Output image
Can somebody help me figure out what is happening here or where my understanding is wrong.
NOTE: I used g++ compiler to compile this C++ codes.
Thanks in advance.
wait(NULL) doesn't wait for all children to exit. wait(&wstatus) waits for one child, and puts its exit status into the int wstatus. wait(NULL) waits for one child, and ignores its exit status.
Citation: man 2 wait
How to use the function of "CreatePipe" and "CreateProcessW" in Linux, when I compile the C++ code in Linux, there have some errors as follow: 'CreatePipe' was not declared in this scope. 'CreateProcessW' was not declared in this scope.
Posix/Linux:
int pipe(int pipefd[2]);
pipefd[0] refers to the read end of the pipe.
pipefd[1] refers to the write end of the pipe.
Linux specific:
int pipe2(int pipefd[2], int flags);
When it comes to CreateProcess, the Posix/Linux version is done in a few steps.
Call fork() to create a new process - still running the same program - so two processes will now continue running the same program from the same point where fork() was called. Determining if it's the parent process or child process is done by checking the return value (the process id) from fork().
dup the file descriptors returned by pipe using int dup2(int oldfd, int newfd); to replace stdin and stdout for the new process.
Execute a program in the new process using one of the exec* functions.
// create pipes here
if(pid_t pid = fork(); pid == -1) {
// fork failed
} else if(pid == 0) { // child process goes here (with a new process id)
// dup2(...)
// exec*()
} else { // parent process goes here
// do parenting stuff
}
Example:
#include <unistd.h>
#include <sys/types.h>
#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <stdexcept>
struct Pipe {
Pipe() {
if(pipe(io)) throw std::runtime_error("pipe failure");
}
~Pipe() {
close_rd();
close_wr();
}
void close_rd() { closer(io[0]); }
void close_wr() { closer(io[1]); }
int rd() { return io[0]; }
int wr() { return io[1]; }
private:
void closer(int& fd) {
if(fd != -1) {
close(fd);
fd = -1;
}
}
int io[2];
};
int main() {
Pipe parent_write, parent_read;
if(pid_t pid = fork(); pid == -1) {
// fork failed
return 1;
} else if(pid == 0) { // child process goes here (with a new process id)
// close file descriptors we don't need:
parent_write.close_wr();
parent_read.close_rd();
// duplicate into the place where stdin/stdout was
dup2(parent_write.rd(), fileno(stdin));
dup2(parent_read.wr(), fileno(stdout));
// execute a program
execl("/bin/ls", "/bin/ls", nullptr);
// exec* functions never returns if successful, so if we get here, it failed:
std::exit(1);
} else { // parent process goes here
std::cout << "child process " << pid << " started\n";
}
// close file descriptors we don't need:
parent_write.close_rd();
parent_read.close_wr();
// read data from child process using the file descriptor in parent_read.rd()
char buf[1024];
ssize_t rv;
while((rv = read(parent_read.rd(), buf, 1024))) {
write(fileno(stdout), buf, static_cast<size_t>(rv));
}
// use write(parent_write.wr(), ...) to write to the child.
}
This is the code
pid_t pid;
srand(time(NULL));
for (int i=0; i < 2; i++)
{
pid = fork();
if (pid < 0)
{
std::cout<< "fork failed";
return -1;
}
else if (pid == 0)
{
std::cout<< "Process "<< i+1 << " ID: " << pid <<std::endl;
std::thread one (threadFunction, 0);
std::thread two (threadFunction, 1);
std::thread three (threadFunction, 2);
one.join();
two.join();
three.join();
}
else
{
wait (NULL);
exit(0);
}
}
The loop is supposed to create two different processes but whenever I run this the output pid is always 0. Does this mean it the same process
if pid == 0 your code is executing the child process. If pid is different than 0 your code execute the parent process
see section return value of the man
http://man7.org/linux/man-pages/man2/fork.2.html
you can find out the real pid of the child with function getpid
http://man7.org/linux/man-pages/man2/getpid.2.html
I'm coding a mock shell and I'm currently working on coding pipes with dup2. Here is my code:
bool Pipe::execute() {
int fds[2]; //will hold file descriptors
pipe(fds);
int status;
int errorno;
pid_t child;
child = fork();
if (-1 == child) {
perror("fork failed");
}
if (child == 0) {
dup2(fds[1], STDOUT_FILENO);
close(fds[0]);
close(fds[1]);
this->component->lchild->execute();
_exit(1);
}
else if (child > 0) {
dup2(fds[0], STDIN_FILENO);
close(fds[0]);
close(fds[1]);
this->component->rchild->execute();
waitpid(child, &status, 0);
if ( WIFEXITED(status) ) {
//printf("child exited with = %d\n",WEXITSTATUS(status));
if ( WEXITSTATUS(status) == 0) {
cout << "pipe parent finishing" << endl;
return true;
}
}
return false;
}
}
The this->component->lchild->execute(); and this->component->rchild->execute(); run execvp on the corresponding commands. I've confirmed that each of these return by printing out a statement in the parent process. However, in my Pipe::execute(), it seems like the child process does not finish because the cout statement in the parent process is never printed and I get a segmentation fault after the prompt ($) is initialized (see picture). Here is the main function that initializes the prompt after each execution:
int main()
{
Prompt new_prompt;
while(1) {
new_prompt.initialize();
}
return 0;
}
and here is the initialize() function:
void Prompt::initialize()
{
cout << "$ ";
std::getline(std::cin, input);
parse(input);
run();
input.clear();
tokens.clear();
fflush(stdout);
fflush(stdin);
return;
}
It seems like ls | sort runs fine, but then when the prompt is initialized, a blank line is read into input by getline. I've tried using cin.clear(), cin.ignore, and the fflush and clear() lines above. This blank string is "parsed" and then the run() function is called, which tries to dereference a null pointer. Any ideas on why/where this blank line is being entered into getline? and how do I resolve this? Thank you!
UPDATE: The parent process in the pipe is now finishing. I've also noticed that I'm getting seg faults also for my I/O redirection classes (> and <). I think I'm not flushing the stream or closing the file descriptors correctly...
Here is my execute() function for lchild and rchild:
bool Command::execute() {
int status;
int errorno;
pid_t child;
vector<char *> argv;
for (unsigned i=0; i < this->command.size(); ++i) {
char * cstr = const_cast<char*>(this->command.at(i).c_str());
argv.push_back(cstr);
}
argv.push_back(NULL);
child = fork();
if (-1 == child) {
perror("fork failed");
}
if (child == 0) {
errorno = execvp(*argv.data(), argv.data());
_exit(1);
} else if (child > 0) {
waitpid(child, &status, 0);
if ( WIFEXITED(status) ) {
//printf("child exited with = %d\n",WEXITSTATUS(status));
if ( WEXITSTATUS(status) == 0) {
//cout << "command parent finishing" << endl;
return true;
}
}
return false;
}
}
Here is the bug:
else if (child > 0) {
dup2(fds[0], STDIN_FILENO);
close(fds[0]);
close(fds[1]);
this->component->rchild->execute();
You are closing stdin for the parent, not just the right child. After this the stdin of the parent process is the same as that of the right child.
After that
std::getline(std::cin, input);
Tries to read the output of the left child, rather than the original stdin. By that point the left child had finished and that end of the pipe had been closed. This makes reading stdin fail, and leave input unchanged in its original state.
Edit: Your design has a minor and a major flaws. The minor flaw is that you don't need the fork in Pipe::execute. The major flaw is that the child should be the one who redirects streams and closes the descriptors.
Simply pass input and output parameters through fork() and let the child dup2 these. Don't forget to make it also close unrelated pipe ends. If you don't, the left child will finish but its output pipe will continue living in other processes. As long as other copies of that descriptor live, the right child will never get EOF while reading its pipe end - and week block forever.
I'm writing a simple pipe program that will ask for two commands then run the programs as if they were entered into bash as cmd1 | cmd2. Then it should loop and ask again until one of the commands is quit.
I've already written this much:
#include<iostream>
#include<string>
#include<sys/types.h>
#include<sys/wait.h>
#include<string.h>
#include<unistd.h>
#include<stdlib.h>
#include<stdio.h>
#include<signal.h>
using namespace std;
int main(int argc, char *argv[])
{
int pid1, pid2, errchk;
int pip[2];
char cmd1[128];
char cmd2[128];
int i = 0;
int status;
errchk = pipe(pip);//make pipe
if(errchk == -1)//check for error in pipe
{
perror("pipe");
exit(1);
}
while(i<3)
{
i++;
//Enter commands here
cout<<"Enter cmd1: ";
cin>>cmd1;
cout<<"Enter cmd2: ";
cin>>cmd2;
//if a command is quit... quit
if(strcmp(cmd1,"quit")==0 || strcmp(cmd2,"quit") == 0)
{
cout<<"Quitting...\n";
exit(1);
}
pid1 = fork();
cout<<"first fork makes pids: "<<pid1<<endl;
if(pid1 < 0)
{
perror("fork");
exit(1);
}
else if(pid1 == 0) //MAIN CHILD
{
cout<<"In main child with pid: "<<pid1<<endl;
pid2 = fork();
cout<<"second fork makes pids: "<<pid2<<endl;
if(pid2 == 0)//SUB CHILD 2 to run cmd2
{
cout<<"In child of second fork"<<endl;
close(0);
close(pip[1]);
dup(pip[0]);
execvp(cmd2,argv);//execute command2 and die
}
else if(pid2 > 0)//SUB CHILD 1 to run cmd1
{
cout<<"In parent of second fork"<<endl;
close(1);
close(pip[0]);
dup(pip[1]);
execvp(cmd1,argv);//execute command1 and die
}
}
else if(pid1 > 0) //MAIN PARENT
{
wait(NULL);//wait for cmd1
wait(NULL);//wait for cmd2
cout<<"DONE executing"<<endl; //keep going
}
}
return 0;
}
When I run it and enter ls and wc
The output I get is:
Enter cmd1: ls
Enter cmd2: wc
first fork makes pids: 5785
first fork makes pids: 0
In main child with pid: 0
second fork makes pids: 5786
In parent of second fork
second fork makes pids: 0
In child of second fork
DONE executing
5 5 54
The main problem I have is that I should have Done executing come after ls|wc not the other way around.
I'm thinking the wait(NULL) isn't working but I'm not sure.
Please advise.
And Thank you.
You have:
parent
1. child1
2. child2
2. exec()
1. exec()
When you exec in child1, child2 gets reparented to init, and you can no longer wait for child2 to terminate.
So we need to do a little bit of refactoring to get something looking like:
parent
1. child1
1. exec()
2. child2
2. exec()
wait() x 2
Basing this on your own code, with the refactoring to accomplish something like the look-alike code (some comments in-line):
#include<iostream>
#include<string>
#include<sys/types.h>
#include<sys/wait.h>
#include<string.h>
#include<unistd.h>
#include<stdlib.h>
#include<stdio.h>
#include<signal.h>
using namespace std;
int main(int argc, char *argv[])
{
int pid1, pid2, errchk;
int pip[2];
char cmd1[128];
char cmd2[128];
int status;
while(true)
{
errchk = pipe(pip);//make pipe
if(errchk == -1)//check for error in pipe
{
perror("pipe");
exit(1);
}
//Enter commands here
cout<<"Enter cmd1: ";
cin>>cmd1;
cout<<"Enter cmd2: ";
cin>>cmd2;
//if a command is quit... quit
if(strcmp(cmd1,"quit")==0 || strcmp(cmd2,"quit") == 0)
{
cout<<"Quitting...\n";
exit(1);
}
pid1 = fork();
cout<<"first fork makes pids: "<<pid1<<endl;
if(pid1 < 0)
{
perror("fork");
exit(1);
}
if (pid1 == 0) // in child
{
cout<<"In child of first fork"<<endl;
close(pip[0]); // close read-end of pipe
close(0); // close stdin
close(1); // close stdout
dup2(pip[1], 1); // write-end of pipe is stdout of cmd1
argv[0] = cmd1; // make it look like the command in the ps output
execvp(cmd1,argv);//execute command1 and die
fprintf(stderr, "execvp(1): `%s': %s\n", cmd1, strerror(errno));
return 0;
}
pid2 = fork();
cout<<"second fork makes pids: "<<pid2<<endl;
if (pid2 < 0)
{
perror("fork2");
exit(1);
}
if (pid2 == 0)
{
cout<<"In child of second fork"<<endl;
close(pip[1]); // close write-end of pipe
close(0); // close stdin
dup2(pip[0], 0); // read-end of pipe is stdin of cmd2
argv[0] = cmd2; // update ps output
execvp(cmd2,argv);//execute command2 and die
fprintf(stderr, "execvp(1): `%s': %s\n", cmd2, strerror(errno));
return 0;
}
if(pid1 > 0) //MAIN PARENT
{
// close remaining pipe handles in parent
close(pip[0]);
close(pip[1]);
wait(0);//wait for one command to run
wait(0);//wait for a second command to run
cout<<"DONE executing"<<endl; //keep going
}
}
return 0;
}