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