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. Neither the name of the author nor the names of any co-contributors
14  *    may be used to endorse or promote products derived from this software
15  *    without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  *
29  * $FreeBSD: stable/9/lib/libkse/thread/thr_info.c 174689 2007-12-16 23:29:57Z deischen $
30  */
31 
32 #include "namespace.h"
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <fcntl.h>
36 #include <string.h>
37 #include <unistd.h>
38 #include <pthread.h>
39 #include <errno.h>
40 #include "un-namespace.h"
41 #include "thr_private.h"
42 
43 #ifndef NELEMENTS
44 #define NELEMENTS(arr)	(sizeof(arr) / sizeof(arr[0]))
45 #endif
46 
47 static void	dump_thread(int fd, pthread_t pthread, int long_version);
48 void		_pthread_set_name_np(pthread_t thread, char *name);
49 
50 __weak_reference(_pthread_set_name_np, pthread_set_name_np);
51 
52 struct s_thread_info {
53 	enum pthread_state state;
54 	const char	*name;
55 };
56 
57 /* Static variables: */
58 static const struct s_thread_info thread_info[] = {
59 	{PS_RUNNING	, "Running"},
60         {PS_LOCKWAIT    , "Waiting on an internal lock"},
61 	{PS_MUTEX_WAIT	, "Waiting on a mutex"},
62 	{PS_COND_WAIT	, "Waiting on a condition variable"},
63 	{PS_SLEEP_WAIT	, "Sleeping"},
64 	{PS_SIGSUSPEND	, "Suspended, waiting for a signal"},
65 	{PS_SIGWAIT	, "Waiting for a signal"},
66 	{PS_JOIN	, "Waiting to join"},
67 	{PS_SUSPENDED	, "Suspended"},
68 	{PS_DEAD	, "Dead"},
69 	{PS_DEADLOCK	, "Deadlocked"},
70 	{PS_STATE_MAX	, "Not a real state!"}
71 };
72 
73 void
_thread_dump_info(void)74 _thread_dump_info(void)
75 {
76 	char s[512], tempfile[128];
77 	pthread_t pthread;
78 	int fd, i;
79 
80 	for (i = 0; i < 100000; i++) {
81 		snprintf(tempfile, sizeof(tempfile), "/tmp/pthread.dump.%u.%i",
82 			getpid(), i);
83 		/* Open the dump file for append and create it if necessary: */
84 		if ((fd = __sys_open(tempfile, O_RDWR | O_CREAT | O_EXCL,
85 			0666)) < 0) {
86 				/* Can't open the dump file. */
87 				if (errno == EEXIST)
88 					continue;
89 				/*
90 				 * We only need to continue in case of
91 				 * EEXIT error. Most other error
92 				 * codes means that we will fail all
93 				 * the times.
94 				 */
95 				return;
96 		} else {
97 			break;
98 		}
99 	}
100 	if (i==100000) {
101 		/* all 100000 possibilities are in use :( */
102 		return;
103 	} else {
104 		/* Dump the active threads. */
105 		strcpy(s, "\n\n========\nACTIVE THREADS\n\n");
106 		__sys_write(fd, s, strlen(s));
107 
108 		/* Enter a loop to report each thread in the global list: */
109 		TAILQ_FOREACH(pthread, &_thread_list, tle) {
110 			if (pthread->state != PS_DEAD)
111 				dump_thread(fd, pthread, /*long_verson*/ 1);
112 		}
113 
114 		/*
115 		 * Dump the ready threads.
116 		 * XXX - We can't easily do this because the run queues
117 		 *       are per-KSEG.
118 		 */
119 		strcpy(s, "\n\n========\nREADY THREADS - unimplemented\n\n");
120 		__sys_write(fd, s, strlen(s));
121 
122 
123 		/*
124 		 * Dump the waiting threads.
125 		 * XXX - We can't easily do this because the wait queues
126 		 *       are per-KSEG.
127 		 */
128 		strcpy(s, "\n\n========\nWAITING THREADS - unimplemented\n\n");
129 		__sys_write(fd, s, strlen(s));
130 
131 		/* Close the dump file. */
132 		__sys_close(fd);
133 	}
134 }
135 
136 static void
dump_thread(int fd,pthread_t pthread,int long_version)137 dump_thread(int fd, pthread_t pthread, int long_version)
138 {
139 	struct pthread *curthread = _get_curthread();
140 	char s[512];
141 	int i;
142 
143 	/* Find the state: */
144 	for (i = 0; i < (int)NELEMENTS(thread_info) - 1; i++)
145 		if (thread_info[i].state == pthread->state)
146 			break;
147 
148 	/* Output a record for the thread: */
149 	snprintf(s, sizeof(s),
150 	    "--------------------\n"
151 	    "Thread %p (%s), scope %s, prio %3d, blocked %s, state %s [%s:%d]\n",
152 	    pthread, (pthread->name == NULL) ? "" : pthread->name,
153 	    pthread->attr.flags & PTHREAD_SCOPE_SYSTEM ? "system" : "process",
154 	    pthread->active_priority, (pthread->blocked != 0) ? "yes" : "no",
155 	    thread_info[i].name, pthread->fname, pthread->lineno);
156 	__sys_write(fd, s, strlen(s));
157 
158 	if (long_version != 0) {
159 		/* Check if this is the running thread: */
160 		if (pthread == curthread) {
161 			/* Output a record for the running thread: */
162 			strcpy(s, "This is the running thread\n");
163 			__sys_write(fd, s, strlen(s));
164 		}
165 		/* Check if this is the initial thread: */
166 		if (pthread == _thr_initial) {
167 			/* Output a record for the initial thread: */
168 			strcpy(s, "This is the initial thread\n");
169 			__sys_write(fd, s, strlen(s));
170 		}
171 
172 		/* Process according to thread state: */
173 		switch (pthread->state) {
174 		case PS_SIGWAIT:
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 
185 			snprintf(s, sizeof(s), "waitset (hi) ");
186 			__sys_write(fd, s, strlen(s));
187 			for (i = _SIG_WORDS - 1; i >= 0; i--) {
188 				snprintf(s, sizeof(s), "%08x ",
189 				    pthread->data.sigwait->waitset->__bits[i]);
190 				__sys_write(fd, s, strlen(s));
191 			}
192 			snprintf(s, sizeof(s), "(lo)\n");
193 			__sys_write(fd, s, strlen(s));
194 			break;
195 		/*
196 		 * Trap other states that are not explicitly
197 		 * coded to dump information:
198 		 */
199 		default:
200 			snprintf(s, sizeof(s), "sigmask (hi) ");
201 			__sys_write(fd, s, strlen(s));
202 			for (i = _SIG_WORDS - 1; i >= 0; i--) {
203 				snprintf(s, sizeof(s), "%08x ",
204 				    pthread->sigmask.__bits[i]);
205 				__sys_write(fd, s, strlen(s));
206 			}
207 			snprintf(s, sizeof(s), "(lo)\n");
208 			__sys_write(fd, s, strlen(s));
209 			break;
210 		}
211 	}
212 }
213 
214 /* Set the thread name for debug: */
215 void
_pthread_set_name_np(pthread_t thread,char * name)216 _pthread_set_name_np(pthread_t thread, char *name)
217 {
218 	struct pthread *curthread = _get_curthread();
219 	char *new_name;
220 	char *prev_name;
221 	int ret;
222 
223 	new_name = strdup(name);
224 	/* Add a reference to the target thread. */
225 	if (_thr_ref_add(curthread, thread, 0) != 0) {
226 		free(new_name);
227 		ret = ESRCH;
228 	}
229 	else {
230 		THR_THREAD_LOCK(curthread, thread);
231 		prev_name = thread->name;
232 		thread->name = new_name;
233 		THR_THREAD_UNLOCK(curthread, thread);
234 		_thr_ref_delete(curthread, thread);
235 		if (prev_name != NULL) {
236 			/* Free space for previous name. */
237 			free(prev_name);
238 		}
239 		ret = 0;
240 	}
241 #if 0
242 	/* XXX - Should return error code. */
243 	return (ret);
244 #endif
245 }
246