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