>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