mirror of
https://git.haproxy.org/git/haproxy.git/
synced 2025-11-28 06:11:32 +01:00
[MAJOR] spec I/O: fix allocations of spec entries for an FD
Under some circumstances, it was possible with speculative I/O to
reallocate multiple entries for the same FD if an fd_{set,clr,set}
or fd_{clr,set,clr} sequences were performed before a schedule.
Fix this by keeping a an allocation flag for each fd.
This commit is contained in:
parent
e7150cdcfa
commit
4eac209555
@ -115,7 +115,7 @@ static _syscall4 (int, epoll_wait, int, epfd, struct epoll_event *, events, int,
|
||||
* FIXME: should be a bit field */
|
||||
struct fd_status {
|
||||
unsigned int e:4; // read and write events status.
|
||||
unsigned int s:28; // Position in spec list. Should be last.
|
||||
unsigned int s1:28; // Position in spec list+1. 0=not in list. Should be last.
|
||||
};
|
||||
|
||||
static int nbspec = 0; // current size of the spec list
|
||||
@ -135,27 +135,37 @@ static struct epoll_event ev;
|
||||
|
||||
REGPRM1 static void alloc_spec_entry(const int fd)
|
||||
{
|
||||
if (fd_list[fd].e & FD_EV_RW_SL)
|
||||
if (fd_list[fd].s1)
|
||||
return;
|
||||
fd_list[fd].s = nbspec;
|
||||
spec_list[nbspec++] = fd;
|
||||
fd_list[fd].s1 = nbspec + 1;
|
||||
spec_list[nbspec] = fd;
|
||||
nbspec++;
|
||||
}
|
||||
|
||||
/* removes entry <pos> from the spec list and replaces it with the last one.
|
||||
* The fd_list is adjusted to match the back reference if needed.
|
||||
/* Removes entry used by fd <fd> from the spec list and replaces it with the
|
||||
* last one. The fd_list is adjusted to match the back reference if needed.
|
||||
* If the fd has no entry assigned, return immediately.
|
||||
*/
|
||||
REGPRM1 static void delete_spec_entry(const int pos)
|
||||
REGPRM1 static void release_spec_entry(int fd)
|
||||
{
|
||||
int fd;
|
||||
unsigned int pos;
|
||||
|
||||
pos = fd_list[fd].s1;
|
||||
if (!pos)
|
||||
return;
|
||||
|
||||
fd_list[fd].s1 = 0;
|
||||
pos--;
|
||||
/* we have spec_list[pos]==fd */
|
||||
|
||||
nbspec--;
|
||||
if (pos == nbspec)
|
||||
return;
|
||||
|
||||
/* we replace current FD by the highest one */
|
||||
/* we replace current FD by the highest one, which may sometimes be the same */
|
||||
fd = spec_list[nbspec];
|
||||
fd_list[fd].s1 = pos + 1;
|
||||
spec_list[pos] = fd;
|
||||
fd_list[fd].s = pos;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -234,7 +244,7 @@ REGPRM1 static void __fd_rem(int fd)
|
||||
REGPRM1 static void __fd_clo(int fd)
|
||||
{
|
||||
if (fd_list[fd].e & FD_EV_RW_SL)
|
||||
delete_spec_entry(fd_list[fd].s);
|
||||
release_spec_entry(fd);
|
||||
fd_list[fd].e &= ~(FD_EV_MASK);
|
||||
}
|
||||
|
||||
@ -346,7 +356,7 @@ REGPRM2 static void _do_poll(struct poller *p, struct timeval *exp)
|
||||
/* This fd switched to combinations of either WAIT or
|
||||
* IDLE. It must be removed from the spec list.
|
||||
*/
|
||||
delete_spec_entry(spec_idx);
|
||||
release_spec_entry(fd);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user