[PATCH v5 01/13] tools/libperf: introduce static poll file descriptors

From: Alexey Budankov
Date: Mon Jun 01 2020 - 11:51:18 EST



Implement adding of file descriptors to fixed size (currently 1)
storage at struct fdarray by the dedicated fdarray__add_stat().
Index returned by fdarray__add_stat() is allocated once and unique
thus can safely be used to directly access entry at stat_entries.
Append the static descriptors to the array used by poll() syscall
at fdarray__poll(). Copy poll() result of the descriptors from the
array back to the storage for possible later analysis separately
from descriptors added by fdarray__add().

Signed-off-by: Alexey Budankov <alexey.budankov@xxxxxxxxxxxxxxx>
---
tools/lib/api/fd/array.c | 42 +++++++++++++++++++++++-
tools/lib/api/fd/array.h | 7 ++++
tools/lib/perf/evlist.c | 11 +++++++
tools/lib/perf/include/internal/evlist.h | 2 ++
4 files changed, 61 insertions(+), 1 deletion(-)

diff --git a/tools/lib/api/fd/array.c b/tools/lib/api/fd/array.c
index 58d44d5eee31..b0027f2169c7 100644
--- a/tools/lib/api/fd/array.c
+++ b/tools/lib/api/fd/array.c
@@ -11,10 +11,16 @@

void fdarray__init(struct fdarray *fda, int nr_autogrow)
{
+ int i;
+
fda->entries = NULL;
fda->priv = NULL;
fda->nr = fda->nr_alloc = 0;
fda->nr_autogrow = nr_autogrow;
+
+ fda->nr_stat = 0;
+ for (i = 0; i < FDARRAY__STAT_ENTRIES_MAX; i++)
+ fda->stat_entries[i].fd = -1;
}

int fdarray__grow(struct fdarray *fda, int nr)
@@ -83,6 +89,20 @@ int fdarray__add(struct fdarray *fda, int fd, short revents)
return pos;
}

+int fdarray__add_stat(struct fdarray *fda, int fd, short revents)
+{
+ int pos = fda->nr_stat;
+
+ if (pos >= FDARRAY__STAT_ENTRIES_MAX)
+ return -1;
+
+ fda->stat_entries[pos].fd = fd;
+ fda->stat_entries[pos].events = revents;
+ fda->nr_stat++;
+
+ return pos;
+}
+
int fdarray__filter(struct fdarray *fda, short revents,
void (*entry_destructor)(struct fdarray *fda, int fd, void *arg),
void *arg)
@@ -113,7 +133,27 @@ int fdarray__filter(struct fdarray *fda, short revents,

int fdarray__poll(struct fdarray *fda, int timeout)
{
- return poll(fda->entries, fda->nr, timeout);
+ int nr, i, pos, res;
+
+ nr = fda->nr;
+
+ for (i = 0; i < fda->nr_stat; i++) {
+ if (fda->stat_entries[i].fd != -1) {
+ pos = fdarray__add(fda, fda->stat_entries[i].fd,
+ fda->stat_entries[i].events);
+ if (pos >= 0)
+ fda->priv[pos].idx = i;
+ }
+ }
+
+ res = poll(fda->entries, fda->nr, timeout);
+
+ for (i = nr; i < fda->nr; i++)
+ fda->stat_entries[fda->priv[i].idx] = fda->entries[i];
+
+ fda->nr = nr;
+
+ return res;
}

int fdarray__fprintf(struct fdarray *fda, FILE *fp)
diff --git a/tools/lib/api/fd/array.h b/tools/lib/api/fd/array.h
index b39557d1a88f..9bca72e80b09 100644
--- a/tools/lib/api/fd/array.h
+++ b/tools/lib/api/fd/array.h
@@ -3,6 +3,7 @@
#define __API_FD_ARRAY__

#include <stdio.h>
+#include <poll.h>

struct pollfd;

@@ -16,6 +17,9 @@ struct pollfd;
* I.e. using 'fda->priv[N].idx = * value' where N < fda->nr is ok,
* but doing 'fda->priv = malloc(M)' is not allowed.
*/
+
+#define FDARRAY__STAT_ENTRIES_MAX 1
+
struct fdarray {
int nr;
int nr_alloc;
@@ -25,6 +29,8 @@ struct fdarray {
int idx;
void *ptr;
} *priv;
+ int nr_stat;
+ struct pollfd stat_entries[FDARRAY__STAT_ENTRIES_MAX];
};

void fdarray__init(struct fdarray *fda, int nr_autogrow);
@@ -34,6 +40,7 @@ struct fdarray *fdarray__new(int nr_alloc, int nr_autogrow);
void fdarray__delete(struct fdarray *fda);

int fdarray__add(struct fdarray *fda, int fd, short revents);
+int fdarray__add_stat(struct fdarray *fda, int fd, short revents);
int fdarray__poll(struct fdarray *fda, int timeout);
int fdarray__filter(struct fdarray *fda, short revents,
void (*entry_destructor)(struct fdarray *fda, int fd, void *arg),
diff --git a/tools/lib/perf/evlist.c b/tools/lib/perf/evlist.c
index 6a875a0f01bb..e68e4c08e7c2 100644
--- a/tools/lib/perf/evlist.c
+++ b/tools/lib/perf/evlist.c
@@ -317,6 +317,17 @@ int perf_evlist__add_pollfd(struct perf_evlist *evlist, int fd,
return pos;
}

+int perf_evlist__add_pollfd_stat(struct perf_evlist *evlist, int fd,
+ short revent)
+{
+ int pos = fdarray__add_stat(&evlist->pollfd, fd, revent | POLLERR | POLLHUP);
+
+ if (pos >= 0)
+ fcntl(fd, F_SETFL, O_NONBLOCK);
+
+ return pos;
+}
+
static void perf_evlist__munmap_filtered(struct fdarray *fda, int fd,
void *arg __maybe_unused)
{
diff --git a/tools/lib/perf/include/internal/evlist.h b/tools/lib/perf/include/internal/evlist.h
index 74dc8c3f0b66..2b3b4518c05e 100644
--- a/tools/lib/perf/include/internal/evlist.h
+++ b/tools/lib/perf/include/internal/evlist.h
@@ -46,6 +46,8 @@ struct perf_evlist_mmap_ops {
int perf_evlist__alloc_pollfd(struct perf_evlist *evlist);
int perf_evlist__add_pollfd(struct perf_evlist *evlist, int fd,
void *ptr, short revent);
+int perf_evlist__add_pollfd_stat(struct perf_evlist *evlist, int fd,
+ short revent);

int perf_evlist__mmap_ops(struct perf_evlist *evlist,
struct perf_evlist_mmap_ops *ops,
--
2.24.1