1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * Copyright (C) 2014, Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com> |
4 | */ |
5 | #include "array.h" |
6 | #include <errno.h> |
7 | #include <fcntl.h> |
8 | #include <poll.h> |
9 | #include <stdlib.h> |
10 | #include <unistd.h> |
11 | #include <string.h> |
12 | |
13 | void fdarray__init(struct fdarray *fda, int nr_autogrow) |
14 | { |
15 | fda->entries = NULL; |
16 | fda->priv = NULL; |
17 | fda->nr = fda->nr_alloc = 0; |
18 | fda->nr_autogrow = nr_autogrow; |
19 | } |
20 | |
21 | int fdarray__grow(struct fdarray *fda, int nr) |
22 | { |
23 | struct priv *priv; |
24 | int nr_alloc = fda->nr_alloc + nr; |
25 | size_t psize = sizeof(fda->priv[0]) * nr_alloc; |
26 | size_t size = sizeof(struct pollfd) * nr_alloc; |
27 | struct pollfd *entries = realloc(fda->entries, size); |
28 | |
29 | if (entries == NULL) |
30 | return -ENOMEM; |
31 | |
32 | priv = realloc(fda->priv, psize); |
33 | if (priv == NULL) { |
34 | free(entries); |
35 | return -ENOMEM; |
36 | } |
37 | |
38 | memset(&entries[fda->nr_alloc], 0, sizeof(struct pollfd) * nr); |
39 | memset(&priv[fda->nr_alloc], 0, sizeof(fda->priv[0]) * nr); |
40 | |
41 | fda->nr_alloc = nr_alloc; |
42 | fda->entries = entries; |
43 | fda->priv = priv; |
44 | return 0; |
45 | } |
46 | |
47 | struct fdarray *fdarray__new(int nr_alloc, int nr_autogrow) |
48 | { |
49 | struct fdarray *fda = calloc(1, sizeof(*fda)); |
50 | |
51 | if (fda != NULL) { |
52 | if (fdarray__grow(fda, nr: nr_alloc)) { |
53 | free(fda); |
54 | fda = NULL; |
55 | } else { |
56 | fda->nr_autogrow = nr_autogrow; |
57 | } |
58 | } |
59 | |
60 | return fda; |
61 | } |
62 | |
63 | void fdarray__exit(struct fdarray *fda) |
64 | { |
65 | free(fda->entries); |
66 | free(fda->priv); |
67 | fdarray__init(fda, nr_autogrow: 0); |
68 | } |
69 | |
70 | void fdarray__delete(struct fdarray *fda) |
71 | { |
72 | fdarray__exit(fda); |
73 | free(fda); |
74 | } |
75 | |
76 | int fdarray__add(struct fdarray *fda, int fd, short revents, enum fdarray_flags flags) |
77 | { |
78 | int pos = fda->nr; |
79 | |
80 | if (fda->nr == fda->nr_alloc && |
81 | fdarray__grow(fda, nr: fda->nr_autogrow) < 0) |
82 | return -ENOMEM; |
83 | |
84 | fda->entries[fda->nr].fd = fd; |
85 | fda->entries[fda->nr].events = revents; |
86 | fda->priv[fda->nr].flags = flags; |
87 | fda->nr++; |
88 | return pos; |
89 | } |
90 | |
91 | int fdarray__dup_entry_from(struct fdarray *fda, int pos, struct fdarray *from) |
92 | { |
93 | struct pollfd *entry; |
94 | int npos; |
95 | |
96 | if (pos >= from->nr) |
97 | return -EINVAL; |
98 | |
99 | entry = &from->entries[pos]; |
100 | |
101 | npos = fdarray__add(fda, fd: entry->fd, revents: entry->events, flags: from->priv[pos].flags); |
102 | if (npos >= 0) |
103 | fda->priv[npos] = from->priv[pos]; |
104 | |
105 | return npos; |
106 | } |
107 | |
108 | int fdarray__filter(struct fdarray *fda, short revents, |
109 | void (*entry_destructor)(struct fdarray *fda, int fd, void *arg), |
110 | void *arg) |
111 | { |
112 | int fd, nr = 0; |
113 | |
114 | if (fda->nr == 0) |
115 | return 0; |
116 | |
117 | for (fd = 0; fd < fda->nr; ++fd) { |
118 | if (!fda->entries[fd].events) |
119 | continue; |
120 | |
121 | if (fda->entries[fd].revents & revents) { |
122 | if (entry_destructor) |
123 | entry_destructor(fda, fd, arg); |
124 | |
125 | fda->entries[fd].revents = fda->entries[fd].events = 0; |
126 | continue; |
127 | } |
128 | |
129 | if (!(fda->priv[fd].flags & fdarray_flag__nonfilterable)) |
130 | ++nr; |
131 | } |
132 | |
133 | return nr; |
134 | } |
135 | |
136 | int fdarray__poll(struct fdarray *fda, int timeout) |
137 | { |
138 | return poll(fda->entries, fda->nr, timeout); |
139 | } |
140 | |
141 | int fdarray__fprintf(struct fdarray *fda, FILE *fp) |
142 | { |
143 | int fd, printed = fprintf(fp, "%d [ " , fda->nr); |
144 | |
145 | for (fd = 0; fd < fda->nr; ++fd) |
146 | printed += fprintf(fp, "%s%d" , fd ? ", " : "" , fda->entries[fd].fd); |
147 | |
148 | return printed + fprintf(fp, " ]" ); |
149 | } |
150 | |