shell в c: отвечать на SIGTSTP только после нажатия клавиши ввода на клавиатуре

Я пытаюсь написать оболочку в c. Частично это обработчик для перехвата сигнала SIGTSTP и установки его на перевод программ в режим "только передний план".

Вот соответствующие фрагменты кода:

//global variables
int global;

//header
void catch_tstp(int);

//main function
int main(int argc, char** argv){
    ...

    // initiate sigaction struct for CTRL-Z action
    struct sigaction ctrlz_act;
    ctrlz_act.sa_handler = catch_tstp;
    ctrlz_act.sa_flags = SA_SIGINFO|SA_RESTART;
    sigfillset(&(ctrlz_act.sa_mask));
    sigaction(SIGTSTP, &ctrlz_act, NULL);
    global = 0;

    ...
}

//handler
void catch_tstp(int sig){
    if(sig == SIGTSTP){
        if(global){
            global=0;
            printf("Entering foreground-only mode (& is now ignored)\n");
        }
        else{
            global=1;
            printf("Exiting foreground-only mode\n");
        }
    }
}

Прямо сейчас мой вывод выглядит так:

: ^ZExiting foreground-only mode             //pressed ctrl+z
             //nothing here, had to press enter again
:            //pressing enter just gives me another :, which is what I want
: ^ZEntering foreground-only mode (& is now ignored)
^ZExiting foreground-only mode

Я надеюсь, что результат может выглядеть следующим образом:

: ^Z
Entering foreground-only mode (& is now ignored)
:   //":"should show up own automatically on the next line after I press ctrl-z, then enter 
: ^Z
Exiting foreground-only mode
:

Может кто-нибудь указать мне, что я делаю неправильно? Любая помощь будет принята с благодарностью. Спасибо!

1 ответ

У вас есть несколько проблем с вашим обработчиком сигналов и тем, как вы его настраиваете.

Как я уже отмечал в комментариях, обработчик сигнала может безопасно обращаться к переменной области файла, такой как global только если эта переменная volatile и имеет тип sig_atomic_t, Если он пытается получить доступ к какой-либо другой переменной, то существует риск, что он не увидит самое последнее значение, установленное для этой переменной, этот код вне области действия обработчика не увидит значение, если оно есть, которое обработчик записывает в него. переменная, и что значение переменной будет повреждено из-за того, что записи обработчика сигнала не являются атомарными.

Более серьезная проблема, также уже отмеченная в комментариях, заключается в том, что SA_SIGINFO флаг для sigaction() говорит вам, что вы указали обработчик через sa_sigaction член вашего struct sigaction в то время как вы фактически указали это через sa_handler член. Если вы укажете обработчик через sa_handler тогда вы должны опустить SA_SIGINFO от флагов и наоборот. Если вы укажете SA_SIGINFO Неправильно помечайте, тогда получение сигнала приведет к неопределенному поведению, либо вызвав ваш обработчик с неправильным числом аргументов, либо попытавшись вызвать функцию через указатель на функцию мусора.

Кроме того, все функции, вызываемые обработчиком сигнала, должны быть безопасны для асинхронного сигнала. Запись для "сигнала" в главе 7 руководства содержит список функций, которые безопасно вызывать, и printf() не среди них.

Но главное, что мешает вашему желанию

":" должно появиться автоматически в следующей строке после нажатия Ctrl-Z

кажется, что вы включили SA_RESTART среди флагов sigaction. Этот флаг вызывает (некоторые) системные функции, которые прерываются при получении сигнала, автоматически перезапускается после завершения работы обработчика сигнала вместо возврата EINTR ошибка или частичный результат для их абонентов. В вашем конкретном случае, если ваша оболочка получает SIGSTP во время чтения команды перезапуск чтения означает, что элемент управления не возвращается в оболочку для печати нового приглашения. Это также может означать, что символы, введенные до ^Z, будут потеряны, в зависимости от того, как вы читаете команду.


Кроме того, из сообщений вашей программы кажется, что у вас может быть неправильное представление о значении и использовании ^Z и SIGSTP интерфейсом терминала и стандартной оболочкой. Они служат для управления заданиями для заданий, выполняемых оболочкой; они не в первую очередь о режиме самой оболочки. Нет необходимости, чтобы оболочка поддерживала флаг или велась иначе после получения ^Z (вне области действия самого обработчика сигнала) - необходимое интерактивное поведение вытекает, прежде всего, из того факта, что оболочка может читать со стандартного ввода только когда это на переднем плане.

Когда оболочка получает SIGSTP,

  • если он находится на переднем плане, он ничего не должен делать (и избегать потери необработанного ввода).
  • если он находится в фоновом режиме, он должен отправить SIGSTOP (обратите внимание на разницу) на группу процессов переднего плана и, при необходимости, верните себя на передний план. В этом случае он может выдать сообщение и / или запрос.
Другие вопросы по тегам