mirror of
http://git.haproxy.org/git/haproxy.git
synced 2026-02-15 00:39:10 +02:00
[MAJOR] modularize the polling mechanisms
select, poll and epoll now have their dedicated functions and have been split into distinct files. Several FD manipulation primitives have been provided with each poller. The rest of the code needs to be cleaned to remove traces of StaticReadEvent/StaticWriteEvent. A trick involving a macro has temporarily been used right now. Some work needs to be done to factorize tests and sets everywhere.
This commit is contained in:
264
src/ev_select.c
Normal file
264
src/ev_select.c
Normal file
@@ -0,0 +1,264 @@
|
||||
/*
|
||||
* FD polling functions for generic select()
|
||||
*
|
||||
* Copyright 2000-2007 Willy Tarreau <w@1wt.eu>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version
|
||||
* 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <unistd.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <common/compat.h>
|
||||
#include <common/config.h>
|
||||
#include <common/time.h>
|
||||
|
||||
#include <types/fd.h>
|
||||
#include <types/global.h>
|
||||
|
||||
#include <proto/fd.h>
|
||||
#include <proto/polling.h>
|
||||
#include <proto/task.h>
|
||||
|
||||
|
||||
static fd_set *ReadEvent, *WriteEvent;
|
||||
static fd_set *StaticReadEvent, *StaticWriteEvent;
|
||||
|
||||
|
||||
/*
|
||||
* Benchmarks performed on a Pentium-M notebook show that using functions
|
||||
* instead of the usual macros improve the FD_* performance by about 80%,
|
||||
* and that marking them regparm(2) adds another 20%.
|
||||
*/
|
||||
REGPRM2 static int __fd_isset(const int fd, const int dir)
|
||||
{
|
||||
fd_set *ev;
|
||||
if (dir == DIR_RD)
|
||||
ev = StaticReadEvent;
|
||||
else
|
||||
ev = StaticWriteEvent;
|
||||
|
||||
return FD_ISSET(fd, ev);
|
||||
}
|
||||
|
||||
REGPRM2 static void __fd_set(const int fd, const int dir)
|
||||
{
|
||||
fd_set *ev;
|
||||
if (dir == DIR_RD)
|
||||
ev = StaticReadEvent;
|
||||
else
|
||||
ev = StaticWriteEvent;
|
||||
|
||||
FD_SET(fd, ev);
|
||||
}
|
||||
|
||||
REGPRM2 static void __fd_clr(const int fd, const int dir)
|
||||
{
|
||||
fd_set *ev;
|
||||
if (dir == DIR_RD)
|
||||
ev = StaticReadEvent;
|
||||
else
|
||||
ev = StaticWriteEvent;
|
||||
|
||||
FD_CLR(fd, ev);
|
||||
}
|
||||
|
||||
REGPRM2 static int __fd_cond_s(const int fd, const int dir)
|
||||
{
|
||||
int ret;
|
||||
fd_set *ev;
|
||||
if (dir == DIR_RD)
|
||||
ev = StaticReadEvent;
|
||||
else
|
||||
ev = StaticWriteEvent;
|
||||
|
||||
ret = !FD_ISSET(fd, ev);
|
||||
if (ret)
|
||||
FD_SET(fd, ev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
REGPRM2 static int __fd_cond_c(const int fd, const int dir)
|
||||
{
|
||||
int ret;
|
||||
fd_set *ev;
|
||||
if (dir == DIR_RD)
|
||||
ev = StaticReadEvent;
|
||||
else
|
||||
ev = StaticWriteEvent;
|
||||
|
||||
ret = FD_ISSET(fd, ev);
|
||||
if (ret)
|
||||
FD_CLR(fd, ev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
REGPRM1 static void __fd_rem(const int fd)
|
||||
{
|
||||
FD_CLR(fd, StaticReadEvent);
|
||||
FD_CLR(fd, StaticWriteEvent);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Initialization of the select() poller.
|
||||
* Returns 0 in case of failure, non-zero in case of success. If it fails, it
|
||||
* disables the poller by setting its pref to 0.
|
||||
*/
|
||||
REGPRM1 static int select_init(struct poller *p)
|
||||
{
|
||||
__label__ fail_swevt, fail_srevt, fail_wevt, fail_revt;
|
||||
int fd_set_bytes;
|
||||
|
||||
p->private = NULL;
|
||||
fd_set_bytes = sizeof(fd_set) * (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE;
|
||||
|
||||
if ((ReadEvent = (fd_set *)calloc(1, fd_set_bytes)) == NULL)
|
||||
goto fail_revt;
|
||||
|
||||
if ((WriteEvent = (fd_set *)calloc(1, fd_set_bytes)) == NULL)
|
||||
goto fail_wevt;
|
||||
|
||||
if ((StaticReadEvent = (fd_set *)calloc(1, fd_set_bytes)) == NULL)
|
||||
goto fail_srevt;
|
||||
|
||||
if ((StaticWriteEvent = (fd_set *)calloc(1, fd_set_bytes)) == NULL)
|
||||
goto fail_swevt;
|
||||
|
||||
return 1;
|
||||
|
||||
fail_swevt:
|
||||
free(StaticReadEvent);
|
||||
fail_srevt:
|
||||
free(WriteEvent);
|
||||
fail_wevt:
|
||||
free(ReadEvent);
|
||||
fail_revt:
|
||||
p->pref = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Termination of the select() poller.
|
||||
* Memory is released and the poller is marked as unselectable.
|
||||
*/
|
||||
REGPRM1 static void select_term(struct poller *p)
|
||||
{
|
||||
if (StaticWriteEvent)
|
||||
free(StaticWriteEvent);
|
||||
if (StaticReadEvent)
|
||||
free(StaticReadEvent);
|
||||
if (WriteEvent)
|
||||
free(WriteEvent);
|
||||
if (ReadEvent)
|
||||
free(ReadEvent);
|
||||
p->private = NULL;
|
||||
p->pref = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Select() poller
|
||||
*/
|
||||
REGPRM2 static void select_poll(struct poller *p, int wait_time)
|
||||
{
|
||||
int status;
|
||||
int fd, i;
|
||||
struct timeval delta;
|
||||
int readnotnull, writenotnull;
|
||||
int fds;
|
||||
char count;
|
||||
|
||||
/* allow select to return immediately when needed */
|
||||
delta.tv_sec = delta.tv_usec = 0;
|
||||
if (wait_time > 0) { /* FIXME */
|
||||
/* Convert to timeval */
|
||||
/* to avoid eventual select loops due to timer precision */
|
||||
wait_time += SCHEDULER_RESOLUTION;
|
||||
delta.tv_sec = wait_time / 1000;
|
||||
delta.tv_usec = (wait_time % 1000) * 1000;
|
||||
}
|
||||
|
||||
/* let's restore fdset state */
|
||||
|
||||
readnotnull = 0; writenotnull = 0;
|
||||
for (i = 0; i < (maxfd + FD_SETSIZE - 1)/(8*sizeof(int)); i++) {
|
||||
readnotnull |= (*(((int*)ReadEvent)+i) = *(((int*)StaticReadEvent)+i)) != 0;
|
||||
writenotnull |= (*(((int*)WriteEvent)+i) = *(((int*)StaticWriteEvent)+i)) != 0;
|
||||
}
|
||||
|
||||
// /* just a verification code, needs to be removed for performance */
|
||||
// for (i=0; i<maxfd; i++) {
|
||||
// if (FD_ISSET(i, ReadEvent) != FD_ISSET(i, StaticReadEvent))
|
||||
// abort();
|
||||
// if (FD_ISSET(i, WriteEvent) != FD_ISSET(i, StaticWriteEvent))
|
||||
// abort();
|
||||
//
|
||||
// }
|
||||
|
||||
status = select(maxfd,
|
||||
readnotnull ? ReadEvent : NULL,
|
||||
writenotnull ? WriteEvent : NULL,
|
||||
NULL,
|
||||
(wait_time >= 0) ? &delta : NULL);
|
||||
|
||||
tv_now(&now);
|
||||
|
||||
if (status <= 0)
|
||||
return;
|
||||
|
||||
for (fds = 0; (fds << INTBITS) < maxfd; fds++) {
|
||||
if ((((int *)(ReadEvent))[fds] | ((int *)(WriteEvent))[fds]) == 0)
|
||||
continue;
|
||||
|
||||
for (count = 1<<INTBITS, fd = fds << INTBITS; count && fd < maxfd; count--, fd++) {
|
||||
/* if we specify read first, the accepts and zero reads will be
|
||||
* seen first. Moreover, system buffers will be flushed faster.
|
||||
*/
|
||||
if (FD_ISSET(fd, ReadEvent)) {
|
||||
if (fdtab[fd].state == FD_STCLOSE)
|
||||
continue;
|
||||
fdtab[fd].cb[DIR_RD].f(fd);
|
||||
}
|
||||
|
||||
if (FD_ISSET(fd, WriteEvent)) {
|
||||
if (fdtab[fd].state == FD_STCLOSE)
|
||||
continue;
|
||||
fdtab[fd].cb[DIR_WR].f(fd);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* The only exported function. Returns 1.
|
||||
*/
|
||||
int select_register(struct poller *p)
|
||||
{
|
||||
p->name = "select";
|
||||
p->pref = 150;
|
||||
p->private = NULL;
|
||||
|
||||
p->init = select_init;
|
||||
p->term = select_term;
|
||||
p->poll = select_poll;
|
||||
p->isset = __fd_isset;
|
||||
p->set = __fd_set;
|
||||
p->clr = __fd_clr;
|
||||
p->clo = p->rem = __fd_rem;
|
||||
p->cond_s = __fd_cond_s;
|
||||
p->cond_c = __fd_cond_c;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Local variables:
|
||||
* c-indent-level: 8
|
||||
* c-basic-offset: 8
|
||||
* End:
|
||||
*/
|
||||
Reference in New Issue
Block a user