pid = fork();
if(pid == 0 && background == 1){
// performs background process
pid2 = fork();
if(pid2 == 0){
// grandchild process
} else {
// child process
exit(0);
}
} else if(pid == 0){
// child process
} else {
//parent process
waitpid(pid, NULL, 0);
}
My question is I'm trying to perform a background process using double forks but I'm not 100% sure it works or not with the way I set it up, another question is after I double fork what is a good way to handle the orpaned children, can I just leave them or will that cause an issue? this is for a unix shell.
Related
I'm working on my own little shell program in C. When I run the child process as a background process, I would like to ignore the input from the user coming from the parent process. I am currently trying to pipe it then close stdin for the child, but the input still goes to the child.
else // A process
{
pid_t child_pid;
char lastArgument = args[currArgsIndex-1][0];
if (lastArgument != '&'){ //Normal process
if((child_pid = fork()) == 0) {
execvp(filepath, args);
exit(0);
}
else
{
while(wait(NULL) != child_pid);
}
}
else { // Background
args[currArgsIndex-1] = NULL;
int process_pipe[2];
pipe(process_pipe); // Piping
if((child_pid = fork()) == 0) {
close(process_pipe[0]); // Ignore stdin for child
execvp(filepath, args);
exit(0);
}
}
}
You create a pipe and close the read end, but you never say that the pipe should be stdin.
It sounds like your intention was instead to 1. open the pipe only in the child, 2. close the write end so that no data can be read, 3. set the read end as stdin:
else { // Background
args[currArgsIndex-1] = NULL;
if((child_pid = fork()) == 0) {
int process_pipe[2];
pipe(process_pipe); // Piping
dup2(process_pipe[0], 0); // Copy read end as stdin
close(process_pipe[0]); // Close FD that is now unused
close(process_pipe[1]); // Close write end so no data can be read
execvp(filepath, args);
perror("execvp failed");
exit(1); // exit with error
}
}
There's no point having a pipe though. You can more easily open /dev/null for reading and setting that as stdin. Alternatively, simply close stdin entirely (some programs will complain):
else { // Background
args[currArgsIndex-1] = NULL;
if((child_pid = fork()) == 0) {
close(0); // Close stdin
execvp(filepath, args);
/* error handling */
}
Be aware that real shells allow redirecting to backgrounded processes, in which case none of the above will work:
wc -l < myfile &
Real shells will in fact not close or redirect stdin at all, but will put the command in its own process group that's not controlling the terminal. The process will then receive a SIGTSTP when it tries to read from stdin, and you can then use fg to bring it to the foreground to start typing data.
So my output for the code below includes printing D twice, and I can't seem to understand why. It'll be great if someone could explain it to me.
int main() {
int r = fork();
printf("B\n");
int t = fork();
printf("C\n");
if(r == 0) {
printf("D\n");
} else if (r > 0 && t == 0){
printf("E\n");
}
printf("F\n");
return 0;
}
Thanks.
Let's use naming convention to easily describe how the code runs. Let's call the parent that executes X=fork() Xparent and the forked child Xchild. Parents end up with X > 0 and child with X==0.
You have a parent that executes r=fork() and t=fork() making it an Rparent and a Tparent.
We now know that Rchild will have r==0 and Tchild will have t==0.
However, the older child, Rchild, executes t=fork() making it a Tparent and forking a Tchild.
The Tchild forked by Rchild will have r==0, memories from parent and child are cloned.
Hence you end up with Rchild having r==0 and its child having r==0. Two processes printing D.
SO,
There are many similar questions, however none that I have been able to use. My code snippet is as follows:
for(int j=0; j<N; j++) {
pid_t pid = fork();
if (pid == -1) {
exit(-1); //err
} else if (pid == 0) {//kid
stringstream ss;
ss<<j;
execlp("./sub","sub",ss.str().c_str(),NULL);
exit(0);
} else {
/* parent */
}
}
my executing code in sub(.cpp) is:
int main( int argc, char **argv )
{
cout<<argv[i]<<endl;
exit(0);
}
my output is as such:
[terminal prompt '$'] 4
2
3
etc.
Is there a way I could prevent the prompt from displaying on the exec call? and why is it ONLY displaying on the first exec call, and not on every one?
What you see is the normal prompt of your shell, because the parent process terminates very quickly. It is not the output of the exec call. The forked processes print their output after the parent process has terminated.
You can use waitpid() in the parent process to "wait" until all forked process have terminated.
I have a subprocess (running on MacOS) that I want to kill itself if the parent quits, exits, terminates, is killed or crashes. Having followed the advice from How to make child process die after parent exits? I can't get it to quietly kill itself if the parent program crashes. It will go to 100% CPU until I manually kill it.
Here are the key points of the code:
int main(int argc, char *argv[])
{
// Catch signals
signal(SIGINT, interruptHandler);
signal(SIGABRT, interruptHandler);
signal(SIGTERM, interruptHandler);
signal(SIGPIPE, interruptHandler);
// Create kqueue event filter
int kqueue_fd = kqueue();
struct kevent kev, recv_kev;
EV_SET(&kev, parent_pid, EVFILT_PROC, EV_ADD|EV_ENABLE, NOTE_EXIT, 0, NULL);
kevent(kqueue_fd, &kev, 1, NULL, 0, NULL);
struct pollfd kqpoll;
kqpoll.fd = kqueue_fd;
kqpoll.events = POLLIN;
// Start a run loop
while(processEvents())
{
if(kill(parent_pid, 0) == -1)
if(errno == ESRCH)
break;
if(poll(&kqpoll, 1, 0) == 1)
if(kevent(kqueue_fd, NULL, 0, &recv_kev, 1, NULL))
break;
parent_pid = getppid();
if(parent_pid == 1)
break;
sleep(a_short_time);
// (simple code here causes subprocess to sleep longer if it hasn't
// received any events recently)
}
}
Answering my own question here:
The reason for this problem was not down to detecting whether the parent process had died. In processEvents() I was polling the pipe from the parent process to see if there was any communication. When the parent died, poll() returned a value of 1 and the read loop thought there was infinite data waiting to be read.
The solution was to detect whether the pipe had been disconnected or not.
Attempting to implement a poor man's test of whether a process is still running or not (essentially an equivalent of the trivial kill(pid, 0).)
Hoped to be able to simply call OpenProcess with some minimal desired access then test for either GetLastError() == ERROR_INVALID_PARAMETER or GetExitCodeProcess(...) != STILL_ACTIVE.
Nice try... Running on Windows XP, as administrator:
HANDLE hProc = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pid);
if (!hProc) {
DWORD dwLastError = GetLastError();
}
...fails miserably with dwLastError == ERROR_ACCESS_DENIED when pid is owned by a different (not SYSTEM) user. Moreover, if pid was originally owned by a different user but has since terminated, OpenProcess also fails with ERROR_ACCESS_DENIED (not ERROR_INVALID_PARAMETER.)
Do I have to use Process32First/Process32Next or EnumProcesses?
I absolutely do not want to use SeDebugPrivilege.
Thanks,
V
If you have a process ID:
// this should succeed even when a medium integrity process
// requests access to a high integrity process
if (HANDLE h = OpenProcess(SYNCHRONIZE, FALSE, pid))
{
// do a wait, if the handle is signaled: not running
DWORD wait = WaitForSingleObject(h, 0);
if (wait == WAIT_OBJECT_0) return FALSE;
}
// cannot get a handle to the process:
// probably running at system integrity level
// I'm not sure how reliable this check is, but it seems to work:
// if access is denied: running
// if invalid parameter: not running
else if (GetLastError() != ERROR_ACCESS_DENIED) return FALSE;
If you have a window handle that should be valid for as long as the process is running, this is a good alternative:
if (hWnd && !IsWindow(hWnd)) return FALSE;
static BOOL
isProcessAlive(DWORD th32ProcessID) {
BOOL bSuccess = FALSE;
HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (hSnap != INVALID_HANDLE_VALUE) {
PROCESSENTRY32 pe32 = { sizeof(pe32), 0 };
if (Process32First(hSnap, &pe32)) {
while (pe32.th32ProcessID != pid && Process32Next(hSnap, &pe32));
_ASSERT(GetLastError() == 0 || GetLastError() == ERROR_NO_MORE_FILES);
bSuccess = (pe32.th32ProcessID == th32ProcessID);
}
CloseHandle(hSnap);
}
return bSuccess;
}