]>
Commit | Line | Data |
---|---|---|
acddc0ed | 1 | // SPDX-License-Identifier: GPL-2.0-or-later |
5c52c06c DL |
2 | /* |
3 | * Pull-driven write event handler | |
4 | * Copyright (C) 2019 David Lamparter | |
5c52c06c DL |
5 | */ |
6 | ||
7 | #ifndef _WRITEPOLL_H | |
8 | #define _WRITEPOLL_H | |
9 | ||
10 | #include <stdbool.h> | |
11 | #include <stdint.h> | |
12 | ||
cb37cb33 | 13 | #include "event.h" |
5c52c06c DL |
14 | #include "stream.h" |
15 | ||
17e38209 RW |
16 | #ifdef __cplusplus |
17 | extern "C" { | |
18 | #endif | |
19 | ||
5c52c06c DL |
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 | */ | |
cd9d0537 | 48 | extern struct pullwr *_pullwr_new(struct event_loop *tm, int fd, void *arg, |
2453d15d DS |
49 | void (*fill)(void *, struct pullwr *), |
50 | void (*err)(void *, struct pullwr *, | |
51 | bool eof)); | |
5c52c06c DL |
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 | { | |
95 | pullwr_write(pullwr, s->data, stream_get_endp(s)); | |
96 | } | |
97 | ||
98 | extern void pullwr_stats(struct pullwr *pullwr, uint64_t *total_written, | |
99 | size_t *pending, size_t *kernel_pending); | |
100 | ||
17e38209 RW |
101 | #ifdef __cplusplus |
102 | } | |
103 | #endif | |
104 | ||
5c52c06c | 105 | #endif /* _WRITEPOLL_H */ |