I'm reading APUE about process groups. The book says,
In most job-control shells, this function(setpgid) is called after a fork to have the child set its own process group ID. One of these calls is redundant, but by doing both, we are guaranteed that the child is placed into its own process group before either process assumes that this has happened.
I wrote the following piece of code in order to verify my understanding. Error handling is omitted.
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
printf("process ID: %d\n", getpid());
printf("process group ID: %d\n", getpgrp());
exit(0);
}
output (run it directly into a shell):
process ID: 4388
process group ID: 4388
output (run inside of vim):
process ID: 4401
process group ID: 4400 // pid of vim (through ps)
Why do the results differ? Doesn't vim fork a shell to execute a command? If it does, what is the difference or in other words, why the process group ID not equal to process ID like the first output?
BTW, does fork always automatically set the process group ID of child process? I tried to print the process group ID of a child process before set it and it printed the process ID of the parent process.
Many thanks.
It looks like that the shell gives you a new pgid when it starts your command; and vim doesn't.
Related
I am building a feature, where I can open and close files in vi editor. I am using execlp() system call in C for opening a file in a new terminal window in a new child process. Here is how it looks:
void openFile (char *fileName) {
int pid=fork();
if (pid==0){
execlp("gnome-terminal", "gnome-terminal", "--", "vi", fileName, NULL) ;
}
insert(fileName, pid);
return;
}
So for closing the file, I have the child process Id.
void closeProcess (int pid){
printf("killing %d\n", pid);
kill(pid, SIGKILL);
return;
}
Now the challenge is this process id is not the same as the vi editor process id. Killing this process is not closing the vi editor.
Here are some example processes. The process id that I have in pid variable is 25803 but is now dead. To kill vi editor I need the process id 25815.
How killing vi process working.
Here is my current program output, which doesn't close vi editor for that file.
How can I kill the terminal window and vi?
Between the fork() and execlp() you will need to set up a process group id. Then when killing, use the group id.
int setpgid(0, 0);
When this is called in the child, the first 0 is shorthand for "me". The second 0 is shorthand for "use the pid". So this means "create a new process group and put me in that group."
When killing, use the PID you have been using. But it will also handle all children of the group.
How do you get the Process Group ID for a given process?
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
int main() {
int pid = 20989; // That PID has a PGID of 20988
int pgid = getpgid(pid);
printf("pgid = %d\n", pgid);
}
Alternatively you can use this ps command:
ps xao pid,ppid,pgid,sid,command
Why should I avoid using SIGKILL?
The KILL signal instructs Linux to end the job immediately. Any open files are closed in place. There is no clean up of user land state by the application.
Alternatively, sending SIGTERM instructs the application to end. Permitting the application to close all files, save their state, and prepare to end.
So I have this simple program that sleeps for 4 second if the value returned by fork is '0' meaning that the child process is executing, I've tried using sleep in child process but the program is blocked, and flushing standard output isn't working...
code:
#include <stdio.h>
#include <unistd.h>
int main(int argc, char const *argv[]) {
pid_t value = fork();
if (value == 0) {
sleep(4);
}
printf("Value returned by fork: %d\n", value);
printf("I'm the process N°%d\n", getpid());
return 0;
}
I'm running on Ubuntu 20.04.3 LTS.
Output:
Value returned by fork: 12618
I'm the process N°12617\
farouk#farouk-HP-Pavilion-Desktop-TP01-1xxx:~/sysexp$ Value returned by fork: 0
I'm the process N°12618
To allow this question to have an accepted answer.
The child process is not blocking the shell. The shell gave its prompt and the child wrote some output after the prompt, leaving the cursor at the start of a line without a shell prompt visible — because the shell prompt already appeared earlier.
There are a variety of ways around this.
The simplest is just to type a command such as ps and hit return, noting that the shell executes it, and that the ps output does not list the child process. If you type the ps command quick enough, you might see the child listed in the output before its output appears.
Another is to modify the program so that it waits for all child processes to exit before it exits — using wait() or waitpid(). The same code can be used in the child and the parent since the child will have no children of its own. The call to the wait function will return immediately with a 'no more children' status (error).
You can find extensive discussion of all this in the comments — I've chosen to make this a Community Wiki answer since there was a lot of activity in the comments that identified the gist of this answer.
I am trying to learn the fork() and wait() system calls. If I run this code :
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
int main (){
printf("Hi, I am the parent with pid %d \n ",getpid());
int rc = fork();
printf("Fork returned : %d \n ",rc);
printf("I am the process with pid %d \n ",getpid());
wait(NULL);
return 0;
}
I get the output as expected on the terminal :
Hi, I am the parent with pid 3639
Fork returned : 3640
I am the process with pid 3639
Fork returned : 0
I am the process with pid 3640
However , If I remove wait(NULL) , I get a strange output on the terminal :
Hi, I am the parent with pid 3715
Fork returned : 3716
I am the process with pid 3715
John#John-VirtualBox:~/Fork5$ Fork returned : 0
I am the process with pid 3716
I totally understand that , we use wait() to make the parent process waits for the child to end executiion so that we can remove it from the process table and deallocate its PID . But here , if I remove the wait , we see that the terminal is called again :
John#John-VirtualBox:~/Fork5$ Fork returned : 0
I am the process with pid 3716
And even it doesn't return again back . I don't understand what this have to do with the functionality of wait ? Or in other words , why wait will fix this issue ?
The sequence of events appears to be:
The shell is the parent process to your program. When it forks your program your program inherits the standard streams (to the terminal).
Your program forks a child process which also inherits the standard streams (to the terminal).
When your parent process terminates, the shell notices (because it is waiting) and issues a prompt to the terminal.
However, your program’s child has not yet terminated, so after the shell issues its prompt the child prints its output (and then terminates).
You will notice that the shell does not issue a second prompt after the child terminates. (The shell does not know anything about your child process.)
Order of output
The fact that you get complete output lines (instead of anything interleaved) is because the standard streams for all processes are in line oriented mode.
However, there is no guarantee of order between processes. The OS scheduler can order them any way it wants. Your child could have printed before the parent.
:O)
I am using the getpid and get the pid of current process. Now I am try to get the pid of other process using process name. How to get the other process pid?
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
int main(void)
{
printf("My pid:%d\n", getpid());
return 0;
}
You could use popen() with the command program pidof to get the pid of any program.
Like this:
char line[total_length];
FILE * command = popen("pidof ...","r");
fgets(line,total_length,command);
pid_t pid = strtoul(line,NULL,10);
pclose(command);
Edit:
Please see: How to get the PID of a process in Linux in C
1: The most common way, used by daemons. Store the pid number in a file/files. Then other processes can easily find them.
2: Portable way, spawn a child process to executes ps with a pipe. Then you can parse the text output and find your target process.
3: Non-portable way, parse the /proc/ filesystem
Often, 1 is combined with 2 or 3, in order to verify that the pid is correct.
I'm trying to get the pid, the ppid and the pgid
and no matter what I do getpgid(pid) always gives me the pid.
At first, I was using it like this:
printf("PGID: %d", getpgid());
Then I realized, getpgid was taking a pid as argument so I did this:
printf("PGID: %d", getpgid(getpid()));
But this is still giving me the same number as the pid...
So I tried this:
pid_t pid;
pid = getpid();
printf("PGID: %d", getpgid(pid));
And this still doesn't work... Any idea why?
PS: I'm a beginner in c.
The process group leader is always the one that has pid == pgid, so perhaps you are making always the same test (on a process group leader) and this is the reason of getting always the same pgid as the pid of the process. When a process becomes a group leader, the kernel assigns it it's own pid as the pgid, so perhaps you are always getting that if you are checking in only one process. Bash uses process groups to distinguish background jobs and do job control, so every command you execute from a bash(1) shell will have a new process group and one of these processes (the only one if you only launched one process) will have the same the pgid and the pid of one of the processes of the job you are requesting.
The reason of this logic (to use the pid of the process group leader as the pgid) is to not have to deal with active process groups as no more groups than processed can be in the system... so when a new group id is needed the nearest process available is the own process that triggers the new process group creation, so assigning its own pid as pgid is no harmful.
For a simple example... just try the same program you used to demonstrate the pid and pgid values in a long pipe by piping them (you should try to print the output to stderr instead of stdout or all the outputs will get lost in the input buffer of the next process in the pipe):
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main()
{
int pid = getpid();
fprintf(stderr, "pid=%d; pgid=%d\n", pid, getpgid(pid));
exit(EXIT_SUCCESS);
}
and then
$ testpgid | testpgid | testpgid
pid=3819; pgid=3819
pid=3820; pgid=3819
pid=3821; pgid=3819
$ testpgid | testpgid | testpgid
pid=3833; pgid=3833
pid=3835; pgid=3833
pid=3834; pgid=3833
getpid() returns the process ID of the current process.
When a process is running, the kernel schedules its runtime - especially it assigns a PID to it - such information is stored inside the kernel address space, in data structures (e.g. inside a task struct).
Thus, when a process calls the getpid() system call, the kernel just has to look in the task structure of the calling process.
It is a group ID of the process specified by pid.
Suppose if we consider pid as zero then the ID of the current process is used in it. getpgrp() and getpgid(0) are equivalent to each other.
e.g. pid_t getpgid(pid_t pid);