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);
Related
I'm answering my own question here because all of the other threads talking about this gave generally inefficient solutions to this problem[refer to title].
The most logical way to find the PID of a program is with getpid. However for some reason getpid command always gives you the PID that is two numbers behind the actual program ID it's about to be assigned. I'm sure someone more familiar with the linux kernel will be sure to explain why I'm an idiot in the comments below, so the reasoning for the -2 pid is probably down there.
Anyway, here's a reverse engineered c script(from MTU) that gives you the PID of the program.
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
void main(void)
{
pid_t pid;
char fetch[50];
pid = getpid();
int pid2=pid+2;
sprintf(fetch, "echo hello world! my PID is %d", pid2);
system(fetch);
}
However for some reason getpid command always gives you the PID that is two numbers behind the actual program ID it's about to be assigned.
Well, getpid returns the PID of the current process.
How can it return the PID of a new process that doesn't exist yet? How could it possibly know?
The current process has a process ID. When you call system, it creates a child process, with its own process ID. Presumably the child process then creates another child to execute the command you passed to system.
By default the first child's PID will be the current process PID + 1. And the second child's PID will be the current process PID + 2. However, if either of those IDs are already in use (or you hit the maximum value of a pid_t and wrap around), this brittle logic will break completely.
If you want to get a child process' PID, call fork directly:
pid_t childpid = fork();
if (childpid < 0) {
perror("failed to fork");
exit(1);
}
if (childpid == 0) {
/* this path executes in the child process */
exec_command_in_child();
} else {
/* this path executes in the parent */
wait_or_kill_or_something(childpid);
}
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)
How to write a programm to show whether it's a child or parent process after the fork() is used?
I need to find other way then checking the return value of fork() or getpid() function.
I know e.g. that process resource utilizations (getrusage(2)) and CPU time counters (times(2)) are reset to zero in the child. How i can use for example that knowledge (or other child-parents differences) to determine my problem?
Thank you for your help!
Setup a signal handler for SIGCHLD in one of the processes and end the other one. If the SIGCHLD handler gets called you know the child died. If not the parent died.
Another (less distructive) way it to call wait(). If it returns ECHLD no child is around, thus the calling process is the child. If it blocks, at least one child is around, thus the calling process is the parent.
Or call waitpid() with PID of the other process. The same logic on the result as for wait() applies.
You could exploit the fact that the parent will be a process group leader (and thus its pid will be the same as its process group id) while the child will be a member of that process group and thus its pid will be different from the process group id:
#include <stdio.h>
#include <unistd.h>
main(int argc, char **argv) {
char *self = NULL;
fork(); /* looking at return value would be cheating */
int pid = getpid();
int pgid = getpgid(0);
if (pid == pgid)
self = "Parent";
else
self = "Child";
printf("%s pid = %d pgid = %d\n", self, pid, pgid);
}
Running yields:
$ ./pgid
Parent pid = 29400 pgid = 29400
Child pid = 29401 pgid = 29400
This does of course still use getpid() but not in the same way you describe above.
On Linux, you might also use proc(5). The process of pid 1234 is described by the directory /proc/1234/ and you could read sequentially and parse the /proc/1234/status pseudo-file to get all that information.
To understand a bit more, read the proc(5) man page, then type
cat /proc/self/status
cat /proc/$$/status
cat /proc/self/maps
cat /proc/$$/maps
in a terminal, and try to understand the output. You might parse it programmatically (e.g. with FILE*f = fopen("/proc/1234/status","r"); then do some fgets or fscanf on f; then fclose(f);)
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.
Suppose pid X is a process group leader and X terminates, but other processes in the process group remain running (with X as their pgid). Will Linux prevent the value X from being assigned as a pid to a new process?
I ask this because of a failure condition POSIX allows for setsid:
[EPERM] The calling process is already a process group leader, or the process group ID of a process other than the calling process matches the process ID of the calling process.
This error seems to be an unrecoverable condition for code using process groups (i.e. shells) that would be triggered "at random", making it even more odious. I would assume any implementation aiming at sane levels of quality would avoid reassigning X as a pid while it's still in use as a pgid, but I can't find this documented anywhere.
Not a problem, because fork guarantees:
The child process ID also shall not match any active process group ID.
And fork is the only way to create new processes.
Nemo is correct that POSIX guarantees that fork() will not re-use an existing PGID as a PID; however, there is more to the story.
Process groups, and process group leaders, can also be changed using setpgid(). The following example code causes the existence of a process group equal to the PID of the current process, which the current process is not in:
#define _XOPEN_SOURCE 500
#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>
#include <signal.h>
int main()
{
pid_t pgrp_orig;
pid_t child;
int status;
/* Fork so that we are not a process group leader */
if (fork()) {
/* Grandparent process */
wait(&status);
return 0;
}
/* Record our original process group, then start a new one */
pgrp_orig = getpgrp();
if (setpgid(0, 0))
perror("setpgid");
child = fork();
if (!child) {
/* Child process */
pause();
return 0;
}
/* Switch back to original process group. Child remains in the new one */
if (setpgid(0, pgrp_orig))
perror("setpgid");
printf("Parent pid=%ld, pgid=%ld\n", (long)getpid(), (long)getpgrp());
printf("Child pid=%ld, pgid=%ld\n", (long)child, (long)getpgid(child));
/* Wake child up to finish up */
kill(child, SIGUSR1);
wait(&status);
return 0;
}
Note that if the parent process tries to call setsid() here before the child exits, the failure condition you asked about will be triggered.
However, due to the restrictions on the allowable transitions that setpgid() can cause, this can't cause the kind of random failures you're worried about. The breakage is confined to a single session.