nis_thread_funcs.c revision 91760536453132b0d3369ad5543622a5478007e6
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#include <syslog.h>
#include <errno.h>
#include <sys/resource.h>
#include <dirent.h>
#include <string.h>
#include "nis_proc.h"
#include "nis_svc.h"
/* Track last time we started processing a request */
static struct timeval last_activity = {0, 0};
/* Max interval between checking number of open fd:s */
/*
* Purge since now minus delta depending on number of open fd:s, in seconds.
*
* The array values were chosen to do the following:
*
* Behave like the old code (7200 seconds purge delta) for a very small
* number of open fd:s
*
* Give reasonably smooth purge behavior for realistic fd growth rates,
* as observed at customer site.
*
* Become aggressive about purging at high numbers of open fd:s, to
* reduce the risk of running out of fd:s.
*/
static int purge_deltas[] = {
7200, 6900, 6600, 6300, 6000, 5400, 4800, 4200,
3600, 3000, 1800, 1200, 600, 300, 75, 60
};
/* ARGSUSED1 */
static int
(*(int *)countp)++;
return (0);
}
static long
fd_open_count(void) {
int count = 0;
return (count);
}
/* servloop_sleep and servloop_wake are protected by the same mutex */
static time_t servloop_wake = 0;
static DECLMUTEXLOCK(servloop_sleep);
int
int ret;
(void) gettimeofday(&tv, 0);
}
if (servloop_wake != 0) {
/* If we're past the servloop_wake time, reset and return */
servloop_wake = 0;
return (0);
}
/* servloop_wake may limit our sleep */
}
}
&servloop_sleep_pmutex, &ts);
/* Reset servloop_wake if necessary */
if (servloop_wake != 0) {
(void) gettimeofday(&tv, 0);
servloop_wake = 0;
}
return (ret);
}
void
wakeup_servloop(void) {
(void) pthread_cond_signal(&servloop_sleep);
}
/*
* Return the update batching timeout.
*/
updateBatchingTimeout(void) {
switch (ldapConfig.updateBatching) {
case upd_none:
return (0);
case accumulate:
case bounded_accumulate:
default:
return (DIR_IDLE_TIME);
}
/* NOTREACHED */
}
/*
* Establish the time when the servloop next should wake up to check
* if replicas should be pinged. If we change the wake up time, we
* always wake up the servloop so that it will take the new wakeup time
* into account when it goes back to sleep.
*/
void
int doWakeup = 0;
doWakeup = 1;
}
if (doWakeup)
}
void
mark_activity(void) {
static DECLMUTEXLOCK(last_activity);
(void) gettimeofday(&last_activity, 0);
}
void *
long dtbsize;
long last_purge = 0;
long fd_check = 0;
long fd_check_interval = FD_CHECK_DEF;
long purge_delta = purge_deltas[
long prev_since;
long cur_open_fd;
/*
* get the maximum number of file descriptors for poll
*/
for (;;) {
/*
* Check open fd:s if more than 'fd_check_interval' seconds
* since last time.
*
* XXX: The somewhat complicated code below sets the
* purge_delta depending on the number of open fd:s,
* using linear interpolation in the purge_deltas[]
* array.
*/
long index;
int deltas = (sizeof (purge_deltas)/
sizeof (purge_deltas[0]));
cur_open_fd = fd_open_count();
if (index < 0) {
purge_delta = purge_deltas[0];
/* Interpolate */
} else {
}
if (fd_check_interval > FD_CHECK_DEF)
/*
* Run a purge on virtual circuits unused since now
* minus purge_delta seconds, if
*
* The new purge cutoff would be more recent than
* the one used in the last purge, and
*
* We have a fairly large number of fd:s open
* (more than 128, if deltas=16 and dtbsize=1024),
*
* or
*
* More than 'purge_delta' seconds have passed
* since the last purge.
*/
}
}
}
/* Perform deferred frees */
/*
* No activity while we slept. Remove tables from
* standby mode and go back to sleep.
*/
(void) db_standby(0);
}
/* the force_checkpoint flag is set by -F or ping -C */
if (force_checkpoint) {
/*
* Give the local databases a chance to
* checkpoint their data.
*/
if (verbose)
"Service Checkpoint...");
if (checkpoint_log()) {
if (verbose)
"checkpoint succeeded.");
} else if (verbose)
}
}
/* Not reached */
}
#define NO_ENTRY_OBJS 96
void *
callback_thread(void *varg) {
char *table;
int i;
if (verbose)
else
/* If we couldn't create a client handle we're hosed */
if (! cback) {
return (0);
}
cbres = 0;
queued = 0;
else
queued++;
} else {
if (d_obj) {
queued++;
}
}
/*
* the object is either already assigned to
* cbarray or destroyed.
*/
if (queued == NO_ENTRY_OBJS) {
if (verbose)
"list: sent entry, status = %s",
for (i = 0; i < NO_ENTRY_OBJS; i++) {
}
queued = 0;
"nis_list_svc: callback to %s returned %s",
}
break;
}
}
/*
* Note: that the db_next_entry function will
* free this data. Technically this is an error
* but it is convienient.
*/
}
if (queued) {
"nis_list_svc: callback to %s returned %s",
for (i = 0; i < queued; i++)
}
if (status != RPC_SUCCESS) {
if (status == RPC_AUTHERROR) {
"Authentication ERROR in talking to %s.",
arg->cbhostname);
} else {
"RPC ERROR in talking to %s.",
arg->cbhostname);
}
xdr_nis_error, (char *)&result,
} else {
xdr_void, (char *)(0),
}
}
/* Our parent thread allocated this, but it's our job to deallocate */
/*
* The periodic thread cleanup (or the TSD destructor, if all else
* fails) will take care of the loose ends
*/
return (0);
}
/* From nis_xx_proc.c */
#define CB_BUF_SIZE 128
/*
* Perform the actual dump work on behalf of nis_dump_svc().
*/
void *
dumpsvc_thread(void *varg) {
int i, queued_objs;
int cbres = 0;
char namebuf[1024];
int totlobjs = 0;
int skipobjs = 0;
long boost = 0;
if (arg == 0)
return (0);
queued_objs = 0;
if (verbose)
NULL);
"nis_dump_svc (child): Couldn't read table '%s'",
while (! cbres) {
}
skipobjs++;
} else {
totlobjs++;
}
/*
* This won't be true should we skip
* recent updates but let's test for
* it anyway.
*/
if (queued_objs == CB_BUF_SIZE) {
for (i = 0; i < CB_BUF_SIZE; i++)
if (rstat != RPC_SUCCESS) {
"nis_dump_svc (child): Callback failed with RPC error %s.",
return (0);
}
queued_objs = 0;
}
break;
}
}
if (queued_objs) {
if (! cbres) {
xdr_cback_data, (char *)&cbarg,
if (rstat != RPC_SUCCESS) {
"nis_dump_svc (child): Callback failed with RPC error %s.",
return (0);
}
}
for (i = 0; i < queued_objs; i++)
queued_objs = 0;
}
boost = 0; /* on to next table */
}
if (verbose)
tv);
/*
* Since the callback function handling this FINISH rpc
* call does not reply, so we basically ignore it if a
* RPC_TIMEDOUT message is returned. Only log other types
* of non-successful messages.
*/
"nis_dump_svc[%d]: Finish handshake returned %s",
}
return (0);
}