Coverage Report

Created: 2025-11-11 06:17

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/frr/lib/pullwr.h
Line
Count
Source
1
// SPDX-License-Identifier: GPL-2.0-or-later
2
/*
3
 * Pull-driven write event handler
4
 * Copyright (C) 2019  David Lamparter
5
 */
6
7
#ifndef _WRITEPOLL_H
8
#define _WRITEPOLL_H
9
10
#include <stdbool.h>
11
#include <stdint.h>
12
13
#include "frrevent.h"
14
#include "stream.h"
15
16
#ifdef __cplusplus
17
extern "C" {
18
#endif
19
20
struct pullwr;
21
22
/* This is a "pull-driven" write event handler.  Instead of having some buffer
23
 * or being driven by the availability of data, it triggers on the space being
24
 * available on the socket for data to be written on and then calls fill() to
25
 * get data to be sent.
26
 *
27
 * pullwr_* maintains an "idle" vs. "active" state, going into idle when a
28
 * fill() call completes without feeing more data into it.  The overall
29
 * semantics are:
30
 * - to put data out, call pullwr_write().  This is possible from both inside
31
 *   fill() callbacks or anywhere else.  Doing so puts the pullwr into
32
 *   active state.
33
 * - in active state, the fill() callback will be called and should feed more
34
 *   data in.  It should NOT loop to push out more than one "unit" of data;
35
 *   the pullwr code handles this by calling fill() until it has enough data.
36
 * - if there's nothing more to be sent, fill() returns without doing anything
37
 *   and pullwr goes into idle state after flushing all buffered data out.
38
 * - when new data becomes available, pullwr_bump() should be called to put
39
 *   the pullwr back into active mode so it will collect data from fill(),
40
 *   or you can directly call pullwr_write().
41
 * - only calling pullwr_write() from within fill() is the cleanest way of
42
 *   doing things.
43
 *
44
 * When the err() callback is called, the pullwr should be considered unusable
45
 * and released with pullwr_del().  This can be done from inside the callback,
46
 * the pullwr code holds no more references on it when calling err().
47
 */
48
extern struct pullwr *_pullwr_new(struct event_loop *tm, int fd, void *arg,
49
          void (*fill)(void *, struct pullwr *),
50
          void (*err)(void *, struct pullwr *,
51
                bool eof));
52
extern void pullwr_del(struct pullwr *pullwr);
53
54
/* type-checking wrapper.  makes sure fill() and err() take a first argument
55
 * whose type is identical to the type of arg.
56
 * => use "void fill(struct mystruct *arg, ...)" - no "void *arg"
57
 */
58
#define pullwr_new(tm, fd, arg, fill, err) ({                                  \
59
  void (*fill_typechk)(typeof(arg), struct pullwr *) = fill;          \
60
  void (*err_typechk)(typeof(arg), struct pullwr *, bool) = err;      \
61
  _pullwr_new(tm, fd, arg, (void *)fill_typechk, (void *)err_typechk);   \
62
})
63
64
/* max_spin_usec is the time after which the pullwr event handler will stop
65
 *   trying to get more data from fill() and yield control back to the
66
 *   thread_master.  It does reschedule itself to continue later; this is
67
 *   only to make sure we don't freeze the entire process if we're piping a
68
 *   lot of data to a local endpoint that reads quickly (i.e. no backpressure)
69
 *
70
 *   default: 2500 (2.5 ms)
71
 *
72
 * write_threshold is the amount of data buffered from fill() calls at which
73
 *   the pullwr code starts calling write().  But this is not a "limit".
74
 *   pullwr will keep poking fill() for more data until
75
 *   (a) max_spin_usec is reached; fill() will be called again later after
76
 *       returning to the thread_master to give other events a chance to run
77
 *   (b) fill() returns without pushing any data onto the pullwr with
78
 *       pullwr_write(), so fill() will NOT be called again until a call to
79
 *       pullwr_bump() or pullwr_write() comes in.
80
 *
81
 *   default: 16384 (16 kB)
82
 *
83
 * passing 0 for either value (or not calling it at all) uses the default.
84
 */
85
extern void pullwr_cfg(struct pullwr *pullwr, int64_t max_spin_usec,
86
           size_t write_threshold);
87
88
extern void pullwr_bump(struct pullwr *pullwr);
89
extern void pullwr_write(struct pullwr *pullwr,
90
    const void *data, size_t len);
91
92
static inline void pullwr_write_stream(struct pullwr *pullwr,
93
    struct stream *s)
94
0
{
95
0
  pullwr_write(pullwr, s->data, stream_get_endp(s));
96
0
}
Unexecuted instantiation: pullwr.c:pullwr_write_stream
Unexecuted instantiation: bgp_packet.c:pullwr_write_stream
97
98
extern void pullwr_stats(struct pullwr *pullwr, uint64_t *total_written,
99
       size_t *pending, size_t *kernel_pending);
100
101
#ifdef __cplusplus
102
}
103
#endif
104
105
#endif /* _WRITEPOLL_H */