子进程中的Ctrl Z 会破坏ncurses 的reset_prog_mode

问题描述 投票:0回答:1

我正在编写一个 ncurses 应用程序,它显示目录中的文件,并获取用户选择的文件并在 vim 中打开,问题是当我按 ctrl z 暂时关闭 vim 时,在恢复并关闭 vim 后,我的程序在很多方面都搞砸了。

  1. 光标变得可见,调用 curs_set(0) 再次隐藏它没有任何作用
  2. 如果我不调用 redrawwin(stdscr) (刷新不执行任何操作),屏幕缓冲区只会保留我运行 fg 之前的终端屏幕。
  3. 关闭程序后,ncurses 不会恢复原始 shell 状态,除了 shell 提示之外,我的应用程序关闭时的状态仍保留在屏幕上。

这里有可运行的示例https://pastebin.com/tEdLkaPP 在 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();
                    }

c++ c linux ncurses
1个回答
0
投票

查看乔·布莱克爵士的回答中的https://stackoverflow.com/a/4891565/4769313后,我意识到如果我在自定义信号处理程序中处理SIGTSTP,我需要运行kill(getpid(), SIGSTOP )实际上让进程停止。 因此,使用下面的自定义处理程序,一切似乎都按预期工作。 需要注意的是,您必须在 initscr 之后注册信号处理程序,否则 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();

© www.soinside.com 2019 - 2024. All rights reserved.