thr_info.c revision 35130
1/*
2 * Copyright (c) 1995 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 REGENTS 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 */
33#include <stdio.h>
34#include <fcntl.h>
35#include <string.h>
36#include <unistd.h>
37#ifdef _THREAD_SAFE
38#include <pthread.h>
39#include "pthread_private.h"
40
41struct s_thread_info {
42	enum pthread_state state;
43	char           *name;
44};
45
46/* Static variables: */
47static const struct s_thread_info thread_info[] = {
48	{PS_RUNNING	, "Running"},
49	{PS_SIGTHREAD	, "Waiting on signal thread"},
50	{PS_MUTEX_WAIT	, "Waiting on a mutex"},
51	{PS_COND_WAIT	, "Waiting on a condition variable"},
52	{PS_FDLR_WAIT	, "Waiting for a file read lock"},
53	{PS_FDLW_WAIT	, "Waiting for a file write lock"},
54	{PS_FDR_WAIT	, "Waiting for read"},
55	{PS_FDW_WAIT	, "Waiting for write"},
56	{PS_FILE_WAIT	, "Waiting for FILE lock"},
57	{PS_SELECT_WAIT	, "Waiting on select"},
58	{PS_SLEEP_WAIT	, "Sleeping"},
59	{PS_WAIT_WAIT	, "Waiting process"},
60	{PS_SIGWAIT	, "Waiting for a signal"},
61	{PS_JOIN	, "Waiting to join"},
62	{PS_SUSPENDED	, "Suspended"},
63	{PS_DEAD	, "Dead"},
64	{PS_STATE_MAX	, "Not a real state!"}
65};
66
67void
68_thread_dump_info(void)
69{
70	char            s[128];
71	int             fd;
72	int             i;
73	int             j;
74	pthread_t       pthread;
75
76	/* Open the dump file for append and create it if necessary: */
77	if ((fd = _thread_sys_open("/tmp/uthread.dump", O_RDWR | O_CREAT | O_APPEND, 0666)) < 0) {
78		/* Can't open the dump file. */
79	} else {
80		/* Output a header for active threads: */
81		strcpy(s, "\n\n=============\nACTIVE THREADS\n\n");
82		_thread_sys_write(fd, s, strlen(s));
83
84		/* Enter a loop to report each thread in the global list: */
85		for (pthread = _thread_link_list; pthread != NULL; pthread = pthread->nxt) {
86			/* Find the state: */
87			for (j = 0; j < (sizeof(thread_info) / sizeof(struct s_thread_info)) - 1; j++)
88				if (thread_info[j].state == pthread->state)
89					break;
90			/* Output a record for the current thread: */
91			sprintf(s, "--------------------\nThread %p (%s) prio %3d state %s [%s:%d]\n",
92				pthread, (pthread->name == NULL) ? "":pthread->name, pthread->pthread_priority, thread_info[j].name,pthread->fname,pthread->lineno);
93			_thread_sys_write(fd, s, strlen(s));
94
95			/* Check if this is the running thread: */
96			if (pthread == _thread_run) {
97				/* Output a record for the running thread: */
98				strcpy(s, "This is the running thread\n");
99				_thread_sys_write(fd, s, strlen(s));
100			}
101			/* Check if this is the initial thread: */
102			if (pthread == _thread_initial) {
103				/* Output a record for the initial thread: */
104				strcpy(s, "This is the initial thread\n");
105				_thread_sys_write(fd, s, strlen(s));
106			}
107			/* Process according to thread state: */
108			switch (pthread->state) {
109			/* File descriptor read lock wait: */
110			case PS_FDLR_WAIT:
111			case PS_FDLW_WAIT:
112			case PS_FDR_WAIT:
113			case PS_FDW_WAIT:
114				/* Write the lock details: */
115				sprintf(s, "fd %d[%s:%d]", pthread->data.fd.fd, pthread->data.fd.fname, pthread->data.fd.branch);
116				_thread_sys_write(fd, s, strlen(s));
117				sprintf(s, "owner %pr/%pw\n", _thread_fd_table[pthread->data.fd.fd]->r_owner, _thread_fd_table[pthread->data.fd.fd]->w_owner);
118				_thread_sys_write(fd, s, strlen(s));
119				break;
120
121			/*
122			 * Trap other states that are not explicitly
123			 * coded to dump information:
124			 */
125			default:
126				/* Nothing to do here. */
127				break;
128			}
129		}
130
131		/* Check if there are no dead threads: */
132		if (_thread_dead == NULL) {
133			/* Output a record: */
134			strcpy(s, "\n\nTHERE ARE NO DEAD THREADS\n");
135			_thread_sys_write(fd, s, strlen(s));
136		} else {
137			/* Output a header for dead threads: */
138			strcpy(s, "\n\nDEAD THREADS\n\n");
139			_thread_sys_write(fd, s, strlen(s));
140
141			/*
142			 * Enter a loop to report each thread in the global
143			 * dead thread list:
144			 */
145			for (pthread = _thread_dead; pthread != NULL; pthread = pthread->nxt) {
146				/* Output a record for the current thread: */
147				sprintf(s, "Thread %p prio %3d [%s:%d]\n", pthread, pthread->pthread_priority,pthread->fname,pthread->lineno);
148				_thread_sys_write(fd, s, strlen(s));
149			}
150		}
151
152		/* Output a header for file descriptors: */
153		strcpy(s, "\n\n=============\nFILE DESCRIPTOR TABLE\n\n");
154		_thread_sys_write(fd, s, strlen(s));
155
156		/* Enter a loop to report file descriptor lock usage: */
157		for (i = 0; i < _thread_dtablesize; i++) {
158			/*
159			 * Check if memory is allocated for this file
160			 * descriptor:
161			 */
162			if (_thread_fd_table[i] != NULL) {
163				/* Report the file descriptor lock status: */
164				sprintf(s, "fd[%3d] read owner %p count %d [%s:%d]\n        write owner %p count %d [%s:%d]\n",
165					i,
166					_thread_fd_table[i]->r_owner,
167					_thread_fd_table[i]->r_lockcount,
168					_thread_fd_table[i]->r_fname,
169					_thread_fd_table[i]->r_lineno,
170					_thread_fd_table[i]->w_owner,
171					_thread_fd_table[i]->w_lockcount,
172					_thread_fd_table[i]->w_fname,
173					_thread_fd_table[i]->w_lineno);
174				_thread_sys_write(fd, s, strlen(s));
175			}
176		}
177
178		/* Close the dump file: */
179		_thread_sys_close(fd);
180	}
181	return;
182}
183
184/* Set the thread name for debug: */
185void
186pthread_set_name_np(pthread_t thread, char *name)
187{
188	/* Check if the caller has specified a valid thread: */
189	if (thread != NULL && thread->magic == PTHREAD_MAGIC)
190		thread->name = strdup(name);
191	return;
192}
193#endif
194