I'm writing my own shell, but no fork gives my child_pid = 0...
What's wrong there?
while(true)
{
read_command(command);
if ((child_pid = fork()) == -1)
{
fprintf(stderr, "can't fork\n");
exit(1);
}
else if (child_pid == 0) //child
{
status=execl("./myShell" command);
}
else
{
wait(status); //parent
}
}
I guess that the (child_pid == -1) is not entered... Is the father (else) branch entered twice (by both process) or what?
Anyway I can't see a bug in that snippet of code. If you're sure your execution flow gets there, and has an unpredictable behavior its because of a bug.
I doubt glibc is bugged on your system: my best guess is that your program has got a broken pointer that broke everything. This is the most common cause of this kind of really weird behaviors.
Your code is OK. Add a debug print in if(child_pid == 0) and make sure it is not called. If fork cannot create a child, it sets errno to indicate the error occurred.
Related
I have a process that forks in order to execute a subprocess, which receive an entry from stdin and writes to stdout.
My code in short is as follows:
int fd[2];
int fd2[2];
if (pipe(fd) < 0 || pipe(fd2) < 0)
throws exception;
pid_t p = fork();
if (p == 0) // child
{
close(fd[0]); //not needed
dup2( fd[1],STDOUT_FILENO);
dup2( fd[1],STDERR_FILENO);
close(fd2[1]); //not needed
//what if write calls on parent process execute first?
//how to handle that situation
dup2( fd2[0],STDIN_FILENO);
string cmd="./childbin";
if (execl(cmd.c_str(),(char *) NULL) == -1)
{
exit (-1);
}
exit(-1);
}
else if (p > 0) // parent
{
close(fd[1]); //not needed
close(fd2[0]);
if (write(fd2[1],command.c_str(),command.size())<0)
{
throw exception;
}
close(fd2[1]);
//waits for child to finish.
//child process actually hangs on reading for ever from stdin.
pidret=waitpid(p,&status,WNOHANG))==0)
.......
}
The child process remains waiting forever for data in STDIN. Is there maybe a race condition between the child and parent process? I think that could be the problem but not quite sure and also not sure how to fix it.
Thanks in advance.
Update:
Some useful information.
The parent process is a daemon and this code runs several times per second. It works 97% of the times (~3% of the cases, the child process remains in the state described before).
UPDATE 2
After added validation in dup2 call, there is no error there, next condition is never raised.
if(dup2(...) == -1) {
syslog(...)
}
Your missing a wait that is why you in 3% of the cases run the parent before the child. See the example at the bottom.
Also you should call close on the fd's you don't use before doing anything else.
I am using version 0.5 of Boost.Process. Documentation can be found here. I am using Mac OS X Yosemite.
My problem: I am launching a compilation as a child process. I want to wait for the process to finish.
When my child process compiles correctly, everything is ok.
But when my child process does not compile, my code seems to crash when calling boost::process::wait_for_exit.
My user code looks like this:
EDIT: Code has been edited to match latest, more correct version (still does not work).
s::error_code ec{};
bp::child child = bp::execute(bpi::set_args(compilationCommand),
bpi::bind_stderr(outErrLog_),
bpi::bind_stdout(outErrLog_),
bpi::inherit_env(),
bpi::set_on_error(ec));
bool compilationSuccessful = true;
if (!ec) {
s::error_code ec2;
bp::wait_for_exit(child, ec2);
if (ec2)
compilationSuccessful = false;
}
The internal implementation of bp::wait_for_exit:
template <class Process>
inline int wait_for_exit(const Process &p, boost::system::error_code &ec)
{
pid_t ret;
int status;
do
{
ret = ::waitpid(p.pid, &status, 0);
} while ((ret == -1 && errno == EINTR) || (ret != -1 && !WIFEXITED(status)));
if (ret == -1) {
BOOST_PROCESS_RETURN_LAST_SYSTEM_ERROR("waitpid(2) failed");
}
else
ec.clear();
return status;
}
The code after ::waitpidis never reached when my compilation command fails. The error shown is: "child has exited; pid: xxxx; uid: yyy; exit value: 1".
Questions:
Is this a bug or I am misusing boost::process::wait_for_exit.
Any workaround for avoiding the crash I am getting that is portable?
Just looking at your code, the first thing that strikes me is that you don't actually test the "ec" variable that says whether execute() succeeded or not until after you call wait_for_exit(). If you're calling wait_for_exit() with an invalid child process, it's quite understandable that it would crash.
Start by checking "ec" before calling wait_for_exit().
So the problem was that Boost.Test modifies the signals stack in some way.
This signal stack modification has interactions with Boost.Process and code cannot be reliably tested, at least in the default Boost.Test configuration.
I rewrote the tests with a normal main and some functions and it did the job.
I've been tasked to create a program that takes a text file that contains a list of programs as input. It then needs to run valgrind on the programs (one at a time) until valgrind ends or until the program hits a max allotted time. I have the program doing everything I need it to do EXCEPT it isn't waiting for valgrind to finish. The code I'm using has this format:
//code up to this point is working properly
pid_t pid = fork();
if(pid == 0){
string s = "sudo valgrind --*options omitted*" + testPath + " &>" + outPath;
system(s.c_str());
exit(0);
}
//code after here seems to also be working properly
I'm running into an issue where the child just calls the system and moves on without waiting for valgrind to finish. As such I'm guessing that system isn't the right call to use, but I don't know what call I should be making. Can anyone tell me how to get the child to wait for valgrind to finish?
I think that you are looking for fork/execv. Here is an example:
http://www.cs.ecu.edu/karl/4630/spr01/example1.html
An other alternative could be popen.
You can fork and exec your program and then wait for it to finish. See the following example.
pid_t pid = vfork();
if(pid == -1)
{
perror("fork() failed");
return -1;
}
else if(pid == 0)
{
char *args[] = {"/bin/sleep", "5", (char *)0};
execv("/bin/sleep", args);
}
int child_status;
int child_pid = wait(&child_status);
printf("Child %u finished with status %d\n", child_pid, child_status);
I have the helper function below, used to execute a command and get the return value on posix systems. I used to use popen, but it is impossible to get the return code of an application with popen if it runs and exits before popen/pclose gets a chance to do its work.
The following helper function creates a process fork, uses execvp to run the desired external process, and then the parent uses waitpid to get the return code. I'm seeing odd cases where it's refusing to run.
When called with wait = true, waitpid should return the exit code of the application no matter what. However, I'm seeing stdout output that specifies the return code should be non-zero, yet the return code is zero. Testing the external process in a regular shell, then echoing $? returns non-zero, so it's not a problem w/ the external process not returning the right code. If it's of any help, the external process being run is mount(8) (yes, I know I can use mount(2) but that's besides the point).
I apologize in advance for a code dump. Most of it is debugging/logging:
inline int ForkAndRun(const std::string &command, const std::vector<std::string> &args, bool wait = false, std::string *output = NULL)
{
std::string debug;
std::vector<char*> argv;
for(size_t i = 0; i < args.size(); ++i)
{
argv.push_back(const_cast<char*>(args[i].c_str()));
debug += "\"";
debug += args[i];
debug += "\" ";
}
argv.push_back((char*)NULL);
neosmart::logger.Debug("Executing %s", debug.c_str());
int pipefd[2];
if (pipe(pipefd) != 0)
{
neosmart::logger.Error("Failed to create pipe descriptor when trying to launch %s", debug.c_str());
return EXIT_FAILURE;
}
pid_t pid = fork();
if (pid == 0)
{
close(pipefd[STDIN_FILENO]); //child isn't going to be reading
dup2(pipefd[STDOUT_FILENO], STDOUT_FILENO);
close(pipefd[STDOUT_FILENO]); //now that it's been dup2'd
dup2(pipefd[STDOUT_FILENO], STDERR_FILENO);
if (execvp(command.c_str(), &argv[0]) != 0)
{
exit(EXIT_FAILURE);
}
return 0;
}
else if (pid < 0)
{
neosmart::logger.Error("Failed to fork when trying to launch %s", debug.c_str());
return EXIT_FAILURE;
}
else
{
close(pipefd[STDOUT_FILENO]);
int exitCode = 0;
if (wait)
{
waitpid(pid, &exitCode, wait ? __WALL : (WNOHANG | WUNTRACED));
std::string result;
char buffer[128];
ssize_t bytesRead;
while ((bytesRead = read(pipefd[STDIN_FILENO], buffer, sizeof(buffer)-1)) != 0)
{
buffer[bytesRead] = '\0';
result += buffer;
}
if (wait)
{
if ((WIFEXITED(exitCode)) == 0)
{
neosmart::logger.Error("Failed to run command %s", debug.c_str());
neosmart::logger.Info("Output:\n%s", result.c_str());
}
else
{
neosmart::logger.Debug("Output:\n%s", result.c_str());
exitCode = WEXITSTATUS(exitCode);
if (exitCode != 0)
{
neosmart::logger.Info("Return code %d", (exitCode));
}
}
}
if (output)
{
result.swap(*output);
}
}
close(pipefd[STDIN_FILENO]);
return exitCode;
}
}
Note that the command is run OK with the correct parameters, the function proceeds without any problems, and WIFEXITED returns TRUE. However, WEXITSTATUS returns 0, when it should be returning something else.
Probably isn't your main issue, but I think I see a small problem. In your child process, you have...
dup2(pipefd[STDOUT_FILENO], STDOUT_FILENO);
close(pipefd[STDOUT_FILENO]); //now that it's been dup2'd
dup2(pipefd[STDOUT_FILENO], STDERR_FILENO); //but wait, this pipe is closed!
But I think what you want is:
dup2(pipefd[STDOUT_FILENO], STDOUT_FILENO);
dup2(pipefd[STDOUT_FILENO], STDERR_FILENO);
close(pipefd[STDOUT_FILENO]); //now that it's been dup2'd for both, can close
I don't have much experience with forks and pipes in Linux, but I did write a similar function pretty recently. You can take a look at the code to compare, if you'd like. I know that my function works.
execAndRedirect.cpp
I'm using the mongoose library, and grepping my code for SIGCHLD revealed that using mg_start from mongoose results in setting SIGCHLD to SIG_IGN.
From the waitpid man page, on Linux a SIGCHLD set to SIG_IGN will not create a zombie process, so waitpid will fail if the process has already successfully run and exited - but will run OK if it hasn't yet. This was the cause of the sporadic failure of my code.
Simply re-setting SIGCHLD after calling mg_start to a void function that does absolutely nothing was enough to keep the zombie records from being immediately erased.
Per #Geoff_Montee's advice, there was a bug in my redirect of STDERR, but this was not responsible for the problem as execvp does not store the return value in STDERR or even STDOUT, but rather in the kernel object associated with the parent process (the zombie record).
#jilles' warning about non-contiguity of vector in C++ does not apply for C++03 and up (only valid for C++98, though in practice, most C++98 compilers did use contiguous storage, anyway) and was not related to this issue. However, the advice on reading from the pipe before blocking and checking the output of waitpid is spot-on.
I've found that pclose does NOT block and wait for the process to end, contrary to the documentation (this is on CentOS 6). I've found that I need to call pclose and then call waitpid(pid,&status,0); to get the true return value.
I'm trying to execute an external program from inside my Linux C++ program.
I'm calling the method system("gedit") to launch an instance of the Gedit editor. However my problem is while the Gedit window is open, my C++ program waits for it to exit.
How can I call an external program without waiting for it to exit?
You will need to use fork and exec
int fork_rv = fork();
if (fork_rv == 0)
{
// we're in the child
execl("/path/to/gedit", "gedit", 0);
// in case execl fails
_exit(1);
}
else if (fork_rv == -1)
{
// error could not fork
}
You will also need to reap your child so as not to leave a zombie process.
void reap_child(int sig)
{
int status;
waitpid(-1, &status, WNOHANG);
}
int main()
{
signal(SIGCHLD, reap_child);
...
}
In regards to zombie processes, you have a second option. It uses a bit more resources (this flavor forks twice), but the benefit is you can keep your wait closer to your fork which is nicer in terms of maintenance.
int fork_rv = fork();
if (fork_rv == 0)
{
fork_rv = fork();
if (fork_rv == 0)
{
// we're in the child
execl("/path/to/gedit", "gedit", 0);
// if execl fails
_exit(1);
}
else if (fork_rv == -1)
{
// fork fails
_exit(2);
}
_exit(0);
}
else if (fork_rv != -1)
{
// parent wait for the child (which will exit quickly)
int status;
waitpid(fork_rv, &status, 0);
}
else if (fork_rv == -1)
{
// error could not fork
}
What this last flavor does is create a child, which in turns creates a grandchild and the grandchild is what exec's your gedit program. The child itself exits and the parent process can reap it right away. So an extra fork but you keep all the code in one place.
Oh, let me say it!
http://en.wikipedia.org/wiki/Fork-exec
Fork! :)
First, did you try to launch in background with system("gedit&")?
If that does not work, try spawning a new thread and running gedit from there.
I presume that you are not concerned with the result of the edit, or the contents of the edited file?