* nis/nss_nis/nis-service.c: Avoid passing pointer to static

variable around.  Reduce number of memory allocations by creating
	list of memory pools.
This commit is contained in:
Ulrich Drepper 2006-04-28 18:42:24 +00:00
parent 912873399c
commit 4718026de2
2 changed files with 104 additions and 40 deletions

View File

@ -1,5 +1,9 @@
2006-04-28 Ulrich Drepper <drepper@redhat.com> 2006-04-28 Ulrich Drepper <drepper@redhat.com>
* nis/nss_nis/nis-service.c: Avoid passing pointer to static
variable around. Reduce number of memory allocations by creating
list of memory pools.
* nis/ypclnt.c (__xdr_ypresp_all): Minor optimization in string * nis/ypclnt.c (__xdr_ypresp_all): Minor optimization in string
handling. Fix typo in comment. handling. Fix typo in comment.

View File

@ -40,17 +40,18 @@ __libc_lock_define_initialized (static, lock)
struct response_t struct response_t
{ {
struct response_t *next; struct response_t *next;
char val[0]; size_t size;
char mem[0];
}; };
struct intern_t typedef struct intern_t
{ {
struct response_t *start; struct response_t *start;
struct response_t *next; struct response_t *next;
}; size_t offset;
typedef struct intern_t intern_t; } intern_t;
static intern_t intern = { NULL, NULL }; static intern_t intern;
struct search_t struct search_t
{ {
@ -68,26 +69,50 @@ static int
saveit (int instatus, char *inkey, int inkeylen, char *inval, saveit (int instatus, char *inkey, int inkeylen, char *inval,
int invallen, char *indata) int invallen, char *indata)
{ {
intern_t *intern = (intern_t *) indata;
if (instatus != YP_TRUE) if (instatus != YP_TRUE)
return 1; return 1;
if (inkey && inkeylen > 0 && inval && invallen > 0) if (inkey && inkeylen > 0 && inval && invallen > 0)
{ {
struct response_t *newp = malloc (sizeof (struct response_t) struct response_t *bucket = intern.next;
+ invallen + 1);
if (newp == NULL)
return 1; /* We have no error code for out of memory */
if (intern->start == NULL) if (__builtin_expect (bucket == NULL, 0))
intern->start = newp; {
else #define MINSIZE 4096 - 4 * sizeof (void *)
intern->next->next = newp; const size_t minsize = MAX (MINSIZE, 2 * (invallen + 1));
intern->next = newp; bucket = malloc (sizeof (struct response_t) + minsize);
if (bucket == NULL)
/* We have no error code for out of memory. */
return 1;
newp->next = NULL; bucket->next = NULL;
*((char *) mempcpy (newp->val, inval, invallen)) = '\0'; bucket->size = minsize;
intern.start = intern.next = bucket;
intern.offset = 0;
}
else if (__builtin_expect (invallen + 1 > bucket->size - intern.offset,
0))
{
/* We need a new (larger) buffer. */
const size_t newsize = 2 * MAX (bucket->size, invallen + 1);
struct response_t *newp = malloc (sizeof (struct response_t)
+ newsize);
if (newp == NULL)
/* We have no error code for out of memory. */
return 1;
/* Mark the old bucket as full. */
bucket->size = intern.offset;
newp->next = NULL;
newp->size = newsize;
bucket = intern.next = bucket->next = newp;
intern.offset = 0;
}
*((char *) mempcpy (&bucket->mem[intern.offset], inval, invallen))
= '\0';
intern.offset += invallen + 1;
} }
return 0; return 0;
@ -153,15 +178,19 @@ dosearch (int instatus, char *inkey, int inkeylen, char *inval,
} }
static enum nss_status static enum nss_status
internal_nis_endservent (intern_t * intern) internal_nis_endservent (void)
{ {
while (intern->start != NULL) struct response_t *curr = intern.next;
while (curr != NULL)
{ {
intern->next = intern->start; struct response_t *last = curr;
intern->start = intern->start->next; curr = curr->next;
free (intern->next); free (last);
} }
intern.next = intern.start = NULL;
return NSS_STATUS_SUCCESS; return NSS_STATUS_SUCCESS;
} }
@ -172,7 +201,7 @@ _nss_nis_endservent (void)
__libc_lock_lock (lock); __libc_lock_lock (lock);
status = internal_nis_endservent (&intern); status = internal_nis_endservent ();
__libc_lock_unlock (lock); __libc_lock_unlock (lock);
@ -180,7 +209,7 @@ _nss_nis_endservent (void)
} }
static enum nss_status static enum nss_status
internal_nis_setservent (intern_t *intern) internal_nis_setservent (void)
{ {
char *domainname; char *domainname;
struct ypall_callback ypcb; struct ypall_callback ypcb;
@ -189,12 +218,16 @@ internal_nis_setservent (intern_t *intern)
if (yp_get_default_domain (&domainname)) if (yp_get_default_domain (&domainname))
return NSS_STATUS_UNAVAIL; return NSS_STATUS_UNAVAIL;
(void) internal_nis_endservent (intern); (void) internal_nis_endservent ();
ypcb.foreach = saveit; ypcb.foreach = saveit;
ypcb.data = (char *) intern; ypcb.data = NULL;
status = yperr2nss (yp_all (domainname, "services.byname", &ypcb)); status = yperr2nss (yp_all (domainname, "services.byname", &ypcb));
intern->next = intern->start;
/* Mark the last buffer as full. */
intern.next->size = intern.offset;
intern.next = intern.start;
return status; return status;
} }
@ -206,7 +239,7 @@ _nss_nis_setservent (int stayopen)
__libc_lock_lock (lock); __libc_lock_lock (lock);
status = internal_nis_setservent (&intern); status = internal_nis_setservent ();
__libc_lock_unlock (lock); __libc_lock_unlock (lock);
@ -215,29 +248,56 @@ _nss_nis_setservent (int stayopen)
static enum nss_status static enum nss_status
internal_nis_getservent_r (struct servent *serv, char *buffer, internal_nis_getservent_r (struct servent *serv, char *buffer,
size_t buflen, int *errnop, intern_t *data) size_t buflen, int *errnop)
{ {
struct parser_data *pdata = (void *) buffer; struct parser_data *pdata = (void *) buffer;
int parse_res; int parse_res;
char *p; char *p;
if (data->start == NULL) if (intern.start == NULL)
internal_nis_setservent (data); internal_nis_setservent ();
/* Get the next entry until we found a correct one. */ /* Get the next entry until we found a correct one. */
do do
{ {
if (data->next == NULL) struct response_t *bucket = intern.next;
return NSS_STATUS_NOTFOUND;
p = strncpy (buffer, data->next->val, buflen); if (intern.offset >= bucket->size)
while (isspace (*p)) {
++p; if (bucket->next == NULL)
return NSS_STATUS_NOTFOUND;
/* We look at all the content in the current bucket. Go on
to the next. */
bucket = intern.next = bucket->next;
intern.offset = 0;
}
for (p = &bucket->mem[intern.offset]; isspace (*p); ++p)
++intern.offset;
size_t len = strlen (p) + 1;
if (__builtin_expect (len > buflen, 0))
{
*errnop = ERANGE;
return NSS_STATUS_TRYAGAIN;
}
/* We unfortunately have to copy the data in the user-provided
buffer because that buffer might be around for a very long
time and the servent structure must remain valid. If we would
rely on the BUCKET memory the next 'setservent' or 'endservent'
call would destroy it.
The important thing is that it is a single NUL-terminated
string. This is what the parsing routine expects. */
p = memcpy (buffer, &bucket->mem[intern.offset], len);
parse_res = _nss_files_parse_servent (p, serv, pdata, buflen, errnop); parse_res = _nss_files_parse_servent (p, serv, pdata, buflen, errnop);
if (__builtin_expect (parse_res == -1, 0)) if (__builtin_expect (parse_res == -1, 0))
return NSS_STATUS_TRYAGAIN; return NSS_STATUS_TRYAGAIN;
data->next = data->next->next;
intern.offset += len;
} }
while (!parse_res); while (!parse_res);
@ -252,7 +312,7 @@ _nss_nis_getservent_r (struct servent *serv, char *buffer, size_t buflen,
__libc_lock_lock (lock); __libc_lock_lock (lock);
status = internal_nis_getservent_r (serv, buffer, buflen, errnop, &intern); status = internal_nis_getservent_r (serv, buffer, buflen, errnop);
__libc_lock_unlock (lock); __libc_lock_unlock (lock);