thr_info.c revision 144518
1/*
2 * Copyright (c) 1995-1998 John Birrell <jb@cimlogic.com.au>
3 * All rights reserved.
4 *
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.
19 *
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.
31 *
32 * $FreeBSD: head/lib/libthr/thread/thr_info.c 144518 2005-04-02 01:20:00Z davidxu $
33 */
34
35#include <stdio.h>
36#include <stdlib.h>
37#include <fcntl.h>
38#include <string.h>
39#include <unistd.h>
40#include <pthread.h>
41#include <errno.h>
42
43#include "thr_private.h"
44
45#ifndef NELEMENTS
46#define NELEMENTS(arr)	(sizeof(arr) / sizeof(arr[0]))
47#endif
48
49static void	dump_thread(int fd, pthread_t pthread, int long_version);
50
51__weak_reference(_pthread_set_name_np, pthread_set_name_np);
52
53struct s_thread_info {
54	enum pthread_state state;
55	char           *name;
56};
57
58/* Static variables: */
59static const struct s_thread_info thread_info[] = {
60	{PS_RUNNING	, "Running"},
61	{PS_MUTEX_WAIT	, "Waiting on a mutex"},
62	{PS_JOIN	, "Waiting to join"},
63	{PS_SUSPENDED	, "Suspended"},
64	{PS_DEAD	, "Dead"},
65	{PS_DEADLOCK	, "Deadlocked"},
66	{PS_STATE_MAX	, "Not a real state!"}
67};
68
69void
70_thread_dump_info(void)
71{
72	char s[512], tmpfile[128];
73	pthread_t pthread;
74	int fd, i;
75
76	for (i = 0; i < 100000; i++) {
77		snprintf(tmpfile, sizeof(tmpfile), "/tmp/pthread.dump.%u.%i",
78			getpid(), i);
79		/* Open the dump file for append and create it if necessary: */
80		if ((fd = __sys_open(tmpfile, O_RDWR | O_CREAT | O_EXCL,
81			0666)) < 0) {
82				/* Can't open the dump file. */
83				if (errno == EEXIST)
84					continue;
85				/*
86				 * We only need to continue in case of
87				 * EEXIT error. Most other error
88				 * codes means that we will fail all
89				 * the times.
90				 */
91				return;
92		} else {
93			break;
94		}
95	}
96	if (i==100000) {
97		/* all 100000 possibilities are in use :( */
98		return;
99	} else {
100		/* Dump the active threads. */
101		strcpy(s, "\n\n========\nACTIVE THREADS\n\n");
102		__sys_write(fd, s, strlen(s));
103
104		/* Enter a loop to report each thread in the global list: */
105		TAILQ_FOREACH(pthread, &_thread_list, tle) {
106			if (pthread->state != PS_DEAD)
107				dump_thread(fd, pthread, /*long_verson*/ 1);
108		}
109
110		/*
111		 * Dump the ready threads.
112		 * XXX - We can't easily do this because the run queues
113		 *       are per-KSEG.
114		 */
115		strcpy(s, "\n\n========\nREADY THREADS - unimplemented\n\n");
116		__sys_write(fd, s, strlen(s));
117
118
119		/*
120		 * Dump the waiting threads.
121		 * XXX - We can't easily do this because the wait queues
122		 *       are per-KSEG.
123		 */
124		strcpy(s, "\n\n========\nWAITING THREADS - unimplemented\n\n");
125		__sys_write(fd, s, strlen(s));
126
127		/* Close the dump file. */
128		__sys_close(fd);
129	}
130}
131
132static void
133dump_thread(int fd, pthread_t pthread, int long_version)
134{
135	struct pthread *curthread = _get_curthread();
136	char s[512];
137	int i;
138
139	/* Find the state: */
140	for (i = 0; i < NELEMENTS(thread_info) - 1; i++)
141		if (thread_info[i].state == pthread->state)
142			break;
143
144	/* Output a record for the thread: */
145	snprintf(s, sizeof(s),
146	    "--------------------\n"
147	    "Thread %p (%s), scope %s, prio %3d, state %s [%s:%d]\n",
148	    pthread, (pthread->name == NULL) ? "" : pthread->name,
149	    pthread->attr.flags & PTHREAD_SCOPE_SYSTEM ? "system" : "process",
150	    pthread->active_priority,
151	    thread_info[i].name, pthread->fname, pthread->lineno);
152	__sys_write(fd, s, strlen(s));
153
154	if (long_version != 0) {
155		/* Check if this is the running thread: */
156		if (pthread == curthread) {
157			/* Output a record for the running thread: */
158			strcpy(s, "This is the running thread\n");
159			__sys_write(fd, s, strlen(s));
160		}
161		/* Check if this is the initial thread: */
162		if (pthread == _thr_initial) {
163			/* Output a record for the initial thread: */
164			strcpy(s, "This is the initial thread\n");
165			__sys_write(fd, s, strlen(s));
166		}
167
168		/* Process according to thread state: */
169		switch (pthread->state) {
170		/*
171		 * Trap other states that are not explicitly
172		 * coded to dump information:
173		 */
174		default:
175			snprintf(s, sizeof(s), "sigmask (hi) ");
176			__sys_write(fd, s, strlen(s));
177			for (i = _SIG_WORDS - 1; i >= 0; i--) {
178				snprintf(s, sizeof(s), "%08x ",
179				    pthread->sigmask.__bits[i]);
180				__sys_write(fd, s, strlen(s));
181			}
182			snprintf(s, sizeof(s), "(lo)\n");
183			__sys_write(fd, s, strlen(s));
184			break;
185		}
186	}
187}
188
189/* Set the thread name for debug: */
190void
191_pthread_set_name_np(pthread_t thread, char *name)
192{
193	/* Check if the caller has specified a valid thread: */
194	if (thread != NULL && thread->magic == THR_MAGIC) {
195		if (thread->name != NULL) {
196			/* Free space for previous name. */
197			free(thread->name);
198		}
199		thread->name = strdup(name);
200	}
201}
202