lolek
lolek

Reputation: 59

Child processes with fork

I am trying to make a simple C program that will call the fork method three times and display identifiers of child processes (UID, GID, PID, PPID, PGID). And I am struggling with proper understanding what is really happening. There is my code in which I use separate methods for method fork() and for displaying identifiers, and also in for for parent process I am trying to use the waitpid method to wait for all child processes to die. I am really confused now because I cannot get it working in a way that clearly says it works in proper way. Can you give me any suggestions or show a better way for my problem?

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>

void identifiers();
void forkMethod();

int main(void)
{ 
    forkMethod();
    return 0;
}

void forkMethod()
{
    int k;
    int status;
    for (k=0;k<3;k++){
        switch (fork()) {
        case -1:
            perror("fork error");
            exit(EXIT_FAILURE);
            break;
        case 0:         
            identifiers();  
            break;
        default:
            //wait(&status);
            waitpid(getpid(), &status, WNOHANG);
            sleep(1);
            break;
        }
    }
}

void identifiers()
{
    pid_t pid = getpid();
    pid_t ppid = getppid();
    pid_t pgid = getpgid(pid);
    pid_t uid = getuid();
    pid_t gid = getgid();
    printf("UID:%d GID:%d PID:%d PPID:%d PGID:%d\n", uid, gid, pid, ppid, pgid);
}

// ===========================================================

First thank you all for answers and pointing all of these mistakes I made,

I know the code is horrible and probably still have a few issues but now i think i have what i wanted to.

As @John Bollinger ask what is main functionality that is my list: 1. Write a function that displays identifiers UID, GUID, PID, PPID, PGID for specified process 2. call fork() function 3 times and display these identifiers for child processes 3. Use the sleep function to display processes in order from the oldest 4. display a processes tree based on results.

Thank you @juhist and @Jonathan Leffler for sharp and simple explanation. If there any significant issues in code please post

and know the final code is:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>

void identifiers(); // function that display identifiers
void forkMethod(); // function that calls fork() function 3 times
void tree(int); // function displaying processes tree

int main(void)
{ 
identifiers(); // displaying ID's for parent process
printf("Parent pid: %d\n", getpid());   
printf("Child processes: \n");      

forkMethod();   

return 0;
}

void forkMethod()
{
int k;
int status;
int pid;

for (k=0;k<3;k++){
pid = fork();
    switch (pid) {
    case -1:
        perror("fork error");
        exit(EXIT_FAILURE);
        break;
    case 0: 
    identifiers(); 
    exit(0);             
    default:           
    tree(getpid());            
    wait(&status); 
        sleep(1);   
    break;
    }
}
}

void identifiers()
{
pid_t pid = getpid();
pid_t ppid = getppid();
pid_t pgid = getpgid(pid);
pid_t uid = getuid();
pid_t gid = getgid();
printf("\nUID:%d GID:%d PID:%d PPID:%d PGID:%d\n", uid, gid, pid, ppid, pgid);
}

void tree(int pid)
{
char pstree[] = "pstree -np "; 
char cmd[12];
sprintf(cmd, "%s%d", pstree, pid);
system(cmd);
}           

Upvotes: 0

Views: 1254

Answers (2)

juhist
juhist

Reputation: 4314

One of your problems is in this code:

case 0:         
    identifiers();  
    break;

Surely you meant to do this instead:

case 0:
    identifiers();
    exit(0);

Otherwise the child process will continue execution and you will get too many forks.

The other problem is that you're calling waitpid() with the parent pid, not the child pid. The calls does nothing useful as you're using the WNOHANG argument. Either use wait() or store the pid of the child as returned by fork somewhere and use that pid as the argument of waitpid().

Furthermore, you should consider checking the return value of waitpid(). In larger programs, if you have signal handlers it is possible that the call will be interrupted by signal and returns an error code with errno == EINTR. It is good practice to retry system calls interrupted by a signal and check for other possible error returns, too.

Upvotes: 4

user3629249
user3629249

Reputation: 16540

On this line:

waitpid(getpid(), &status, WNOHANG);

The getpid() will always get the parent pid, not the pid of the child. Suggest changing switch(fork()) to

pid= fork(); switch(pid) { ... }

and the waitpid line to

waitpid(pid, &status, 0);

Upvotes: 3

Related Questions