• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

systemd / systemd / 26546993077

27 May 2026 08:34PM UTC coverage: 72.995% (+0.3%) from 72.667%
26546993077

push

github

bluca
test-pressure: set timeout to make not wait forever

If this runs on a slow or busy machine, then we may not get enough
pressure to trigger the event sources. In such case, the test does not
finish. It is problematic when the test is _not_ run with 'meson test',
e.g. debian/ubuntu CIs.

Let's introduce a timeout for each event loop, and skip test cases
gracefully.

8 of 12 new or added lines in 1 file covered. (66.67%)

19671 existing lines in 226 files now uncovered.

337119 of 461841 relevant lines covered (72.99%)

1326365.62 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

82.95
/src/basic/io-util.c
1
/* SPDX-License-Identifier: LGPL-2.1-or-later */
2

3
#include <fcntl.h>
4
#include <poll.h>
5
#include <stdio.h>
6
#include <string.h>
7
#include <sys/epoll.h>          /* IWYU pragma: keep */
8
#include <time.h>
9
#include <unistd.h>
10

11
#include "errno-util.h"
12
#include "fiber-ops.h"
13
#include "io-util.h"
14
#include "time-util.h"
15

16
uint32_t poll_events_to_epoll(uint32_t events) {
116✔
17
        return (events & POLLIN    ? EPOLLIN    : 0) |
116✔
18
               (events & POLLOUT   ? EPOLLOUT   : 0) |
19
               (events & POLLPRI   ? EPOLLPRI   : 0) |
20
               (events & POLLERR   ? EPOLLERR   : 0) |
21
               (events & POLLHUP   ? EPOLLHUP   : 0) |
116✔
22
               (events & POLLRDHUP ? EPOLLRDHUP : 0);
23
}
24

UNCOV
25
uint32_t epoll_events_to_poll(uint32_t events) {
×
UNCOV
26
        return (events & EPOLLIN    ? POLLIN    : 0) |
×
27
               (events & EPOLLOUT   ? POLLOUT   : 0) |
28
               (events & EPOLLPRI   ? POLLPRI   : 0) |
29
               (events & EPOLLERR   ? POLLERR   : 0) |
UNCOV
30
               (events & EPOLLHUP   ? POLLHUP   : 0) |
×
31
               (events & EPOLLRDHUP ? POLLRDHUP : 0);
32
}
33

34
int flush_fd(int fd) {
3,930✔
35
        int count = 0;
3,930✔
36

37
        /* Read from the specified file descriptor, until POLLIN is not set anymore, throwing away everything
38
         * read. Note that some file descriptors (notable IP sockets) will trigger POLLIN even when no data can be read
39
         * (due to IP packet checksum mismatches), hence this function is only safe to be non-blocking if the fd used
40
         * was set to non-blocking too. */
41

42
        for (;;) {
7,346✔
43
                char buf[LINE_MAX];
7,346✔
44
                ssize_t l;
7,346✔
45
                int r;
7,346✔
46

47
                r = fd_wait_for_event(fd, POLLIN, 0);
7,346✔
48
                if (r == -EINTR)
7,346✔
UNCOV
49
                        continue;
×
50
                if (r < 0)
7,346✔
51
                        return r;
3,930✔
52
                if (r == 0)
7,346✔
53
                        return count;
54

55
                l = read(fd, buf, sizeof(buf));
3,416✔
56
                if (l < 0) {
3,416✔
UNCOV
57
                        if (errno == EINTR)
×
UNCOV
58
                                continue;
×
UNCOV
59
                        if (errno == EAGAIN)
×
60
                                return count;
61

UNCOV
62
                        return -errno;
×
63
                } else if (l == 0)
3,416✔
64
                        return count;
65

66
                if (l > INT_MAX-count) /* On overflow terminate */
3,416✔
67
                        return INT_MAX;
68

69
                count += (int) l;
3,416✔
70
        }
71
}
72

73
ssize_t loop_read(int fd, void *buf, size_t nbytes, bool do_poll) {
18,932✔
74
        uint8_t *p = ASSERT_PTR(buf);
18,932✔
75
        ssize_t n = 0;
18,932✔
76

77
        assert(fd >= 0);
18,932✔
78

79
        /* If called with nbytes == 0, let's call read() at least once, to validate the operation */
80

81
        if (nbytes > (size_t) SSIZE_MAX)
18,932✔
82
                return -EINVAL;
83

84
        /* do_poll == false means "don't wait, return what we have if EAGAIN". If the fd is already
85
         * non-blocking, read() can't block the thread, so the non-fiber path satisfies that semantic
86
         * correctly even from a fiber. Only use the fiber path when the fd is blocking (where read()
87
         * would otherwise block the entire event loop). */
88
        int flags = 0;
18,932✔
89
        if (fiber_ops_is_set() && !do_poll) {
18,932✔
90
                flags = fcntl(fd, F_GETFL);
4✔
91
                if (flags < 0)
4✔
UNCOV
92
                        return -errno;
×
93
        }
94

95
        do {
33,253✔
96
                ssize_t k;
33,253✔
97

98
                if (fiber_ops_is_set() && (do_poll || !FLAGS_SET(flags, O_NONBLOCK))) {
33,253✔
99
                        /* On a fiber the read op suspends on EAGAIN until data is available, so we don't
100
                         * need a separate poll step or the do_poll knob. */
101
                        k = fiber_ops_read(fd, p, nbytes);
19✔
102
                        if (k < 0)
19✔
103
                                return n > 0 ? n : k;
×
104
                } else {
105
                        k = read(fd, p, nbytes);
33,234✔
106
                        if (k < 0) {
33,234✔
107
                                if (errno == EINTR)
1✔
UNCOV
108
                                        continue;
×
109

110
                                if (errno == EAGAIN && do_poll) {
1✔
111

112
                                        /* We knowingly ignore any return value here,
113
                                         * and expect that any error/EOF is reported
114
                                         * via read() */
115

UNCOV
116
                                        (void) fd_wait_for_event(fd, POLLIN, USEC_INFINITY);
×
UNCOV
117
                                        continue;
×
118
                                }
119

120
                                return n > 0 ? n : -errno;
1✔
121
                        }
122
                }
123

124
                if (k == 0)
33,252✔
125
                        return n;
126

127
                assert((size_t) k <= nbytes);
18,721✔
128
                assert(k <= SSIZE_MAX - n);
18,721✔
129

130
                p += k;
18,721✔
131
                nbytes -= k;
18,721✔
132
                n += k;
18,721✔
133
        } while (nbytes > 0);
18,721✔
134

135
        return n;
136
}
137

138
int loop_read_exact(int fd, void *buf, size_t nbytes, bool do_poll) {
4,039✔
139
        ssize_t n;
4,039✔
140

141
        n = loop_read(fd, buf, nbytes, do_poll);
4,039✔
142
        if (n < 0)
4,039✔
UNCOV
143
                return (int) n;
×
144
        if ((size_t) n != nbytes)
4,039✔
145
                return -EIO;
1✔
146

147
        return 0;
148
}
149

150
int loop_write_full(int fd, const void *buf, size_t nbytes, usec_t timeout) {
31,546✔
151
        const uint8_t *p;
31,546✔
152
        usec_t end;
31,546✔
153
        int r;
31,546✔
154

155
        assert(fd >= 0);
31,546✔
156
        assert(buf || nbytes == 0);
31,546✔
157

158
        if (nbytes == 0) {
31,546✔
159
                static const dummy_t dummy[0];
160
                assert_cc(sizeof(dummy) == 0);
161
                p = (const void*) dummy; /* Some valid pointer, in case NULL was specified */
162
        } else {
163
                if (nbytes == SIZE_MAX)
31,545✔
164
                        nbytes = strlen(buf);
403✔
165
                else if (_unlikely_(nbytes > (size_t) SSIZE_MAX))
31,142✔
166
                        return -EINVAL;
167

168
                p = buf;
169
        }
170

171
        /* timeout == 0 means "don't wait, return -EAGAIN if not ready". If the fd is already
172
         * non-blocking, write() can't block the thread, so the non-fiber path satisfies that
173
         * semantic correctly even from a fiber. Only use the fiber path when the fd is blocking
174
         * (where write() would otherwise block the entire event loop). */
175
        int flags = 0;
31,546✔
176
        if (fiber_ops_is_set() && timeout == 0) {
31,546✔
177
                flags = fcntl(fd, F_GETFL);
8✔
178
                if (flags < 0)
8✔
UNCOV
179
                        return -errno;
×
180
        }
181

182
        if (fiber_ops_is_set() && !FLAGS_SET(flags, O_NONBLOCK)) {
31,546✔
183
                /* On a fiber the write op suspends on EAGAIN until the fd is writable; honor the
184
                 * caller's timeout via a deadline scope. */
185
                FIBER_OPS_TIMEOUT(timestamp_is_set(timeout) ? timeout : USEC_INFINITY);
23✔
186

187
                while (nbytes > 0) {
17✔
188
                        ssize_t k = fiber_ops_write(fd, p, nbytes);
10✔
189
                        if (k < 0)
10✔
190
                                return (int) k;
1✔
191
                        if (_unlikely_(nbytes > 0 && k == 0)) /* Can't really happen */
9✔
192
                                return -EIO;
193

194
                        assert((size_t) k <= nbytes);
9✔
195
                        p += k;
9✔
196
                        nbytes -= k;
9✔
197
                }
198

199
                return 0;
200
        }
201

202
        /* When timeout is 0 or USEC_INFINITY this is not used. But we initialize it to a sensible value. */
203
        end = timestamp_is_set(timeout) ? usec_add(now(CLOCK_MONOTONIC), timeout) : USEC_INFINITY;
31,601✔
204

205
        do {
31,539✔
206
                ssize_t k;
31,539✔
207

208
                k = write(fd, p, nbytes);
31,539✔
209
                if (k < 0) {
31,539✔
210
                        if (errno == EINTR)
2✔
UNCOV
211
                                continue;
×
212

213
                        if (errno != EAGAIN || timeout == 0)
2✔
214
                                return -errno;
2✔
215

UNCOV
216
                        usec_t wait_for;
×
217

UNCOV
218
                        if (timeout == USEC_INFINITY)
×
219
                                wait_for = USEC_INFINITY;
220
                        else {
UNCOV
221
                                usec_t t = now(CLOCK_MONOTONIC);
×
UNCOV
222
                                if (t >= end)
×
223
                                        return -ETIME;
224

UNCOV
225
                                wait_for = usec_sub_unsigned(end, t);
×
226
                        }
227

UNCOV
228
                        r = fd_wait_for_event(fd, POLLOUT, wait_for);
×
UNCOV
229
                        if (timeout == USEC_INFINITY || ERRNO_IS_NEG_TRANSIENT(r))
×
230
                                /* If timeout == USEC_INFINITY we knowingly ignore any return value
231
                                 * here, and expect that any error/EOF is reported via write() */
UNCOV
232
                                continue;
×
UNCOV
233
                        if (r < 0)
×
234
                                return r;
UNCOV
235
                        if (r == 0)
×
236
                                return -ETIME;
UNCOV
237
                        continue;
×
238
                }
239

240
                if (_unlikely_(nbytes > 0 && k == 0)) /* Can't really happen */
31,537✔
241
                        return -EIO;
242

243
                assert((size_t) k <= nbytes);
31,537✔
244

245
                p += k;
31,537✔
246
                nbytes -= k;
31,537✔
247
        } while (nbytes > 0);
31,537✔
248

249
        return 0;
250
}
251

252
int pipe_eof(int fd) {
22✔
253
        int r;
22✔
254

255
        r = fd_wait_for_event(fd, POLLIN, 0);
22✔
256
        if (r <= 0)
22✔
257
                return r;
258

259
        return !!(r & POLLHUP);
22✔
260
}
261

262
int ppoll_usec_full(struct pollfd *fds, size_t n_fds, usec_t timeout, const sigset_t *ss) {
528,573✔
263
        int r;
528,573✔
264

265
        assert(fds || n_fds == 0);
528,573✔
266

267
        /* This is a wrapper around ppoll() that does primarily two things:
268
         *
269
         *  ✅ Takes a usec_t instead of a struct timespec
270
         *
271
         *  ✅ Guarantees that if an invalid fd is specified we return EBADF (i.e. converts POLLNVAL to
272
         *     EBADF). This is done because EBADF is a programming error usually, and hence should bubble up
273
         *     as error, and not be eaten up as non-error POLLNVAL event.
274
         *
275
         *  ⚠️ ⚠️ ⚠️ Note that this function does not add any special handling for EINTR. Don't forget
276
         *  poll()/ppoll() will return with EINTR on any received signal always, there is no automatic
277
         *  restarting via SA_RESTART available. Thus, typically you want to handle EINTR not as an error,
278
         *  but just as reason to restart things, under the assumption you use a more appropriate mechanism
279
         *  to handle signals, such as signalfd() or signal handlers. ⚠️ ⚠️ ⚠️
280
         */
281

282
        if (n_fds == 0 && timeout == 0)
528,573✔
283
                return 0;
528,573✔
284

285
        r = fiber_ops_ppoll(fds, n_fds, timeout == USEC_INFINITY ? NULL : TIMESPEC_STORE(timeout), ss);
528,573✔
286
        if (r <= 0)
528,573✔
287
                return r;
288

289
        for (size_t i = 0, n = r; i < n_fds && n > 0; i++) {
952,276✔
290
                if (fds[i].revents == 0)
477,137✔
291
                        continue;
1,895✔
292
                if (fds[i].revents & POLLNVAL)
475,242✔
293
                        return -EBADF;
294
                n--;
475,242✔
295
        }
296

297
        return r;
298
}
299

300
int fd_wait_for_event(int fd, int event, usec_t timeout) {
70,323✔
301
        struct pollfd pollfd = {
70,323✔
302
                .fd = fd,
303
                .events = event,
304
        };
305
        int r;
70,323✔
306

307
        /* ⚠️ ⚠️ ⚠️ Keep in mind you almost certainly want to handle -EINTR gracefully in the caller, see
308
         * ppoll_usec() above! ⚠️ ⚠️ ⚠️ */
309

310
        r = ppoll_usec(&pollfd, 1, timeout);
70,323✔
311
        if (r <= 0)
70,323✔
312
                return r;
70,323✔
313

314
        return pollfd.revents;
16,899✔
315
}
316

317
static size_t nul_length(const uint8_t *p, size_t sz) {
306,400,896✔
318
        size_t n = 0;
306,400,896✔
319

320
        assert(p);
306,400,896✔
321

322
        while (sz > 0) {
861,626,555✔
323
                if (*p != 0)
861,622,002✔
324
                        break;
325

326
                n++;
555,225,659✔
327
                p++;
555,225,659✔
328
                sz--;
555,225,659✔
329
        }
330

331
        return n;
306,400,896✔
332
}
333

334
ssize_t sparse_write(int fd, const void *p, size_t sz, size_t run_length) {
6,710✔
335
        const uint8_t *q, *w, *e;
6,710✔
336
        ssize_t l;
6,710✔
337

338
        q = w = p;
6,710✔
339
        e = q + sz;
6,710✔
340
        while (q < e) {
306,407,606✔
341
                size_t n;
306,400,896✔
342

343
                n = nul_length(q, e - q);
306,400,896✔
344

345
                /* If there are more than the specified run length of
346
                 * NUL bytes, or if this is the beginning or the end
347
                 * of the buffer, then seek instead of write */
348
                if ((n > run_length) ||
306,400,896✔
349
                    (n > 0 && q == p) ||
306,222,590✔
350
                    (n > 0 && q + n >= e)) {
21,831,337✔
351
                        if (q > w) {
179,368✔
352
                                l = write(fd, w, q - w);
175,408✔
353
                                if (l < 0)
175,408✔
UNCOV
354
                                        return -errno;
×
355
                                if (l != q -w)
175,408✔
356
                                        return -EIO;
357
                        }
358

359
                        if (lseek(fd, n, SEEK_CUR) < 0)
179,368✔
UNCOV
360
                                return -errno;
×
361

362
                        q += n;
179,368✔
363
                        w = q;
179,368✔
364
                } else if (n > 0)
21,830,600✔
365
                        q += n;
366
                else
367
                        q++;
284,390,928✔
368
        }
369

370
        if (q > w) {
6,710✔
371
                l = write(fd, w, q - w);
2,157✔
372
                if (l < 0)
2,157✔
UNCOV
373
                        return -errno;
×
374
                if (l != q - w)
2,157✔
375
                        return -EIO;
376
        }
377

378
        return q - (const uint8_t*) p;
6,710✔
379
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc