mirror of
https://sourceware.org/git/glibc.git
synced 2024-11-21 20:40:05 +00:00
Update.
2004-10-03 Ulrich Drepper <drepper@redhat.com> * nscd/connections.c: Implement alternative loop for main thread which uses epoll. * sysdeps/unix/sysv/linux/Makefile [subdir=nscd] (CFLAGS-connections.c): Add -DHAVE_EPOLL. * nscd/Makefile (CFLAGS-initgrcache.c): Add to CFLAGS-* variables, don't replace old content.
This commit is contained in:
parent
1945c96f2b
commit
fc03df7aa6
10
ChangeLog
10
ChangeLog
@ -1,5 +1,15 @@
|
||||
2004-10-03 Ulrich Drepper <drepper@redhat.com>
|
||||
|
||||
* nscd/connections.c: Implement alternative loop for main thread
|
||||
which uses epoll.
|
||||
* sysdeps/unix/sysv/linux/Makefile [subdir=nscd]
|
||||
(CFLAGS-connections.c): Add -DHAVE_EPOLL.
|
||||
|
||||
2004-10-02 Ulrich Drepper <drepper@redhat.com>
|
||||
|
||||
* nscd/Makefile (CFLAGS-initgrcache.c): Add to CFLAGS-* variables,
|
||||
don't replace old content.
|
||||
|
||||
* nscd/connections.c: Rewrite handling of incoming connections. All
|
||||
are handled by one thread which then hands of the descriptors for the
|
||||
real work to the worker threads.
|
||||
|
@ -70,28 +70,28 @@ CFLAGS-nscd_getai.c = -fexceptions
|
||||
CFLAGS-nscd_initgroups.c = -fexceptions
|
||||
|
||||
ifeq (yesyes,$(have-fpie)$(build-shared))
|
||||
CFLAGS-nscd.c = -fpie
|
||||
CFLAGS-connections.c = -fpie
|
||||
CFLAGS-pwdcache.c = -fpie
|
||||
CFLAGS-getpwnam_r.c = -fpie
|
||||
CFLAGS-getpwuid_r.c = -fpie
|
||||
CFLAGS-grpcache.c = -fpie
|
||||
CFLAGS-getgrnam_r.c = -fpie
|
||||
CFLAGS-getgrgid_r.c = -fpie
|
||||
CFLAGS-hstcache.c = -fpie
|
||||
CFLAGS-gethstbyad_r.c = -fpie
|
||||
CFLAGS-gethstbynm2_r.c = -fpie
|
||||
CFLAGS-dbg_log.c = -fpie
|
||||
CFLAGS-nscd_conf.c = -fpie
|
||||
CFLAGS-nscd_stat.c = -fpie
|
||||
CFLAGS-cache.c = -fpie
|
||||
CFLAGS-xmalloc.c = -fpie
|
||||
CFLAGS-xstrdup.c = -fpie
|
||||
CFLAGS-mem.c = -fpie
|
||||
CFLAGS-nscd_setup_thread.c = -fpie
|
||||
CFLAGS-aicache.c = -fpie
|
||||
CFLAGS-selinux.c = -fpie
|
||||
CFLAGS-initgrcache.c = -fpie
|
||||
CFLAGS-nscd.c += -fpie
|
||||
CFLAGS-connections.c += -fpie
|
||||
CFLAGS-pwdcache.c += -fpie
|
||||
CFLAGS-getpwnam_r.c += -fpie
|
||||
CFLAGS-getpwuid_r.c += -fpie
|
||||
CFLAGS-grpcache.c += -fpie
|
||||
CFLAGS-getgrnam_r.c += -fpie
|
||||
CFLAGS-getgrgid_r.c += -fpie
|
||||
CFLAGS-hstcache.c += -fpie
|
||||
CFLAGS-gethstbyad_r.c += -fpie
|
||||
CFLAGS-gethstbynm2_r.c += -fpie
|
||||
CFLAGS-dbg_log.c += -fpie
|
||||
CFLAGS-nscd_conf.c += -fpie
|
||||
CFLAGS-nscd_stat.c += -fpie
|
||||
CFLAGS-cache.c += -fpie
|
||||
CFLAGS-xmalloc.c += -fpie
|
||||
CFLAGS-xstrdup.c += -fpie
|
||||
CFLAGS-mem.c += -fpie
|
||||
CFLAGS-nscd_setup_thread.c += -fpie
|
||||
CFLAGS-aicache.c += -fpie
|
||||
CFLAGS-selinux.c += -fpie
|
||||
CFLAGS-initgrcache.c += -fpie
|
||||
|
||||
$(objpfx)nscd: $(addprefix $(objpfx),$(nscd-modules:=.o))
|
||||
$(LINK.o) -pie -Wl,-O1 \
|
||||
|
@ -32,6 +32,9 @@
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <arpa/inet.h>
|
||||
#ifdef HAVE_EPOLL
|
||||
# include <sys/epoll.h>
|
||||
#endif
|
||||
#include <sys/mman.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/poll.h>
|
||||
@ -1017,34 +1020,56 @@ handle_request: request received (Version = %d)"), req.version);
|
||||
}
|
||||
|
||||
|
||||
static unsigned int nconns;
|
||||
|
||||
static void
|
||||
fd_ready (int fd)
|
||||
{
|
||||
pthread_mutex_lock (&readylist_lock);
|
||||
|
||||
/* Find an empty entry in FDLIST. */
|
||||
size_t inner;
|
||||
for (inner = 0; inner < nconns; ++inner)
|
||||
if (fdlist[inner].next == NULL)
|
||||
break;
|
||||
assert (inner < nconns);
|
||||
|
||||
fdlist[inner].fd = fd;
|
||||
|
||||
if (readylist == NULL)
|
||||
readylist = fdlist[inner].next = &fdlist[inner];
|
||||
else
|
||||
{
|
||||
fdlist[inner].next = readylist->next;
|
||||
readylist = readylist->next = &fdlist[inner];
|
||||
}
|
||||
|
||||
bool do_signal = true;
|
||||
if (__builtin_expect (nready == 0, 0))
|
||||
{
|
||||
++client_queued;
|
||||
do_signal = false;
|
||||
}
|
||||
|
||||
pthread_mutex_unlock (&readylist_lock);
|
||||
|
||||
/* Tell one of the worker threads there is work to do. */
|
||||
if (do_signal)
|
||||
pthread_cond_signal (&readylist_cond);
|
||||
}
|
||||
|
||||
|
||||
/* Time a connection was accepted. */
|
||||
static time_t *starttime;
|
||||
|
||||
|
||||
static void
|
||||
__attribute__ ((__noreturn__))
|
||||
main_loop (void)
|
||||
main_loop_poll (void)
|
||||
{
|
||||
/* Determine how much room for descriptors we should initially
|
||||
allocate. This might need to change later if we cap the number
|
||||
with MAXCONN. */
|
||||
const long int nfds = sysconf (_SC_OPEN_MAX);
|
||||
unsigned int nconns;
|
||||
#define MINCONN 32
|
||||
#define MAXCONN 16384
|
||||
if (nfds == -1 || nfds > MAXCONN)
|
||||
nconns = MAXCONN;
|
||||
else if (nfds < MINCONN)
|
||||
nconns = MINCONN;
|
||||
else
|
||||
nconns = nfds;
|
||||
|
||||
struct pollfd *conns = (struct pollfd *) xmalloc (nconns
|
||||
* sizeof (conns[0]));
|
||||
|
||||
/* We need two mirroring arrays filled with the times the connection
|
||||
was accepted and a place to pass descriptors on to the worker
|
||||
threads. We cannot put this in the same data structure as the
|
||||
CONNS data since CONNS is passed as an array to poll(). */
|
||||
time_t *starttime = (time_t *) xmalloc (nconns * sizeof (starttime[0]));
|
||||
fdlist = (struct fdlist *) xcalloc (nconns, sizeof (fdlist[0]));
|
||||
|
||||
conns[0].fd = sock;
|
||||
conns[0].events = POLLRDNORM;
|
||||
size_t nused = 1;
|
||||
@ -1074,17 +1099,9 @@ main_loop (void)
|
||||
/* We have a new incoming connection. Accept the connection. */
|
||||
int fd = TEMP_FAILURE_RETRY (accept (sock, NULL, NULL));
|
||||
|
||||
if (fd >= 0)
|
||||
/* use the descriptor if we have not reached the limit. */
|
||||
if (fd >= 0 && firstfree < nconns)
|
||||
{
|
||||
/* We have a new file descriptor. Keep it around
|
||||
and wait until data becomes available. */
|
||||
if (firstfree == nconns)
|
||||
{
|
||||
// XXX Maybe extend array. For now, reject
|
||||
close (fd);
|
||||
goto reject_out;
|
||||
}
|
||||
|
||||
conns[firstfree].fd = fd;
|
||||
conns[firstfree].events = POLLRDNORM;
|
||||
starttime[firstfree] = now;
|
||||
@ -1096,44 +1113,13 @@ main_loop (void)
|
||||
while (firstfree < nused && conns[firstfree].fd != -1);
|
||||
}
|
||||
|
||||
reject_out:
|
||||
--n;
|
||||
}
|
||||
|
||||
for (size_t cnt = 1; cnt < nused && n > 0; ++cnt)
|
||||
if (conns[cnt].revents != 0)
|
||||
{
|
||||
pthread_mutex_lock (&readylist_lock);
|
||||
|
||||
/* Find an empty entry in FDLIST. */
|
||||
size_t inner;
|
||||
for (inner = 0; inner < nconns; ++inner)
|
||||
if (fdlist[inner].next == NULL)
|
||||
break;
|
||||
assert (inner < nconns);
|
||||
|
||||
fdlist[inner].fd = conns[cnt].fd;
|
||||
|
||||
if (readylist == NULL)
|
||||
readylist = fdlist[inner].next = &fdlist[inner];
|
||||
else
|
||||
{
|
||||
fdlist[inner].next = readylist->next;
|
||||
readylist = readylist->next = &fdlist[inner];
|
||||
}
|
||||
|
||||
bool do_signal = true;
|
||||
if (__builtin_expect (nready == 0, 0))
|
||||
{
|
||||
++client_queued;
|
||||
do_signal = false;
|
||||
}
|
||||
|
||||
pthread_mutex_unlock (&readylist_lock);
|
||||
|
||||
/* Tell one of the worker threads there is work to do. */
|
||||
if (do_signal)
|
||||
pthread_cond_signal (&readylist_cond);
|
||||
fd_ready (conns[cnt].fd);
|
||||
|
||||
/* Clean up the CONNS array. */
|
||||
conns[cnt].fd = -1;
|
||||
@ -1150,15 +1136,16 @@ main_loop (void)
|
||||
|
||||
/* Now find entries which have timed out. */
|
||||
assert (nused > 0);
|
||||
for (size_t cnt = nused - 1; cnt > 0; --cnt)
|
||||
{
|
||||
/* We make the timeout length depend on the number of file
|
||||
descriptors currently used. */
|
||||
|
||||
/* We make the timeout length depend on the number of file
|
||||
descriptors currently used. */
|
||||
#define ACCEPT_TIMEOUT \
|
||||
(MAX_ACCEPT_TIMEOUT \
|
||||
- ((MAX_ACCEPT_TIMEOUT - MIN_ACCEPT_TIMEOUT) * nused) / nconns)
|
||||
time_t laststart = now - ACCEPT_TIMEOUT;
|
||||
|
||||
time_t laststart = now - ACCEPT_TIMEOUT;
|
||||
for (size_t cnt = nused - 1; cnt > 0; --cnt)
|
||||
{
|
||||
if (conns[cnt].fd != -1 && starttime[cnt] < laststart)
|
||||
{
|
||||
/* Remove the entry, it timed out. */
|
||||
@ -1177,6 +1164,99 @@ main_loop (void)
|
||||
}
|
||||
|
||||
|
||||
#ifdef HAVE_EPOLL
|
||||
static void
|
||||
main_loop_epoll (int efd)
|
||||
{
|
||||
struct epoll_event ev = { 0, };
|
||||
int nused = 1;
|
||||
size_t highest = 0;
|
||||
|
||||
/* Add the socket. */
|
||||
ev.events = EPOLLRDNORM;
|
||||
ev.data.fd = sock;
|
||||
if (epoll_ctl (efd, EPOLL_CTL_ADD, sock, &ev) == -1)
|
||||
/* We cannot use epoll. */
|
||||
return;
|
||||
|
||||
while (1)
|
||||
{
|
||||
struct epoll_event revs[100];
|
||||
# define nrevs (sizeof (revs) / sizeof (revs[0]))
|
||||
|
||||
int n = epoll_wait (efd, revs, nrevs, MAIN_THREAD_TIMEOUT);
|
||||
|
||||
time_t now = time (NULL);
|
||||
|
||||
for (int cnt = 0; cnt < n; ++cnt)
|
||||
if (revs[cnt].data.fd == sock)
|
||||
{
|
||||
/* A new connection. */
|
||||
int fd = TEMP_FAILURE_RETRY (accept (sock, NULL, NULL));
|
||||
|
||||
if (fd >= 0)
|
||||
{
|
||||
/* Try to add the new descriptor. */
|
||||
ev.data.fd = fd;
|
||||
if (fd >= nconns
|
||||
|| epoll_ctl (efd, EPOLL_CTL_ADD, fd, &ev) == -1)
|
||||
/* The descriptor is too large or something went
|
||||
wrong. Close the descriptor. */
|
||||
close (fd);
|
||||
else
|
||||
{
|
||||
/* Remember when we accepted the connection. */
|
||||
starttime[fd] = now;
|
||||
|
||||
if (fd > highest)
|
||||
highest = fd;
|
||||
|
||||
++nused;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Remove the descriptor from the epoll descriptor. */
|
||||
struct epoll_event ev = { 0, };
|
||||
(void) epoll_ctl (efd, EPOLL_CTL_DEL, revs[cnt].data.fd, &ev);
|
||||
|
||||
/* Get a worked to handle the request. */
|
||||
fd_ready (revs[cnt].data.fd);
|
||||
|
||||
/* Reset the time. */
|
||||
starttime[revs[cnt].data.fd] = 0;
|
||||
if (revs[cnt].data.fd == highest)
|
||||
do
|
||||
--highest;
|
||||
while (highest > 0 && starttime[highest] == 0);
|
||||
|
||||
--nused;
|
||||
}
|
||||
|
||||
/* Now look for descriptors for accepted connections which have
|
||||
no reply in too long of a time. */
|
||||
time_t laststart = now - ACCEPT_TIMEOUT;
|
||||
for (int cnt = highest; cnt > STDERR_FILENO; --cnt)
|
||||
if (cnt != sock && starttime[cnt] != 0 && starttime[cnt] < laststart)
|
||||
{
|
||||
/* We are waiting for this one for too long. Close it. */
|
||||
struct epoll_event ev = {0, };
|
||||
(void) epoll_ctl (efd, EPOLL_CTL_DEL, cnt, &ev);
|
||||
|
||||
(void) close (cnt);
|
||||
|
||||
starttime[cnt] = 0;
|
||||
if (cnt == highest)
|
||||
--highest;
|
||||
}
|
||||
else if (cnt != sock && starttime[cnt] == 0 && cnt == highest)
|
||||
--highest;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/* Start all the threads we want. The initial process is thread no. 1. */
|
||||
void
|
||||
start_threads (void)
|
||||
@ -1216,9 +1296,36 @@ start_threads (void)
|
||||
|
||||
pthread_attr_destroy (&attr);
|
||||
|
||||
/* Determine how much room for descriptors we should initially
|
||||
allocate. This might need to change later if we cap the number
|
||||
with MAXCONN. */
|
||||
const long int nfds = sysconf (_SC_OPEN_MAX);
|
||||
#define MINCONN 32
|
||||
#define MAXCONN 16384
|
||||
if (nfds == -1 || nfds > MAXCONN)
|
||||
nconns = MAXCONN;
|
||||
else if (nfds < MINCONN)
|
||||
nconns = MINCONN;
|
||||
else
|
||||
nconns = nfds;
|
||||
|
||||
/* We need memory to pass descriptors on to the worker threads. */
|
||||
fdlist = (struct fdlist *) xcalloc (nconns, sizeof (fdlist[0]));
|
||||
/* Array to keep track when connection was accepted. */
|
||||
starttime = (time_t *) xcalloc (nconns, sizeof (starttime[0]));
|
||||
|
||||
/* In the main thread we execute the loop which handles incoming
|
||||
connections. */
|
||||
main_loop ();
|
||||
#ifdef HAVE_EPOLL
|
||||
int efd = epoll_create (100);
|
||||
if (efd != -1)
|
||||
{
|
||||
main_loop_epoll (efd);
|
||||
close (efd);
|
||||
}
|
||||
#endif
|
||||
|
||||
main_loop_poll ();
|
||||
}
|
||||
|
||||
|
||||
|
@ -150,3 +150,7 @@ ifeq ($(subdir),rt)
|
||||
CFLAGS-mq_send.c += -fexceptions
|
||||
CFLAGS-mq_receive.c += -fexceptions
|
||||
endif
|
||||
|
||||
ifeq ($(subdir),nscd)
|
||||
CFLAGS-connections.c += -DHAVE_EPOLL
|
||||
endif
|
||||
|
Loading…
Reference in New Issue
Block a user