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