2 * Copyright (c) 1995-1998 John Birrell <jb@cimlogic.com.au>
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by John Birrell.
16 * 4. Neither the name of the author nor the names of any co-contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * $FreeBSD: src/lib/libc_r/uthread/uthread_info.c,v 1.14.2.9 2003/02/15 05:35:31 kris Exp $
43 #include "pthread_private.h"
46 #define NELEMENTS(arr) (sizeof(arr) / sizeof(arr[0]))
49 static void dump_thread(int fd
, pthread_t pthread
, int long_version
);
51 struct s_thread_info
{
52 enum pthread_state state
;
56 /* Static variables: */
57 static const struct s_thread_info thread_info
[] = {
58 {PS_RUNNING
, "Running"},
59 {PS_SIGTHREAD
, "Waiting on signal thread"},
60 {PS_MUTEX_WAIT
, "Waiting on a mutex"},
61 {PS_COND_WAIT
, "Waiting on a condition variable"},
62 {PS_FDLR_WAIT
, "Waiting for a file read lock"},
63 {PS_FDLW_WAIT
, "Waiting for a file write lock"},
64 {PS_FDR_WAIT
, "Waiting for read"},
65 {PS_FDW_WAIT
, "Waiting for write"},
66 {PS_POLL_WAIT
, "Waiting on poll"},
67 {PS_SELECT_WAIT
, "Waiting on select"},
68 {PS_SLEEP_WAIT
, "Sleeping"},
69 {PS_WAIT_WAIT
, "Waiting process"},
70 {PS_SIGSUSPEND
, "Suspended, waiting for a signal"},
71 {PS_SIGWAIT
, "Waiting for a signal"},
72 {PS_SPINBLOCK
, "Waiting for a spinlock"},
73 {PS_JOIN
, "Waiting to join"},
74 {PS_SUSPENDED
, "Suspended"},
76 {PS_DEADLOCK
, "Deadlocked"},
77 {PS_STATE_MAX
, "Not a real state!"}
81 _thread_dump_info(void)
88 char tmpfile
[PATH_MAX
];
91 if (issetugid() != 0 || (tmpdir
= getenv("TMPDIR")) == NULL
)
93 for (i
= 0; i
< 100000; i
++) {
94 snprintf(tmpfile
, sizeof(tmpfile
), "%s/uthread.dump.%u.%i",
96 /* Open the dump file for append and create it if necessary: */
97 if ((fd
= __sys_open(tmpfile
, O_RDWR
| O_CREAT
| O_EXCL
,
99 /* Can't open the dump file. */
103 * We only need to continue in case of
104 * EEXIT error. Most other error
105 * codes means that we will fail all
114 /* all 100000 possibilities are in use :( */
117 /* Output a header for active threads: */
118 strcpy(s
, "\n\n=============\nACTIVE THREADS\n\n");
119 __sys_extpwrite(fd
, s
, strlen(s
), O_FBLOCKING
, -1);
121 /* Enter a loop to report each thread in the global list: */
122 TAILQ_FOREACH(pthread
, &_thread_list
, tle
) {
123 dump_thread(fd
, pthread
, /*long_verson*/ 1);
126 /* Output a header for ready threads: */
127 strcpy(s
, "\n\n=============\nREADY THREADS\n\n");
128 __sys_extpwrite(fd
, s
, strlen(s
), O_FBLOCKING
, -1);
130 /* Enter a loop to report each thread in the ready queue: */
131 TAILQ_FOREACH (pq_list
, &_readyq
.pq_queue
, pl_link
) {
132 TAILQ_FOREACH(pthread
, &pq_list
->pl_head
, pqe
) {
133 dump_thread(fd
, pthread
, /*long_version*/ 0);
137 /* Output a header for waiting threads: */
138 strcpy(s
, "\n\n=============\nWAITING THREADS\n\n");
139 __sys_extpwrite(fd
, s
, strlen(s
), O_FBLOCKING
, -1);
141 /* Enter a loop to report each thread in the waiting queue: */
142 TAILQ_FOREACH (pthread
, &_waitingq
, pqe
) {
143 dump_thread(fd
, pthread
, /*long_version*/ 0);
146 /* Output a header for threads in the work queue: */
147 strcpy(s
, "\n\n=============\nTHREADS IN WORKQ\n\n");
148 __sys_extpwrite(fd
, s
, strlen(s
), O_FBLOCKING
, -1);
150 /* Enter a loop to report each thread in the waiting queue: */
151 TAILQ_FOREACH (pthread
, &_workq
, qe
) {
152 dump_thread(fd
, pthread
, /*long_version*/ 0);
155 /* Check if there are no dead threads: */
156 if (TAILQ_FIRST(&_dead_list
) == NULL
) {
157 /* Output a record: */
158 strcpy(s
, "\n\nTHERE ARE NO DEAD THREADS\n");
159 __sys_extpwrite(fd
, s
, strlen(s
), O_FBLOCKING
, -1);
161 /* Output a header for dead threads: */
162 strcpy(s
, "\n\nDEAD THREADS\n\n");
163 __sys_extpwrite(fd
, s
, strlen(s
), O_FBLOCKING
, -1);
166 * Enter a loop to report each thread in the global
169 TAILQ_FOREACH(pthread
, &_dead_list
, dle
) {
170 dump_thread(fd
, pthread
, /*long_version*/ 0);
174 /* Output a header for file descriptors: */
175 snprintf(s
, sizeof(s
), "\n\n=============\nFILE DESCRIPTOR "
176 "TABLE (table size %d)\n\n", _thread_dtablesize
);
177 __sys_extpwrite(fd
, s
, strlen(s
), O_FBLOCKING
, -1);
179 /* Enter a loop to report file descriptor lock usage: */
180 for (i
= 0; i
< _thread_dtablesize
; i
++) {
182 * Check if memory is allocated for this file
185 if (_thread_fd_table
[i
] != NULL
) {
186 /* Report the file descriptor lock status: */
187 snprintf(s
, sizeof(s
),
188 "fd[%3d] read owner %p count %d [%s:%d]\n"
189 " write owner %p count %d [%s:%d]\n",
190 i
, _thread_fd_table
[i
]->r_owner
,
191 _thread_fd_table
[i
]->r_lockcount
,
192 _thread_fd_table
[i
]->r_fname
,
193 _thread_fd_table
[i
]->r_lineno
,
194 _thread_fd_table
[i
]->w_owner
,
195 _thread_fd_table
[i
]->w_lockcount
,
196 _thread_fd_table
[i
]->w_fname
,
197 _thread_fd_table
[i
]->w_lineno
);
198 __sys_extpwrite(fd
, s
, strlen(s
), O_FBLOCKING
, -1);
202 /* Close the dump file: */
208 dump_thread(int fd
, pthread_t pthread
, int long_version
)
210 struct pthread
*curthread
= _get_curthread();
214 /* Find the state: */
215 for (i
= 0; i
< NELEMENTS(thread_info
) - 1; i
++)
216 if (thread_info
[i
].state
== pthread
->state
)
219 /* Output a record for the thread: */
220 snprintf(s
, sizeof(s
),
221 "--------------------\nThread %p (%s) prio %3d state %s [%s:%d]\n",
222 pthread
, (pthread
->name
== NULL
) ? "" : pthread
->name
,
223 pthread
->active_priority
, thread_info
[i
].name
, pthread
->fname
,
225 __sys_extpwrite(fd
, s
, strlen(s
), O_FBLOCKING
, -1);
227 if (long_version
!= 0) {
228 /* Check if this is the running thread: */
229 if (pthread
== curthread
) {
230 /* Output a record for the running thread: */
231 strcpy(s
, "This is the running thread\n");
232 __sys_extpwrite(fd
, s
, strlen(s
), O_FBLOCKING
, -1);
234 /* Check if this is the initial thread: */
235 if (pthread
== _thread_initial
) {
236 /* Output a record for the initial thread: */
237 strcpy(s
, "This is the initial thread\n");
238 __sys_extpwrite(fd
, s
, strlen(s
), O_FBLOCKING
, -1);
240 /* Process according to thread state: */
241 switch (pthread
->state
) {
242 /* File descriptor read lock wait: */
247 /* Write the lock details: */
248 snprintf(s
, sizeof(s
), "fd %d[%s:%d]",
250 pthread
->data
.fd
.fname
,
251 pthread
->data
.fd
.branch
);
252 __sys_extpwrite(fd
, s
, strlen(s
), O_FBLOCKING
, -1);
255 snprintf(s
, sizeof(s
), "sigmask (hi)");
256 __sys_extpwrite(fd
, s
, strlen(s
), O_FBLOCKING
, -1);
257 for (i
= _SIG_WORDS
- 1; i
>= 0; i
--) {
258 snprintf(s
, sizeof(s
), "%08x\n",
259 pthread
->sigmask
.__bits
[i
]);
260 __sys_extpwrite(fd
, s
, strlen(s
), O_FBLOCKING
, -1);
262 snprintf(s
, sizeof(s
), "(lo)\n");
263 __sys_extpwrite(fd
, s
, strlen(s
), O_FBLOCKING
, -1);
266 * Trap other states that are not explicitly
267 * coded to dump information:
270 /* Nothing to do here. */
276 /* Set the thread name for debug: */
278 _pthread_set_name_np(pthread_t thread
, const char *name
)
280 /* Check if the caller has specified a valid thread: */
281 if (thread
!= NULL
&& thread
->magic
== PTHREAD_MAGIC
) {
282 if (thread
->name
!= NULL
) {
283 /* Free space for previous name. */
286 thread
->name
= strdup(name
);
290 __strong_reference(_pthread_set_name_np
, pthread_set_name_np
);