113546Sjulian/*
235509Sjb * Copyright (c) 1995-1998 John Birrell <jb@cimlogic.com.au>
313546Sjulian * All rights reserved.
413546Sjulian *
513546Sjulian * Redistribution and use in source and binary forms, with or without
613546Sjulian * modification, are permitted provided that the following conditions
713546Sjulian * are met:
813546Sjulian * 1. Redistributions of source code must retain the above copyright
913546Sjulian *    notice, this list of conditions and the following disclaimer.
1013546Sjulian * 2. Redistributions in binary form must reproduce the above copyright
1113546Sjulian *    notice, this list of conditions and the following disclaimer in the
1213546Sjulian *    documentation and/or other materials provided with the distribution.
13165967Simp * 3. Neither the name of the author nor the names of any co-contributors
1413546Sjulian *    may be used to endorse or promote products derived from this software
1513546Sjulian *    without specific prior written permission.
1613546Sjulian *
1713546Sjulian * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND
1813546Sjulian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1913546Sjulian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2049439Sdeischen * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2113546Sjulian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2213546Sjulian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2313546Sjulian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2413546Sjulian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2513546Sjulian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2613546Sjulian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2713546Sjulian * SUCH DAMAGE.
2813546Sjulian *
2950476Speter * $FreeBSD$
3013546Sjulian */
31174112Sdeischen
32174112Sdeischen#include "namespace.h"
3313546Sjulian#include <stdio.h>
3467097Sdeischen#include <stdlib.h>
3513546Sjulian#include <fcntl.h>
3613546Sjulian#include <string.h>
3713546Sjulian#include <unistd.h>
3813546Sjulian#include <pthread.h>
3942500Simp#include <errno.h>
40174112Sdeischen#include "un-namespace.h"
41103388Smini#include "thr_private.h"
4213546Sjulian
4368516Sdeischen#ifndef NELEMENTS
4468516Sdeischen#define NELEMENTS(arr)	(sizeof(arr) / sizeof(arr[0]))
4568516Sdeischen#endif
4668516Sdeischen
4768516Sdeischenstatic void	dump_thread(int fd, pthread_t pthread, int long_version);
48174112Sdeischenvoid		_pthread_set_name_np(pthread_t thread, char *name);
4968516Sdeischen
5075369Sdeischen__weak_reference(_pthread_set_name_np, pthread_set_name_np);
5168516Sdeischen
5213546Sjulianstruct s_thread_info {
5313546Sjulian	enum pthread_state state;
54174112Sdeischen	const char	*name;
5513546Sjulian};
5613546Sjulian
5713546Sjulian/* Static variables: */
5813546Sjulianstatic const struct s_thread_info thread_info[] = {
5913546Sjulian	{PS_RUNNING	, "Running"},
60113658Sdeischen        {PS_LOCKWAIT    , "Waiting on an internal lock"},
6113546Sjulian	{PS_MUTEX_WAIT	, "Waiting on a mutex"},
6213546Sjulian	{PS_COND_WAIT	, "Waiting on a condition variable"},
6313546Sjulian	{PS_SLEEP_WAIT	, "Sleeping"},
64113658Sdeischen	{PS_SIGSUSPEND	, "Suspended, waiting for a signal"},
65113658Sdeischen	{PS_SIGWAIT	, "Waiting for a signal"},
6613546Sjulian	{PS_JOIN	, "Waiting to join"},
6713546Sjulian	{PS_SUSPENDED	, "Suspended"},
6813546Sjulian	{PS_DEAD	, "Dead"},
6944963Sjb	{PS_DEADLOCK	, "Deadlocked"},
7013546Sjulian	{PS_STATE_MAX	, "Not a real state!"}
7113546Sjulian};
7213546Sjulian
7313546Sjulianvoid
7413546Sjulian_thread_dump_info(void)
7513546Sjulian{
76174112Sdeischen	char s[512], tempfile[128];
77113658Sdeischen	pthread_t pthread;
78113658Sdeischen	int fd, i;
7913546Sjulian
8068516Sdeischen	for (i = 0; i < 100000; i++) {
81174112Sdeischen		snprintf(tempfile, sizeof(tempfile), "/tmp/pthread.dump.%u.%i",
8242500Simp			getpid(), i);
8342500Simp		/* Open the dump file for append and create it if necessary: */
84174112Sdeischen		if ((fd = __sys_open(tempfile, O_RDWR | O_CREAT | O_EXCL,
8542500Simp			0666)) < 0) {
8642500Simp				/* Can't open the dump file. */
8742500Simp				if (errno == EEXIST)
8842500Simp					continue;
8942500Simp				/*
9042500Simp				 * We only need to continue in case of
9142500Simp				 * EEXIT error. Most other error
9242500Simp				 * codes means that we will fail all
9342500Simp				 * the times.
9442500Simp				 */
9542500Simp				return;
9642500Simp		} else {
9742500Simp			break;
9842500Simp		}
9942500Simp	}
10042500Simp	if (i==100000) {
10142500Simp		/* all 100000 possibilities are in use :( */
10242500Simp		return;
10313546Sjulian	} else {
104113658Sdeischen		/* Dump the active threads. */
105113658Sdeischen		strcpy(s, "\n\n========\nACTIVE THREADS\n\n");
10671581Sdeischen		__sys_write(fd, s, strlen(s));
10713546Sjulian
10813546Sjulian		/* Enter a loop to report each thread in the global list: */
10948046Sjb		TAILQ_FOREACH(pthread, &_thread_list, tle) {
110113658Sdeischen			if (pthread->state != PS_DEAD)
111113658Sdeischen				dump_thread(fd, pthread, /*long_verson*/ 1);
11213546Sjulian		}
11313546Sjulian
114113658Sdeischen		/*
115113658Sdeischen		 * Dump the ready threads.
116113658Sdeischen		 * XXX - We can't easily do this because the run queues
117113658Sdeischen		 *       are per-KSEG.
118113658Sdeischen		 */
119113658Sdeischen		strcpy(s, "\n\n========\nREADY THREADS - unimplemented\n\n");
12071581Sdeischen		__sys_write(fd, s, strlen(s));
12144963Sjb
12244963Sjb
123113658Sdeischen		/*
124113658Sdeischen		 * Dump the waiting threads.
125113658Sdeischen		 * XXX - We can't easily do this because the wait queues
126113658Sdeischen		 *       are per-KSEG.
127113658Sdeischen		 */
128113658Sdeischen		strcpy(s, "\n\n========\nWAITING THREADS - unimplemented\n\n");
12971581Sdeischen		__sys_write(fd, s, strlen(s));
13044963Sjb
131113658Sdeischen		/* Close the dump file. */
13271581Sdeischen		__sys_close(fd);
13313546Sjulian	}
13413546Sjulian}
13535130Sjb
13668516Sdeischenstatic void
13768516Sdeischendump_thread(int fd, pthread_t pthread, int long_version)
13868516Sdeischen{
139113658Sdeischen	struct pthread *curthread = _get_curthread();
140113658Sdeischen	char s[512];
141113658Sdeischen	int i;
14268516Sdeischen
14368516Sdeischen	/* Find the state: */
144174112Sdeischen	for (i = 0; i < (int)NELEMENTS(thread_info) - 1; i++)
14568516Sdeischen		if (thread_info[i].state == pthread->state)
14668516Sdeischen			break;
14768516Sdeischen
14868516Sdeischen	/* Output a record for the thread: */
14968516Sdeischen	snprintf(s, sizeof(s),
150113658Sdeischen	    "--------------------\n"
151117297Sdavidxu	    "Thread %p (%s), scope %s, prio %3d, blocked %s, state %s [%s:%d]\n",
15268516Sdeischen	    pthread, (pthread->name == NULL) ? "" : pthread->name,
153117297Sdavidxu	    pthread->attr.flags & PTHREAD_SCOPE_SYSTEM ? "system" : "process",
154113658Sdeischen	    pthread->active_priority, (pthread->blocked != 0) ? "yes" : "no",
155113658Sdeischen	    thread_info[i].name, pthread->fname, pthread->lineno);
15671581Sdeischen	__sys_write(fd, s, strlen(s));
15768516Sdeischen
15868516Sdeischen	if (long_version != 0) {
15968516Sdeischen		/* Check if this is the running thread: */
16071581Sdeischen		if (pthread == curthread) {
16168516Sdeischen			/* Output a record for the running thread: */
16268516Sdeischen			strcpy(s, "This is the running thread\n");
16371581Sdeischen			__sys_write(fd, s, strlen(s));
16468516Sdeischen		}
16568516Sdeischen		/* Check if this is the initial thread: */
166113658Sdeischen		if (pthread == _thr_initial) {
16768516Sdeischen			/* Output a record for the initial thread: */
16868516Sdeischen			strcpy(s, "This is the initial thread\n");
16971581Sdeischen			__sys_write(fd, s, strlen(s));
17068516Sdeischen		}
171117305Sdavidxu
17268516Sdeischen		/* Process according to thread state: */
17368516Sdeischen		switch (pthread->state) {
174113658Sdeischen		case PS_SIGWAIT:
175117305Sdavidxu			snprintf(s, sizeof(s), "sigmask (hi) ");
176117305Sdavidxu			__sys_write(fd, s, strlen(s));
177117305Sdavidxu			for (i = _SIG_WORDS - 1; i >= 0; i--) {
178117305Sdavidxu				snprintf(s, sizeof(s), "%08x ",
179117305Sdavidxu				    pthread->sigmask.__bits[i]);
180117305Sdavidxu				__sys_write(fd, s, strlen(s));
181117305Sdavidxu			}
182117305Sdavidxu			snprintf(s, sizeof(s), "(lo)\n");
183117305Sdavidxu			__sys_write(fd, s, strlen(s));
184117305Sdavidxu
185117297Sdavidxu			snprintf(s, sizeof(s), "waitset (hi) ");
186113658Sdeischen			__sys_write(fd, s, strlen(s));
187113658Sdeischen			for (i = _SIG_WORDS - 1; i >= 0; i--) {
188117297Sdavidxu				snprintf(s, sizeof(s), "%08x ",
189120325Sdavidxu				    pthread->data.sigwait->waitset->__bits[i]);
190116977Sdavidxu				__sys_write(fd, s, strlen(s));
191116977Sdavidxu			}
192116977Sdavidxu			snprintf(s, sizeof(s), "(lo)\n");
193116977Sdavidxu			__sys_write(fd, s, strlen(s));
194113658Sdeischen			break;
19568516Sdeischen		/*
19668516Sdeischen		 * Trap other states that are not explicitly
19768516Sdeischen		 * coded to dump information:
19868516Sdeischen		 */
19968516Sdeischen		default:
200117305Sdavidxu			snprintf(s, sizeof(s), "sigmask (hi) ");
201117305Sdavidxu			__sys_write(fd, s, strlen(s));
202117305Sdavidxu			for (i = _SIG_WORDS - 1; i >= 0; i--) {
203117305Sdavidxu				snprintf(s, sizeof(s), "%08x ",
204117305Sdavidxu				    pthread->sigmask.__bits[i]);
205117305Sdavidxu				__sys_write(fd, s, strlen(s));
206117305Sdavidxu			}
207117305Sdavidxu			snprintf(s, sizeof(s), "(lo)\n");
208117305Sdavidxu			__sys_write(fd, s, strlen(s));
20968516Sdeischen			break;
21068516Sdeischen		}
21168516Sdeischen	}
21268516Sdeischen}
21368516Sdeischen
21435130Sjb/* Set the thread name for debug: */
21535130Sjbvoid
216113658Sdeischen_pthread_set_name_np(pthread_t thread, char *name)
21735130Sjb{
218168964Sdeischen	struct pthread *curthread = _get_curthread();
219168964Sdeischen	char *new_name;
220168964Sdeischen	char *prev_name;
221168964Sdeischen	int ret;
222168964Sdeischen
223168964Sdeischen	new_name = strdup(name);
224168964Sdeischen	/* Add a reference to the target thread. */
225168964Sdeischen	if (_thr_ref_add(curthread, thread, 0) != 0) {
226168964Sdeischen		free(new_name);
227168964Sdeischen		ret = ESRCH;
228168964Sdeischen	}
229168964Sdeischen	else {
230168964Sdeischen		THR_THREAD_LOCK(curthread, thread);
231168964Sdeischen		prev_name = thread->name;
232168964Sdeischen		thread->name = new_name;
233168964Sdeischen		THR_THREAD_UNLOCK(curthread, thread);
234168964Sdeischen		_thr_ref_delete(curthread, thread);
235168964Sdeischen		if (prev_name != NULL) {
23660658Sjasone			/* Free space for previous name. */
237168964Sdeischen			free(prev_name);
23860658Sjasone		}
239168964Sdeischen		ret = 0;
24060658Sjasone	}
241168964Sdeischen#if 0
242168964Sdeischen	/* XXX - Should return error code. */
243168964Sdeischen	return (ret);
244168964Sdeischen#endif
24535130Sjb}
246