(root)/
glibc-2.38/
hurd/
alloc-fd.c
       1  /* Copyright (C) 1994-2023 Free Software Foundation, Inc.
       2     This file is part of the GNU C Library.
       3  
       4     The GNU C Library is free software; you can redistribute it and/or
       5     modify it under the terms of the GNU Lesser General Public
       6     License as published by the Free Software Foundation; either
       7     version 2.1 of the License, or (at your option) any later version.
       8  
       9     The GNU C Library is distributed in the hope that it will be useful,
      10     but WITHOUT ANY WARRANTY; without even the implied warranty of
      11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      12     Lesser General Public License for more details.
      13  
      14     You should have received a copy of the GNU Lesser General Public
      15     License along with the GNU C Library; if not, see
      16     <https://www.gnu.org/licenses/>.  */
      17  
      18  #include <hurd.h>
      19  #include <hurd/fd.h>
      20  #include <hurd/resource.h>
      21  #include <stdlib.h>
      22  #include "hurdmalloc.h"		/* XXX */
      23  
      24  /* Allocate a new file descriptor and return it, locked.  The new
      25     descriptor number will be no less than FIRST_FD.  If the table is full,
      26     set errno to EMFILE and return NULL.  If FIRST_FD is negative or bigger
      27     than the size of the table, set errno to EINVAL and return NULL.  */
      28  
      29  struct hurd_fd *
      30  _hurd_alloc_fd (int *fd, int first_fd)
      31  {
      32    int i;
      33    void *crit;
      34    long int rlimit;
      35  
      36    if (first_fd < 0)
      37      return __hurd_fail (EINVAL), NULL;
      38  
      39    crit = _hurd_critical_section_lock ();
      40  
      41    __mutex_lock (&_hurd_dtable_lock);
      42  
      43   search:
      44    for (i = first_fd; i < _hurd_dtablesize; ++i)
      45      {
      46        struct hurd_fd *d = _hurd_dtable[i];
      47        if (d == NULL)
      48  	{
      49  	  /* Allocate a new descriptor structure for this slot,
      50  	     initializing its port cells to nil.  The test below will catch
      51  	     and return this descriptor cell after locking it.  */
      52  	  d = _hurd_new_fd (MACH_PORT_NULL, MACH_PORT_NULL);
      53  	  if (d == NULL)
      54  	    {
      55  	      __mutex_unlock (&_hurd_dtable_lock);
      56  	      _hurd_critical_section_unlock (crit);
      57  	      return NULL;
      58  	    }
      59  	  _hurd_dtable[i] = d;
      60  	}
      61  
      62        __spin_lock (&d->port.lock);
      63        if (d->port.port == MACH_PORT_NULL)
      64  	{
      65  	  __mutex_unlock (&_hurd_dtable_lock);
      66  	  _hurd_critical_section_unlock (crit);
      67  	  if (fd != NULL)
      68  	    *fd = i;
      69  	  return d;
      70  	}
      71        else
      72  	__spin_unlock (&d->port.lock);
      73      }
      74  
      75    __mutex_lock (&_hurd_rlimit_lock);
      76    rlimit = _hurd_rlimits[RLIMIT_OFILE].rlim_cur;
      77    __mutex_unlock (&_hurd_rlimit_lock);
      78  
      79    if (first_fd < rlimit)
      80      {
      81        /* The descriptor table is full.  Check if we have reached the
      82  	 resource limit, or only the allocated size.  */
      83        if (_hurd_dtablesize < rlimit)
      84  	{
      85  	  /* Enlarge the table.  */
      86  	  int save = errno;
      87  	  struct hurd_fd **new;
      88  	  /* Try to double the table size, but don't exceed the limit,
      89  	     and make sure it exceeds FIRST_FD.  */
      90  	  int size = _hurd_dtablesize * 2;
      91  	  if (size > rlimit)
      92  	    size = rlimit;
      93  	  else if (size <= first_fd)
      94  	    size = first_fd + 1;
      95  
      96  	  if (size * sizeof (*_hurd_dtable) < size)
      97  	    {
      98  	      /* Integer overflow! */
      99  	      __hurd_fail (ENOMEM);
     100  	      goto out;
     101  	    }
     102  
     103  	  /* If we fail to allocate that, decrement the desired size
     104  	     until we succeed in allocating it.  */
     105  	  do
     106  	    new = realloc (_hurd_dtable, size * sizeof (*_hurd_dtable));
     107  	  while (new == NULL && size-- > first_fd);
     108  
     109  	  if (new != NULL)
     110  	    {
     111  	      /* We managed to allocate a new table.  Now install it.  */
     112  	      errno = save;
     113  	      if (first_fd < _hurd_dtablesize)
     114  		first_fd = _hurd_dtablesize;
     115  	      /* Initialize the new slots.  */
     116  	      for (i = _hurd_dtablesize; i < size; ++i)
     117  		new[i] = NULL;
     118  	      _hurd_dtablesize = size;
     119  	      _hurd_dtable = new;
     120  	      /* Go back to the loop to initialize the first new slot.  */
     121  	      goto search;
     122  	    }
     123  	  else
     124  	    __hurd_fail (ENOMEM);
     125  	}
     126        else
     127  	__hurd_fail (EMFILE);
     128      }
     129    else
     130      __hurd_fail (EINVAL);	/* Bogus FIRST_FD value.  */
     131  
     132   out:
     133    __mutex_unlock (&_hurd_dtable_lock);
     134    _hurd_critical_section_unlock (crit);
     135  
     136    return NULL;
     137  }