aboutsummaryrefslogtreecommitdiff
path: root/sysdeps/mach/hurd/dup2.c
diff options
context:
space:
mode:
Diffstat (limited to 'sysdeps/mach/hurd/dup2.c')
-rw-r--r--sysdeps/mach/hurd/dup2.c40
1 files changed, 30 insertions, 10 deletions
diff --git a/sysdeps/mach/hurd/dup2.c b/sysdeps/mach/hurd/dup2.c
index f4ec623b05..c4b16698b8 100644
--- a/sysdeps/mach/hurd/dup2.c
+++ b/sysdeps/mach/hurd/dup2.c
@@ -58,8 +58,7 @@ DEFUN(__dup2, (fd, fd2), int fd AND int fd2)
io_t ctty = _hurd_port_get (&d->ctty, &ctty_ulink);
io_t port = _hurd_port_locked_get (&d->port, &ulink); /* Unlocks D. */
- __mutex_lock (&_hurd_dtable_lock);
- if (fd2 < 0 || fd2 >= _hurd_dtablesize)
+ if (fd2 < 0)
{
errno = EBADF;
fd2 = -1;
@@ -67,16 +66,37 @@ DEFUN(__dup2, (fd, fd2), int fd AND int fd2)
else
{
/* Get a hold of the destination descriptor. */
- struct hurd_fd *d2 = _hurd_dtable[fd2];
- if (d2 == NULL)
+ struct hurd_fd *d2;
+
+ if (fd2 >= _hurd_dtablesize)
+ {
+ /* The table is not large enough to hold the destination
+ descriptor. Enlarge it as necessary to allocate this
+ descriptor. */
+ __mutex_unlock (&_hurd_dtable_lock);
+ /* We still hold FD1's lock, but this is safe because
+ _hurd_alloc_fd will only examine the cells starting
+ at FD2. */
+ d2 = _hurd_alloc_fd (NULL, fd2);
+ if (d2)
+ __spin_unlock (&d2->port.lock);
+ __mutex_lock (&_hurd_dtable_lock);
+ }
+ else
{
- /* Must allocate a new one. We don't initialize the port cells
- with this call so that if it fails (out of memory), we will
- not have already added user references for the ports, which we
- would then have to deallocate. */
- d2 = _hurd_dtable[fd2] = _hurd_new_fd (MACH_PORT_NULL,
- MACH_PORT_NULL);
+ d2 = _hurd_dtable[fd2];
+ if (d2 == NULL)
+ {
+ /* Must allocate a new one. We don't initialize the port
+ cells with this call so that if it fails (out of
+ memory), we will not have already added user
+ references for the ports, which we would then have to
+ deallocate. */
+ d2 = _hurd_dtable[fd2] = _hurd_new_fd (MACH_PORT_NULL,
+ MACH_PORT_NULL);
+ }
}
+
if (d2 == NULL)
{
fd2 = -1;