(root)/
glibc-2.38/
hurd/
report-wait.c
       1  /* Report on what a thread in our task is waiting for.
       2     Copyright (C) 1996-2023 Free Software Foundation, Inc.
       3     This file is part of the GNU C Library.
       4  
       5     The GNU C Library is free software; you can redistribute it and/or
       6     modify it under the terms of the GNU Lesser General Public
       7     License as published by the Free Software Foundation; either
       8     version 2.1 of the License, or (at your option) any later version.
       9  
      10     The GNU C Library is distributed in the hope that it will be useful,
      11     but WITHOUT ANY WARRANTY; without even the implied warranty of
      12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      13     Lesser General Public License for more details.
      14  
      15     You should have received a copy of the GNU Lesser General Public
      16     License along with the GNU C Library; if not, see
      17     <https://www.gnu.org/licenses/>.  */
      18  
      19  #include <hurd.h>
      20  #include <hurd/signal.h>
      21  #include <hurd/fd.h>
      22  #include <string.h>
      23  #include <assert.h>
      24  #include <hurd/msg_server.h>
      25  #include <thread_state.h>
      26  #include <intr-msg.h>
      27  
      28  static char *
      29  describe_number (char *description, const char *flavor, long int i, size_t size)
      30  {
      31    unsigned long int j;
      32    char *limit = description + size;
      33    char *p = flavor == NULL ? description : __stpncpy (description, flavor, size);
      34    char *end;
      35  
      36    if (p == limit)
      37      return p;
      38  
      39    /* Handle sign.  */
      40    if (i < 0)
      41      {
      42        i = -i;
      43        *p++ = '-';
      44      }
      45  
      46    if (p == limit)
      47      return p;
      48  
      49    /* Allocate space for the number at the end of DESCRIPTION.  */
      50    for (j = i; j >= 10; j /= 10)
      51      p++;
      52    end = p + 1;
      53  
      54    if (end < limit)
      55      *end = '\0';
      56    else
      57      end = limit;
      58  
      59    do
      60      {
      61        if (p < limit)
      62  	*p = '0' + i % 10;
      63        p--;
      64        i /= 10;
      65      } while (i != 0);
      66  
      67    return end;
      68  }
      69  
      70  static char *
      71  describe_port (char *description, mach_port_t port, size_t size)
      72  {
      73    int i;
      74  
      75    if (port == MACH_PORT_NULL)
      76      return __stpncpy (description, "(null)", size);
      77    if (port == MACH_PORT_DEAD)
      78      return __stpncpy (description, "(dead)", size);
      79  
      80    if (port == __mach_task_self ())
      81      return __stpncpy (description, "task-self", size);
      82  
      83    for (i = 0; i < _hurd_nports; ++i)
      84      if (port == _hurd_ports[i].port)
      85        return describe_number (description, "init#", i, size);
      86  
      87    if (_hurd_init_dtable)
      88      {
      89        for (i = 0; i < _hurd_init_dtablesize; ++i)
      90  	if (port == _hurd_init_dtable[i])
      91  	  return describe_number (description, "fd#", i, size);
      92      }
      93    if (_hurd_dtable)
      94      {
      95        for (i = 0; i < _hurd_dtablesize; ++i)
      96  	if (_hurd_dtable[i] == NULL)
      97  	  continue;
      98  	else if (port == _hurd_dtable[i]->port.port)
      99  	  return describe_number (description, "fd#", i, size);
     100  	else if (port == _hurd_dtable[i]->ctty.port)
     101  	  return describe_number (description, "bgfd#", i, size);
     102      }
     103  
     104    return describe_number (description, "port#", port, size);
     105  }
     106  
     107  
     108  /* We want _HURD_ITIMER_THREAD, but don't want to link in the itimer code
     109     unnecessarily.  */
     110  extern thread_t _hurd_itimer_thread; /* XXX */
     111  weak_extern (_hurd_itimer_thread)
     112  
     113  kern_return_t
     114  _S_msg_report_wait (mach_port_t msgport, thread_t thread,
     115  		    string_t description, mach_msg_id_t *msgid)
     116  {
     117    char *limit = description + 1024; /* XXX */
     118    char *cur = description;
     119    *msgid = 0;
     120  
     121    if (thread == _hurd_msgport_thread)
     122      /* Cute.  */
     123      cur = __stpncpy (cur, "msgport", limit - cur);
     124    else if (&_hurd_itimer_thread && thread == _hurd_itimer_thread)
     125      cur = __stpncpy (cur, "itimer", limit - cur);
     126    else
     127      {
     128        /* Make sure this is really one of our threads.  */
     129  
     130        struct hurd_sigstate *ss;
     131  
     132        __mutex_lock (&_hurd_siglock);
     133        for (ss = _hurd_sigstates; ss != NULL; ss = ss->next)
     134  	if (ss->thread == thread)
     135  	  break;
     136        __mutex_unlock (&_hurd_siglock);
     137        if (ss == NULL)
     138  	/* To hell with you.  */
     139  	return EINVAL;
     140  
     141        if (ss->suspended != MACH_PORT_NULL)
     142  	cur = __stpncpy (cur, "sigsuspend", limit - cur);
     143        else
     144  	{
     145  	  /* Examine the thread's state to see if it is blocked in an RPC.  */
     146  
     147  	  struct machine_thread_state state;
     148  	  mach_msg_type_number_t count = MACHINE_THREAD_STATE_COUNT;
     149  	  error_t err;
     150  
     151  	  err = __thread_get_state (thread, MACHINE_THREAD_STATE_FLAVOR,
     152  				    (natural_t *) &state, &count);
     153  	  if (err)
     154  	    return err;
     155  	  assert (count == MACHINE_THREAD_STATE_COUNT);
     156  	  if (SYSCALL_EXAMINE (&state, msgid))
     157  	    {
     158  	      mach_port_t send_port, rcv_port;
     159  	      mach_msg_option_t option;
     160  	      mach_msg_timeout_t timeout;
     161  
     162  	      /* Blocked in a system call.  */
     163  	      if (*msgid == -25
     164  		  /* mach_msg system call.  Examine its parameters.  */
     165  		  && MSG_EXAMINE (&state, msgid, &rcv_port, &send_port,
     166  				  &option, &timeout) == 0)
     167  		{
     168  		  if (send_port != MACH_PORT_NULL && *msgid != 0)
     169  		    {
     170  		      /* For the normal case of RPCs, we consider the
     171  			 destination port to be the interesting thing
     172  			 whether we are in fact sending or receiving at the
     173  			 moment.  That tells us who we are waiting for the
     174  			 reply from.  */
     175  		      if (send_port == ss->intr_port)
     176  			{
     177  			  /* This is a Hurd interruptible RPC.
     178  			     Mark it by surrounding the port description
     179  			     string with [...] brackets.  */
     180  			  if (cur < limit)
     181  			    *cur++ = '[';
     182  			  cur = describe_port (cur, send_port, limit - cur);
     183  			  if (cur < limit)
     184  			    *cur++ = ']';
     185  			}
     186  		      else
     187  			cur = describe_port (cur, send_port, limit - cur);
     188  		    }
     189  		  else if (rcv_port != MACH_PORT_NULL)
     190  		    {
     191  		      /* This system call had no send port, but had a
     192  			 receive port.  The msgid we extracted is then just
     193  			 some garbage or perhaps the msgid of the last
     194  			 message this thread received, but it's not a
     195  			 helpful thing to return.  */
     196  		      cur = describe_port (cur, rcv_port, limit - cur);
     197  		      cur = __stpncpy (cur, ":rcv", limit - cur);
     198  		      *msgid = 0;
     199  		    }
     200  		  else if ((option & (MACH_RCV_MSG|MACH_RCV_TIMEOUT))
     201  			   == (MACH_RCV_MSG|MACH_RCV_TIMEOUT))
     202  		    {
     203  		      /* A receive with no valid port can be used for a
     204  			 pure timeout.  Report the timeout value (counted
     205  			 in milliseconds); note this is the original total
     206  			 time, not the time remaining.  */
     207  		      cur = describe_number (cur, 0, timeout, limit - cur);
     208  		      cur = __stpncpy (cur, "ms", limit - cur);
     209  		      *msgid = 0;
     210  		    }
     211  		  else
     212  		    {
     213  		      cur = __stpncpy (cur, "mach_msg", limit - cur);
     214  		      *msgid = 0;
     215  		    }
     216  		}
     217  	      else		/* Some other system call.  */
     218  		{
     219  		  cur = describe_number (cur, "syscall#", *msgid, limit - cur);
     220  		  *msgid = 0;
     221  		}
     222  	    }
     223  	}
     224      }
     225  
     226    __mach_port_deallocate (__mach_task_self (), thread);
     227  
     228    if (cur == limit)
     229      return ENOMEM;
     230  
     231    *cur = '\0';
     232    return 0;
     233  }
     234  
     235  kern_return_t
     236  _S_msg_describe_ports (mach_port_t msgport, mach_port_t refport,
     237  		       const mach_port_t *ports, mach_msg_type_number_t nports,
     238  		       char **desc, mach_msg_type_number_t *desclen)
     239  {
     240    char *p, *end;
     241  
     242    if (__USEPORT (AUTH, msgport != port))
     243      return EPERM;
     244  
     245    end = *desc + *desclen;
     246    p = *desc;
     247    while (nports-- > 0)
     248      {
     249        char this[200];
     250        describe_port (this, *ports++, sizeof this);
     251        p = __stpncpy (p, this, end - p);
     252        if (p == end && p[-1] != '\0')
     253  	return ENOMEM;
     254      }
     255  
     256    *desclen = p - *desc;
     257    return 0;
     258  }