MEDIUM: fd: simplify the fd_*_{recv,send} functions using BTS/BTR

Now that we don't have to update FD_EV_POLLED_* at the same time as
FD_EV_ACTIVE_*, we don't need to use a CAS anymore, a bit-test-and-set
operation is enough. Doing so reduces the code size by a bit more than
1 kB. One function was special, fd_done_recv(), whose comments and doc
were inaccurate for the part related to the lack of polling.
This commit is contained in:
Willy Tarreau 2019-09-04 13:22:50 +02:00
parent 5bee3e2f47
commit f8ecc7f667
2 changed files with 28 additions and 58 deletions

View File

@ -218,28 +218,18 @@ static inline int fd_active(const int fd)
/* Disable processing recv events on fd <fd> */ /* Disable processing recv events on fd <fd> */
static inline void fd_stop_recv(int fd) static inline void fd_stop_recv(int fd)
{ {
unsigned char old, new; if (!(fdtab[fd].state & FD_EV_ACTIVE_R) ||
!HA_ATOMIC_BTR(&fdtab[fd].state, FD_EV_ACTIVE_R_BIT))
old = fdtab[fd].state;
do {
if (!(old & FD_EV_ACTIVE_R))
return; return;
new = old & ~FD_EV_ACTIVE_R;
} while (unlikely(!_HA_ATOMIC_CAS(&fdtab[fd].state, &old, new)));
updt_fd_polling(fd); updt_fd_polling(fd);
} }
/* Disable processing send events on fd <fd> */ /* Disable processing send events on fd <fd> */
static inline void fd_stop_send(int fd) static inline void fd_stop_send(int fd)
{ {
unsigned char old, new; if (!(fdtab[fd].state & FD_EV_ACTIVE_W) ||
!HA_ATOMIC_BTR(&fdtab[fd].state, FD_EV_ACTIVE_W_BIT))
old = fdtab[fd].state;
do {
if (!(old & FD_EV_ACTIVE_W))
return; return;
new = old & ~FD_EV_ACTIVE_W;
} while (unlikely(!_HA_ATOMIC_CAS(&fdtab[fd].state, &old, new)));
updt_fd_polling(fd); updt_fd_polling(fd);
} }
@ -260,14 +250,10 @@ static inline void fd_stop_both(int fd)
/* Report that FD <fd> cannot receive anymore without polling (EAGAIN detected). */ /* Report that FD <fd> cannot receive anymore without polling (EAGAIN detected). */
static inline void fd_cant_recv(const int fd) static inline void fd_cant_recv(const int fd)
{ {
unsigned char old, new; /* marking ready never changes polled status */
if (!(fdtab[fd].state & FD_EV_READY_R) ||
old = fdtab[fd].state; !HA_ATOMIC_BTR(&fdtab[fd].state, FD_EV_READY_R_BIT))
do {
if (!(old & FD_EV_READY_R))
return; return;
new = old & ~FD_EV_READY_R;
} while (unlikely(!_HA_ATOMIC_CAS(&fdtab[fd].state, &old, new)));
} }
/* Report that FD <fd> may receive again without polling. */ /* Report that FD <fd> may receive again without polling. */
@ -279,35 +265,26 @@ static inline void fd_may_recv(const int fd)
return; return;
} }
/* Disable readiness when polled. This is useful to interrupt reading when it /* Disable readiness when active. This is useful to interrupt reading when it
* is suspected that the end of data might have been reached (eg: short read). * is suspected that the end of data might have been reached (eg: short read).
* This can only be done using level-triggered pollers, so if any edge-triggered * This can only be done using level-triggered pollers, so if any edge-triggered
* is ever implemented, a test will have to be added here. * is ever implemented, a test will have to be added here.
*/ */
static inline void fd_done_recv(const int fd) static inline void fd_done_recv(const int fd)
{ {
unsigned char old, new; /* removing ready never changes polled status */
if ((fdtab[fd].state & (FD_EV_ACTIVE_R|FD_EV_READY_R)) != (FD_EV_ACTIVE_R|FD_EV_READY_R) ||
old = fdtab[fd].state; !HA_ATOMIC_BTR(&fdtab[fd].state, FD_EV_READY_R_BIT))
do {
if ((old & (FD_EV_ACTIVE_R|FD_EV_READY_R)) != (FD_EV_ACTIVE_R|FD_EV_READY_R))
return; return;
new = old & ~FD_EV_READY_R;
} while (unlikely(!_HA_ATOMIC_CAS(&fdtab[fd].state, &old, new)));
updt_fd_polling(fd);
} }
/* Report that FD <fd> cannot send anymore without polling (EAGAIN detected). */ /* Report that FD <fd> cannot send anymore without polling (EAGAIN detected). */
static inline void fd_cant_send(const int fd) static inline void fd_cant_send(const int fd)
{ {
unsigned char old, new; /* removing ready never changes polled status */
if (!(fdtab[fd].state & FD_EV_READY_W) ||
old = fdtab[fd].state; !HA_ATOMIC_BTR(&fdtab[fd].state, FD_EV_READY_W_BIT))
do {
if (!(old & FD_EV_READY_W))
return; return;
new = old & ~FD_EV_READY_W;
} while (unlikely(!_HA_ATOMIC_CAS(&fdtab[fd].state, &old, new)));
} }
/* Report that FD <fd> may send again without polling (EAGAIN not detected). */ /* Report that FD <fd> may send again without polling (EAGAIN not detected). */
@ -322,28 +299,18 @@ static inline void fd_may_send(const int fd)
/* Prepare FD <fd> to try to receive */ /* Prepare FD <fd> to try to receive */
static inline void fd_want_recv(int fd) static inline void fd_want_recv(int fd)
{ {
unsigned char old, new; if ((fdtab[fd].state & FD_EV_ACTIVE_R) ||
HA_ATOMIC_BTS(&fdtab[fd].state, FD_EV_ACTIVE_R_BIT))
old = fdtab[fd].state;
do {
if (old & FD_EV_ACTIVE_R)
return; return;
new = old | FD_EV_ACTIVE_R;
} while (unlikely(!_HA_ATOMIC_CAS(&fdtab[fd].state, &old, new)));
updt_fd_polling(fd); updt_fd_polling(fd);
} }
/* Prepare FD <fd> to try to send */ /* Prepare FD <fd> to try to send */
static inline void fd_want_send(int fd) static inline void fd_want_send(int fd)
{ {
unsigned char old, new; if ((fdtab[fd].state & FD_EV_ACTIVE_W) ||
HA_ATOMIC_BTS(&fdtab[fd].state, FD_EV_ACTIVE_W_BIT))
old = fdtab[fd].state;
do {
if (old & FD_EV_ACTIVE_W)
return; return;
new = old | FD_EV_ACTIVE_W;
} while (unlikely(!_HA_ATOMIC_CAS(&fdtab[fd].state, &old, new)));
updt_fd_polling(fd); updt_fd_polling(fd);
} }

View File

@ -52,7 +52,10 @@ enum {
#define FD_EV_READY 2U #define FD_EV_READY 2U
/* bits positions for a few flags */ /* bits positions for a few flags */
#define FD_EV_ACTIVE_R_BIT 0
#define FD_EV_READY_R_BIT 1 #define FD_EV_READY_R_BIT 1
#define FD_EV_ACTIVE_W_BIT 4
#define FD_EV_READY_W_BIT 5 #define FD_EV_READY_W_BIT 5
#define FD_EV_STATUS (FD_EV_ACTIVE | FD_EV_READY) #define FD_EV_STATUS (FD_EV_ACTIVE | FD_EV_READY)