Возникли проблемы при работе с сигналом SIGINT в C / UNIX - PullRequest
0 голосов
/ 10 ноября 2019

У меня есть эта программа на C, которая запускает базовую оболочку для UNIX, и я хочу сделать что-то конкретное. По сути, всякий раз, когда я нажимаю CTRL + CI, я пытаюсь уничтожить все дочерние процессы, но поддерживаю родительский процесс, чтобы вернуться к следующей строке ввода. Код ниже, кажется, работает как предназначено для основных команд, таких как дата, whoami и т. Д. Однако, когда я запускаю следующие команды для тестирования, оболочка не возвращается назад, чтобы получить больше ввода, и любой текст, введенный впоследствии, ничего не делает.

$sleep 100 
$CTRL+C

Чтобы остановить оболочку, я должен использовать CTRL + Zзаставить программу остановиться. Мне нужен сигнал SIGINT, чтобы прервать дочернюю команду сна и заставить родителя вернуться к запросу пользователя после уничтожения дочерних процессов, но, очевидно, я сделал что-то не так. Вот вывод, объясняющий, что я имею в виду.

$ ./a3shell2
--------myShell > date
 Input command is: date
Sat Nov  9 15:38:08 CST 2019
--------myShell > whoami
 Input command is: whoami
klm46
--------myShell > ^C
Caught SIGINT!
killing children
date
 Input command is: date
Sat Nov  9 15:38:20 CST 2019
--------myShell > sleep 100
 Input command is: sleep 100
^C
Caught SIGINT!
killing children
date
date
whoami
^Z
[2]+  Stopped                 ./a3shell2

Программа Shell:

/* ----------------------------------------------------------------- */
/* PROGRAM  simple shell.c progam                                    */
/* ----------------------------------------------------------------- */
#include <sys/types.h>
#include <sys/wait.h>
#include <errno.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sysexits.h>
#include <unistd.h>
#include <assert.h>
#include <sched.h>

pid_t pid = 0;

void sig_int(int signo) 
{
    printf("\nCaught SIGINT!\n");
  printf("killing children\n"); 
  if (pid != 0) 
  {
    kill(pid, SIGKILL); 
    pid = 0; 
  }
}

char *getinput(char *buffer, size_t buflen) 
{
    printf("--------myShell > ");
    return fgets(buffer, buflen, stdin);
}

/* ----------------------------------------------------------------- */
/* FUNCTION  parse:                                                  */
/* ----------------------------------------------------------------- */

void  parse(char *line, char **argv)
{
     while (*line != '\0') {       /* if not the end of line ....... */ 
          while (*line == ' ' || *line == '\t' || *line == '\n')
               *line++ = '\0';     /* replace white spaces with 0    */
          *argv++ = line;          /* save the argument position     */
          while (*line != '\0' && *line != ' ' && 
                 *line != '\t' && *line != '\n') 
               line++;             /* skip the argument until ...    */
     }
     *argv = '\0';                 /* mark the end of argument list  */
}

/* ----------------------------------------------------------------- */
/* FUNCTION execute:                                                 */
/* ----------------------------------------------------------------- */

void execute(char **argv)
{
     //pid_t  pid;
     int    status;

     if ((pid = fork()) < 0) {     /* fork a child process           */
          printf("*** ERROR: forking child process failed\n");
          exit(1);
     }
     else if (pid == 0) {          /* for the child process:         */
          if (execvp(*argv, argv) < 0) {     /* execute the command  */
               printf("*** ERROR: exec failed\n");
               exit(1);
          }
     }
     else {                                  /* for the parent:      */
          while (wait(&status) != pid)       /* wait for completion  */
               ;
     }
}

/* ----------------------------------------------------------------- */
/*                  The main program starts here                     */
/* ----------------------------------------------------------------- */

void  main(void)
{

     char  line[1024];             /* the input line                 */
     char  *argv[64];              /* the command line argument      */
     size_t linelen;

if (signal(SIGINT, sig_int) == SIG_ERR) 
  {
        fprintf(stderr, "signal error: %s\n", strerror(errno));
        exit(1);
    }

     while (1) 
     {                   /* repeat until done ....         */
          getinput(line, sizeof(line));
          line[strlen(line) - 1] = '\0';
          printf(" Input command is: %s \n", line);

          parse(line, argv);       /*   parse the line               */

          if (strcmp(argv[0], "exit") == 0)  /* is it an "exit"?     */
               exit(0);            /*   exit if it is                */

          execute(argv);           /* otherwise, execute the command */
     }
}

1 Ответ

1 голос
/ 10 ноября 2019

Ваша оболочка застревает в бесконечной петле wait(&status) != pid, когда вы CTRL + C .

SIGINT прерывает wait(), и ваш обработчик сигналаустанавливает глобальную переменную pid в ноль. Когда управление возвращается в цикл, оно никогда не закончится: pid равно нулю, а wait() может возвращать только PID и -1 , но никогда не обнуляется.

(Вы непосмотрите на это поведение с date и whoami, потому что эти дочерние процессы уже завершены к тому времени, когда вы запускаете CTRL + C . В этом случае вы, вероятно, прерываете fgets(),не wait(), а отправка SIGKILL на уже набранный PID. Это тоже нехорошо, поскольку существует вероятность повторного использования PID при отправке SIGKILL.)

В качестве отступления,Непонятно, что на самом деле происходит, когда SIGINT прерывает ваш wait() вызов, так как signal() исторически различался на разных платформах. Вызов может быть прерван, возвращая -1 (EINTR), или он может возобновить wait(), возвращая PID kill() ed потомка. В данном случае это спорный вопрос - ни один из них не соответствует нулю, который вы ищете в данный момент, - но это хорошая причина для использования sigaction(), а не signal().

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...