]> CyberLeo.Net >> Repos - FreeBSD/releng/7.2.git/blob - lib/libkse/thread/thr_info.c
Create releng/7.2 from stable/7 in preparation for 7.2-RELEASE.
[FreeBSD/releng/7.2.git] / lib / libkse / thread / thr_info.c
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$
30  */
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <fcntl.h>
34 #include <string.h>
35 #include <unistd.h>
36 #include <pthread.h>
37 #include <errno.h>
38 #include "thr_private.h"
39
40 #ifndef NELEMENTS
41 #define NELEMENTS(arr)  (sizeof(arr) / sizeof(arr[0]))
42 #endif
43
44 LT10_COMPAT_PRIVATE(_pthread_set_name_np);
45 LT10_COMPAT_DEFAULT(pthread_set_name_np);
46
47 static void     dump_thread(int fd, pthread_t pthread, int long_version);
48
49 __weak_reference(_pthread_set_name_np, pthread_set_name_np);
50
51 struct s_thread_info {
52         enum pthread_state state;
53         char           *name;
54 };
55
56 /* Static variables: */
57 static const struct s_thread_info thread_info[] = {
58         {PS_RUNNING     , "Running"},
59         {PS_LOCKWAIT    , "Waiting on an internal lock"},
60         {PS_MUTEX_WAIT  , "Waiting on a mutex"},
61         {PS_COND_WAIT   , "Waiting on a condition variable"},
62         {PS_SLEEP_WAIT  , "Sleeping"},
63         {PS_SIGSUSPEND  , "Suspended, waiting for a signal"},
64         {PS_SIGWAIT     , "Waiting for a signal"},
65         {PS_JOIN        , "Waiting to join"},
66         {PS_SUSPENDED   , "Suspended"},
67         {PS_DEAD        , "Dead"},
68         {PS_DEADLOCK    , "Deadlocked"},
69         {PS_STATE_MAX   , "Not a real state!"}
70 };
71
72 void
73 _thread_dump_info(void)
74 {
75         char s[512], tmpfile[128];
76         pthread_t pthread;
77         int fd, i;
78
79         for (i = 0; i < 100000; i++) {
80                 snprintf(tmpfile, sizeof(tmpfile), "/tmp/pthread.dump.%u.%i",
81                         getpid(), i);
82                 /* Open the dump file for append and create it if necessary: */
83                 if ((fd = __sys_open(tmpfile, O_RDWR | O_CREAT | O_EXCL,
84                         0666)) < 0) {
85                                 /* Can't open the dump file. */
86                                 if (errno == EEXIST)
87                                         continue;
88                                 /*
89                                  * We only need to continue in case of
90                                  * EEXIT error. Most other error
91                                  * codes means that we will fail all
92                                  * the times.
93                                  */
94                                 return;
95                 } else {
96                         break;
97                 }
98         }
99         if (i==100000) {
100                 /* all 100000 possibilities are in use :( */
101                 return;
102         } else {
103                 /* Dump the active threads. */
104                 strcpy(s, "\n\n========\nACTIVE THREADS\n\n");
105                 __sys_write(fd, s, strlen(s));
106
107                 /* Enter a loop to report each thread in the global list: */
108                 TAILQ_FOREACH(pthread, &_thread_list, tle) {
109                         if (pthread->state != PS_DEAD)
110                                 dump_thread(fd, pthread, /*long_verson*/ 1);
111                 }
112
113                 /*
114                  * Dump the ready threads.
115                  * XXX - We can't easily do this because the run queues
116                  *       are per-KSEG.
117                  */
118                 strcpy(s, "\n\n========\nREADY THREADS - unimplemented\n\n");
119                 __sys_write(fd, s, strlen(s));
120
121
122                 /*
123                  * Dump the waiting threads.
124                  * XXX - We can't easily do this because the wait queues
125                  *       are per-KSEG.
126                  */
127                 strcpy(s, "\n\n========\nWAITING THREADS - unimplemented\n\n");
128                 __sys_write(fd, s, strlen(s));
129
130                 /* Close the dump file. */
131                 __sys_close(fd);
132         }
133 }
134
135 static void
136 dump_thread(int fd, pthread_t pthread, int long_version)
137 {
138         struct pthread *curthread = _get_curthread();
139         char s[512];
140         int i;
141
142         /* Find the state: */
143         for (i = 0; i < NELEMENTS(thread_info) - 1; i++)
144                 if (thread_info[i].state == pthread->state)
145                         break;
146
147         /* Output a record for the thread: */
148         snprintf(s, sizeof(s),
149             "--------------------\n"
150             "Thread %p (%s), scope %s, prio %3d, blocked %s, state %s [%s:%d]\n",
151             pthread, (pthread->name == NULL) ? "" : pthread->name,
152             pthread->attr.flags & PTHREAD_SCOPE_SYSTEM ? "system" : "process",
153             pthread->active_priority, (pthread->blocked != 0) ? "yes" : "no",
154             thread_info[i].name, pthread->fname, pthread->lineno);
155         __sys_write(fd, s, strlen(s));
156
157         if (long_version != 0) {
158                 /* Check if this is the running thread: */
159                 if (pthread == curthread) {
160                         /* Output a record for the running thread: */
161                         strcpy(s, "This is the running thread\n");
162                         __sys_write(fd, s, strlen(s));
163                 }
164                 /* Check if this is the initial thread: */
165                 if (pthread == _thr_initial) {
166                         /* Output a record for the initial thread: */
167                         strcpy(s, "This is the initial thread\n");
168                         __sys_write(fd, s, strlen(s));
169                 }
170         
171                 /* Process according to thread state: */
172                 switch (pthread->state) {
173                 case PS_SIGWAIT:
174                         snprintf(s, sizeof(s), "sigmask (hi) ");
175                         __sys_write(fd, s, strlen(s));
176                         for (i = _SIG_WORDS - 1; i >= 0; i--) {
177                                 snprintf(s, sizeof(s), "%08x ",
178                                     pthread->sigmask.__bits[i]);
179                                 __sys_write(fd, s, strlen(s));
180                         }
181                         snprintf(s, sizeof(s), "(lo)\n");
182                         __sys_write(fd, s, strlen(s));
183
184                         snprintf(s, sizeof(s), "waitset (hi) ");
185                         __sys_write(fd, s, strlen(s));
186                         for (i = _SIG_WORDS - 1; i >= 0; i--) {
187                                 snprintf(s, sizeof(s), "%08x ",
188                                     pthread->data.sigwait->waitset->__bits[i]);
189                                 __sys_write(fd, s, strlen(s));
190                         }
191                         snprintf(s, sizeof(s), "(lo)\n");
192                         __sys_write(fd, s, strlen(s));
193                         break;
194                 /*
195                  * Trap other states that are not explicitly
196                  * coded to dump information:
197                  */
198                 default:
199                         snprintf(s, sizeof(s), "sigmask (hi) ");
200                         __sys_write(fd, s, strlen(s));
201                         for (i = _SIG_WORDS - 1; i >= 0; i--) {
202                                 snprintf(s, sizeof(s), "%08x ",
203                                     pthread->sigmask.__bits[i]);
204                                 __sys_write(fd, s, strlen(s));
205                         }
206                         snprintf(s, sizeof(s), "(lo)\n");
207                         __sys_write(fd, s, strlen(s));
208                         break;
209                 }
210         }
211 }
212
213 /* Set the thread name for debug: */
214 void
215 _pthread_set_name_np(pthread_t thread, char *name)
216 {
217         struct pthread *curthread = _get_curthread();
218         char *new_name;
219         char *prev_name;
220         int ret;
221
222         new_name = strdup(name);
223         /* Add a reference to the target thread. */
224         if (_thr_ref_add(curthread, thread, 0) != 0) {
225                 free(new_name);
226                 ret = ESRCH;
227         }
228         else {
229                 THR_THREAD_LOCK(curthread, thread);
230                 prev_name = thread->name;
231                 thread->name = new_name;
232                 THR_THREAD_UNLOCK(curthread, thread);
233                 _thr_ref_delete(curthread, thread);
234                 if (prev_name != NULL) {
235                         /* Free space for previous name. */
236                         free(prev_name);
237                 }
238                 ret = 0;
239         }
240 #if 0
241         /* XXX - Should return error code. */
242         return (ret);
243 #endif
244 }