2013-04-27 42 views
0

我自我實現一個Linux外殼程序。我即將完成,但我需要解決殭屍進程的問題。在此程序中,通過將「&」添加到命令中,可以指定要運行的命令應該在後臺運行。防止自我實現的linux外殼中的殭屍進程(C++)

例如,睡眠3&將執行睡眠功能30秒,但立即允許用戶無需等待而輸入另一命令。

我的問題是,在我當前的實現中,後臺進程開始,但我不知道如何在程序執行完成時通知程序。

我需要知道它何時完成執行,因爲我有一個名爲「jobs」的內置函數。該功能將打印出當前正在運行的程序列表。

理想的情況下,如果我執行 「睡眠30 &」,然後立即運行 「工作」 睡眠結束前,應該表現出這樣的事情:

[1] [進程ID HERE]睡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

你需要創建一個SIGCHLD處理程序,做一個等待的過程,然後啓用使用處理信號(SIGCHLD,處理程序)。

+0

我找到了一個更好的解決方案。我試圖發表評論,但它不適合。在下面檢查。 – HesNotTheStig 2013-04-27 03:45:05

+0

嘎! Stackoverflow有關於回答你自己的問題和編輯評論的愚蠢規則。我在這裏找到了解決方案。檢查橡皮人的第二篇文章。 http://www.daniweb.com/software-development/cpp/threads/364407/handling-sigchld-to-prevent-zombie-processes – HesNotTheStig 2013-04-27 03:51:45

+0

當然應該工作,雖然不像他,我更喜歡信號。 – DrC 2013-04-27 04:32:31