mirror of
http://git.haproxy.org/git/haproxy.git/
synced 2025-01-03 18:52:04 +00:00
MINOR: fd: factorize the fd_takeover() exit path to make it safer
Since there was a risk of leaving fd_takeover() without properly stopping the fd, let's take this opportunity for factoring the code around a commont exit point that's common to both double-cas and locked modes. This means using the "ret" variable inside the double-CAS code, and inverting the loop to first test the old values. Doing do also produces cleaner code because the compiler cannot factorize common exit paths using asm statements that are present in some atomic ops.
This commit is contained in:
parent
4297363de3
commit
f1cad38281
34
src/fd.c
34
src/fd.c
@ -343,9 +343,9 @@ __decl_thread(__decl_rwlock(fd_mig_lock));
|
||||
*/
|
||||
int fd_takeover(int fd, void *expected_owner)
|
||||
{
|
||||
#ifndef HA_HAVE_CAS_DW
|
||||
int ret = -1;
|
||||
|
||||
#ifndef HA_HAVE_CAS_DW
|
||||
if (_HA_ATOMIC_OR(&fdtab[fd].running_mask, tid_bit) == tid_bit) {
|
||||
HA_RWLOCK_WRLOCK(OTHER_LOCK, &fd_mig_lock);
|
||||
if (fdtab[fd].owner == expected_owner) {
|
||||
@ -354,15 +354,6 @@ int fd_takeover(int fd, void *expected_owner)
|
||||
}
|
||||
HA_RWLOCK_WRUNLOCK(OTHER_LOCK, &fd_mig_lock);
|
||||
}
|
||||
|
||||
_HA_ATOMIC_AND(&fdtab[fd].running_mask, ~tid_bit);
|
||||
/* Make sure the FD doesn't have the active bit. It is possible that
|
||||
* the fd is polled by the thread that used to own it, the new thread
|
||||
* is supposed to call subscribe() later, to activate polling.
|
||||
*/
|
||||
if (ret != -1)
|
||||
fd_stop_recv(fd);
|
||||
return ret;
|
||||
#else
|
||||
unsigned long old_masks[2];
|
||||
unsigned long new_masks[2];
|
||||
@ -376,26 +367,25 @@ int fd_takeover(int fd, void *expected_owner)
|
||||
* if it happens, then the owner will no longer be the expected
|
||||
* connection.
|
||||
*/
|
||||
if (fdtab[fd].owner != expected_owner) {
|
||||
_HA_ATOMIC_AND(&fdtab[fd].running_mask, ~tid_bit);
|
||||
return -1;
|
||||
if (fdtab[fd].owner == expected_owner) {
|
||||
while (old_masks[0] == tid_bit && old_masks[1]) {
|
||||
if (_HA_ATOMIC_DWCAS(&fdtab[fd].running_mask, &old_masks, &new_masks)) {
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
do {
|
||||
if (old_masks[0] != tid_bit || !old_masks[1]) {
|
||||
_HA_ATOMIC_AND(&fdtab[fd].running_mask, ~tid_bit);
|
||||
return -1;
|
||||
}
|
||||
} while (!(_HA_ATOMIC_DWCAS(&fdtab[fd].running_mask, &old_masks,
|
||||
&new_masks)));
|
||||
}
|
||||
#endif /* HW_HAVE_CAS_DW */
|
||||
|
||||
_HA_ATOMIC_AND(&fdtab[fd].running_mask, ~tid_bit);
|
||||
|
||||
/* Make sure the FD doesn't have the active bit. It is possible that
|
||||
* the fd is polled by the thread that used to own it, the new thread
|
||||
* is supposed to call subscribe() later, to activate polling.
|
||||
*/
|
||||
if (likely(ret == 0))
|
||||
fd_stop_recv(fd);
|
||||
|
||||
return 0;
|
||||
#endif /* HW_HAVE_CAS_DW */
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Deletes an FD from the fdsets.
|
||||
|
Loading…
Reference in New Issue
Block a user