aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--nscd/connections.c222
1 files changed, 122 insertions, 100 deletions
diff --git a/nscd/connections.c b/nscd/connections.c
index 3628877..c80ba96 100644
--- a/nscd/connections.c
+++ b/nscd/connections.c
@@ -19,6 +19,7 @@
02111-1307 USA. */
#include <assert.h>
+#include <atomic.h>
#include <error.h>
#include <errno.h>
#include <grp.h>
@@ -130,6 +131,9 @@ int nthreads = -1;
/* Socket for incoming connections. */
static int sock;
+/* Number of times clients had to wait. */
+unsigned long int client_queued;
+
/* Initialize database information structures. */
void
@@ -435,145 +439,163 @@ nscd_run (void *p)
long int my_number = (long int) p;
struct pollfd conn;
int run_prune = my_number < lastdb && dbs[my_number].enabled;
- time_t now = time (NULL);
- time_t next_prune = now + CACHE_PRUNE_INTERVAL;
- int timeout = run_prune ? 1000 * (next_prune - now) : -1;
+ time_t next_prune = run_prune ? time (NULL) + CACHE_PRUNE_INTERVAL : 0;
+ static unsigned long int nready;
conn.fd = sock;
conn.events = POLLRDNORM;
while (1)
{
- int nr = poll (&conn, 1, timeout);
+ int nr;
+
+ /* One more thread available. */
+ atomic_increment (&nready);
+
+ no_conn:
+ if (run_prune)
+ do
+ {
+ time_t now = time (NULL);
+ int timeout = now < next_prune ? 1000 * (next_prune - now) : 0;
+
+ nr = poll (&conn, 1, timeout);
+
+ if (nr == 0)
+ {
+ /* The `poll' call timed out. It's time to clean up the
+ cache. */
+ atomic_decrement (&nready);
+ assert (my_number < lastdb);
+ prune_cache (&dbs[my_number], time(NULL));
+ now = time (NULL);
+ next_prune = now + CACHE_PRUNE_INTERVAL;
+ goto try_get;
+ }
+ }
+ while ((conn.revents & POLLRDNORM) == 0);
+
+ got_data:;
+ /* We have a new incoming connection. Accept the connection. */
+ int fd = TEMP_FAILURE_RETRY (accept (conn.fd, NULL, NULL));
+ request_header req;
+ char buf[256];
+ uid_t uid = 0;
+#ifdef SO_PEERCRED
+ pid_t pid = 0;
+#endif
- if (nr == 0)
+ if (__builtin_expect (fd, 0) < 0)
{
- /* The `poll' call timed out. It's time to clean up the cache. */
- assert (my_number < lastdb);
- now = time (NULL);
- prune_cache (&dbs[my_number], now);
- next_prune = now + CACHE_PRUNE_INTERVAL;
- timeout = 1000 * (next_prune - now);
- continue;
+ dbg_log (_("while accepting connection: %s"),
+ strerror_r (errno, buf, sizeof (buf)));
+ goto no_conn;
}
- /* We have a new incoming connection. */
- if (conn.revents & (POLLRDNORM|POLLERR|POLLHUP|POLLNVAL))
+ /* This thread is busy. */
+ atomic_decrement (&nready);
+
+ /* Now read the request. */
+ if (__builtin_expect (TEMP_FAILURE_RETRY (read (fd, &req, sizeof (req)))
+ != sizeof (req), 0))
{
- /* Accept the connection. */
- int fd = TEMP_FAILURE_RETRY (accept (conn.fd, NULL, NULL));
- request_header req;
- char buf[256];
- uid_t uid = 0;
+ if (debug_level > 0)
+ dbg_log (_("short read while reading request: %s"),
+ strerror_r (errno, buf, sizeof (buf)));
+ close (fd);
+ continue;
+ }
+
+ /* Some systems have no SO_PEERCRED implementation. They don't
+ care about security so we don't as well. */
#ifdef SO_PEERCRED
- pid_t pid = 0;
-#endif
+ if (secure_in_use)
+ {
+ struct ucred caller;
+ socklen_t optlen = sizeof (caller);
- if (__builtin_expect (fd, 0) < 0)
+ if (getsockopt (fd, SOL_SOCKET, SO_PEERCRED, &caller, &optlen) < 0)
{
- dbg_log (_("while accepting connection: %s"),
+ dbg_log (_("error getting callers id: %s"),
strerror_r (errno, buf, sizeof (buf)));
- continue;
- }
-
- /* Now read the request. */
- if (__builtin_expect (TEMP_FAILURE_RETRY (read (fd, &req,
- sizeof (req)))
- != sizeof (req), 0))
- {
- if (debug_level > 0)
- dbg_log (_("short read while reading request: %s"),
- strerror_r (errno, buf, sizeof (buf)));
close (fd);
continue;
}
- /* Some systems have no SO_PEERCRED implementation. They don't
- care about security so we don't as well. */
-#ifdef SO_PEERCRED
- if (secure_in_use)
- {
- struct ucred caller;
- socklen_t optlen = sizeof (caller);
-
- if (getsockopt (fd, SOL_SOCKET, SO_PEERCRED,
- &caller, &optlen) < 0)
- {
- dbg_log (_("error getting callers id: %s"),
- strerror_r (errno, buf, sizeof (buf)));
- close (fd);
- continue;
- }
-
- if (req.type < GETPWBYNAME || req.type > LASTDBREQ
- || secure[serv2db[req.type]])
- uid = caller.uid;
+ if (req.type < GETPWBYNAME || req.type > LASTDBREQ
+ || secure[serv2db[req.type]])
+ uid = caller.uid;
pid = caller.pid;
- }
- else if (__builtin_expect (debug_level > 0, 0))
- {
- struct ucred caller;
- socklen_t optlen = sizeof (caller);
+ }
+ else if (__builtin_expect (debug_level > 0, 0))
+ {
+ struct ucred caller;
+ socklen_t optlen = sizeof (caller);
- if (getsockopt (fd, SOL_SOCKET, SO_PEERCRED,
- &caller, &optlen) == 0)
- pid = caller.pid;
- }
+ if (getsockopt (fd, SOL_SOCKET, SO_PEERCRED, &caller, &optlen) == 0)
+ pid = caller.pid;
+ }
#endif
- /* It should not be possible to crash the nscd with a silly
- request (i.e., a terribly large key). We limit the size
- to 1kb. */
- if (__builtin_expect (req.key_len, 1) < 0
- || __builtin_expect (req.key_len, 1) > 1024)
+ /* It should not be possible to crash the nscd with a silly
+ request (i.e., a terribly large key). We limit the size to 1kb. */
+ if (__builtin_expect (req.key_len, 1) < 0
+ || __builtin_expect (req.key_len, 1) > 1024)
+ {
+ if (debug_level > 0)
+ dbg_log (_("key length in request too long: %d"), req.key_len);
+ close (fd);
+ continue;
+ }
+ else
+ {
+ /* Get the key. */
+ char keybuf[req.key_len];
+
+ if (__builtin_expect (TEMP_FAILURE_RETRY (read (fd, keybuf,
+ req.key_len))
+ != req.key_len, 0))
{
if (debug_level > 0)
- dbg_log (_("key length in request too long: %d"), req.key_len);
+ dbg_log (_("short read while reading request key: %s"),
+ strerror_r (errno, buf, sizeof (buf)));
close (fd);
continue;
}
- else
+
+ if (__builtin_expect (debug_level, 0) > 0)
{
- /* Get the key. */
- char keybuf[req.key_len];
-
- if (__builtin_expect (TEMP_FAILURE_RETRY (read (fd, keybuf,
- req.key_len))
- != req.key_len, 0))
- {
- if (debug_level > 0)
- dbg_log (_("short read while reading request key: %s"),
- strerror_r (errno, buf, sizeof (buf)));
- close (fd);
- continue;
- }
-
- if (__builtin_expect (debug_level, 0) > 0)
- {
#ifdef SO_PEERCRED
- if (pid != 0)
- dbg_log (_("\
+ if (pid != 0)
+ dbg_log (_("\
handle_request: request received (Version = %d) from PID %ld"),
- req.version, (long int) pid);
- else
+ req.version, (long int) pid);
+ else
#endif
- dbg_log (_("\
+ dbg_log (_("\
handle_request: request received (Version = %d)"), req.version);
- }
+ }
- /* Phew, we got all the data, now process it. */
- handle_request (fd, &req, keybuf, uid);
+ /* Phew, we got all the data, now process it. */
+ handle_request (fd, &req, keybuf, uid);
- /* We are done. */
- close (fd);
- }
+ /* We are done. */
+ close (fd);
}
- if (run_prune)
+ /* Just determine whether any data is present. We do this to
+ measure whether clients are queued up. */
+ try_get:
+ nr = poll (&conn, 1, 0);
+ if (nr != 0)
{
- now = time (NULL);
- timeout = now < next_prune ? 1000 * (next_prune - now) : 0;
+ if (nready == 0)
+ ++client_queued;
+
+ atomic_increment (&nready);
+
+ goto got_data;
}
}
}