nis: Fix leak on realloc failure in nis_getnames [BZ #28150]
[glibc.git] / hurd / report-wait.c
blob7d28a41b6c4bff97dfd32f169ae15fa9bba5d979
1 /* Report on what a thread in our task is waiting for.
2 Copyright (C) 1996-2021 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
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.
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.
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/>. */
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>
28 static char *
29 describe_number (char *description, const char *flavor, long int i, size_t size)
31 unsigned long int j;
32 char *limit = description + size;
33 char *p = flavor == NULL ? description : __stpncpy (description, flavor, size);
34 char *end;
36 if (p == limit)
37 return p;
39 /* Handle sign. */
40 if (i < 0)
42 i = -i;
43 *p++ = '-';
46 if (p == limit)
47 return p;
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;
54 if (end < limit)
55 *end = '\0';
56 else
57 end = limit;
61 if (p < limit)
62 *p = '0' + i % 10;
63 p--;
64 i /= 10;
65 } while (i != 0);
67 return end;
70 static char *
71 describe_port (char *description, mach_port_t port, size_t size)
73 int i;
75 if (port == MACH_PORT_NULL)
76 return __stpncpy (description, "(null)", size);
77 if (port == MACH_PORT_DEAD)
78 return __stpncpy (description, "(dead)", size);
80 if (port == __mach_task_self ())
81 return __stpncpy (description, "task-self", size);
83 for (i = 0; i < _hurd_nports; ++i)
84 if (port == _hurd_ports[i].port)
85 return describe_number (description, "init#", i, size);
87 if (_hurd_init_dtable)
89 for (i = 0; i < _hurd_init_dtablesize; ++i)
90 if (port == _hurd_init_dtable[i])
91 return describe_number (description, "fd#", i, size);
93 if (_hurd_dtable)
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);
104 return describe_number (description, "port#", port, size);
108 /* We want _HURD_ITIMER_THREAD, but don't want to link in the itimer code
109 unnecessarily. */
110 #if 0 /* libc.so.0.0 needs this defined, so make it a weak alias for now. */
111 extern thread_t _hurd_itimer_thread; /* XXX */
112 weak_extern (_hurd_itimer_thread)
113 #else
114 static thread_t default_hurd_itimer_thread;
115 weak_alias (default_hurd_itimer_thread, _hurd_itimer_thread)
116 #endif
118 kern_return_t
119 _S_msg_report_wait (mach_port_t msgport, thread_t thread,
120 string_t description, mach_msg_id_t *msgid)
122 char *limit = description + 1024; /* XXX */
123 char *cur = description;
124 *msgid = 0;
126 if (thread == _hurd_msgport_thread)
127 /* Cute. */
128 cur = __stpncpy (cur, "msgport", limit - cur);
129 else if (&_hurd_itimer_thread && thread == _hurd_itimer_thread)
130 cur = __stpncpy (cur, "itimer", limit - cur);
131 else
133 /* Make sure this is really one of our threads. */
135 struct hurd_sigstate *ss;
137 __mutex_lock (&_hurd_siglock);
138 for (ss = _hurd_sigstates; ss != NULL; ss = ss->next)
139 if (ss->thread == thread)
140 break;
141 __mutex_unlock (&_hurd_siglock);
142 if (ss == NULL)
143 /* To hell with you. */
144 return EINVAL;
146 if (ss->suspended != MACH_PORT_NULL)
147 cur = __stpncpy (cur, "sigsuspend", limit - cur);
148 else
150 /* Examine the thread's state to see if it is blocked in an RPC. */
152 struct machine_thread_state state;
153 mach_msg_type_number_t count = MACHINE_THREAD_STATE_COUNT;
154 error_t err;
156 err = __thread_get_state (thread, MACHINE_THREAD_STATE_FLAVOR,
157 (natural_t *) &state, &count);
158 if (err)
159 return err;
160 assert (count == MACHINE_THREAD_STATE_COUNT);
161 if (SYSCALL_EXAMINE (&state, msgid))
163 mach_port_t send_port, rcv_port;
164 mach_msg_option_t option;
165 mach_msg_timeout_t timeout;
167 /* Blocked in a system call. */
168 if (*msgid == -25
169 /* mach_msg system call. Examine its parameters. */
170 && MSG_EXAMINE (&state, msgid, &rcv_port, &send_port,
171 &option, &timeout) == 0)
173 if (send_port != MACH_PORT_NULL && *msgid != 0)
175 /* For the normal case of RPCs, we consider the
176 destination port to be the interesting thing
177 whether we are in fact sending or receiving at the
178 moment. That tells us who we are waiting for the
179 reply from. */
180 if (send_port == ss->intr_port)
182 /* This is a Hurd interruptible RPC.
183 Mark it by surrounding the port description
184 string with [...] brackets. */
185 if (cur < limit)
186 *cur++ = '[';
187 cur = describe_port (cur, send_port, limit - cur);
188 if (cur < limit)
189 *cur++ = ']';
191 else
192 cur = describe_port (cur, send_port, limit - cur);
194 else if (rcv_port != MACH_PORT_NULL)
196 /* This system call had no send port, but had a
197 receive port. The msgid we extracted is then just
198 some garbage or perhaps the msgid of the last
199 message this thread received, but it's not a
200 helpful thing to return. */
201 cur = describe_port (cur, rcv_port, limit - cur);
202 cur = __stpncpy (cur, ":rcv", limit - cur);
203 *msgid = 0;
205 else if ((option & (MACH_RCV_MSG|MACH_RCV_TIMEOUT))
206 == (MACH_RCV_MSG|MACH_RCV_TIMEOUT))
208 /* A receive with no valid port can be used for a
209 pure timeout. Report the timeout value (counted
210 in milliseconds); note this is the original total
211 time, not the time remaining. */
212 cur = describe_number (cur, 0, timeout, limit - cur);
213 cur = __stpncpy (cur, "ms", limit - cur);
214 *msgid = 0;
216 else
218 cur = __stpncpy (cur, "mach_msg", limit - cur);
219 *msgid = 0;
222 else /* Some other system call. */
224 cur = describe_number (cur, "syscall#", *msgid, limit - cur);
225 *msgid = 0;
231 __mach_port_deallocate (__mach_task_self (), thread);
233 if (cur == limit)
234 return ENOMEM;
236 *cur = '\0';
237 return 0;
240 kern_return_t
241 _S_msg_describe_ports (mach_port_t msgport, mach_port_t refport,
242 mach_port_t *ports, mach_msg_type_number_t nports,
243 char **desc, mach_msg_type_number_t *desclen)
245 char *p, *end;
247 if (__USEPORT (AUTH, msgport != port))
248 return EPERM;
250 end = *desc + *desclen;
251 p = *desc;
252 while (nports-- > 0)
254 char this[200];
255 describe_port (this, *ports++, sizeof this);
256 p = __stpncpy (p, this, end - p);
257 if (p == end && p[-1] != '\0')
258 return ENOMEM;
261 *desclen = p - *desc;
262 return 0;