Back to index

glibc  2.9
report-wait.c
Go to the documentation of this file.
00001 /* Report on what a thread in our task is waiting for.
00002    Copyright (C) 1996,1997,1999,2002,2005 Free Software Foundation, Inc.
00003    This file is part of the GNU C Library.
00004 
00005    The GNU C Library is free software; you can redistribute it and/or
00006    modify it under the terms of the GNU Lesser General Public
00007    License as published by the Free Software Foundation; either
00008    version 2.1 of the License, or (at your option) any later version.
00009 
00010    The GNU C Library is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY; without even the implied warranty of
00012    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013    Lesser General Public License for more details.
00014 
00015    You should have received a copy of the GNU Lesser General Public
00016    License along with the GNU C Library; if not, write to the Free
00017    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
00018    02111-1307 USA.  */
00019 
00020 #include <hurd.h>
00021 #include <hurd/signal.h>
00022 #include <hurd/fd.h>
00023 #include <string.h>
00024 #include <assert.h>
00025 #include <hurd/msg_server.h>
00026 #include <thread_state.h>
00027 #include <intr-msg.h>
00028 
00029 static char *
00030 describe_number (string_t description, const char *flavor, long int i)
00031 {
00032   unsigned long int j;
00033   char *p = flavor ? description : __stpcpy (description, flavor);
00034   char *end;
00035 
00036   /* Handle sign.  */
00037   if (i < 0)
00038     {
00039       i = -i;
00040       *p++ = '-';
00041     }
00042 
00043   /* Allocate space for the number at the end of DESCRIPTION.  */
00044   for (j = i; j >= 10; j /= 10)
00045     p++;
00046   end = p + 1;
00047   *end = '\0';
00048 
00049   do
00050     {
00051       *p-- = '0' + i % 10;
00052       i /= 10;
00053     } while (i != 0);
00054 
00055   return end;
00056 }
00057 
00058 static char *
00059 describe_port (string_t description, mach_port_t port)
00060 {
00061   int i;
00062 
00063   if (port == MACH_PORT_NULL)
00064     return __stpcpy (description, "(null)");
00065   if (port == MACH_PORT_DEAD)
00066     return __stpcpy (description, "(dead)");
00067 
00068   if (port == __mach_task_self ())
00069     return __stpcpy (description, "task-self");
00070 
00071   for (i = 0; i < _hurd_nports; ++i)
00072     if (port == _hurd_ports[i].port)
00073       return describe_number (description, "init#", i);
00074 
00075   if (_hurd_init_dtable)
00076     {
00077       for (i = 0; i < _hurd_init_dtablesize; ++i)
00078        if (port == _hurd_init_dtable[i])
00079          return describe_number (description, "fd#", i);
00080     }
00081   else if (_hurd_dtable)
00082     {
00083       for (i = 0; i < _hurd_dtablesize; ++i)
00084        if (_hurd_dtable[i] == NULL)
00085          continue;
00086        else if (port == _hurd_dtable[i]->port.port)
00087          return describe_number (description, "fd#", i);
00088        else if (port == _hurd_dtable[i]->ctty.port)
00089          return describe_number (description, "bgfd#", i);
00090     }
00091 
00092   return describe_number (description, "port#", port);
00093 }
00094 
00095 
00096 /* We want _HURD_ITIMER_THREAD, but don't want to link in the itimer code
00097    unnecessarily.  */
00098 #if 0 /* libc.so.0.0 needs this defined, so make it a weak alias for now.  */
00099 extern thread_t _hurd_itimer_thread; /* XXX */
00100 weak_extern (_hurd_itimer_thread)
00101 #else
00102 static thread_t default_hurd_itimer_thread;
00103 weak_alias (default_hurd_itimer_thread, _hurd_itimer_thread)
00104 #endif
00105 
00106 kern_return_t
00107 _S_msg_report_wait (mach_port_t msgport, thread_t thread,
00108                   string_t description, mach_msg_id_t *msgid)
00109 {
00110   *msgid = 0;
00111 
00112   if (thread == _hurd_msgport_thread)
00113     /* Cute.  */
00114     strcpy (description, "msgport");
00115   else if (&_hurd_itimer_thread && thread == _hurd_itimer_thread)
00116     strcpy (description, "itimer");
00117   else
00118     {
00119       /* Make sure this is really one of our threads.  */
00120 
00121       struct hurd_sigstate *ss;
00122 
00123       __mutex_lock (&_hurd_siglock);
00124       for (ss = _hurd_sigstates; ss != NULL; ss = ss->next)
00125        if (ss->thread == thread)
00126          break;
00127       __mutex_unlock (&_hurd_siglock);
00128       if (ss == NULL)
00129        /* To hell with you.  */
00130        return EINVAL;
00131 
00132       if (ss->suspended != MACH_PORT_NULL)
00133        strcpy (description, "sigsuspend");
00134       else
00135        {
00136          /* Examine the thread's state to see if it is blocked in an RPC.  */
00137 
00138          struct machine_thread_state state;
00139          mach_msg_type_number_t count = MACHINE_THREAD_STATE_COUNT;
00140          error_t err;
00141 
00142          err = __thread_get_state (thread, MACHINE_THREAD_STATE_FLAVOR,
00143                                 (natural_t *) &state, &count);
00144          if (err)
00145            return err;
00146          assert (count == MACHINE_THREAD_STATE_COUNT);
00147          if (SYSCALL_EXAMINE (&state, msgid))
00148            {
00149              mach_port_t send_port, rcv_port;
00150              mach_msg_option_t option;
00151              mach_msg_timeout_t timeout;
00152 
00153              /* Blocked in a system call.  */
00154              if (*msgid == -25
00155                 /* mach_msg system call.  Examine its parameters.  */
00156                 && MSG_EXAMINE (&state, msgid, &send_port, &rcv_port,
00157                               &option, &timeout) == 0)
00158               {
00159                 char *p;
00160                 if (send_port != MACH_PORT_NULL && *msgid != 0)
00161                   {
00162                     /* For the normal case of RPCs, we consider the
00163                       destination port to be the interesting thing
00164                       whether we are in fact sending or receiving at the
00165                       moment.  That tells us who we are waiting for the
00166                       reply from.  */
00167                     if (send_port == ss->intr_port)
00168                      {
00169                        /* This is a Hurd interruptible RPC.
00170                           Mark it by surrounding the port description
00171                           string with [...] brackets.  */
00172                        description[0] = '[';
00173                        p = describe_port (description + 1, send_port);
00174                        *p++ = ']';
00175                        *p = '\0';
00176                      }
00177                     else
00178                      (void) describe_port (description, send_port);
00179                   }
00180                 else if (rcv_port != MACH_PORT_NULL)
00181                   {
00182                     /* This system call had no send port, but had a
00183                       receive port.  The msgid we extracted is then just
00184                       some garbage or perhaps the msgid of the last
00185                       message this thread received, but it's not a
00186                       helpful thing to return.  */
00187                     strcpy (describe_port (description, rcv_port), ":rcv");
00188                     *msgid = 0;
00189                   }
00190                 else if ((option & (MACH_RCV_MSG|MACH_RCV_TIMEOUT))
00191                         == (MACH_RCV_MSG|MACH_RCV_TIMEOUT))
00192                   {
00193                     /* A receive with no valid port can be used for a
00194                       pure timeout.  Report the timeout value (counted
00195                       in milliseconds); note this is the original total
00196                       time, not the time remaining.  */
00197                     strcpy (describe_number (description, 0, timeout), "ms");
00198                     *msgid = 0;
00199                   }
00200                 else
00201                   {
00202                     strcpy (description, "mach_msg");
00203                     *msgid = 0;
00204                   }
00205               }
00206              else           /* Some other system call.  */
00207               {
00208                 (void) describe_number (description, "syscall#", *msgid);
00209                 *msgid = 0;
00210               }
00211            }
00212          else
00213            description[0] = '\0';
00214        }
00215     }
00216 
00217   __mach_port_deallocate (__mach_task_self (), thread);
00218   return 0;
00219 }
00220 
00221 kern_return_t
00222 _S_msg_describe_ports (mach_port_t msgport, mach_port_t refport,
00223                      mach_port_t *ports, mach_msg_type_number_t nports,
00224                      char **desc, mach_msg_type_number_t *desclen)
00225 {
00226   char *p, *end;
00227 
00228   if (__USEPORT (AUTH, msgport != port))
00229     return EPERM;
00230 
00231   end = *desc + *desclen;
00232   p = *desc;
00233   while (nports-- > 0)
00234     {
00235       char this[200];
00236       describe_port (this, *ports++);
00237       p = __stpncpy (p, this, end - p);
00238       if (p == end && p[-1] != '\0')
00239        return ENOMEM;
00240     }
00241 
00242   *desclen = p - *desc;
00243   return 0;
00244 }