I understand using the "fork()" function to create a child process. I understand that the fork() function returns the PID of the child process. However, can fork() be used to create a different child process? I thought forking was when a process created a copy of itself. If so, can I not use fork to open a new process? I don't want to use system() for several reasons.
Finally, how can I check if the process has finished?
Thanks...
Essentially, what I want to do is run another process, given the location (probably through input), wait for it to finish, and then print the result (return value). I'd also like to be able to print it's PID and destroy the process if I want to, but that won't be hard because fork() returns the PID...
Edit: I'm thinking instead I could use execl() and fork() to somehow get execl() to replace the child process instead. How could I do that?
#include "executor.h"
int exec(std::string path) {
pid_t PID = 0;
int result = 0, filedes[2], status;
/* Create child process: */
PID = fork();
if (PID == -1) {
return 1;
}
result = pipe(filedes);
if (PID != 0) {
std::cout << "Created child process. PID: " << PID << "\n";
}
if (result == -1) {
return 1;
}
if (PID == 0) { // This is the child process
std::string prog = "./" + path;
execvp(prog.c_str(), NULL); // Execute the program
} else { // This is the parent process
waitpid(PID, &status, 0); // Wait for the child process to return.
std::cout << "Process returned " << WEXITSTATUS(status) << ".\n";
std::cout << "Press enter.\n";
}
return 0;
}
I think it works, it gets the return value but the program I try to run doesn't seem to be able to do anything.
Will I need to use the pipe I have with the child process to let it interact with the terminal?
No, never mind, it works :)
Yay, now I have one of those things that some IDEs have (such as Code::Blocks).
Remember that it is possible (though unlikely) that line 26 will fail. If it does, you need to exit() with an appropriate error code so that line 28 will notice that the child failed.
int myInt = execvp(prog.c_str(), NULL);
if (myInt) {
return myInt;
}
?
And why might line 26 fail? Just because functions sometimes do, or because of the way I'm using it?
Computerquip, I'm not sure why I declared PID before using it. I guess I'm still in C mode from the other day.
Also, you can declare multiple variables on the same type on a single line, they have to be comma separated.
execvp will fail for any reason the man page says it will fail. For example, the program was
not found, was not executable, you didn't have permission to execute it, you had too many
running processes already, etc. etc.
execvp() returns only upon failure. On success it never returns.
If it fails, the parent will see the return value 1 (whatever you pass to exit()). If it
succeeds, the parent will see whatever return value the child's main() returns.
You can look up any of the waitpid() functions (there are several) to know when the
child exit and receive the return code or you can register a signal handler for SIGCHLD
(which you'll receive the when child exits) and then do a non-blocking waitpid()).
I tried to keep function sizes down. Hopefully, it doesn't detract from legibility.
I'm not sure if I'm implementing execvp() right. It works, but I'd still like to know it's not going to be bugged.
When I used your above example (with a different error message, although "Aiiie!" made me laugh) the error message was always showing...
If you're wondering why I used FILENAME_MAX for the hostname[] buffer's size, I couldn't think of anything better to set it to, and I wanted to hurry up and test the program.
#ifndef _RUNNER_H_
#define _RUNNER_H_
// STL includes
#include <iostream> // For IO and std::strings
#include <cstdlib> // For exit()
#include <cerrno> // For errno
// Other includes (for fork(), pipe() and waitpid())
#include <unistd.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <signal.h> // For kill() to work
// Macros:
// None
// Globals:
// None
// Function prototypes
// In main.cpp:
int main(int, char**); // Entry point
void error(std::string); // Prints a given error message to the cerr stream, for consistency.
// In sort.cpp:
int sort(int, char**); // Sorts argv and calls an appropriate function
int search(std::string, std::string, int, int);
// Searches for parameters in two strings
// In exec.cpp:
void exec(std::string); // Executes a given program
#endif
I was thinking I could use another child process to do the timing. It would be on an infinite loop with an iterator, and it would sleep for 1 second before incrementing the iterator.
When the first child returns, I would send it a SIGKILL or something and it would return how many iterations (how many seconds) it had done.
The problem for that is if the program lasted more than 4 or so minutes it would return 0 (apparently the maximum value a program can return is 255 and 5 minutes is 300 seconds).
So I thought of another way. I could maybe send the child a signal, but not SIGKILL - instead, I would send it another signal, and upon receiving this signal it would print how long it had been looping for.
How could I send/receive signals?
My other alternative would be to use pipes, but as I've never done anything with signals, and I know how to use pipes already, I think it will be better to use signals.
Thanks.
I just decided to incorporate this into a larger project. As it is able to work via command line arguments; I thought it would be fun to create a simple shell.