summaryrefslogtreecommitdiff
path: root/app-shells/zsh/files/zsh-5.8.1-performance_regression_fix.patch
blob: 14a3f38eb96d94a40c2e1306f0de7f5f0bf0f14c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
From cbe8d2bcdc20682464217856aa48628804637f28 Mon Sep 17 00:00:00 2001
From: Bart Schaefer <schaefer@zsh.org>
Date: Thu, 28 Apr 2022 21:06:51 -0700
Subject: [PATCH] 50133: use read-ahead and lseek-rewind for efficient
 line-buffered input

---
 ChangeLog    |  6 ++++++
 Src/input.c  | 24 ++++++++++++++++++++-
 configure.ac | 59 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 88 insertions(+), 1 deletion(-)

diff --git a/ChangeLog b/ChangeLog
index cae2fc4e3..79c77741b 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,9 @@
+2022-04-28  Bart Schaefer  <schaefer@zsh.org>
+
+	* 50133 (Bart, PWS, Jun-ichi): Src/input.c, configure.ac: when
+	lseek(2) is available, use it to check for and rewind read-ahead
+	for more efficient line-buffered input.
+
 2022-03-03  Peter Stephenson  <p.w.stephenson@ntlworld.com>
 
 	* 49792: Src/input.c, Test/A01grammar.ztst: Use line buffering
diff --git a/Src/input.c b/Src/input.c
index caa8e23b0..6cc1b8a51 100644
--- a/Src/input.c
+++ b/Src/input.c
@@ -217,12 +217,34 @@ shinbufrestore(void)
 static int
 shingetchar(void)
 {
-    int nread;
+    int nread, rsize = isset(SHINSTDIN) ? 1 : SHINBUFSIZE;
 
     if (shinbufptr < shinbufendptr)
 	return STOUC(*shinbufptr++);
 
     shinbufreset();
+#ifdef USE_LSEEK
+    if (rsize == 1 && lseek(SHIN, 0, SEEK_CUR) != (off_t)-1)
+	rsize = SHINBUFSIZE;
+    if (rsize > 1) {
+	do {
+	    errno = 0;
+	    nread = read(SHIN, shinbuffer, rsize);
+	} while (nread < 0 && errno == EINTR);
+	if (nread <= 0)
+	    return -1;
+	if (isset(SHINSTDIN) &&
+	    (shinbufendptr = memchr(shinbuffer, '\n', nread))) {
+	    shinbufendptr++;
+	    rsize = (shinbufendptr - shinbuffer);
+	    if (nread > rsize &&
+		lseek(SHIN, -(nread - rsize), SEEK_CUR) < 0)
+		zerr("lseek(%d, %d): %e", SHIN, -(nread - rsize), errno);
+	} else
+	    shinbufendptr = shinbuffer + nread;
+	return STOUC(*shinbufptr++);
+    }
+#endif
     for (;;) {
        errno = 0;
        nread = read(SHIN, shinbufendptr, 1);
diff --git a/configure.ac b/configure.ac
index af8c5bba8..42f2837cd 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2304,6 +2304,65 @@ if test x$zsh_cv_sys_fifo = xyes; then
   AC_DEFINE(HAVE_FIFOS)
 fi
 
+dnl -----------
+dnl check that lseek() correctly reports seekability.
+dnl -----------
+AC_CACHE_CHECK(if lseek() correctly reports seekability,
+zsh_cv_sys_lseek,
+[AC_RUN_IFELSE([AC_LANG_SOURCE([[
+#include <stdio.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+int main() {
+    int pipefd[2], fd;
+    off_t ret;
+    char* tmpfile = "seekfiletest.tmp";
+    if ((fd = open(tmpfile, O_CREAT, S_IRUSR)) < 0) {
+	fprintf(stderr, "creating file failed\n");
+	return 1;
+    }
+    ret = lseek(fd, 0, SEEK_CUR);
+    close(fd);
+    unlink(tmpfile);
+    if (ret == (off_t)-1) {
+	fprintf(stderr, "lseek on regular file failed\n");
+	return 1;
+    }
+    if (pipe(pipefd) < 0) {
+	fprintf(stderr, "creating pipe failed\n");
+	return 1;
+    }
+    write(pipefd[1], "abcdefgh", 8);
+    ret = lseek(pipefd[0], 0, SEEK_CUR);
+    close(pipefd[0]);
+    close(pipefd[1]);
+    if (ret != (off_t)-1) {
+	fprintf(stderr, "lseek on pipe succeeded\n");
+	return 1;
+    }
+    if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
+	fprintf(stderr, "creating UNIX domain socket failed\n");
+	return 1;
+    }
+    ret = lseek(fd, 0, SEEK_CUR);
+    close(fd);
+    if (ret != (off_t)-1) {
+	fprintf(stderr, "lseek on UNIX domain socket succeeded\n");
+	return 1;
+    }
+    return 0;
+}
+]])],[zsh_cv_sys_lseek=yes],[zsh_cv_sys_lseek=no],[zsh_cv_sys_lseek=yes])
+])
+AH_TEMPLATE([USE_LSEEK],
+[Define to 1 if lseek() can be used for SHIN.])
+if test x$zsh_cv_sys_lseek = xyes; then
+  AC_DEFINE(USE_LSEEK)
+fi
+
 dnl -----------
 dnl test for whether link() works
 dnl for instance, BeOS R4.51 doesn't support hard links yet
-- 
2.36.0