Fix typo.
[dragonfly.git] / lib / libc_r / uthread / uthread_info.c
blob24890d649a3ac9ae742facd2e852ffce9f55d9d4
1 /*
2 * Copyright (c) 1995-1998 John Birrell <jb@cimlogic.com.au>
3 * All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
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
30 * SUCH DAMAGE.
32 * $FreeBSD: src/lib/libc_r/uthread/uthread_info.c,v 1.14.2.9 2003/02/15 05:35:31 kris Exp $
33 * $DragonFly: src/lib/libc_r/uthread/uthread_info.c,v 1.6 2007/01/08 21:41:53 dillon Exp $
35 #include <errno.h>
36 #include <fcntl.h>
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <string.h>
40 #include <paths.h>
41 #include <pthread.h>
42 #include <unistd.h>
43 #include "pthread_private.h"
45 #ifndef NELEMENTS
46 #define NELEMENTS(arr) (sizeof(arr) / sizeof(arr[0]))
47 #endif
49 static void dump_thread(int fd, pthread_t pthread, int long_version);
51 struct s_thread_info {
52 enum pthread_state state;
53 char *name;
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"},
75 {PS_DEAD , "Dead"},
76 {PS_DEADLOCK , "Deadlocked"},
77 {PS_STATE_MAX , "Not a real state!"}
80 void
81 _thread_dump_info(void)
83 char s[512];
84 int fd;
85 int i;
86 pthread_t pthread;
87 char *tmpdir;
88 char tmpfile[PATH_MAX];
89 pq_list_t *pq_list;
91 if (issetugid() != 0 || (tmpdir = getenv("TMPDIR")) == NULL)
92 tmpdir = _PATH_TMP;
93 for (i = 0; i < 100000; i++) {
94 snprintf(tmpfile, sizeof(tmpfile), "%s/uthread.dump.%u.%i",
95 tmpdir, getpid(), 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,
98 0644)) < 0) {
99 /* Can't open the dump file. */
100 if (errno == EEXIST)
101 continue;
103 * We only need to continue in case of
104 * EEXIT error. Most other error
105 * codes means that we will fail all
106 * the times.
108 return;
109 } else {
110 break;
113 if (i==100000) {
114 /* all 100000 possibilities are in use :( */
115 return;
116 } else {
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);
160 } else {
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
167 * dead thread list:
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
183 * descriptor:
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: */
203 __sys_close(fd);
207 static void
208 dump_thread(int fd, pthread_t pthread, int long_version)
210 struct pthread *curthread = _get_curthread();
211 char s[512];
212 int i;
214 /* Find the state: */
215 for (i = 0; i < NELEMENTS(thread_info) - 1; i++)
216 if (thread_info[i].state == pthread->state)
217 break;
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,
224 pthread->lineno);
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: */
243 case PS_FDLR_WAIT:
244 case PS_FDLW_WAIT:
245 case PS_FDR_WAIT:
246 case PS_FDW_WAIT:
247 /* Write the lock details: */
248 snprintf(s, sizeof(s), "fd %d[%s:%d]",
249 pthread->data.fd.fd,
250 pthread->data.fd.fname,
251 pthread->data.fd.branch);
252 __sys_extpwrite(fd, s, strlen(s), O_FBLOCKING, -1);
253 break;
254 case PS_SIGWAIT:
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);
264 break;
266 * Trap other states that are not explicitly
267 * coded to dump information:
269 default:
270 /* Nothing to do here. */
271 break;
276 /* Set the thread name for debug: */
277 void
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. */
284 free(thread->name);
286 thread->name = strdup(name);
290 __strong_reference(_pthread_set_name_np, pthread_set_name_np);