>From d9db93f246cd937ac3fc1514c6faa4798c1c2a57 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Diego=20Aur=C3=A9lio=20Mesquita?= Date: Sun, 12 Aug 2018 13:42:01 -0300 Subject: [PATCH] filter: replace fork with pthread MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit So that file descriptors can be adequately shared. Outputting the buffer (or marked region) should share as much context with nano main process as possible, using a thread is better than another process in this case. This fixes https://savannah.gnu.org/bugs/?54499. Signed-off-by: Marco Diego Aurélio Mesquita --- configure.ac | 15 ++++++++++++++- src/text.c | 56 ++++++++++++++++++++++++++++++++++++++++---------------- 2 files changed, 54 insertions(+), 17 deletions(-) diff --git a/configure.ac b/configure.ac index 08f3e4d3..425e0165 100644 --- a/configure.ac +++ b/configure.ac @@ -583,9 +583,22 @@ AC_CHECK_LIB([$CURSES_LIB_NAME], [key_defined], [AC_DEFINE(HAVE_KEY_DEFINED, 1, [Define this if your curses library has the key_defined() function.])], [], [$CURSES_LIB]) +dnl Check for pthreads + +AX_PTHREAD +if test "x$ax_pthread_ok" = xno; then + AC_MSG_ERROR([Building nano requires pthreads]) +fi + +dnl AX_PTHREADS leaves PTHREAD_LIBS empty for gcc and sets PTHREAD_CFLAGS +dnl to -pthread, which causes problems if we need -lpthread to appear in +dnl pkgconfig files. + +test -z "$PTHREAD_LIBS" && PTHREAD_LIBS="-lpthread" + dnl Parse any configure options. -LIBS="$LIBS $CURSES_LIB" +LIBS="$LIBS $CURSES_LIB $PTHREAD_LIBS" AC_SUBST(CURSES_LIB) diff --git a/src/text.c b/src/text.c index b5269029..b2abfa27 100644 --- a/src/text.c +++ b/src/text.c @@ -30,6 +30,10 @@ #include #include #include +#include + +static filestruct *outbuffer = NULL; + /* Output buffer to be piped out. */ #ifndef NANO_TINY static pid_t pid_of_command = -1; @@ -1098,21 +1102,27 @@ RETSIGTYPE cancel_the_command(int signal) kill(pid_of_command, SIGKILL); } -/* Send the text that starts at the given line to file descriptor fd. */ -void send_data(const filestruct *line, int fd) +/* Sends the current buffer or cutbuffer to file descriptor. */ +void *send_data(void *fds) { - FILE *tube = fdopen(fd, "w"); + int *to_fd = ((int*)fds); + filestruct *line = outbuffer; + filestruct *prev; - if (tube == NULL) - return; + /* Send each line (except a final empty line) and free output buffer. */ + while (line != NULL) { + if (line->next != NULL || line->data[0] != '\0') + dprintf(to_fd[1], "%s%s", line->data, line->next == NULL ? "" : "\n"); - /* Send each line, except a final empty line. */ - while (line != NULL && (line->next != NULL || line->data[0] != '\0')) { - fprintf(tube, "%s%s", line->data, line->next == NULL ? "" : "\n"); + prev = line; line = line->next; + free(prev); } - fclose(tube); + close(to_fd[0]); + close(to_fd[1]); + + return NULL; } /* Execute the given command in a shell. Return TRUE on success. */ @@ -1127,6 +1137,8 @@ bool execute_command(const char *command) /* Original and temporary handlers for SIGINT. */ bool setup_failed = FALSE; /* Whether setting up the temporary SIGINT handler failed. */ + pthread_t output_buffer_thread; + /* Thread that will output current buffer or selection. */ /* Create a pipe to read the command's output from, and, if needed, * a pipe to feed the command's input through. */ @@ -1175,6 +1187,9 @@ bool execute_command(const char *command) /* If the command starts with "|", pipe buffer or region to the command. */ if (should_pipe) { filestruct *was_cutbuffer = cutbuffer; + const filestruct *line; + filestruct *previous = NULL; + filestruct *next; cutbuffer = NULL; #ifdef ENABLE_MULTIBUFFER @@ -1196,15 +1211,24 @@ bool execute_command(const char *command) update_undo(CUT); } - if (fork() == 0) { - close(to_fd[0]); - send_data(cutbuffer != NULL ? cutbuffer : openfile->fileage, to_fd[1]); - close(to_fd[1]); - exit(0); + /* Make a copy of current buffer or marked region */ + line = cutbuffer != NULL ? cutbuffer : openfile->fileage; + while (line != NULL) { + next = nmalloc(sizeof(filestruct)); + next->next = NULL; + next->data = mallocstrcpy(NULL, line->data); + + if (previous == NULL) + outbuffer = next; + else + previous->next = next; + + previous = next; + line = line->next; } - close(to_fd[0]); - close(to_fd[1]); + /* Another thread will output the data. */ + pthread_create(&output_buffer_thread, NULL, &send_data, to_fd); #ifdef ENABLE_MULTIBUFFER if (ISSET(MULTIBUFFER)) -- 2.11.0