LinuxQuestions.org
Download your favorite Linux distribution at LQ ISO.
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices


Reply
  Search this Thread
Old 04-20-2023, 09:35 AM   #1
gzorp
LQ Newbie
 
Registered: Nov 2022
Posts: 7

Rep: Reputation: 0
Process Groups : prompt and result problem, catching zombies in custom shell in C


Hi! I am trying to create my own shell in CPP/C. I am having some trouble with the children produced when pipelines are used. First of all, I am using process groups to achieve this, because I want the ^Z and ^C signals to work for the child processes that are created using fork and actually do what they are supposed to do.

Let's suppose I have the command
PHP Code:
 ls -al grep something 
. Since they are pipelined there should be two processes that are being forked and that run parallel. I am also using process groups to achieve this goal. My approach has been: On a function for the job, inside a for loop, run for any intermediate process the code as should be expected: a fork(), the appropriate
PHP Code:
setpgid(), tcsetpgrp() 
calls for the child as well as any signal handling. If the function has reached the final process (e.g. grep something from the above example) run everything normally as above, but also add the waiting from the father.

The father waits for every process in a process group to end using the following code:

PHP Code:
while(waitpid(-job->pgid, &statusWUNTRACED) != -1) {
   if (
WSTOPSIG(status)) {
      break;
   }
}; 
If it detects a child was stopped, it breaks so it does not wait anymore for it. I am also checking for any zombie processes at the beginning of the main loop as shown below:

PHP Code:
std::string userInput;

while (
1) {
        
int pid;
        
int status;

        while ((
pid waitpid(-1, &statusWNOHANG|WUNTRACED)) > 0) {
             
// Caught zombie process
        
}

        
myshell_promt(); // Just a print
        
std::getline(std::cinuserInput);
        if (
userInput == "") { continue; }
        if (
userInput == "exit") { break; }

        
// Parse and execute command
        
printf("Next command!\n");

Although it works (or so it seems I guess), there are times the result is like this:

PHP Code:
Next command!
-
rw-r--r--  1 something something    536 Apr 19 18:25 something_else.cpp
mysc
:> -rw-r--r--  1 something something    414 Apr 20 10:37 something.cpp 
or even:

PHP Code:
Next command!
mysc:> 
-
rw-r--r--  1 something something    536 Apr 19 18:25 something_else.cpp
-rw-r--r--  1 something something    414 Apr 20 10:37 something.cpp 
and then I wait for the next command from the user. However, this is not what I want. I want to see the prompt after the end result. I can't seem to figure out what exactly goes wrong.
The following shows the execution for the processes, where forks are made:

PHP Code:
pid_t childpid;
    
int status 0;

    
childpid fork();

    if (
childpid 0) {
        
perror("Creating child process");
        return -
1;
    } else if (
childpid == 0) {
        
// Update the process class to hold the correct pid
        
proc->set_pid(getpid());

        
// Will only get executed once per job
        // to set the job's group id to that of the first process' ID
        
if (job->get_pgid() == -) {
            
// Initialize pgid, only for the first process
            
job->set_pgid(proc->get_pid());
        }
      
        
// Attach the process to the process group
        
setpgid(0job->get_pgid());

        
signal(SIGINTSIG_DFL);
        
signal(SIGSTOPSIG_DFL);
        
signal(SIGTSTPSIG_DFL);
        
signal(SIGQUITSIG_DFL);
        
signal(SIGCHLDSIG_DFL);
        
signal(SIGTTINSIG_DFL);
        
signal(SIGTTOUSIG_DFL);

        
// Play with pipes ...
        
        
if (execvp(proc->argv[0], proc->argv) < 0) {
            
printf("mysh: %s: command not found\n"proc->argv[0]);
            exit(
0);
        }
        
printf("Assert it does not come here!\n");
        exit(
0);

    } else {
        
// Same exact code as the child, in order to assure it doesn't matter which gets here first
        // the correct things will happen, and avoid races
        
proc->set_pid(childpid);

        if (
job->get_pgid() == -) {
            
job->set_pgid(proc->get_pid());
        }
        
setpgid(childpidjob->get_pgid());
        
        
// Only the last process will get called with the mode set as FOREGROUND_EXECUTION
        // So it can wait for all previous ones to end
        
if (mode == FOREGROUND_EXECUTION) {
            
// If foreground, set it to have control of the terminal
            // close pipes ...
            // give control of the terminal to the process group
            
tcsetpgrp(0job->get_pgid());
            
// now wait for the job
            
status shell->wait_for_job(job->id);
            
signal(SIGTTOUSIG_IGN);
            
// Get back control of the terminal
            
tcsetpgrp(0getpid());
            
signal(SIGTTOUSIG_DFL);
        }
    }

    return 
status
I thought about using a signal handler for SIGCHLD, but I don't know how to do that exactly, or if that would even work. Any thoughts? Thanks a lot!

Last edited by gzorp; 04-20-2023 at 09:37 AM.
 
Old 04-20-2023, 10:20 AM   #2
NevemTeve
Senior Member
 
Registered: Oct 2011
Location: Budapest
Distribution: Debian/GNU/Linux, AIX
Posts: 4,479
Blog Entries: 1

Rep: Reputation: 1695Reputation: 1695Reputation: 1695Reputation: 1695Reputation: 1695Reputation: 1695Reputation: 1695Reputation: 1695Reputation: 1695Reputation: 1695Reputation: 1695
My best suggestions are gdb and strace. (Debug-prints can also help.)
 
  


Reply

Tags
c++, groups, processes, unix


Thread Tools Search this Thread
Search this Thread:

Advanced Search

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off



Similar Threads
Thread Thread Starter Forum Replies Last Post
Shell Script to take 2 inputs and process the result shadownet Linux - Newbie 3 05-24-2013 12:58 PM
High CPU Usage and 12 zombies??? kopper27 Linux - Newbie 3 04-05-2010 03:54 PM
Catching SIG of running process with bash mashiox Programming 13 11-30-2009 11:13 PM
Checking for zombies and how to resolve it depam Linux - Security 6 06-27-2006 12:12 PM
catching a rogue or unknown process that last miliseconds on an "idle system" Emmanuel_uk Linux - Security 3 06-11-2006 04:42 PM

LinuxQuestions.org > Forums > Non-*NIX Forums > Programming

All times are GMT -5. The time now is 03:45 PM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Open Source Consulting | Domain Registration