>From d94bf537d7fdda13f4432bb60a98a8bd19d8e18d Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Fri, 5 Jul 2019 16:48:22 -0700 Subject: [PATCH] areadlink-with-size: improve efficiency MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If the guessed size is 0, guess 200 first, to avoid a sequence of small readlinks in the usual case. Reallocate at the end to the actual size, to avoid memory waste. Based on a suggestion by Pádraig Brady. * lib/areadlink-with-size.c (areadlink_with_size): Use a small stack buffer when the stated size is zero. * modules/areadlink-with-size (Depends-on): Add strdup-posix. --- ChangeLog | 11 +++++++++++ lib/areadlink-with-size.c | 26 ++++++++++++++++++++------ modules/areadlink-with-size | 1 + 3 files changed, 32 insertions(+), 6 deletions(-) diff --git a/ChangeLog b/ChangeLog index 98d5531b1..b07e26335 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,14 @@ +2019-07-05 Paul Eggert + + areadlink-with-size: improve efficiency + If the guessed size is 0, guess 200 first, to avoid a sequence of + small readlinks in the usual case. Reallocate at the end to the + actual size, to avoid memory waste. Based on a suggestion by + Pádraig Brady. + * lib/areadlink-with-size.c (areadlink_with_size): + Use a small stack buffer when the stated size is zero. + * modules/areadlink-with-size (Depends-on): Add strdup-posix. + 2019-07-05 Bruno Haible getcwd-lgpl, getcwd: Don't call realloc when it is pointless. diff --git a/lib/areadlink-with-size.c b/lib/areadlink-with-size.c index 364cc0858..9f1f7959f 100644 --- a/lib/areadlink-with-size.c +++ b/lib/areadlink-with-size.c @@ -60,18 +60,30 @@ areadlink_with_size (char const *file, size_t size) ? symlink_max + 1 : INITIAL_LIMIT_BOUND); + /* Size of stack buffer for initial readlink when the link size hint + is zero. */ + enum { stackbuf_size = 200 }; + /* The initial buffer size for the link value. */ - size_t buf_size = size < initial_limit ? size + 1 : initial_limit; + size_t buf_size = (size == 0 ? stackbuf_size + : size < initial_limit ? size + 1 : initial_limit); while (1) { ssize_t r; size_t link_length; - char *buffer = malloc (buf_size); + char stackbuf[stackbuf_size]; + char *buf = stackbuf; + char *buffer = NULL; + + if (! (size == 0 && buf_size == stackbuf_size)) + { + buf = buffer = malloc (buf_size); + if (!buffer) + return NULL; + } - if (buffer == NULL) - return NULL; - r = readlink (file, buffer, buf_size); + r = readlink (file, buf, buf_size); link_length = r; /* On AIX 5L v5.3 and HP-UX 11i v2 04/09, readlink returns -1 @@ -86,7 +98,9 @@ areadlink_with_size (char const *file, size_t size) if (link_length < buf_size) { - buffer[link_length] = 0; + buf[link_length] = 0; + if (!buffer) + return strdup (buf); /* Shrink BUFFER before returning it. */ if (link_length + 1 < buf_size) { diff --git a/modules/areadlink-with-size b/modules/areadlink-with-size index 82a902187..a4ab0e178 100644 --- a/modules/areadlink-with-size +++ b/modules/areadlink-with-size @@ -9,6 +9,7 @@ Depends-on: readlink ssize_t stdint +strdup-posix unistd configure.ac: -- 2.17.1