Coverage Report

Created: 2026-09-03 06:33

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/haproxy/include/haproxy/fd-t.h
Line
Count
Source
1
/*
2
 * include/haproxy/fd-t.h
3
 * File descriptors states - check src/fd.c for explanations.
4
 *
5
 * Copyright (C) 2000-2014 Willy Tarreau - w@1wt.eu
6
 *
7
 * This library is free software; you can redistribute it and/or
8
 * modify it under the terms of the GNU Lesser General Public
9
 * License as published by the Free Software Foundation, version 2.1
10
 * exclusively.
11
 *
12
 * This library is distributed in the hope that it will be useful,
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15
 * Lesser General Public License for more details.
16
 *
17
 * You should have received a copy of the GNU Lesser General Public
18
 * License along with this library; if not, write to the Free Software
19
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
20
 */
21
22
#ifndef _HAPROXY_FD_T_H
23
#define _HAPROXY_FD_T_H
24
25
#include <haproxy/api-t.h>
26
#include <haproxy/port_range-t.h>
27
#include <haproxy/show_flags-t.h>
28
29
/* Direction for each FD event update */
30
enum {
31
  DIR_RD=0,
32
  DIR_WR=1,
33
};
34
35
36
/* fdtab[].state is a composite state describing what is known about the FD.
37
 * For now, the following information are stored in it:
38
 *   - event configuration and status for each direction (R,W) split into
39
 *     active, ready, shutdown categories (FD_EV_*). These are known by their
40
 *     bit values as well so that test-and-set bit operations are possible.
41
 *
42
 *   - last known polling status (FD_POLL_*). For ease of troubleshooting,
43
 *     avoid visually mixing these ones with the other ones above. 3 of these
44
 *     flags are updated on each poll() report (FD_POLL_IN, FD_POLL_OUT,
45
 *     FD_POLL_PRI). FD_POLL_HUP and FD_POLL_ERR are "sticky" in that once they
46
 *     are reported, they will not be cleared until the FD is closed.
47
 */
48
49
/* bits positions for a few flags */
50
0
#define FD_EV_ACTIVE_R_BIT 0
51
0
#define FD_EV_READY_R_BIT  1
52
0
#define FD_EV_SHUT_R_BIT   2
53
/* unused: 3 */
54
55
0
#define FD_EV_ACTIVE_W_BIT 4
56
0
#define FD_EV_READY_W_BIT  5
57
0
#define FD_EV_SHUT_W_BIT   6
58
0
#define FD_EV_ERR_RW_BIT   7
59
60
0
#define FD_POLL_IN_BIT     8
61
0
#define FD_POLL_PRI_BIT    9
62
0
#define FD_POLL_OUT_BIT   10
63
0
#define FD_POLL_ERR_BIT   11
64
0
#define FD_POLL_HUP_BIT   12
65
66
/* info/config bits */
67
0
#define FD_LINGER_RISK_BIT 16  /* must kill lingering before closing */
68
0
#define FD_CLONED_BIT      17  /* cloned socket, requires EPOLL_CTL_DEL on close */
69
#define FD_INITIALIZED_BIT 18  /* init phase was done (e.g. output pipe set non-blocking) */
70
0
#define FD_ET_POSSIBLE_BIT 19  /* edge-triggered is possible on this FD */
71
0
#define FD_EXPORTED_BIT    20  /* FD is exported and must not be closed */
72
#define FD_EXCL_SYSCALL_BIT 21 /* a syscall claims exclusivity on this FD */
73
0
#define FD_DISOWN_BIT      22  /* this fd will be closed by some external code */
74
#define FD_MUST_CLOSE_BIT  23  /* this fd will be closed by some external code */
75
#define FD_HAS_PORT_BIT    24  /* This fd had a port allocated from a port range */
76
#define FD_OWNER_PR_BIT    27 /* The owner is actually a port range */
77
78
79
/* and flag values */
80
0
#define FD_EV_ACTIVE_R  (1U << FD_EV_ACTIVE_R_BIT)
81
0
#define FD_EV_ACTIVE_W  (1U << FD_EV_ACTIVE_W_BIT)
82
0
#define FD_EV_ACTIVE_RW (FD_EV_ACTIVE_R | FD_EV_ACTIVE_W)
83
84
0
#define FD_EV_READY_R   (1U << FD_EV_READY_R_BIT)
85
0
#define FD_EV_READY_W   (1U << FD_EV_READY_W_BIT)
86
#define FD_EV_READY_RW  (FD_EV_READY_R | FD_EV_READY_W)
87
88
/* note that when FD_EV_SHUT is set, ACTIVE and READY are cleared */
89
0
#define FD_EV_SHUT_R    (1U << FD_EV_SHUT_R_BIT)
90
0
#define FD_EV_SHUT_W    (1U << FD_EV_SHUT_W_BIT)
91
#define FD_EV_SHUT_RW   (FD_EV_SHUT_R | FD_EV_SHUT_W)
92
93
/* note that when FD_EV_ERR is set, SHUT is also set. Also, ERR is for both
94
 * directions at once (write error, socket dead, etc).
95
 */
96
0
#define FD_EV_ERR_RW    (1U << FD_EV_ERR_RW_BIT)
97
98
/* mask covering all use cases above */
99
#define FD_EV_ANY       (FD_EV_ACTIVE_RW | FD_EV_READY_RW | FD_EV_SHUT_RW | FD_EV_ERR_RW)
100
101
/* polling status */
102
0
#define FD_POLL_IN          (1U << FD_POLL_IN_BIT)
103
0
#define FD_POLL_PRI         (1U << FD_POLL_PRI_BIT)
104
0
#define FD_POLL_OUT         (1U << FD_POLL_OUT_BIT)
105
0
#define FD_POLL_ERR         (1U << FD_POLL_ERR_BIT)
106
0
#define FD_POLL_HUP         (1U << FD_POLL_HUP_BIT)
107
0
#define FD_POLL_UPDT_MASK   (FD_POLL_IN | FD_POLL_PRI | FD_POLL_OUT)
108
#define FD_POLL_ANY_MASK    (FD_POLL_IN | FD_POLL_PRI | FD_POLL_OUT | FD_POLL_ERR | FD_POLL_HUP)
109
110
/* information/configuration flags */
111
0
#define FD_LINGER_RISK      (1U << FD_LINGER_RISK_BIT)
112
0
#define FD_CLONED           (1U << FD_CLONED_BIT)
113
#define FD_INITIALIZED      (1U << FD_INITIALIZED_BIT)
114
0
#define FD_ET_POSSIBLE      (1U << FD_ET_POSSIBLE_BIT)
115
0
#define FD_EXPORTED         (1U << FD_EXPORTED_BIT)
116
#define FD_EXCL_SYSCALL     (1U << FD_EXCL_SYSCALL_BIT)
117
0
#define FD_DISOWN           (1U << FD_DISOWN_BIT)
118
#define FD_MUST_CLOSE       (1U << FD_MUST_CLOSE_BIT)
119
#define FD_HAS_PORT         (1U << FD_HAS_PORT_BIT)
120
#define FD_OWNER_PR         (1U << FD_OWNER_PR_BIT)
121
122
/* This function is used to report flags in debugging tools. Please reflect
123
 * below any single-bit flag addition above in the same order via the
124
 * __APPEND_FLAG macro. The new end of the buffer is returned.
125
 */
126
static forceinline char *fd_show_flags(char *buf, size_t len, const char *delim, uint flg)
127
0
{
128
0
#define _(f, ...) __APPEND_FLAG(buf, len, delim, flg, f, #f, __VA_ARGS__)
129
0
  /* prologue */
130
0
  _(0);
131
0
  /* flags */
132
0
  _(FD_EV_ACTIVE_R, _(FD_EV_ACTIVE_W, _(FD_EV_READY_R, _(FD_EV_READY_W,
133
0
  _(FD_EV_SHUT_R, _(FD_EV_SHUT_W, _(FD_EV_ERR_RW, _(FD_POLL_IN,
134
0
  _(FD_POLL_PRI, _(FD_POLL_OUT, _(FD_POLL_ERR, _(FD_POLL_HUP,
135
0
  _(FD_LINGER_RISK, _(FD_CLONED, _(FD_INITIALIZED, _(FD_ET_POSSIBLE,
136
0
  _(FD_EXPORTED, _(FD_EXCL_SYSCALL, _(FD_DISOWN)))))))))))))))))));
137
0
  /* epilogue */
138
0
  _(~0U);
139
0
  return buf;
140
0
#undef _
141
0
}
Unexecuted instantiation: tools.c:fd_show_flags
Unexecuted instantiation: applet.c:fd_show_flags
Unexecuted instantiation: cfgparse.c:fd_show_flags
Unexecuted instantiation: channel.c:fd_show_flags
Unexecuted instantiation: cli.c:fd_show_flags
Unexecuted instantiation: connection.c:fd_show_flags
Unexecuted instantiation: debug.c:fd_show_flags
Unexecuted instantiation: dgram.c:fd_show_flags
Unexecuted instantiation: errors.c:fd_show_flags
Unexecuted instantiation: fd.c:fd_show_flags
Unexecuted instantiation: frontend.c:fd_show_flags
Unexecuted instantiation: haproxy.c:fd_show_flags
Unexecuted instantiation: http_ana.c:fd_show_flags
Unexecuted instantiation: http_ext.c:fd_show_flags
Unexecuted instantiation: http_htx.c:fd_show_flags
Unexecuted instantiation: http_rules.c:fd_show_flags
Unexecuted instantiation: limits.c:fd_show_flags
Unexecuted instantiation: listener.c:fd_show_flags
Unexecuted instantiation: log.c:fd_show_flags
Unexecuted instantiation: mailers.c:fd_show_flags
Unexecuted instantiation: mworker.c:fd_show_flags
Unexecuted instantiation: peers.c:fd_show_flags
Unexecuted instantiation: pool.c:fd_show_flags
Unexecuted instantiation: proto_rhttp.c:fd_show_flags
Unexecuted instantiation: proto_sockpair.c:fd_show_flags
Unexecuted instantiation: protocol.c:fd_show_flags
Unexecuted instantiation: proxy.c:fd_show_flags
Unexecuted instantiation: queue.c:fd_show_flags
Unexecuted instantiation: resolvers.c:fd_show_flags
Unexecuted instantiation: ring.c:fd_show_flags
Unexecuted instantiation: sample.c:fd_show_flags
Unexecuted instantiation: server.c:fd_show_flags
Unexecuted instantiation: session.c:fd_show_flags
Unexecuted instantiation: signal.c:fd_show_flags
Unexecuted instantiation: sink.c:fd_show_flags
Unexecuted instantiation: sock.c:fd_show_flags
Unexecuted instantiation: sock_inet.c:fd_show_flags
Unexecuted instantiation: stats-html.c:fd_show_flags
Unexecuted instantiation: stats-proxy.c:fd_show_flags
Unexecuted instantiation: stats.c:fd_show_flags
Unexecuted instantiation: stconn.c:fd_show_flags
Unexecuted instantiation: stick_table.c:fd_show_flags
Unexecuted instantiation: stream.c:fd_show_flags
Unexecuted instantiation: task.c:fd_show_flags
Unexecuted instantiation: tcp_rules.c:fd_show_flags
Unexecuted instantiation: tcpcheck.c:fd_show_flags
Unexecuted instantiation: thread.c:fd_show_flags
Unexecuted instantiation: trace.c:fd_show_flags
Unexecuted instantiation: vars.c:fd_show_flags
Unexecuted instantiation: action.c:fd_show_flags
Unexecuted instantiation: activity.c:fd_show_flags
Unexecuted instantiation: backend.c:fd_show_flags
Unexecuted instantiation: cfgparse-global.c:fd_show_flags
Unexecuted instantiation: cfgparse-listen.c:fd_show_flags
Unexecuted instantiation: check.c:fd_show_flags
Unexecuted instantiation: compression.c:fd_show_flags
Unexecuted instantiation: dns.c:fd_show_flags
Unexecuted instantiation: dns_ring.c:fd_show_flags
Unexecuted instantiation: event_hdl.c:fd_show_flags
Unexecuted instantiation: extcheck.c:fd_show_flags
Unexecuted instantiation: filters.c:fd_show_flags
Unexecuted instantiation: flt_decomp.c:fd_show_flags
Unexecuted instantiation: flt_http_comp.c:fd_show_flags
Unexecuted instantiation: haterm.c:fd_show_flags
Unexecuted instantiation: http_fetch.c:fd_show_flags
Unexecuted instantiation: lb_chash.c:fd_show_flags
Unexecuted instantiation: lb_fwlc.c:fd_show_flags
Unexecuted instantiation: mux_spop.c:fd_show_flags
Unexecuted instantiation: pattern.c:fd_show_flags
Unexecuted instantiation: payload.c:fd_show_flags
Unexecuted instantiation: proto_tcp.c:fd_show_flags
Unexecuted instantiation: stats-file.c:fd_show_flags
Unexecuted instantiation: stats-json.c:fd_show_flags
Unexecuted instantiation: cache.c:fd_show_flags
Unexecuted instantiation: fcgi-app.c:fd_show_flags
Unexecuted instantiation: flt_spoe.c:fd_show_flags
142
143
/* FD update status after fd_update_events() */
144
enum {
145
  FD_UPDT_DONE = 0,    // update done, nothing else to be done
146
  FD_UPDT_CLOSED,      // FD was closed
147
  FD_UPDT_MIGRATED,    // FD was migrated, ignore it now
148
};
149
150
/* This is the value used to mark a file descriptor as dead. This value is
151
 * negative, this is important so that tests on fd < 0 properly match. It
152
 * also has the nice property of being highly negative but neither overflowing
153
 * nor changing sign on 32-bit machines when multiplied by sizeof(fdtab).
154
 * This ensures that any unexpected dereference of such an uninitialized
155
 * file descriptor will lead to so large a dereference that it will crash
156
 * the process at the exact location of the bug with a clean stack trace
157
 * instead of causing silent manipulation of other FDs. And it's readable
158
 * when found in a dump.
159
 */
160
0
#define DEAD_FD_MAGIC 0xFDDEADFD
161
162
/* fdlist_entry: entry used by the fd cache.
163
 *    >= 0 means we're in the cache and gives the FD of the next in the cache,
164
 *      -1 means we're in the cache and the last element,
165
 *      -2 means the entry is locked,
166
 *   <= -3 means not in the cache, and next element is -4-fd
167
 *
168
 * It must remain 8-aligned so that aligned CAS operations may be done on both
169
 * entries at once.
170
 */
171
struct fdlist_entry {
172
  int next;
173
  int prev;
174
} ALIGNED(8);
175
176
/* head of the fd cache, per-group */
177
struct fdlist {
178
  int first;
179
  int last;
180
} ALIGNED(64);
181
182
/* info about one given fd. Note: only align on cache lines when using threads;
183
 * 32-bit small archs can put everything in 32-bytes when threads are disabled.
184
 * refc_tgid is an atomic 32-bit composite value made of 16 higher bits
185
 * containing a refcount on tgid and the running_mask, and 16 lower bits
186
 * containing a thread group ID and a lock bit on the 16th. The tgid may only
187
 * be changed when refc is zero and running may only be checked/changed when
188
 * refc is held and shows the reader is alone. An FD with tgid zero belongs to
189
 * nobody.
190
 */
191
struct fdtab {
192
  unsigned long running_mask;          /* mask of thread IDs currently using the fd */
193
  unsigned long thread_mask;           /* mask of thread IDs authorized to process the fd */
194
  unsigned long update_mask;           /* mask of thread IDs having an update for fd */
195
  struct fdlist_entry update;          /* Entry in the global update list */
196
  void (*iocb)(int fd);                /* I/O handler */
197
  void *owner;                         /* the connection or listener associated with this fd, NULL if closed */
198
  unsigned int state;                  /* FD state for read and write directions (FD_EV_*) + FD_POLL_* */
199
  unsigned int refc_tgid;              /* refcounted tgid, updated atomically */
200
  /* the info below are mainly used for epoll debugging/strengthening.
201
   * they're filling the rest of the cache line but may easily be dropped
202
   * if the room is needed for more important stuff.
203
   */
204
  unsigned int nb_takeover;            /* number of times this FD was taken over since inserted (used for debugging) */
205
  unsigned int generation;             /* number of times this FD was closed before (used for epoll strengthening) */
206
#ifdef DEBUG_FD
207
  unsigned int event_count;            /* number of events reported */
208
#endif
209
} THREAD_ALIGNED();
210
211
/* polled mask, one bit per thread and per direction for each FD */
212
struct polled_mask {
213
  unsigned long poll_recv;
214
  unsigned long poll_send;
215
};
216
217
/*
218
 * Poller descriptors.
219
 *  - <name> is initialized by the poller's register() function, and should not
220
 *    be allocated, just linked to.
221
 *  - <pref> is initialized by the poller's register() function. It is set to 0
222
 *    by default, meaning the poller is disabled. init() should set it to 0 in
223
 *    case of failure. term() must set it to 0. A generic unoptimized select()
224
 *    poller should set it to 100.
225
 *  - <private> is initialized by the poller's init() function, and cleaned by
226
 *    the term() function.
227
 *  - clo() should be used to do indicate the poller that fd will be closed.
228
 *  - poll() calls the poller, expiring at <exp>, or immediately if <wake> is set
229
 *  - flags indicate what the poller supports (HAP_POLL_F_*)
230
 */
231
232
#define HAP_POLL_F_RDHUP        0x00000001                   /* the poller notifies of HUP with reads */
233
0
#define HAP_POLL_F_ERRHUP       0x00000002                   /* the poller reports ERR and HUP */
234
0
#define HAP_POLL_F_NO_FD_SHARING 0x00000004                  /* the poller supports not sharing fds across thread groups */
235
236
struct poller {
237
  void   *private;                                     /* any private data for the poller */
238
  void   (*clo)(const int fd);                 /* mark <fd> as closed */
239
  void   (*poll)(struct poller *p, int exp, int wake);  /* the poller itself */
240
  int    (*init)(struct poller *p);            /* poller initialization */
241
  void   (*term)(struct poller *p);            /* termination of this poller */
242
  int    (*test)(struct poller *p);            /* pre-init check of the poller */
243
  int    (*fork)(struct poller *p);            /* post-fork re-opening */
244
  void   (*fixup_tgid_takeover)(struct poller *p, const int fd, const int old_tid, const int old_tgid); /* Fixup anything necessary after a FD takeover across tgids */
245
  const char   *name;                                  /* poller name */
246
  unsigned int flags;                                  /* HAP_POLL_F_* */
247
  int    pref;                                         /* try pollers with higher preference first */
248
};
249
250
#endif /* _HAPROXY_FD_T_H */
251
252
/*
253
 * Local variables:
254
 *  c-indent-level: 8
255
 *  c-basic-offset: 8
256
 * End:
257
 */