diff --git a/src/terminal.cc b/src/terminal.cc index 8103af4..afd0e23 100644 --- a/src/terminal.cc +++ b/src/terminal.cc @@ -4,79 +4,59 @@ #include "singletons.h" #include #include -#include #include //TODO: remove using namespace std; //TODO: remove -int execute_status=-1; -std::mutex async_and_sync_execute_mutex; -std::unordered_map > async_execute_descriptors; -std::unordered_map async_execute_status; - -//TODO: Windows... -//Coppied partially from http://www.linuxprogrammingblog.com/code-examples/sigaction -void signal_execl_exit(int sig, siginfo_t *siginfo, void *context) { - async_and_sync_execute_mutex.lock(); - if(async_execute_descriptors.find(siginfo->si_pid)!=async_execute_descriptors.end()) { - close(async_execute_descriptors.at(siginfo->si_pid)[0]); - close(async_execute_descriptors.at(siginfo->si_pid)[1]); - close(async_execute_descriptors.at(siginfo->si_pid)[2]); - } - int status; - while (waitpid(siginfo->si_pid, &status, WNOHANG) > 0) {} - - if(async_execute_descriptors.find(siginfo->si_pid)!=async_execute_descriptors.end()) { - async_execute_status[siginfo->si_pid]=status; - async_execute_descriptors.erase(siginfo->si_pid); - } - else - execute_status=status; - async_and_sync_execute_mutex.unlock(); -} - //TODO: Windows... -//TODO: Someone who knows this stuff see if I have done something stupid. -//Copied partially from http://stackoverflow.com/questions/12778672/killing-process-that-has-been-created-with-popen2 -pid_t popen3(const char *command, int *input_descriptor, int *output_descriptor, int *error_descriptor) { +//A working implementation of popen3, with all pipes getting closed properly. +//TODO: Eidheim is going to publish this one on his github, along with example uses +pid_t popen3(const char *command, int &stdin, int &stdout, int &stderr) { pid_t pid; int p_stdin[2], p_stdout[2], p_stderr[2]; - if (pipe(p_stdin) != 0 || pipe(p_stdout) != 0 || pipe(p_stderr) != 0) + if (pipe(p_stdin) != 0 || pipe(p_stdout) != 0 || pipe(p_stderr) != 0) { + close(p_stdin[0]); + close(p_stdout[0]); + close(p_stderr[0]); + close(p_stdin[1]); + close(p_stdout[1]); + close(p_stderr[1]); return -1; - + } + pid = fork(); - if (pid < 0) + if (pid < 0) { + close(p_stdin[0]); + close(p_stdout[0]); + close(p_stderr[0]); + close(p_stdin[1]); + close(p_stdout[1]); + close(p_stderr[1]); return pid; + } else if (pid == 0) { close(p_stdin[1]); - dup2(p_stdin[0], 0); close(p_stdout[0]); - dup2(p_stdout[1], 1); close(p_stderr[0]); + dup2(p_stdin[0], 0); + dup2(p_stdout[1], 1); dup2(p_stderr[1], 2); setpgid(0, 0); execl("/bin/sh", "sh", "-c", command, NULL); perror("execl"); - exit(1); + exit(EXIT_FAILURE); } - if (input_descriptor == NULL) - close(p_stdin[1]); - else - *input_descriptor = p_stdin[1]; - - if (output_descriptor == NULL) - close(p_stdout[0]); - else - *output_descriptor = p_stdout[0]; - - if (error_descriptor == NULL) - close(p_stderr[0]); - else - *error_descriptor = p_stderr[0]; + close(p_stdin[0]); + close(p_stdout[1]); + close(p_stderr[1]); + + stdin = p_stdin[1]; + stdout = p_stdout[0]; + stderr = p_stderr[0]; return pid; } @@ -143,13 +123,6 @@ Terminal::Terminal() { } async_print_strings_mutex.unlock(); }); - - //Coppied from http://www.linuxprogrammingblog.com/code-examples/sigaction - struct sigaction act; - memset (&act, '\0', sizeof(act)); - act.sa_sigaction = &signal_execl_exit; - act.sa_flags = SA_SIGINFO; - sigaction(SIGCHLD, &act, NULL); } int Terminal::execute(const std::string &command, const std::string &path) { @@ -159,29 +132,49 @@ int Terminal::execute(const std::string &command, const std::string &path) { boost_path=boost::filesystem::path(path); //TODO: Windows... - cd_path_and_command="cd "+boost_path.string()+" 2>&1 && "+command; + cd_path_and_command="cd "+boost_path.string()+" && "+command; } else cd_path_and_command=command; - - FILE* p; - p = popen(cd_path_and_command.c_str(), "r"); - if (p == NULL) { - print("Error: Failed to run command" + command + "\n"); + + int stdin, stdout, stderr; + auto pid=popen3(cd_path_and_command.c_str(), stdin, stdout, stderr); + + if (pid<=0) { + async_print("Error: Failed to run command: " + command + "\n"); return -1; } else { - char buffer[1024]; - while (fgets(buffer, 1024, p) != NULL) { - print(buffer); - while(gtk_events_pending()) - gtk_main_iteration(); - } - async_and_sync_execute_mutex.lock(); - int exit_code=pclose(p); - if(exit_code==-1) - exit_code=execute_status; - async_and_sync_execute_mutex.unlock(); + std::thread stderr_thread([this, stderr](){ + char buffer[1024]; + ssize_t n; + while ((n=read(stderr, buffer, 1024)) > 0) { + std::string message; + for(ssize_t c=0;c 0) { + std::string message; + for(ssize_t c=0;c 0) { + while ((n=read(stderr, buffer, 1024)) > 0) { std::string message; - for(int c=0;c 0) { - std::string message; - for(int c=0;c 0) { + std::string message; + for(ssize_t c=0;c 0) {} - async_execute_status[pid.first]=status; + async_execute_pids_mutex.lock(); + for(auto &pid: async_execute_pids) { + kill(-pid, SIGINT); } - async_and_sync_execute_mutex.unlock(); + async_execute_pids_mutex.unlock(); } int Terminal::print(const std::string &message, bool bold){ diff --git a/src/terminal.h b/src/terminal.h index a9b9475..4559473 100644 --- a/src/terminal.h +++ b/src/terminal.h @@ -7,6 +7,7 @@ #include #include #include +#include class Terminal : public Gtk::HBox { public: @@ -41,6 +42,9 @@ private: std::vector > async_print_strings; std::mutex async_print_strings_mutex; Glib::RefPtr bold_tag; + + std::mutex async_execute_pids_mutex; + std::unordered_set async_execute_pids; }; #endif // JUCI_TERMINAL_H_