Optimize grantpt.

grantpt was performing two consecutive calls to stat with the same
file name.  Avoid this by creating a special version of the ptsname
function which allows to pass the stat result back to the caller.
This commit is contained in:
Ulrich Drepper 2009-11-24 18:50:32 -08:00
parent 0f622686af
commit aa9890239a
4 changed files with 38 additions and 21 deletions

View file

@ -1,5 +1,15 @@
2009-11-24 Ulrich Drepper <drepper@redhat.com>
* sysdeps/unix/grantpt.c (pts_name): Take additional parameter,
pass it on to __ptsname_internal.
(grantpt): Pass stat64 pointer to pts_name. Remove stat call here.
* sysdeps/unix/sysv/linux/ptsname.c (__ptsname_internal): New function.
All the code from __ptsname_r but take additional parameter. Use that
instead of pointer to local stat64 variable.
(__ptsname_r): Call __ptsname_internal with pointer to local stat64
variable.
* include/stdlib.h: Declare __ptsname_internal.
* sysdeps/unix/grantpt.c (grantpt): Use CLOSE_ALL_FDS is available
before the exec.
* sysdeps/unix/sysv/linux/grantpt.c: New file.

View file

@ -9,6 +9,7 @@
/* Now define the internal interfaces. */
#ifndef __Need_M_And_C
# include <sys/stat.h>
__BEGIN_DECLS
@ -77,6 +78,8 @@ extern int __clearenv (void);
extern char *__canonicalize_file_name (__const char *__name);
extern char *__realpath (__const char *__name, char *__resolved);
extern int __ptsname_r (int __fd, char *__buf, size_t __buflen);
extern int __ptsname_internal (int fd, char *buf, size_t buflen,
struct stat64 *stp);
extern int __getpt (void);
extern int __posix_openpt (int __oflag);

View file

@ -38,7 +38,7 @@
this buffer, a sufficiently long buffer is allocated using malloc,
and returned in PTS. 0 is returned upon success, -1 otherwise. */
static int
pts_name (int fd, char **pts, size_t buf_len)
pts_name (int fd, char **pts, size_t buf_len, struct stat64 *stp)
{
int rv;
char *buf = *pts;
@ -49,7 +49,7 @@ pts_name (int fd, char **pts, size_t buf_len)
if (buf_len)
{
rv = __ptsname_r (fd, buf, buf_len);
rv = __ptsname_internal (fd, buf, buf_len, stp);
if (rv != 0)
{
if (rv == ENOTTY)
@ -107,8 +107,9 @@ grantpt (int fd)
char _buf[512];
#endif
char *buf = _buf;
struct stat64 st;
if (__builtin_expect (pts_name (fd, &buf, sizeof (_buf)), 0))
if (__builtin_expect (pts_name (fd, &buf, sizeof (_buf), &st), 0))
{
int save_errno = errno;
@ -127,10 +128,6 @@ grantpt (int fd)
return -1;
}
struct stat64 st;
if (__xstat64 (_STAT_VER, buf, &st) < 0)
goto cleanup;
/* Make sure that we own the device. */
uid_t uid = __getuid ();
if (st.st_uid != uid)

View file

@ -1,4 +1,4 @@
/* Copyright (C) 1998, 2000, 2001, 2002 Free Software Foundation, Inc.
/* Copyright (C) 1998, 2000, 2001, 2002, 2009 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Zack Weinberg <zack@rabi.phys.columbia.edu>, 1998.
@ -67,14 +67,10 @@ ptsname (int fd)
}
/* Store at most BUFLEN characters of the pathname of the slave pseudo
terminal associated with the master FD is open on in BUF.
Return 0 on success, otherwise an error number. */
int
__ptsname_r (int fd, char *buf, size_t buflen)
__ptsname_internal (int fd, char *buf, size_t buflen, struct stat64 *stp)
{
int save_errno = errno;
struct stat64 st;
unsigned int ptyno;
if (buf == NULL)
@ -93,7 +89,7 @@ __ptsname_r (int fd, char *buf, size_t buflen)
if (__ioctl (fd, TIOCGPTN, &ptyno) == 0)
{
/* Buffer we use to print the number in. For a maximum size for
`int' of 8 bytes we never need more than 20 digits. */
`int' of 8 bytes we never need more than 20 digits. */
char numbuf[21];
const char *devpts = _PATH_DEVPTS;
const size_t devptslen = strlen (_PATH_DEVPTS);
@ -121,20 +117,20 @@ __ptsname_r (int fd, char *buf, size_t buflen)
return ERANGE;
}
if (__fxstat64 (_STAT_VER, fd, &st) < 0)
if (__fxstat64 (_STAT_VER, fd, stp) < 0)
return errno;
/* Check if FD really is a master pseudo terminal. */
if (! MASTER_P (st.st_rdev))
if (! MASTER_P (stp->st_rdev))
{
__set_errno (ENOTTY);
return ENOTTY;
}
ptyno = minor (st.st_rdev);
ptyno = minor (stp->st_rdev);
/* This is for the old BSD pseudo terminals. As of Linux
2.1.115 these are no longer supported. */
if (major (st.st_rdev) == 4)
2.1.115 these are no longer supported. */
if (major (stp->st_rdev) == 4)
ptyno -= 128;
if (ptyno / 16 >= strlen (__libc_ptyname1))
@ -149,12 +145,12 @@ __ptsname_r (int fd, char *buf, size_t buflen)
p[2] = '\0';
}
if (__xstat64 (_STAT_VER, buf, &st) < 0)
if (__xstat64 (_STAT_VER, buf, stp) < 0)
return errno;
/* Check if the name we're about to return really corresponds to a
slave pseudo terminal. */
if (! S_ISCHR (st.st_mode) || ! SLAVE_P (st.st_rdev))
if (! S_ISCHR (stp->st_mode) || ! SLAVE_P (stp->st_rdev))
{
/* This really is a configuration problem. */
__set_errno (ENOTTY);
@ -164,4 +160,15 @@ __ptsname_r (int fd, char *buf, size_t buflen)
__set_errno (save_errno);
return 0;
}
/* Store at most BUFLEN characters of the pathname of the slave pseudo
terminal associated with the master FD is open on in BUF.
Return 0 on success, otherwise an error number. */
int
__ptsname_r (int fd, char *buf, size_t buflen)
{
struct stat64 st;
return __ptsname_internal (fd, buf, buflen, &st);
}
weak_alias (__ptsname_r, ptsname_r)