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