when I use linux console to develop, I use gdb to trace the program's behavior, Always the console print "Detaching after fork from child process 15***." can any body help to explain the sentence in quotation mark? How and Who will do What jobs after Detaching from child process? Thanks first:)
When GDB is debugging a particular process, and the process forks off a child process, GDB can only follow one of the two processes, so it must detach (stop following) the other. This line informs you of this selective detachment. The child process will run without being debugged by GDB.
You can select which process to follow using the set follow-fork-mode command. Use set follow-fork-mode child to follow child processes, and set follow-fork-mode parent to return to the default behavior. For more details, see this page on the Apple development website.
Related
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
int main()
{
int pid = fork();
if (pid) {
sleep(5);
// wait(NULL); // works fine when waited for it.
} else {
execlp("vim", "vim", (char *)NULL);
}
}
When I run this code, vim runs normally then crashes after the 5 seconds (i.e. when its parent exits). When I wait for it (i.e. not letting it become an orphan process), the code works totally fine.
Why does becoming an orphan process become a problem here? Is it something specific to vim?
Why is this even a thing that's visible to vim? I thought that only the parent knows when its children die. But here, I see that somehow, the child notices when it gets adopted, something happens and crashes somehow. Do the children processes get notified when their parent dies as well?
When I run this code, I get this output after the crash:
Vim: Error reading input, exiting...
Vim: preserving files...
Vim: Finished.
This actually happens because of the shell that is executing the binary that forks Vim!
When the shell runs a foreground command, it creates a new process group and makes it the foreground process group of the terminal attached to the shell. In bash 5.0, you can find the code that transfers this responsibility in give_terminal_to(), which uses tcsetpgrp() to set the foreground process group.
It is necessary to set the foreground process group of a terminal correctly, so that the program running in foreground can get signals from the terminal (for example, Ctrl+C sending an interrupt signal, Ctrl+Z sending a terminal stop signal to suspend the process) and also change terminal settings in ways that full-screen programs such as Vim typically do. (The subject of foreground process group is a bit out of scope for this question, just mentioning it here since it plays part in the response.)
When the process (more precisely, the pipeline) executed by the shell terminates, the shell will take back the foreground process group, using the same give_terminal_to() code by calling it with the shell's process group.
This is usually fine, because at the time the executed pipeline is finished, there's usually no process left on that process group, or if there are any, they typically don't hold on to the terminal (for example, if you're launching a background daemon from the shell, the daemon will typically close the stdin/stdout/stderr streams to relinquish access to the terminal.)
But that's not really the case with the setup you proposed, where Vim is still attached to the terminal and part of the foreground process group. When the parent process exits, the shell assumes the pipeline is finished and it will set the foreground process group back to itself, "stealing" it from the former foreground process group which is where Vim is. Consequently, the next time Vim tries to read from the terminal, the read will fail and Vim will exit with the message you reported.
One way to see by yourself that the parent processing exiting does not affect Vim by itself is running it through strace. For example, with the following command (assuming ./vim-launcher is your binary):
$ strace -f -o /tmp/vim-launcher.strace ./vim-launcher
Since strace is running with the -f option to follow forks, it will also start tracing Vim when it's launched. The shell will be executing strace (not vim-launcher), so its foreground pipeline will only end when strace stops running. And strace will not stop running until Vim exits. Vim will work just fine past the 5 seconds, even though it's been reparented to init.
There also used to be an fghack tool, part of daemontools, that accomplished the same task of blocking until all forked children would exit. It would accomplish that by creating a new pipe and have the pipe inherited by the process it spawned, in a way that would get automatically inherited by all other forked children. That way, it could block until all copies of that pipe file descriptor were closed, which typically only happens when all processes exit (unless a background process goes out of its way to close all inherited file descriptors, but that's essentially stating that they don't want to be tracked, and they would most probably have relinquished their access to the terminal by that point.)
I have a collection of processes that I'm starting from a shell script as follows:
#!/bin/bash
#This is a shortcut to start multiple storage services
function finish {
alljobs=$(jobs -p)
if [ ! -z "$alljobs" ]; then
kill $alljobs >/dev/null 2>&1
else
echo "Entire trio ceased running"
fi
}
trap finish EXIT
./storage &
P1=$!
./storage &
P2=$!
./storage &
P3=$!
wait $P1 $P2 $P3
Currently, it executes how I want it to, in that when I send a ctrl+c signal to it, the script sends that signal to all my background processes.
However: I've now extended these programs so that, based on connections/messages they receive from clients, they may do an execv, killing themselves and starting up a new, separate program. (For the curious, they're simulating a "server dead" state by starting up an idling process, which may then receive signals to start up the original process again.)
The problem is that, after the execv, this new process no longer responds to a kill sent by the bash script.
Is there a way to allow for this original script's execution (and subsequent signalling) to also send a signal to the newly exec'd process as well?
I suggest you consider searching for child processes by the parent pid. More specifically, before killing a pid, search for the child processes of that pid using ps and kill those children first. Finally, kill the parent.
I have a feeling that there are race conditions that will cause this to fail in some cases.
Update: my issue was completely unrelated to this script; the pid of the running/rebooted processes never changed, but I was inadvertently inheriting the signals I was blocking in various threads internal to the program. Some sensible calls to pthread_sigmask solved the issue.
Thanks to #Mark for the tips about child processes though; if there were fork calls going on, that would have been a very good approach!
I am trying to implement an application on Linux using C, and I have a requirement that I need to do I/O separately on my child & parent process. Here is what I am looking for
User runs the application, the parent process spawns 3 child processes.
Each of the child process will spawn a thread that waits for the user input.
There should be an intuitive method by which the user can specify which of the child process he is interacting with.
Ideally I would like if each of the child processes is executed on different terminal, that way it is very clear to the user with whom he is interacting.
I saw a similar question in Executing child process in new terminal, but the answer is not very clear regarding the steps involved. It seems to suggest that it can be done by execing the xterm like this xterm -e sh -c, but it is not confirmed. I would also want to setup some IPC between the parent <--> child & child <--> child process as well, so if I launch the child process in a new terminal by execing xterm, who is the child of my parent process? Is it xterm? If so, the code that I actually want to execute in my child process, will it get executed as a child of xterm?
Assume that you have already spawned the three child processes and that you run your parent on tty1.
tty1: Now contains all the diagnostics information
tty2: Child process 1
tty3: Child process 2
tty4: Child process 3
tty5: User input
So each child process will read from its tty as if it were a file (note: requires root permissions). To give input to, say, child process 2, go to tty5 and type in this command:
cat - >/dev/tty3
Then type in the input to your program, and then press Ctrl-D. Your child process 2 should now recieve that input.
EDIT You do not need to actually run the child processes on different ttys. It is only required to run them with root permissions and then read and write from those tty numbers, just as you would read from stdin and write to stdout. Sorry for the confusion.
I am faced with a situation wherein I have process X executing a
a command ( say /bin/ls ). as soon as the process X executes the command ls
I want to put a breakpoint in a function in ls.
Is there any way to do this ?
An easy solution may be to wrap the binary in question (that is called by process X) in a small shell script that starts the process in a debug session and applies pre-configured breakpoints as well.
I can think of two ways to do it.
Simplest is to set follow-fork-mode child whenever new new client process is created GDB will debug the child. However with this mode you will not be able to debug the parent process any more.
In the child process (ls mentioned above) add some code to wait for a signal say SIGCONT at the very beginning. Whenever child process is created attach GDB (new GDB instance) to it with its PID of child process, issue the singnal SIGCONT to continue.
You can use catch exec [1] to stop on exec calls:
(gdb) catch exec
Catchpoint 1 (exec)
(gdb) r
Starting program: /tmp/a.out
process 7544 is executing new program: /bin/ls
Catchpoint 1 (exec'd /bin/ls), 0x00007ffff7ddfaf0 in _start () from /lib64/ld-linux-x86-64.so.2
Then you can do whatever you want with the new process. See also the link in the comment by dbrank0 for various fork-related options.
I want to set a breakpoint for a child process [Task B] which is invoked by another process [Task A].
I used set follow-fork mode child to switch from parant process to child. However, GDB is not stopping in child task rather it runs and return to the Task B.
Is there a way I can stop in child task and debug it?
I have found this resource to be useful in the past for things of this nature http://www.delorie.com/gnu/docs/gdb/gdb_26.html
And of course as the first comment to your question suggests, double check that the breakpoint is actually in the child execution path.