mirror of
https://sourceware.org/git/glibc.git
synced 2025-07-30 22:43:12 +03:00
* nscd/aicache.c (addhstaiX): Check herrno after IPv4 lookup only
when the lookup call failed. * nscd/nscd.h (struct database_dyn): Rename prunelock to prune_lock. Add prune_cond and wakeup_time. (CACHE_PRUNE_INTERNAL): Define. Update declarations of prune_cache and setup_thread. * nscd/connections.c (dbs): Update initializers. (CACHE_PRUNE_INTERNAL): Moved to nscd.h. (nscd_init): Default number of threads is now 4. (invalidate_cache): Take lock before calling prune_cache. (handle_request): If SELinux forbids the request, say so. (readylist_cond): Use static initializer. (nscd_run_prune): New function. Used only by pruning threads. (nscd_run_worder): Renamed from nscd_run. Remove support for pruning here. (fd_ready): Update nscd_run reference. (start_threads): No need to initialize readylist_cond. Start pruning threads separately. * nscd/nscd_setup_thread.c: Change return value type to int and always return 0. * sysdeps/unix/sysv/linux/nscd_setup_thread.c: Change return value type to int and return nonzero value if we can use the TID address hack. * nscd/cache.c (cache_add): If next wakeup time of cleanup thread for the database is later than the new entry's timeout, update the wakeup time and wake the cleanup thread. (prune_cache): Return seconds the next entry in the database is still valid. Remove locking for pruning here. * nscd/nscd.conf: Document default number of threads.
This commit is contained in:
33
ChangeLog
33
ChangeLog
@ -1,8 +1,41 @@
|
|||||||
|
2007-11-05 Ulrich Drepper <drepper@redhat.com>
|
||||||
|
|
||||||
|
* nscd/aicache.c (addhstaiX): Check herrno after IPv4 lookup only
|
||||||
|
when the lookup call failed.
|
||||||
|
|
||||||
|
* nscd/nscd.h (struct database_dyn): Rename prunelock to prune_lock.
|
||||||
|
Add prune_cond and wakeup_time.
|
||||||
|
(CACHE_PRUNE_INTERNAL): Define.
|
||||||
|
Update declarations of prune_cache and setup_thread.
|
||||||
|
* nscd/connections.c (dbs): Update initializers.
|
||||||
|
(CACHE_PRUNE_INTERNAL): Moved to nscd.h.
|
||||||
|
(nscd_init): Default number of threads is now 4.
|
||||||
|
(invalidate_cache): Take lock before calling prune_cache.
|
||||||
|
(handle_request): If SELinux forbids the request, say so.
|
||||||
|
(readylist_cond): Use static initializer.
|
||||||
|
(nscd_run_prune): New function. Used only by pruning threads.
|
||||||
|
(nscd_run_worder): Renamed from nscd_run. Remove support for pruning
|
||||||
|
here.
|
||||||
|
(fd_ready): Update nscd_run reference.
|
||||||
|
(start_threads): No need to initialize readylist_cond.
|
||||||
|
Start pruning threads separately.
|
||||||
|
* nscd/nscd_setup_thread.c: Change return value type to int and always
|
||||||
|
return 0.
|
||||||
|
* sysdeps/unix/sysv/linux/nscd_setup_thread.c: Change return value type
|
||||||
|
to int and return nonzero value if we can use the TID address hack.
|
||||||
|
* nscd/cache.c (cache_add): If next wakeup time of cleanup thread for
|
||||||
|
the database is later than the new entry's timeout, update the
|
||||||
|
wakeup time and wake the cleanup thread.
|
||||||
|
(prune_cache): Return seconds the next entry in the database is still
|
||||||
|
valid. Remove locking for pruning here.
|
||||||
|
* nscd/nscd.conf: Document default number of threads.
|
||||||
|
|
||||||
2007-10-31 Ulrich Drepper <drepper@redhat.com>
|
2007-10-31 Ulrich Drepper <drepper@redhat.com>
|
||||||
|
|
||||||
* sysdeps/x86_64/dl-trampoline.S (_dl_runtime_profile): Make sure
|
* sysdeps/x86_64/dl-trampoline.S (_dl_runtime_profile): Make sure
|
||||||
stack is properly aligned for the target function.
|
stack is properly aligned for the target function.
|
||||||
Correct unwind info.
|
Correct unwind info.
|
||||||
|
|
||||||
* elf/rtld.c (dl_main): Initialize stack and pointer guard early
|
* elf/rtld.c (dl_main): Initialize stack and pointer guard early
|
||||||
when using auditing libraries.
|
when using auditing libraries.
|
||||||
|
|
||||||
|
@ -157,7 +157,7 @@ addhstaiX (struct database_dyn *db, int fd, request_header *req,
|
|||||||
tmpbuf4 = tmpbuf6;
|
tmpbuf4 = tmpbuf6;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Next collect IPv4 information first. */
|
/* Next collect IPv4 information. */
|
||||||
while (1)
|
while (1)
|
||||||
{
|
{
|
||||||
rc4 = 0;
|
rc4 = 0;
|
||||||
@ -170,7 +170,7 @@ addhstaiX (struct database_dyn *db, int fd, request_header *req,
|
|||||||
tmpbuf4 = extend_alloca (tmpbuf4, tmpbuf4len, 2 * tmpbuf4len);
|
tmpbuf4 = extend_alloca (tmpbuf4, tmpbuf4len, 2 * tmpbuf4len);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rc4 != 0 || herrno == NETDB_INTERNAL)
|
if (rc4 != 0 && herrno == NETDB_INTERNAL)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
if (status[0] == NSS_STATUS_SUCCESS
|
if (status[0] == NSS_STATUS_SUCCESS
|
||||||
|
37
nscd/cache.c
37
nscd/cache.c
@ -197,6 +197,20 @@ cache_add (int type, const void *key, size_t len, struct datahead *packet,
|
|||||||
(char *) &table->head->array[hash] - (char *) table->head
|
(char *) &table->head->array[hash] - (char *) table->head
|
||||||
+ sizeof (ref_t), MS_ASYNC);
|
+ sizeof (ref_t), MS_ASYNC);
|
||||||
|
|
||||||
|
/* Perhaps the prune thread for the data is not running in a long
|
||||||
|
time. Wake it if necessary. */
|
||||||
|
time_t next_wakeup = table->wakeup_time;
|
||||||
|
while (next_wakeup + CACHE_PRUNE_INTERVAL > packet->timeout)
|
||||||
|
if (atomic_compare_and_exchange_bool_acq (&table->wakeup_time,
|
||||||
|
packet->timeout,
|
||||||
|
next_wakeup) == 0)
|
||||||
|
{
|
||||||
|
pthread_cond_signal (&table->prune_cond);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
next_wakeup = table->wakeup_time;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -212,7 +226,7 @@ cache_add (int type, const void *key, size_t len, struct datahead *packet,
|
|||||||
actually remove them. This is complicated by the way we have to
|
actually remove them. This is complicated by the way we have to
|
||||||
free the data structures since some hash table entries share the same
|
free the data structures since some hash table entries share the same
|
||||||
data. */
|
data. */
|
||||||
void
|
time_t
|
||||||
prune_cache (struct database_dyn *table, time_t now, int fd)
|
prune_cache (struct database_dyn *table, time_t now, int fd)
|
||||||
{
|
{
|
||||||
size_t cnt = table->head->module;
|
size_t cnt = table->head->module;
|
||||||
@ -226,7 +240,9 @@ prune_cache (struct database_dyn *table, time_t now, int fd)
|
|||||||
int32_t resp = 0;
|
int32_t resp = 0;
|
||||||
writeall (fd, &resp, sizeof (resp));
|
writeall (fd, &resp, sizeof (resp));
|
||||||
}
|
}
|
||||||
return;
|
|
||||||
|
/* No need to do this again anytime soon. */
|
||||||
|
return 24 * 60 * 60;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If we check for the modification of the underlying file we invalidate
|
/* If we check for the modification of the underlying file we invalidate
|
||||||
@ -256,21 +272,6 @@ prune_cache (struct database_dyn *table, time_t now, int fd)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This function can be called from the cleanup thread but also in
|
|
||||||
response to an invalidate command. Make sure only one thread is
|
|
||||||
running. When not serving INVALIDATE request, no need for the
|
|
||||||
second thread to wait around. */
|
|
||||||
if (__builtin_expect (pthread_mutex_trylock (&table->prunelock) != 0, 0))
|
|
||||||
{
|
|
||||||
/* The work is already being done. */
|
|
||||||
if (fd == -1)
|
|
||||||
return;
|
|
||||||
|
|
||||||
/* We have to wait until the thread is done and then run again
|
|
||||||
so that the large NOW value invalidates all entries. */
|
|
||||||
pthread_mutex_lock (&table->prunelock);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* We run through the table and find values which are not valid anymore.
|
/* We run through the table and find values which are not valid anymore.
|
||||||
|
|
||||||
Note that for the initial step, finding the entries to be removed,
|
Note that for the initial step, finding the entries to be removed,
|
||||||
@ -473,5 +474,5 @@ prune_cache (struct database_dyn *table, time_t now, int fd)
|
|||||||
if (any)
|
if (any)
|
||||||
gc (table);
|
gc (table);
|
||||||
|
|
||||||
pthread_mutex_unlock (&table->prunelock);
|
return next_timeout - now;
|
||||||
}
|
}
|
||||||
|
@ -104,7 +104,7 @@ struct database_dyn dbs[lastdb] =
|
|||||||
{
|
{
|
||||||
[pwddb] = {
|
[pwddb] = {
|
||||||
.lock = PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP,
|
.lock = PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP,
|
||||||
.prunelock = PTHREAD_MUTEX_INITIALIZER,
|
.prune_lock = PTHREAD_MUTEX_INITIALIZER,
|
||||||
.enabled = 0,
|
.enabled = 0,
|
||||||
.check_file = 1,
|
.check_file = 1,
|
||||||
.persistent = 0,
|
.persistent = 0,
|
||||||
@ -123,7 +123,7 @@ struct database_dyn dbs[lastdb] =
|
|||||||
},
|
},
|
||||||
[grpdb] = {
|
[grpdb] = {
|
||||||
.lock = PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP,
|
.lock = PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP,
|
||||||
.prunelock = PTHREAD_MUTEX_INITIALIZER,
|
.prune_lock = PTHREAD_MUTEX_INITIALIZER,
|
||||||
.enabled = 0,
|
.enabled = 0,
|
||||||
.check_file = 1,
|
.check_file = 1,
|
||||||
.persistent = 0,
|
.persistent = 0,
|
||||||
@ -142,7 +142,7 @@ struct database_dyn dbs[lastdb] =
|
|||||||
},
|
},
|
||||||
[hstdb] = {
|
[hstdb] = {
|
||||||
.lock = PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP,
|
.lock = PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP,
|
||||||
.prunelock = PTHREAD_MUTEX_INITIALIZER,
|
.prune_lock = PTHREAD_MUTEX_INITIALIZER,
|
||||||
.enabled = 0,
|
.enabled = 0,
|
||||||
.check_file = 1,
|
.check_file = 1,
|
||||||
.persistent = 0,
|
.persistent = 0,
|
||||||
@ -161,7 +161,7 @@ struct database_dyn dbs[lastdb] =
|
|||||||
},
|
},
|
||||||
[servdb] = {
|
[servdb] = {
|
||||||
.lock = PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP,
|
.lock = PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP,
|
||||||
.prunelock = PTHREAD_MUTEX_INITIALIZER,
|
.prune_lock = PTHREAD_MUTEX_INITIALIZER,
|
||||||
.enabled = 0,
|
.enabled = 0,
|
||||||
.check_file = 1,
|
.check_file = 1,
|
||||||
.persistent = 0,
|
.persistent = 0,
|
||||||
@ -210,10 +210,6 @@ static struct
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/* Number of seconds between two cache pruning runs. */
|
|
||||||
#define CACHE_PRUNE_INTERVAL 15
|
|
||||||
|
|
||||||
|
|
||||||
/* Initial number of threads to use. */
|
/* Initial number of threads to use. */
|
||||||
int nthreads = -1;
|
int nthreads = -1;
|
||||||
/* Maximum number of threads to use. */
|
/* Maximum number of threads to use. */
|
||||||
@ -495,7 +491,7 @@ nscd_init (void)
|
|||||||
|
|
||||||
if (nthreads == -1)
|
if (nthreads == -1)
|
||||||
/* No configuration for this value, assume a default. */
|
/* No configuration for this value, assume a default. */
|
||||||
nthreads = 2 * lastdb;
|
nthreads = 4;
|
||||||
|
|
||||||
for (size_t cnt = 0; cnt < lastdb; ++cnt)
|
for (size_t cnt = 0; cnt < lastdb; ++cnt)
|
||||||
if (dbs[cnt].enabled)
|
if (dbs[cnt].enabled)
|
||||||
@ -898,7 +894,11 @@ invalidate_cache (char *key, int fd)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (dbs[number].enabled)
|
if (dbs[number].enabled)
|
||||||
prune_cache (&dbs[number], LONG_MAX, fd);
|
{
|
||||||
|
pthread_mutex_lock (&dbs[number].prune_lock);
|
||||||
|
prune_cache (&dbs[number], LONG_MAX, fd);
|
||||||
|
pthread_mutex_unlock (&dbs[number].prune_lock);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
resp = 0;
|
resp = 0;
|
||||||
@ -970,9 +970,13 @@ cannot handle old request version %d; current version is %d"),
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Make the SELinux check before we go on to the standard checks. */
|
/* Perform the SELinux check before we go on to the standard checks. */
|
||||||
if (selinux_enabled && nscd_request_avc_has_perm (fd, req->type) != 0)
|
if (selinux_enabled && nscd_request_avc_has_perm (fd, req->type) != 0)
|
||||||
return;
|
{
|
||||||
|
if (debug_level > 0)
|
||||||
|
dbg_log (_("request not handled due to missing permission"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
struct database_dyn *db = reqinfo[req->type].db;
|
struct database_dyn *db = reqinfo[req->type].db;
|
||||||
|
|
||||||
@ -1336,7 +1340,7 @@ static struct fdlist *readylist;
|
|||||||
/* Conditional variable and mutex to signal availability of entries in
|
/* Conditional variable and mutex to signal availability of entries in
|
||||||
READYLIST. The condvar is initialized dynamically since we might
|
READYLIST. The condvar is initialized dynamically since we might
|
||||||
use a different clock depending on availability. */
|
use a different clock depending on availability. */
|
||||||
static pthread_cond_t readylist_cond;
|
static pthread_cond_t readylist_cond = PTHREAD_COND_INITIALIZER;
|
||||||
static pthread_mutex_t readylist_lock = PTHREAD_MUTEX_INITIALIZER;
|
static pthread_mutex_t readylist_lock = PTHREAD_MUTEX_INITIALIZER;
|
||||||
|
|
||||||
/* The clock to use with the condvar. */
|
/* The clock to use with the condvar. */
|
||||||
@ -1346,32 +1350,76 @@ static clockid_t timeout_clock = CLOCK_REALTIME;
|
|||||||
static unsigned long int nready;
|
static unsigned long int nready;
|
||||||
|
|
||||||
|
|
||||||
/* This is the main loop. It is replicated in different threads but the
|
/* Function for the clean-up threads. */
|
||||||
`poll' call makes sure only one thread handles an incoming connection. */
|
|
||||||
static void *
|
static void *
|
||||||
__attribute__ ((__noreturn__))
|
__attribute__ ((__noreturn__))
|
||||||
nscd_run (void *p)
|
nscd_run_prune (void *p)
|
||||||
{
|
{
|
||||||
const long int my_number = (long int) p;
|
const long int my_number = (long int) p;
|
||||||
const int run_prune = my_number < lastdb && dbs[my_number].enabled;
|
assert (dbs[my_number].enabled);
|
||||||
|
|
||||||
|
int dont_need_update = setup_thread (&dbs[my_number]);
|
||||||
|
|
||||||
|
/* We are running. */
|
||||||
|
dbs[my_number].head->timestamp = time (NULL);
|
||||||
|
|
||||||
struct timespec prune_ts;
|
struct timespec prune_ts;
|
||||||
int to = 0;
|
if (clock_gettime (timeout_clock, &prune_ts) == -1)
|
||||||
char buf[256];
|
/* Should never happen. */
|
||||||
|
abort ();
|
||||||
|
|
||||||
if (run_prune)
|
/* Compute the initial timeout time. Prevent all the timers to go
|
||||||
|
off at the same time by adding a db-based value. */
|
||||||
|
prune_ts.tv_sec += CACHE_PRUNE_INTERVAL + my_number;
|
||||||
|
|
||||||
|
pthread_mutex_lock (&dbs[my_number].prune_lock);
|
||||||
|
while (1)
|
||||||
{
|
{
|
||||||
setup_thread (&dbs[my_number]);
|
/* Wait, but not forever. */
|
||||||
|
int e = pthread_cond_timedwait (&dbs[my_number].prune_cond,
|
||||||
|
&dbs[my_number].prune_lock,
|
||||||
|
&prune_ts);
|
||||||
|
assert (e == 0 || e == ETIMEDOUT);
|
||||||
|
|
||||||
/* We are running. */
|
time_t next_wait;
|
||||||
dbs[my_number].head->timestamp = time (NULL);
|
time_t now = time (NULL);
|
||||||
|
if (e == ETIMEDOUT || now >= dbs[my_number].wakeup_time)
|
||||||
|
{
|
||||||
|
next_wait = prune_cache (&dbs[my_number], now, -1);
|
||||||
|
next_wait = MAX (next_wait, CACHE_PRUNE_INTERVAL);
|
||||||
|
/* If clients cannot determine for sure whether nscd is running
|
||||||
|
we need to wake up occasionally to update the timestamp.
|
||||||
|
Wait 90% of the update period. */
|
||||||
|
#define UPDATE_MAPPING_TIMEOUT (MAPPING_TIMEOUT * 9 / 10)
|
||||||
|
if (__builtin_expect (! dont_need_update, 0))
|
||||||
|
next_wait = MIN (UPDATE_MAPPING_TIMEOUT, next_wait);
|
||||||
|
|
||||||
|
/* Make it known when we will wake up again. */
|
||||||
|
dbs[my_number].wakeup_time = now + next_wait;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
/* The cache was just pruned. Do not do it again now. Just
|
||||||
|
use the new timeout value. */
|
||||||
|
next_wait = dbs[my_number].wakeup_time - now;
|
||||||
|
|
||||||
if (clock_gettime (timeout_clock, &prune_ts) == -1)
|
if (clock_gettime (timeout_clock, &prune_ts) == -1)
|
||||||
/* Should never happen. */
|
/* Should never happen. */
|
||||||
abort ();
|
abort ();
|
||||||
|
|
||||||
/* Compute timeout time. */
|
/* Compute next timeout time. */
|
||||||
prune_ts.tv_sec += CACHE_PRUNE_INTERVAL;
|
prune_ts.tv_sec += next_wait;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* This is the main loop. It is replicated in different threads but
|
||||||
|
the the use of the ready list makes sure only one thread handles an
|
||||||
|
incoming connection. */
|
||||||
|
static void *
|
||||||
|
__attribute__ ((__noreturn__))
|
||||||
|
nscd_run_worker (void *p)
|
||||||
|
{
|
||||||
|
char buf[256];
|
||||||
|
|
||||||
/* Initial locking. */
|
/* Initial locking. */
|
||||||
pthread_mutex_lock (&readylist_lock);
|
pthread_mutex_lock (&readylist_lock);
|
||||||
@ -1382,26 +1430,7 @@ nscd_run (void *p)
|
|||||||
while (1)
|
while (1)
|
||||||
{
|
{
|
||||||
while (readylist == NULL)
|
while (readylist == NULL)
|
||||||
{
|
pthread_cond_wait (&readylist_cond, &readylist_lock);
|
||||||
if (run_prune)
|
|
||||||
{
|
|
||||||
/* Wait, but not forever. */
|
|
||||||
to = pthread_cond_timedwait (&readylist_cond, &readylist_lock,
|
|
||||||
&prune_ts);
|
|
||||||
|
|
||||||
/* If we were woken and there is no work to be done,
|
|
||||||
just start pruning. */
|
|
||||||
if (readylist == NULL && to == ETIMEDOUT)
|
|
||||||
{
|
|
||||||
--nready;
|
|
||||||
pthread_mutex_unlock (&readylist_lock);
|
|
||||||
goto only_prune;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
/* No need to timeout. */
|
|
||||||
pthread_cond_wait (&readylist_cond, &readylist_lock);
|
|
||||||
}
|
|
||||||
|
|
||||||
struct fdlist *it = readylist->next;
|
struct fdlist *it = readylist->next;
|
||||||
if (readylist->next == readylist)
|
if (readylist->next == readylist)
|
||||||
@ -1504,28 +1533,6 @@ handle_request: request received (Version = %d)"), req.version);
|
|||||||
/* We are done. */
|
/* We are done. */
|
||||||
close (fd);
|
close (fd);
|
||||||
|
|
||||||
/* Check whether we should be pruning the cache. */
|
|
||||||
assert (run_prune || to == 0);
|
|
||||||
if (to == ETIMEDOUT)
|
|
||||||
{
|
|
||||||
only_prune:
|
|
||||||
/* The pthread_cond_timedwait() call timed out. It is time
|
|
||||||
to clean up the cache. */
|
|
||||||
assert (my_number < lastdb);
|
|
||||||
prune_cache (&dbs[my_number], time (NULL), -1);
|
|
||||||
|
|
||||||
if (clock_gettime (timeout_clock, &prune_ts) == -1)
|
|
||||||
/* Should never happen. */
|
|
||||||
abort ();
|
|
||||||
|
|
||||||
/* Compute next timeout time. */
|
|
||||||
prune_ts.tv_sec += CACHE_PRUNE_INTERVAL;
|
|
||||||
|
|
||||||
/* In case the list is emtpy we do not want to run the prune
|
|
||||||
code right away again. */
|
|
||||||
to = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Re-locking. */
|
/* Re-locking. */
|
||||||
pthread_mutex_lock (&readylist_lock);
|
pthread_mutex_lock (&readylist_lock);
|
||||||
|
|
||||||
@ -1568,7 +1575,7 @@ fd_ready (int fd)
|
|||||||
/* Try to start another thread to help out. */
|
/* Try to start another thread to help out. */
|
||||||
pthread_t th;
|
pthread_t th;
|
||||||
if (nthreads < max_nthreads
|
if (nthreads < max_nthreads
|
||||||
&& pthread_create (&th, &attr, nscd_run,
|
&& pthread_create (&th, &attr, nscd_run_worker,
|
||||||
(void *) (long int) nthreads) == 0)
|
(void *) (long int) nthreads) == 0)
|
||||||
{
|
{
|
||||||
/* We got another thread. */
|
/* We got another thread. */
|
||||||
@ -1828,10 +1835,6 @@ start_threads (void)
|
|||||||
timeout_clock = CLOCK_MONOTONIC;
|
timeout_clock = CLOCK_MONOTONIC;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
pthread_cond_init (&readylist_cond, &condattr);
|
|
||||||
pthread_condattr_destroy (&condattr);
|
|
||||||
|
|
||||||
|
|
||||||
/* Create the attribute for the threads. They are all created
|
/* Create the attribute for the threads. They are all created
|
||||||
detached. */
|
detached. */
|
||||||
pthread_attr_init (&attr);
|
pthread_attr_init (&attr);
|
||||||
@ -1843,19 +1846,46 @@ start_threads (void)
|
|||||||
if (debug_level == 0)
|
if (debug_level == 0)
|
||||||
nthreads = MAX (nthreads, lastdb);
|
nthreads = MAX (nthreads, lastdb);
|
||||||
|
|
||||||
int nfailed = 0;
|
/* Create the threads which prune the databases. */
|
||||||
|
// XXX Ideally this work would be done by some of the worker threads.
|
||||||
|
// XXX But this is problematic since we would need to be able to wake
|
||||||
|
// XXX them up explicitly as well as part of the group handling the
|
||||||
|
// XXX ready-list. This requires an operation where we can wait on
|
||||||
|
// XXX two conditional variables at the same time. This operation
|
||||||
|
// XXX does not exist (yet).
|
||||||
|
for (long int i = 0; i < lastdb; ++i)
|
||||||
|
{
|
||||||
|
/* Initialize the conditional variable. */
|
||||||
|
if (pthread_cond_init (&dbs[i].prune_cond, &condattr) != 0)
|
||||||
|
{
|
||||||
|
dbg_log (_("could not initialize conditional variable"));
|
||||||
|
exit (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
pthread_t th;
|
||||||
|
if (dbs[i].enabled
|
||||||
|
&& pthread_create (&th, &attr, nscd_run_prune, (void *) i) != 0)
|
||||||
|
{
|
||||||
|
dbg_log (_("could not start clean-up thread; terminating"));
|
||||||
|
exit (1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pthread_condattr_destroy (&condattr);
|
||||||
|
|
||||||
for (long int i = 0; i < nthreads; ++i)
|
for (long int i = 0; i < nthreads; ++i)
|
||||||
{
|
{
|
||||||
pthread_t th;
|
pthread_t th;
|
||||||
if (pthread_create (&th, &attr, nscd_run, (void *) (i - nfailed)) != 0)
|
if (pthread_create (&th, &attr, nscd_run_worker, NULL) != 0)
|
||||||
++nfailed;
|
{
|
||||||
}
|
if (i == 0)
|
||||||
if (nthreads - nfailed < lastdb)
|
{
|
||||||
{
|
dbg_log (_("could not start any worker thread; terminating"));
|
||||||
/* We could not start enough threads. */
|
exit (1);
|
||||||
dbg_log (_("could only start %d threads; terminating"),
|
}
|
||||||
nthreads - nfailed);
|
|
||||||
exit (1);
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Determine how much room for descriptors we should initially
|
/* Determine how much room for descriptors we should initially
|
||||||
|
@ -31,7 +31,7 @@
|
|||||||
|
|
||||||
|
|
||||||
# logfile /var/log/nscd.log
|
# logfile /var/log/nscd.log
|
||||||
# threads 6
|
# threads 4
|
||||||
# max-threads 128
|
# max-threads 128
|
||||||
# server-user nobody
|
# server-user nobody
|
||||||
# stat-user somebody
|
# stat-user somebody
|
||||||
|
13
nscd/nscd.h
13
nscd/nscd.h
@ -59,7 +59,9 @@ typedef enum
|
|||||||
struct database_dyn
|
struct database_dyn
|
||||||
{
|
{
|
||||||
pthread_rwlock_t lock;
|
pthread_rwlock_t lock;
|
||||||
pthread_mutex_t prunelock;
|
pthread_cond_t prune_cond;
|
||||||
|
pthread_mutex_t prune_lock;
|
||||||
|
time_t wakeup_time;
|
||||||
|
|
||||||
int enabled;
|
int enabled;
|
||||||
int check_file;
|
int check_file;
|
||||||
@ -111,6 +113,11 @@ struct database_dyn
|
|||||||
#define DEFAULT_DATASIZE_PER_BUCKET 1024
|
#define DEFAULT_DATASIZE_PER_BUCKET 1024
|
||||||
|
|
||||||
|
|
||||||
|
/* Number of seconds between two cache pruning runs if we do not have
|
||||||
|
better information when it is really needed. */
|
||||||
|
#define CACHE_PRUNE_INTERVAL 15
|
||||||
|
|
||||||
|
|
||||||
/* Global variables. */
|
/* Global variables. */
|
||||||
extern struct database_dyn dbs[lastdb];
|
extern struct database_dyn dbs[lastdb];
|
||||||
extern const char *const dbnames[lastdb];
|
extern const char *const dbnames[lastdb];
|
||||||
@ -189,7 +196,7 @@ extern struct datahead *cache_search (request_type, void *key, size_t len,
|
|||||||
extern int cache_add (int type, const void *key, size_t len,
|
extern int cache_add (int type, const void *key, size_t len,
|
||||||
struct datahead *packet, bool first,
|
struct datahead *packet, bool first,
|
||||||
struct database_dyn *table, uid_t owner);
|
struct database_dyn *table, uid_t owner);
|
||||||
extern void prune_cache (struct database_dyn *table, time_t now, int fd);
|
extern time_t prune_cache (struct database_dyn *table, time_t now, int fd);
|
||||||
|
|
||||||
/* pwdcache.c */
|
/* pwdcache.c */
|
||||||
extern void addpwbyname (struct database_dyn *db, int fd, request_header *req,
|
extern void addpwbyname (struct database_dyn *db, int fd, request_header *req,
|
||||||
@ -258,7 +265,7 @@ extern void gc (struct database_dyn *db);
|
|||||||
|
|
||||||
|
|
||||||
/* nscd_setup_thread.c */
|
/* nscd_setup_thread.c */
|
||||||
extern void setup_thread (struct database_dyn *db);
|
extern int setup_thread (struct database_dyn *db);
|
||||||
|
|
||||||
|
|
||||||
/* Special version of TEMP_FAILURE_RETRY for functions returning error
|
/* Special version of TEMP_FAILURE_RETRY for functions returning error
|
||||||
|
@ -20,8 +20,9 @@
|
|||||||
#include <nscd.h>
|
#include <nscd.h>
|
||||||
|
|
||||||
|
|
||||||
void
|
int
|
||||||
setup_thread (struct database_dyn *db)
|
setup_thread (struct database_dyn *db)
|
||||||
{
|
{
|
||||||
/* Nothing. */
|
/* Nothing. */
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -23,7 +23,7 @@
|
|||||||
#include <sysdep.h>
|
#include <sysdep.h>
|
||||||
|
|
||||||
|
|
||||||
void
|
int
|
||||||
setup_thread (struct database_dyn *db)
|
setup_thread (struct database_dyn *db)
|
||||||
{
|
{
|
||||||
#ifdef __NR_set_tid_address
|
#ifdef __NR_set_tid_address
|
||||||
@ -43,6 +43,8 @@ setup_thread (struct database_dyn *db)
|
|||||||
/* We know the kernel can reset this field when nscd terminates.
|
/* We know the kernel can reset this field when nscd terminates.
|
||||||
So, set the field to a nonzero value which indicates that nscd
|
So, set the field to a nonzero value which indicates that nscd
|
||||||
is certainly running and clients can skip the test. */
|
is certainly running and clients can skip the test. */
|
||||||
db->head->nscd_certainly_running = 1;
|
return db->head->nscd_certainly_running = 1;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user