当主终端关闭时,程序终止

时间:2017-07-27 08:44:41

标签: c++ linux pty

在我的程序中,当我尝试关闭主文件描述符时。突然间我的程序崩溃了,我还没有看到任何核心。有人可以帮我这个。我提供的是我用过的代码。这是我从互联网上复制的代码(http://rachid.koucha.free.fr/tech_corner/pty_pdip.html),只有差异而不是fork我产生一个线程。我知道一些我想念的小信息。有人可以请光明。

提前致谢!!!

int ScalingCommandReceiver::execute_ptcoi_commands_sequence(const char * bc_name, std::vector<cmd_output_pair>& cmd_seq, std::string& output_str)
{
    int fdm, fds;
    int rc;

    output_str.clear();

    fdm = posix_openpt(O_RDWR);
    if (fdm < 0)
    {
        output_str.append("Error on posix_openpt() \n");
        return -1;
    }

    rc = grantpt(fdm);
    if (rc != 0)
    {
        output_str.append("Error on grantpt() \n");
        close(fdm);
        return -1;
    }

    rc = unlockpt(fdm);
    if (rc != 0)
    {
        output_str.append("Error on unlockpt() \n");
        close(fdm);
        return -1;
    }

    // Open the slave side ot the PTY
    fds = open(ptsname(fdm), O_RDWR);

    if (fds < 0)
    {
        output_str.append("Error on posix_openpt() \n");
        close(fdm);
        return -1;
    }


    std::string cp_name ("bc3");

    pt_session_struct *file_refs = NULL;
    file_refs = (pt_session_struct*) ::malloc(sizeof(pt_session_struct));

    if (file_refs == NULL) {
        output_str.append("ERROR: Failed to create the struct info for the thread! \n");
        close(fdm);
        close(fds);
        return -1;
    }


    file_refs->fds = fds;
    file_refs->cp_name = (char*)bc_name;

    //Spawn a thread
    if (ACE_Thread::spawn(ptcoi_command_thread, file_refs, THR_DETACHED) < 0) {
        output_str.append("ERROR: Failed to start ptcoi_command_thread thread! \n");
        close(fdm);
        close(fds);
        ::free(file_refs);
        return -1;
    }

    int i = 0;
    while (i <= cmd_seq_dim)
    {
        char buffer[4096] = {'\0'};
        ssize_t bytes_read = 0;

        int read_res = 0;
        do
        {

            // get the output in buffer
            if((read_res = read(fdm, (buffer + bytes_read), sizeof(buffer))) > 0)
            {
                // The number of bytes read is returned and the file position is advanced by this number.
                // Let's advance also buffer position.
                bytes_read += read_res;
            }
        }
        while((read_res > 0) && !strchr(buffer, cpt_prompt) && (std::string(buffer).find(ptcoi_warning) == std::string::npos));

        if (bytes_read > 0) // No error
        {

            // Send data on standard output or wherever you want
            //Do some operations here

        }
        else
        {
            output_str.append("\nFailed to read from master PTY \n");
        }

        if(i < cmd_seq_dim)
        {
            // Send data on the master side of PTY
            write(fdm, cmd_seq[i].first.c_str(), cmd_seq[i].first.length());

        }
        ++i;
    } // End while


    if(/*have some internal condition*/)
    {
        close(fdm); //Here I observe the crash :-(
        return 0; // OK
    }
    else
    {
        output_str.append ("\nCPT printouts not expected.\n");
        close(fdm);
        return -1; // Failure
    }

    close(fdm);
    return 0; // OK

}

ACE_THR_FUNC_RETURN ScalingCommandReceiver::ptcoi_command_thread(void* ptrParam)
{
        pt_session_struct* fd_list  = (pt_session_struct*) ptrParam;

        struct termios slave_orig_term_settings; // Saved terminal settings
        struct termios new_term_settings; // Current terminal settings


        int fds = fd_list->fds;

        char* cp_name = fd_list->cp_name;

        ::free (fd_list);


        // Save the defaults parameters of the slave side of the PTY
        tcgetattr(fds, &slave_orig_term_settings);

        // Set RAW mode on slave side of PTY
        new_term_settings = slave_orig_term_settings;
        cfmakeraw (&new_term_settings);
        tcsetattr (fds, TCSANOW, &new_term_settings);

        int stdinCopy, stdoutCopy, stdErr;

        stdinCopy = dup (0);

        stdoutCopy = dup (1);

        stdErr = dup (2);

        // The slave side of the PTY becomes the standard input and outputs of the child process
        close(0); // Close standard input (current terminal)
        close(1); // Close standard output (current terminal)
        close(2); // Close standard error (current terminal)

        dup(fds); // PTY becomes standard output (0)
        dup(fds); // PTY becomes standard output (1)
        dup(fds); // PTY becomes standard error (2)


        // Now the original file descriptor is useless
        close(fds);


        // Make the current process a new session leader
        //setsid();

        // As the child is a session leader, set the controlling terminal to be the slave side of the PTY
        // (Mandatory for programs like the shell to make them manage correctly their outputs)
        ioctl(0, TIOCSCTTY, 1);

        // Execution of the program
        char PTCOI [64] = {0};
        snprintf(PTCOI, sizeof(PTCOI), "/opt/ap/mas/bin/mas_cptaspmml PTCOI -cp %s -echo 7", cp_name);

        system(PTCOI); //my command


        close(0); // Close standard input (current terminal)
        close(1); // Close standard output (current terminal)
        close(2); // Close standard error (current terminal)


        dup2 (stdinCopy, 0);
        dup2 (stdoutCopy, 1);
        dup2 (stdErr, 2);


        close (stdinCopy);
        close (stdoutCopy);
        close (stdErr);


        return 0;

}

1 个答案:

答案 0 :(得分:0)

execute_ptcoi_commands_sequence似乎包含daemonize your process所需的步骤:

    // The slave side of the PTY becomes the standard input and outputs of the child process
    close(0); // Close standard input (current terminal)
    close(1); // Close standard output (current terminal)
    close(2); // Close standard error (current terminal)
    . . .

这意味着forksetsid可以与控制终端分离,以便您的流程可以在终端会话之后继续存在。

删除fork后,您的进程仍与控制终端关联,并可能在终端发送SIGHUP时终止。