tools api: Add io__getline
authorIan Rogers <irogers@google.com>
Mon, 3 Apr 2023 18:40:30 +0000 (11:40 -0700)
committerArnaldo Carvalho de Melo <acme@redhat.com>
Tue, 4 Apr 2023 16:23:59 +0000 (13:23 -0300)
Reads a line to allocated memory up to a newline following the getline
API.

Committer notes:

It also adds this new function to the 'api io' 'perf test' entry:

  $ perf test "api io"
   64: Test api io                                                     : Ok
  $

Signed-off-by: Ian Rogers <irogers@google.com>
Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Acked-by: Namhyung Kim <namhyung@kernel.org>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Nathan Chancellor <nathan@kernel.org>
Cc: Nick Desaulniers <ndesaulniers@google.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Tom Rix <trix@redhat.com>
Cc: llvm@lists.linux.dev
Link: https://lore.kernel.org/r/20230403184033.1836023-2-irogers@google.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
tools/lib/api/io.h
tools/perf/tests/api-io.c

index 777c20f6b6047b68593f00ec074db54f50e85bfe..d5e8cf0dada0de34a0cd0cd3d68d608519692d70 100644 (file)
@@ -7,7 +7,9 @@
 #ifndef __API_IO__
 #define __API_IO__
 
+#include <errno.h>
 #include <stdlib.h>
+#include <string.h>
 #include <unistd.h>
 
 struct io {
@@ -112,4 +114,47 @@ static inline int io__get_dec(struct io *io, __u64 *dec)
        }
 }
 
+/* Read up to and including the first newline following the pattern of getline. */
+static inline ssize_t io__getline(struct io *io, char **line_out, size_t *line_len_out)
+{
+       char buf[128];
+       int buf_pos = 0;
+       char *line = NULL, *temp;
+       size_t line_len = 0;
+       int ch = 0;
+
+       /* TODO: reuse previously allocated memory. */
+       free(*line_out);
+       while (ch != '\n') {
+               ch = io__get_char(io);
+
+               if (ch < 0)
+                       break;
+
+               if (buf_pos == sizeof(buf)) {
+                       temp = realloc(line, line_len + sizeof(buf));
+                       if (!temp)
+                               goto err_out;
+                       line = temp;
+                       memcpy(&line[line_len], buf, sizeof(buf));
+                       line_len += sizeof(buf);
+                       buf_pos = 0;
+               }
+               buf[buf_pos++] = (char)ch;
+       }
+       temp = realloc(line, line_len + buf_pos + 1);
+       if (!temp)
+               goto err_out;
+       line = temp;
+       memcpy(&line[line_len], buf, buf_pos);
+       line[line_len + buf_pos] = '\0';
+       line_len += buf_pos;
+       *line_out = line;
+       *line_len_out = line_len;
+       return line_len;
+err_out:
+       free(line);
+       return -ENOMEM;
+}
+
 #endif /* __API_IO__ */
index e91cf2c127f1661111362e086a56ecbccff7c063..6aea84ca6673470b229ad6f046d901dbff66ea98 100644 (file)
@@ -289,6 +289,40 @@ static int test_get_dec(void)
        return ret;
 }
 
+static int test_get_line(void)
+{
+       char path[PATH_MAX];
+       struct io io;
+       char test_string[1024];
+       char *line = NULL;
+       size_t i, line_len = 0;
+       size_t buf_size = 128;
+       int ret = 0;
+
+       for (i = 0; i < 512; i++)
+               test_string[i] = 'a';
+       test_string[512] = '\n';
+       for (i = 513; i < 1023; i++)
+               test_string[i] = 'b';
+       test_string[1023] = '\0';
+
+       if (setup_test(path, test_string, buf_size, &io))
+               return -1;
+
+       EXPECT_EQUAL((int)io__getline(&io, &line, &line_len), 513);
+       EXPECT_EQUAL((int)strlen(line), 513);
+       for (i = 0; i < 512; i++)
+               EXPECT_EQUAL(line[i], 'a');
+       EXPECT_EQUAL(line[512], '\n');
+       EXPECT_EQUAL((int)io__getline(&io, &line, &line_len), 510);
+       for (i = 0; i < 510; i++)
+               EXPECT_EQUAL(line[i], 'b');
+
+       free(line);
+       cleanup_test(path, &io);
+       return ret;
+}
+
 static int test__api_io(struct test_suite *test __maybe_unused,
                        int subtest __maybe_unused)
 {
@@ -300,6 +334,8 @@ static int test__api_io(struct test_suite *test __maybe_unused,
                ret = TEST_FAIL;
        if (test_get_dec())
                ret = TEST_FAIL;
+       if (test_get_line())
+               ret = TEST_FAIL;
        return ret;
 }