防止自我实现的linux shell中的僵尸进程(C ++)

时间:2013-04-27 01:34:40

标签: c++ shell process background zombie-process

我自己实现了一个linux shell。我刚刚完成,但我需要解决僵尸进程的问题。在此计划中,添加“&”对于命令,您可以指定要运行的命令应该在后台运行。

例如,睡眠30&将执行休眠功能30秒,但立即允许用户输入另一个命令而无需等待。

我的问题是,在我当前的实现中,后台进程启动但我不知道如何在程序执行完毕后通知程序。

我需要知道它何时完成执行,因为我有一个名为“jobs”的内置函数。此功能将打印出当前正在运行的程序列表。

理想情况下,如果我执行“sleep 30&”然后在睡眠结束前立即运行“工作”,它应该显示如下:

[1] [这里的进程ID]睡眠30&

但是,如果已经过了30秒并且睡眠已经完成执行,我希望它显示没有进程正在运行。现在,如果我运行“sleep 30&”,它会显示为僵尸进程(在ps -e命令中)。我不想要这个。我该如何解决这个问题?

这是我的代码:

#include <iostream>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <signal.h>
#include <stdio.h>
#include <string.h>
#include <sys/wait.h>
#include <stack>
#include <vector>
#include <ctype.h>
#include <sstream>
using namespace std;

#define MAX_INPUT_STRING_SIZE 80

//This function executes the command that was entered
int executeCommand(char ** commandArguments, int mode, char **supplementalPointer);

//This function parses the command that was entered
int parseCommand(char* inputString, char * commandArguments[], char** supplementalPointer,
    int *modePointer);

//A bit of string handling
void chop(char * sourcePointer);

//print the history of commands
void printHistory();

//print the list of background processes running
void printJobs();

//Return the nth command in the history of commands
string returnNth(int nth);



//Modes
#define NORMAL 00
#define OUTPUT_REDIRECT 11
#define INPUT_REDIRECT 22
#define PIPELINE 33
#define BACKGROUND 44

//This struct defines a job that is stored in the list of background processes
struct job
{
    pid_t processID;
    string command;
    job(pid_t pid, string com)
    {
        processID = pid;
        command = com;
    }
};


//The history of commands entered
stack<string> commandHistory;

//A place to store commands that have been popped before that are added back in
stack<string> popHistory;

//The list of background processes currently running
vector<struct job> jobList;

int main(int argc, char *argv[])
{
    int i, mode = NORMAL, numOfArguments;
    size_t length = MAX_INPUT_STRING_SIZE;
    char *cpt, *inputString, *commandArguments[MAX_INPUT_STRING_SIZE], *supplement = NULL;

    //The string that holds the command that the user entered
    inputString = (char*)malloc(sizeof(char)*MAX_INPUT_STRING_SIZE);

    char currentDirectory[100];

    //continue until "quit" has been entered
    while(strcmp(inputString, "quit\n") != 0)
    {
        mode = NORMAL;

        //get and print the current working directory
        getcwd(currentDirectory, 100);
        cout<<"%"<<currentDirectory<<"% ";

        //get the command from the user
        getline(&inputString, &length, stdin);
        executeFromHistory:
        string inputStringS(inputString);

        //push the command to the history stack
        commandHistory.push(inputStringS);

        //quit the program
        if(inputStringS == "quit\n")
        {
            continue;
        }

        //print the history
        else if(inputStringS == "history\n")
        {
            printHistory();
            continue;
        }

        //print the list of jobs
        else if(inputStringS == "jobs\n")
        {
            printJobs();
            continue;
        }

        else if(inputStringS[0] == '!')
        {
            commandHistory.pop();

            //execute the most recent command
            if(inputStringS[1] == '!')
            {
                if(commandHistory.empty())
                {
                    cout<<"No commands in history"<<endl;
                }
                else
                {
                    inputStringS = commandHistory.top();
                    strcpy(inputString, inputStringS.c_str());
                    goto executeFromHistory;
                }
            }

            //Execute the nth command in history (specified by user)
            else if(isdigit(inputString[1]))
            {
                int nth;
                inputStringS = inputStringS.substr(1);
                istringstream iss(inputStringS);
                iss >> nth;
                if(commandHistory.size() < nth || nth < 1)
                {
                    cout<<"No such command could be found"<<endl;
                }
                else
                {
                    inputStringS = returnNth(nth);
                    strcpy(inputString, inputStringS.c_str());
                    goto executeFromHistory;
                }
            }
            else
            {
                continue;
            }
        }
        //Parse a command and execute
        else
        {
            numOfArguments = parseCommand(inputString, commandArguments, &supplement, &mode);

            //Change directory
            if(strcmp(*commandArguments, "cd") == 0)
            {
                chdir(commandArguments[1]);
            }
            else

            //Execute
            {
                int returnstatus = executeCommand(commandArguments, mode, &supplement);
                if(returnstatus == -1)
                {
                    cout<<"Execution failed"<<endl;
                    continue;
                }
            }
            ;
        }
    }
    return 0;
}

int parseCommand(char * inputString, char *commandArguments[], char **supplementalPointer, 
    int *modePointer)
{
    int numOfArguments = 0;
    bool terminate = false;
    char* sourcePointer = inputString;

    //Continue until the character we are on is NULL and terminate flag has been tripped
    while(*sourcePointer !=  '\0' && !terminate)
    {

        //New argument
        *commandArguments = sourcePointer;
        numOfArguments++;
        while(*sourcePointer != ' ' && *sourcePointer != '\t' && *sourcePointer != '\0'
            && *sourcePointer != '\n' && !terminate)
        {

            //Handle various special characters
            switch(*sourcePointer)
            {
                case '&':
                    *modePointer = BACKGROUND;
                    *commandArguments = '\0';
                    *sourcePointer++;
                    while(*sourcePointer == ' ' || *sourcePointer == '\t')
                    {
                        sourcePointer++;
                    }
                    break;
                case '>':
                    *modePointer = OUTPUT_REDIRECT;
                    *commandArguments = '\0';
                    *sourcePointer++;
                    while(*sourcePointer == ' ' || *sourcePointer == '\t')
                    {
                        sourcePointer++;
                    }
                    *supplementalPointer = sourcePointer;
                    chop(*supplementalPointer);
                    terminate = true;
                    break;
                case '<':
                    *modePointer = INPUT_REDIRECT;
                    *commandArguments = '\0';
                    sourcePointer++;
                    while(*sourcePointer == ' ' || *sourcePointer == '\t')
                    {
                        sourcePointer++;
                    }
                    *supplementalPointer = sourcePointer;
                    chop(*supplementalPointer);
                    terminate = true;
                    break;
                case '|':
                    *modePointer = PIPELINE;
                    *commandArguments = '\0';
                    sourcePointer++;
                    while(*sourcePointer == ' ' || *sourcePointer == '\t')
                    {
                        sourcePointer++;
                    }
                    *supplementalPointer = sourcePointer;
                    terminate = true;
                    break;
            }
            sourcePointer++;
        }
        while((*sourcePointer == ' ' || *sourcePointer == '\t' || *sourcePointer == '\n') &&
            !terminate)
        {
            *sourcePointer = '\0';
            sourcePointer++;
        }
        commandArguments++;
    }
    *commandArguments = '\0';
    return numOfArguments;
}

void chop(char * sourcePointer)
{
    while(*sourcePointer != ' ' && *sourcePointer != '\t' && *sourcePointer != '\n')
    {
        sourcePointer++;
    }
    *sourcePointer = '\0';
}

int executeCommand(char** commandArguments, int mode, char ** supplementalPointer)
{
    pid_t pid1;
    pid_t pid2;
    FILE *filePointer;
    int mode2 = NORMAL;
    int numOfArguments;
    int status1;
    int status2;
    char * commandArguments2[MAX_INPUT_STRING_SIZE];
    char * supplement2 = NULL;
    int pipes[2];

    //Pipeline
    if(mode == PIPELINE)
    {
        if(pipe(pipes))
        {
            cout<<"Pipe failed"<<endl;
            return -1;
        }
        parseCommand(*supplementalPointer, commandArguments2, &supplement2, &mode2);
    }
    pid1 = fork();
    string str(*commandArguments);

    //Push the command to the list of running processes
    jobList.push_back(job(pid1, str));
    if(pid1<0)
    {
        cout<<"Fork failed"<<endl;
        return -1;
    }

    //Child process
    else if(pid1 == 0)
    {
        switch(mode)
        {
            case BACKGROUND:
                //Child process is a background process
                setpgid(0, 0);
            case OUTPUT_REDIRECT:
                filePointer = fopen(*supplementalPointer, "w+");
                dup2(fileno(filePointer), 1);
                break;
            case INPUT_REDIRECT:
                filePointer= fopen(*supplementalPointer, "r");
                dup2(fileno(filePointer), 0);
                break;
            case PIPELINE:
                close(pipes[0]);
                dup2(pipes[1], fileno(stdout));
                close(pipes[1]);
                break;
        }
        execvp(*commandArguments, commandArguments);
    }

    //Parent process
    else
    {
        if(mode == BACKGROUND)
        {

            //Wait for child process to complete
            ;
        }
        else if(mode == PIPELINE)
        {
            waitpid(pid1, &status1, 0);
            pid2 = fork();
            string str2(*commandArguments2);
            jobList.push_back(job(pid2, str2));
            if(pid2 < 0)
            {
                cout<<"fork failed"<<endl;
                return -1;
            }
            else if(pid2 == 0)
            {
                close(pipes[1]);
                dup2(pipes[0], fileno(stdin));
                close(pipes[0]);
                execvp(*commandArguments2, commandArguments);
            }
            else
            {
               close(pipes[0]);
               close(pipes[1]);
            }
        }
        else
        {
            waitpid(pid1, &status1, 0);

        }
    }
    return 1;
}

void printHistory()
{
    int commandHistorySize = commandHistory.size();
    int i;
    string commandPop;
    for(i = commandHistorySize; i > 0; i--)
    {
        commandPop = commandHistory.top();
        cout<<i<<" "<<commandPop;
        commandHistory.pop();
        popHistory.push(commandPop);
    }
    for(i = 0; i < commandHistorySize; i++)
    {
        commandPop = popHistory.top();
        popHistory.pop();
        commandHistory.push(commandPop);
    }
}

//Print list of running processes
void printJobs()
{
    int i;
    for(i = 0; i < jobList.size(); i++)
    {

        //If the process is no longer running, remove it from the list
        if(kill(jobList[i].processID, 0 )!= 0)
        {
            jobList.erase(jobList.begin() + i);
        }
    }
    for(i = 0; i < jobList.size(); i++)
    {
        cout<<"["<<i+1<<"] "<<jobList[i].processID<<" "<<jobList[i].command<<endl;
    }
}

string returnNth(int nth)
{
    int i;
    int commandHistorySize = commandHistory.size();
    string commandPop;
    for(i = commandHistorySize; i > nth; i--)
    {
        commandPop = commandHistory.top();
        commandHistory.pop();
        popHistory.push(commandPop);
    }
    string returnvalue = commandHistory.top();
    for(i = commandHistorySize; i > nth; i--)
    {
        commandPop = popHistory.top();
        popHistory.pop();
        commandHistory.push(commandPop);
    }
    return returnvalue;
}

1 个答案:

答案 0 :(得分:1)

您需要为SIGCHLD创建一个等待进程的处理程序,然后使用signal(SIGCHLD,handler)启用处理程序。