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