]>
git.proxmox.com Git - mirror_frr.git/blob - lib/pullwr.h
1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Pull-driven write event handler
4 * Copyright (C) 2019 David Lamparter
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.
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
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
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
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().
48 extern struct pullwr
*_pullwr_new(struct thread_master
*tm
, int fd
,
50 void (*fill
)(void *, struct pullwr
*),
51 void (*err
)(void *, struct pullwr
*, bool eof
));
52 extern void pullwr_del(struct pullwr
*pullwr
);
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"
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); \
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)
70 * default: 2500 (2.5 ms)
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.
81 * default: 16384 (16 kB)
83 * passing 0 for either value (or not calling it at all) uses the default.
85 extern void pullwr_cfg(struct pullwr
*pullwr
, int64_t max_spin_usec
,
86 size_t write_threshold
);
88 extern void pullwr_bump(struct pullwr
*pullwr
);
89 extern void pullwr_write(struct pullwr
*pullwr
,
90 const void *data
, size_t len
);
92 static inline void pullwr_write_stream(struct pullwr
*pullwr
,
95 pullwr_write(pullwr
, s
->data
, stream_get_endp(s
));
98 extern void pullwr_stats(struct pullwr
*pullwr
, uint64_t *total_written
,
99 size_t *pending
, size_t *kernel_pending
);
105 #endif /* _WRITEPOLL_H */