子进程中的Ctrl Z会中断ncurses的reset_prog_mode

ecr0jaav  于 2023-10-16  发布在  其他
关注(0)|答案(1)|浏览(75)

我正在写一个ncurses应用程序,它显示一个目录中的文件,并接受用户选择的文件并在Vim中打开,问题是,当我点击ccursz暂时关闭vim时,在恢复并关闭vim之后,我的程序在很多方面都一团糟。
1.光标变为可见,再次调用curs_set()隐藏它不会有任何作用
1.如果我不调用redrawwin(stdscr)(刷新什么也不做),屏幕缓冲区只是保持我运行fg之前的终端屏幕。
1.关闭程序后,ncurses不会恢复原始的shell状态,我的应用程序关闭的状态将保留在屏幕上,除了shell提示符。
在Linux 6.5.2和ncurses版本6.4.2上运行
使用execl派生和打开Vim的部分代码

def_prog_mode(); endwin();

                pid_t pid = fork();
                if (pid == -1) {
                    perror("fork");
                } else if (pid == 0) {
                    execl("vim", "vim", <file>, NULL);
                } else {
                    int child_return = 1;
                    waitpid(-1, &child_return, WUNTRACED);
                }

                reset_prog_mode();

                redrawwin(stdscr);

//              Redraws the window

删除ncurses窗口并调用endwin()的代码

exit:
    delwin(win);
    delwin(bottom_win);
    delwin(win_border);
    delwin(bottom_border);
    endwin();
    return 0;

我试过在子进程被SIGSTOP停止时调用def_prog_mode(),然后在子进程被SIGCONT停止时调用reset_prog_mode(),但这并没有改变任何东西。
处理信号的代码

int child_return = 1;

                    while(!WIFEXITED(child_return))
                    {
                        waitpid(-1, &child_return, WUNTRACED | WCONTINUED);

                        if(WIFSTOPPED(child_return))
                            def_prog_mode();
                        else if (WIFCONTINUED(child_return))
                            reset_prog_mode();
                    }
goqiplq2

goqiplq21#

在查看了Jo Black爵士的答案中的https://stackoverflow.com/a/4891565/4769313之后,我意识到如果我在自定义信号处理程序中处理SIGTSTP,我需要运行kill(getpid(),SIGSTOP)来实际停止进程。因此,使用下面的自定义处理程序,一切似乎都按预期工作。需要注意的是,必须在initscr to之后注册信号处理程序,否则ncurses可能会覆盖信号处理程序。

void sig_tstp(__attribute__((unused))int signal)
    {
        endwin();
        kill(getpid(), SIGSTOP);
    }
    
    void sig_cont(__attribute__((unused))int signal)
    {
        reset_prog_mode();
    }

    int main()
    {
        initscr();

        signal(SIGTSTP, sig_tstp);
        signal(SIGCONT, sig_cont);
//      ...
    }

分支代码不再需要处理子进程,直到子进程终止,所以现在它看起来像这样

def_prog_mode(); endwin();

        pid_t pid = fork();
        if (pid == -1) {
            perror("fork");
        } else if (pid == 0) {
            execl(program, program, buf, NULL);
        } else {
            int child_return = 1;
            waitpid(-1, &child_return, 0);
        }

        reset_prog_mode();

相关问题