diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/libc_r/uthread/uthread_info.c | 474 | ||||
-rw-r--r-- | lib/libc_r/uthread/uthread_info_openbsd.c | 364 | ||||
-rw-r--r-- | lib/libpthread/uthread/uthread_info.c | 474 | ||||
-rw-r--r-- | lib/libpthread/uthread/uthread_info_openbsd.c | 364 |
4 files changed, 1168 insertions, 508 deletions
diff --git a/lib/libc_r/uthread/uthread_info.c b/lib/libc_r/uthread/uthread_info.c index 870a283701d..dac30c7e6c4 100644 --- a/lib/libc_r/uthread/uthread_info.c +++ b/lib/libc_r/uthread/uthread_info.c @@ -1,3 +1,4 @@ +/* $OpenBSD: uthread_info.c,v 1.9 1999/11/25 06:57:04 d Exp $ */ /* * Copyright (c) 1995-1998 John Birrell <jb@cimlogic.com.au> * All rights reserved. @@ -20,7 +21,7 @@ * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) @@ -29,20 +30,17 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $OpenBSD: uthread_info.c,v 1.8 1999/05/26 00:18:24 d Exp $ + * $FreeBSD: uthread_info.c,v 1.14 1999/09/29 15:18:38 marcel Exp $ */ #include <stdio.h> #include <fcntl.h> #include <string.h> #include <unistd.h> -#include <stdlib.h> -#include <stddef.h> #ifdef _THREAD_SAFE #include <pthread.h> +#include <errno.h> #include "pthread_private.h" -extern int _thread_sig_statistics[]; - struct s_thread_info { enum pthread_state state; char *name; @@ -50,45 +48,29 @@ struct s_thread_info { /* Static variables: */ static const struct s_thread_info thread_info[] = { - {PS_RUNNING , "running"}, - {PS_SIGTHREAD , "sigthread"}, - {PS_MUTEX_WAIT , "mutex_wait"}, - {PS_COND_WAIT , "cond_wait"}, - {PS_FDLR_WAIT , "fdlr_wait"}, - {PS_FDLW_WAIT , "fdlw_wait"}, - {PS_FDR_WAIT , "fdr_wait"}, - {PS_FDW_WAIT , "fdw_wait"}, - {PS_FILE_WAIT , "file_wait"}, - {PS_SELECT_WAIT , "select_wait"}, - {PS_SLEEP_WAIT , "sleep_wait"}, - {PS_WAIT_WAIT , "wait_wait"}, - {PS_SIGSUSPEND , "sigsuspend"}, - {PS_SIGWAIT , "sigwait"}, - {PS_SPINBLOCK , "spinblock"}, - {PS_JOIN , "join"}, - {PS_SUSPENDED , "suspended"}, - {PS_DEAD , "dead"}, - {PS_DEADLOCK , "deadlock"}, - {PS_STATE_MAX , "xxx"} + {PS_RUNNING , "Running"}, + {PS_SIGTHREAD , "Waiting on signal thread"}, + {PS_MUTEX_WAIT , "Waiting on a mutex"}, + {PS_COND_WAIT , "Waiting on a condition variable"}, + {PS_FDLR_WAIT , "Waiting for a file read lock"}, + {PS_FDLW_WAIT , "Waiting for a file write lock"}, + {PS_FDR_WAIT , "Waiting for read"}, + {PS_FDW_WAIT , "Waiting for write"}, + {PS_FILE_WAIT , "Waiting for FILE lock"}, + {PS_POLL_WAIT , "Waiting on poll"}, + {PS_SELECT_WAIT , "Waiting on select"}, + {PS_SLEEP_WAIT , "Sleeping"}, + {PS_WAIT_WAIT , "Waiting process"}, + {PS_SIGSUSPEND , "Suspended, waiting for a signal"}, + {PS_SIGWAIT , "Waiting for a signal"}, + {PS_SPINBLOCK , "Waiting for a spinlock"}, + {PS_JOIN , "Waiting to join"}, + {PS_SUSPENDED , "Suspended"}, + {PS_DEAD , "Dead"}, + {PS_DEADLOCK , "Deadlocked"}, + {PS_STATE_MAX , "Not a real state!"} }; -const static char info_lead[] = " -"; - -/* Determine a filename for display purposes: */ -static const char * -truncname(const char *name, int maxlen) -{ - int len; - - if (name == NULL) - name = "(null)"; - len = strlen(name); - if (len > maxlen) - return name + len - maxlen; - else - return name; -} - void _thread_dump_info(void) { @@ -97,237 +79,224 @@ _thread_dump_info(void) int i; int j; pthread_t pthread; - const char *state; - - /* Open either the controlling tty or the dump file */ + char tmpfile[128]; + pq_list_t *pq_list; - fd = _thread_sys_open(_PATH_TTY, O_WRONLY | O_APPEND); - if (fd < 0) - fd = _thread_sys_open(INFO_DUMP_FILE, - O_WRONLY | O_APPEND | O_CREAT, 0666); - if (fd < 0) + for (i = 0; i < 100000; i++) { + snprintf(tmpfile, sizeof(tmpfile), "/tmp/uthread.dump.%u.%i", + getpid(), i); + /* Open the dump file for append and create it if necessary: */ + if ((fd = _thread_sys_open(tmpfile, O_RDWR | O_CREAT | O_EXCL, + 0666)) < 0) { + /* Can't open the dump file. */ + if (errno == EEXIST) + continue; + /* + * We only need to continue in case of + * EEXIT error. Most other error + * codes means that we will fail all + * the times. + */ + return; + } else { + break; + } + } + if (i==100000) { + /* all 100000 possibilities are in use :( */ return; - - /* Display a list of active threads */ - - snprintf(s, sizeof s, -#ifdef _THREAD_RUSAGE - " %8s%c%-11s %2s %5s %-8s %5s %5s %s\n", -#else - " %8s%c%-11s %2s %5s %-8s %s\n", -#endif - "id", ' ', "state", "pr", "flag", "name", -#ifdef _THREAD_RUSAGE - "utime", "stime", -#endif - "location"); - _thread_sys_write(fd, s, strlen(s)); - - for (pthread = _thread_link_list; pthread != NULL; - pthread = pthread->nxt) - { - char location[30]; - - /* Find last known file:line checkpoint: */ - if (pthread->fname && pthread->state != PS_RUNNING) - snprintf(location, sizeof location, "%s:%d", - truncname(pthread->fname, 21), pthread->lineno); - else - location[0] = '\0'; - - /* Find the state: */ - for (j = 0; j < (sizeof(thread_info) / - sizeof(struct s_thread_info)) - 1; j++) - if (thread_info[j].state == pthread->state) - break; - state = thread_info[j].name; - - /* Output a record for the current thread: */ - s[0] = 0; - snprintf(s, sizeof(s), -#ifdef _THREAD_RUSAGE - " %8p%c%-11s %2d %c%c%c%c%c %-8.8s %5.2f %5.2f %s\n", -#else - " %8p%c%-11s %2d %c%c%c%c%c %-8.8s %s\n", -#endif - (void *)pthread, - (pthread == _thread_run) ? '*' : ' ', - state, - pthread->base_priority, - (pthread->flags & PTHREAD_EXITING) ? 'E' : - (pthread->flags & PTHREAD_CANCELLING) ? 'C' : - (pthread->flags & PTHREAD_AT_CANCEL_POINT) ? 'c' : ' ', - (pthread->attr.flags & PTHREAD_DETACHED) ? 'D' : ' ', - (pthread->attr.flags & PTHREAD_SCOPE_SYSTEM) ? 'S' : ' ', - (pthread->attr.flags & PTHREAD_INHERIT_SCHED) ? 'I' : ' ', - (pthread->attr.flags & PTHREAD_NOFLOAT) ? 'F' : ' ', - (pthread->name == NULL) ? "" : pthread->name, -#ifdef _THREAD_RUSAGE - pthread->ru_utime.tv_sec + - (double)pthread->ru_utime.tv_usec / 1000000.0, - pthread->ru_stime.tv_sec + - (double)pthread->ru_stime.tv_usec / 1000000.0, -#endif - location - ); + } else { + /* Output a header for active threads: */ + strcpy(s, "\n\n=============\nACTIVE THREADS\n\n"); _thread_sys_write(fd, s, strlen(s)); - /* Process according to thread state: */ - switch (pthread->state) { - /* File descriptor read lock wait: */ - case PS_FDLR_WAIT: - case PS_FDLW_WAIT: - case PS_FDR_WAIT: - case PS_FDW_WAIT: - /* Write the lock details: */ - snprintf(s, sizeof(s), "%s fd %d [%s:%d]\n", - info_lead, - pthread->data.fd.fd, - truncname(pthread->data.fd.fname, 32), - pthread->data.fd.branch); - _thread_sys_write(fd, s, strlen(s)); - s[0] = 0; - snprintf(s, sizeof(s), "%s owner %pr/%pw\n", - info_lead, - _thread_fd_table[pthread->data.fd.fd]->r_owner, - _thread_fd_table[pthread->data.fd.fd]->w_owner); - _thread_sys_write(fd, s, strlen(s)); - break; - case PS_SIGWAIT: - snprintf(s, sizeof(s), "%s sigmask 0x%08lx\n", - info_lead, - (unsigned long)pthread->sigmask); - _thread_sys_write(fd, s, strlen(s)); - break; - case PS_MUTEX_WAIT: - snprintf(s, sizeof(s), - "%s mutex %p\n", - info_lead, - pthread->data.mutex); + /* Enter a loop to report each thread in the global list: */ + TAILQ_FOREACH(pthread, &_thread_list, tle) { + /* Find the state: */ + for (j = 0; j < (sizeof(thread_info) / + sizeof(struct s_thread_info)) - 1; j++) + if (thread_info[j].state == pthread->state) + break; + /* Output a record for the current thread: */ + snprintf(s, sizeof(s), + "--------------------\nThread %p (%s) prio %3d state %s [%s:%d]\n", + pthread, (pthread->name == NULL) ? + "":pthread->name, pthread->base_priority, + thread_info[j].name, + pthread->fname,pthread->lineno); _thread_sys_write(fd, s, strlen(s)); - if (pthread->data.mutex) { - snprintf(s, sizeof(s), - "%s owner %p\n", - info_lead, - NULL /* (*pthread->data.mutex)->m_owner*/); + + /* Check if this is the running thread: */ + if (pthread == _thread_run) { + /* Output a record for the running thread: */ + strcpy(s, "This is the running thread\n"); _thread_sys_write(fd, s, strlen(s)); } - break; - case PS_COND_WAIT: - snprintf(s, sizeof(s), - "%s cond %p\n", - info_lead, - pthread->data.cond); - _thread_sys_write(fd, s, strlen(s)); - break; - case PS_JOIN: - if (pthread->queue) { - struct pthread *t; - - /* Locate the thread through its queue: */ - t = (struct pthread*)(( - (char *)pthread->queue) - - offsetof(struct pthread, join_queue)); - snprintf(s, sizeof(s), - "%s thread %p\n", info_lead, t); + /* Check if this is the initial thread: */ + if (pthread == _thread_initial) { + /* Output a record for the initial thread: */ + strcpy(s, "This is the initial thread\n"); _thread_sys_write(fd, s, strlen(s)); } - break; - case PS_SLEEP_WAIT: - { - struct timeval tv; - struct timespec current_time; - struct timespec remaining_time; - double remain; - - gettimeofday(&tv, NULL); - TIMEVAL_TO_TIMESPEC(&tv, ¤t_time); - timespecsub(&pthread->wakeup_time, - ¤t_time, &remaining_time); - remain = remaining_time.tv_sec - + (double)remaining_time.tv_nsec / 1e9; - snprintf(s, sizeof(s), - "%s wake in %f sec\n", - info_lead, remain); + /* Process according to thread state: */ + switch (pthread->state) { + /* File descriptor read lock wait: */ + case PS_FDLR_WAIT: + case PS_FDLW_WAIT: + case PS_FDR_WAIT: + case PS_FDW_WAIT: + /* Write the lock details: */ + snprintf(s, sizeof(s), "fd %d[%s:%d]", + pthread->data.fd.fd, + pthread->data.fd.fname, + pthread->data.fd.branch); + _thread_sys_write(fd, s, strlen(s)); + snprintf(s, sizeof(s), "owner %pr/%pw\n", + _thread_fd_table[pthread->data.fd.fd]->r_owner, + _thread_fd_table[pthread->data.fd.fd]->w_owner); _thread_sys_write(fd, s, strlen(s)); + break; + case PS_SIGWAIT: + snprintf(s, sizeof(s), "sigmask (hi)"); + _thread_sys_write(fd, s, strlen(s)); + for (i = _SIG_WORDS - 1; i >= 0; i--) { + snprintf(s, sizeof(s), "%08x\n", + pthread->sigmask.__bits[i]); + _thread_sys_write(fd, s, strlen(s)); + } + snprintf(s, sizeof(s), "(lo)\n"); + _thread_sys_write(fd, s, strlen(s)); + break; + + /* + * Trap other states that are not explicitly + * coded to dump information: + */ + default: + /* Nothing to do here. */ + break; } - break; - case PS_SELECT_WAIT: - /* XXX information in pthread->data.select_data */ - break; - default: - /* Nothing to do here. */ - break; } - } - - /* Output a header for file descriptors: */ - snprintf(s, sizeof(s), "file descriptor table, size %d\n", - _thread_dtablesize); - _thread_sys_write(fd, s, strlen(s)); - snprintf(s, sizeof s, - " %3s %8s %4s %21s %8s %4s %21s\n", - "fd", "rdowner", "rcnt", "rdcode", - "wrowner", "wcnt", "wrcode"); - _thread_sys_write(fd, s, strlen(s)); + /* Output a header for ready threads: */ + strcpy(s, "\n\n=============\nREADY THREADS\n\n"); + _thread_sys_write(fd, s, strlen(s)); - /* Enter a loop to report file descriptor lock usage: */ - for (i = 0; i < _thread_dtablesize; i++) { - /* - * Check if memory is allocated for this file - * descriptor: - */ - char rcode[22], wcode[22]; + /* Enter a loop to report each thread in the ready queue: */ + TAILQ_FOREACH (pq_list, &_readyq.pq_queue, pl_link) { + TAILQ_FOREACH(pthread, &pq_list->pl_head, pqe) { + /* Find the state: */ + for (j = 0; j < (sizeof(thread_info) / + sizeof(struct s_thread_info)) - 1; j++) + if (thread_info[j].state == pthread->state) + break; + /* Output a record for the current thread: */ + snprintf(s, sizeof(s), + "--------------------\nThread %p (%s) prio %3d state %s [%s:%d]\n", + pthread, (pthread->name == NULL) ? + "":pthread->name, pthread->base_priority, + thread_info[j].name, + pthread->fname,pthread->lineno); + _thread_sys_write(fd, s, strlen(s)); + } + } - if (_thread_fd_table[i] != NULL) { + /* Output a header for waiting threads: */ + strcpy(s, "\n\n=============\nWAITING THREADS\n\n"); + _thread_sys_write(fd, s, strlen(s)); - /* Find the reader's last file:line: */ - if (_thread_fd_table[i]->r_owner) - snprintf(rcode, sizeof rcode, "%s:%d", - truncname(_thread_fd_table[i]->r_fname, 16), - _thread_fd_table[i]->r_lineno); - else - rcode[0] = '\0'; + /* Enter a loop to report each thread in the waiting queue: */ + TAILQ_FOREACH (pthread, &_waitingq, pqe) { + /* Find the state: */ + for (j = 0; j < (sizeof(thread_info) / + sizeof(struct s_thread_info)) - 1; j++) + if (thread_info[j].state == pthread->state) + break; + /* Output a record for the current thread: */ + snprintf(s, sizeof(s), + "--------------------\nThread %p (%s) prio %3d state %s [%s:%d]\n", + pthread, (pthread->name == NULL) ? + "":pthread->name, pthread->base_priority, + thread_info[j].name, + pthread->fname,pthread->lineno); + _thread_sys_write(fd, s, strlen(s)); + } - /* Find the writer's last file:line: */ - if (_thread_fd_table[i]->w_owner) - snprintf(wcode, sizeof wcode, "%s:%d", - truncname(_thread_fd_table[i]->w_fname, 16), - _thread_fd_table[i]->w_lineno); - else - wcode[0] = '\0'; + /* Output a header for threads in the work queue: */ + strcpy(s, "\n\n=============\nTHREADS IN WORKQ\n\n"); + _thread_sys_write(fd, s, strlen(s)); - /* Report the file descriptor lock status: */ + /* Enter a loop to report each thread in the waiting queue: */ + TAILQ_FOREACH (pthread, &_workq, qe) { + /* Find the state: */ + for (j = 0; j < (sizeof(thread_info) / + sizeof(struct s_thread_info)) - 1; j++) + if (thread_info[j].state == pthread->state) + break; + /* Output a record for the current thread: */ snprintf(s, sizeof(s), - " %3d %8p %4d %21s %8p %4d %21s\n", - i, - _thread_fd_table[i]->r_owner, - _thread_fd_table[i]->r_lockcount, - rcode, - _thread_fd_table[i]->w_owner, - _thread_fd_table[i]->w_lockcount, - wcode - ); + "--------------------\nThread %p (%s) prio %3d state %s [%s:%d]\n", + pthread, (pthread->name == NULL) ? + "":pthread->name, pthread->base_priority, + thread_info[j].name, + pthread->fname,pthread->lineno); _thread_sys_write(fd, s, strlen(s)); } - } - /* Show signal counter statistics: */ - snprintf(s, sizeof s, "sig:"); - for (i = 0; i < NSIG; i++) { - char buf[16] = " xx:xxxxx"; - if (_thread_sig_statistics[i]) { - snprintf(buf, sizeof buf, " %d:%d", i, - _thread_sig_statistics[i]); - strlcat(s, buf, sizeof s); + /* Check if there are no dead threads: */ + if (TAILQ_FIRST(&_dead_list) == NULL) { + /* Output a record: */ + strcpy(s, "\n\nTHERE ARE NO DEAD THREADS\n"); + _thread_sys_write(fd, s, strlen(s)); + } else { + /* Output a header for dead threads: */ + strcpy(s, "\n\nDEAD THREADS\n\n"); + _thread_sys_write(fd, s, strlen(s)); + + /* + * Enter a loop to report each thread in the global + * dead thread list: + */ + TAILQ_FOREACH(pthread, &_dead_list, dle) { + /* Output a record for the current thread: */ + snprintf(s, sizeof(s), + "Thread %p prio %3d [%s:%d]\n", + pthread, pthread->base_priority, + pthread->fname,pthread->lineno); + _thread_sys_write(fd, s, strlen(s)); + } } - } - strlcat(s, "\n", sizeof s); - _thread_sys_write(fd, s, strlen(s)); - /* Close the dump file: */ - _thread_sys_close(fd); + /* Output a header for file descriptors: */ + snprintf(s, sizeof(s), "\n\n=============\nFILE DESCRIPTOR TABLE (table size %d)\n\n",_thread_dtablesize); + _thread_sys_write(fd, s, strlen(s)); + + /* Enter a loop to report file descriptor lock usage: */ + for (i = 0; i < _thread_dtablesize; i++) { + /* + * Check if memory is allocated for this file + * descriptor: + */ + if (_thread_fd_table[i] != NULL) { + /* Report the file descriptor lock status: */ + snprintf(s, sizeof(s), + "fd[%3d] read owner %p count %d [%s:%d]\n write owner %p count %d [%s:%d]\n", + i, + _thread_fd_table[i]->r_owner, + _thread_fd_table[i]->r_lockcount, + _thread_fd_table[i]->r_fname, + _thread_fd_table[i]->r_lineno, + _thread_fd_table[i]->w_owner, + _thread_fd_table[i]->w_lockcount, + _thread_fd_table[i]->w_fname, + _thread_fd_table[i]->w_lineno); + _thread_sys_write(fd, s, strlen(s)); + } + } + + /* Close the dump file: */ + _thread_sys_close(fd); + } return; } @@ -336,11 +305,8 @@ void pthread_set_name_np(pthread_t thread, char *name) { /* Check if the caller has specified a valid thread: */ - if (thread != NULL && thread->magic == PTHREAD_MAGIC) { - if (thread->name != NULL) - free(thread->name); + if (thread != NULL && thread->magic == PTHREAD_MAGIC) thread->name = strdup(name); - } return; } #endif diff --git a/lib/libc_r/uthread/uthread_info_openbsd.c b/lib/libc_r/uthread/uthread_info_openbsd.c new file mode 100644 index 00000000000..5f90bdcea20 --- /dev/null +++ b/lib/libc_r/uthread/uthread_info_openbsd.c @@ -0,0 +1,364 @@ +/* + * Copyright (c) 1995-1998 John Birrell <jb@cimlogic.com.au> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by John Birrell. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $OpenBSD: uthread_info_openbsd.c,v 1.1 1999/11/25 06:57:05 d Exp $ + */ +#include <stdio.h> +#include <fcntl.h> +#include <string.h> +#include <unistd.h> +#include <stdlib.h> +#include <stddef.h> +#include <paths.h> +#include <sys/poll.h> +#ifdef _THREAD_SAFE +#include <pthread.h> +#include "pthread_private.h" + +struct s_thread_info { + enum pthread_state state; + char *name; +}; + +/* Static variables: */ +static const struct s_thread_info thread_info[] = { + {PS_RUNNING , "running"}, + {PS_SIGTHREAD , "sigthread"}, + {PS_MUTEX_WAIT , "mutex_wait"}, + {PS_COND_WAIT , "cond_wait"}, + {PS_FDLR_WAIT , "fdlr_wait"}, + {PS_FDLW_WAIT , "fdlw_wait"}, + {PS_FDR_WAIT , "fdr_wait"}, + {PS_FDW_WAIT , "fdw_wait"}, + {PS_FILE_WAIT , "file_wait"}, + {PS_POLL_WAIT , "poll_wait"}, + {PS_SELECT_WAIT , "select_wait"}, + {PS_SLEEP_WAIT , "sleep_wait"}, + {PS_WAIT_WAIT , "wait_wait"}, + {PS_SIGSUSPEND , "sigsuspend"}, + {PS_SIGWAIT , "sigwait"}, + {PS_SPINBLOCK , "spinblock"}, + {PS_JOIN , "join"}, + {PS_SUSPENDED , "suspended"}, + {PS_DEAD , "dead"}, + {PS_DEADLOCK , "deadlock"}, + {(enum pthread_state)0, "<invalid>"}, +}; + +#define writestring(fd, s) _thread_sys_write(fd, s, (sizeof s) - 1) + +const static char info_lead[] = " -"; + +/* Determine a filename for display purposes: */ +static const char * +truncname(const char *name, int maxlen) +{ + int len; + + if (name == NULL) + name = "(null)"; + len = strlen(name); + if (len > maxlen) + return name + len - maxlen; + else + return name; +} + +static void +_thread_dump_entry(pthread, fd) + pthread_t pthread; + int fd; +{ + pthread_t t; + const char *state; + char s[512]; + char location[30]; + int j; + + /* Find last known file:line checkpoint: */ + if (pthread->fname && pthread->state != PS_RUNNING) + snprintf(location, sizeof location, "%s:%d", + truncname(pthread->fname, 21), pthread->lineno); + else + location[0] = '\0'; + + /* Find the state: */ + for (j = 0; j < (sizeof(thread_info) / + sizeof(struct s_thread_info)) - 1; j++) + if (thread_info[j].state == pthread->state) + break; + state = thread_info[j].name; + + /* Output a record for the current thread: */ + s[0] = 0; + snprintf(s, sizeof(s), + " %8p%c%-11s %2d %c%c%c%c%c%c%c %-8.8s %s\n", + (void *)pthread, + (pthread == _thread_run) ? '*' : ' ', + state, + pthread->active_priority, + (pthread->flags & PTHREAD_FLAGS_PRIVATE) ? 'p' : '-', + (pthread->flags & PTHREAD_EXITING) ? 'e' : + (pthread->flags & PTHREAD_FLAGS_CANCELED) ? 'C' : + (pthread->flags & PTHREAD_FLAGS_CANCELPT) ? 'c' : '-', + (pthread->flags & PTHREAD_FLAGS_TRACE) ? 't' : '-', + (pthread->attr.flags & PTHREAD_DETACHED) ? 'D' : '-', + (pthread->attr.flags & PTHREAD_SCOPE_SYSTEM) ? 'S' : '-', + (pthread->attr.flags & PTHREAD_INHERIT_SCHED) ? 'I' : '-', + (pthread->attr.flags & PTHREAD_NOFLOAT) ? 'F' : '-', + (pthread->name == NULL) ? "" : pthread->name, + location + ); + _thread_sys_write(fd, s, strlen(s)); + + /* Process according to thread state: */ + switch (pthread->state) { + /* File descriptor read lock wait: */ + case PS_FDLR_WAIT: + case PS_FDLW_WAIT: + case PS_FDR_WAIT: + case PS_FDW_WAIT: + /* Write the lock details: */ + snprintf(s, sizeof(s), "%s fd %d [%s:%d]\n", + info_lead, + pthread->data.fd.fd, + truncname(pthread->data.fd.fname, 32), + pthread->data.fd.branch); + _thread_sys_write(fd, s, strlen(s)); + s[0] = 0; + snprintf(s, sizeof(s), "%s owner %pr/%pw\n", + info_lead, + _thread_fd_table[pthread->data.fd.fd]->r_owner, + _thread_fd_table[pthread->data.fd.fd]->w_owner); + _thread_sys_write(fd, s, strlen(s)); + break; + case PS_SIGWAIT: + snprintf(s, sizeof(s), "%s sigmask 0x%08lx\n", + info_lead, + (unsigned long)pthread->sigmask); + _thread_sys_write(fd, s, strlen(s)); + break; + case PS_MUTEX_WAIT: + snprintf(s, sizeof(s), + "%s mutex %p\n", + info_lead, + pthread->data.mutex); + _thread_sys_write(fd, s, strlen(s)); + if (pthread->data.mutex) { + snprintf(s, sizeof(s), + "%s owner %p\n", + info_lead, + NULL /* (*pthread->data.mutex)->m_owner*/); + _thread_sys_write(fd, s, strlen(s)); + } + break; + case PS_COND_WAIT: + snprintf(s, sizeof(s), + "%s cond %p\n", + info_lead, + pthread->data.cond); + _thread_sys_write(fd, s, strlen(s)); + break; + case PS_JOIN: + { + struct pthread *t, **last; + pthread_entry_t *e; + + /* Find the end of the list: */ + for (e = &pthread->qe; e->tqe_next != NULL; + e = &e->tqe_next->qe) + ; + last = &e->tqe_next; + /* Walk backwards to the head: */ + for (e = &pthread->qe; + ((_thread_list_t *)e)->tqh_last != last; + e = (pthread_entry_t *)e->tqe_prev) + ; + /* Convert the head address into a thread address: */ + t = (pthread_t)((caddr_t)e - + offsetof(struct pthread, join_queue)); + snprintf(s, sizeof(s), + "%s thread %p\n", info_lead, t); + _thread_sys_write(fd, s, strlen(s)); + } + break; + case PS_SLEEP_WAIT: + { + struct timeval tv; + struct timespec current_time; + struct timespec remaining_time; + double remain; + + gettimeofday(&tv, NULL); + TIMEVAL_TO_TIMESPEC(&tv, ¤t_time); + timespecsub(&pthread->wakeup_time, + ¤t_time, &remaining_time); + remain = remaining_time.tv_sec + + (double)remaining_time.tv_nsec / 1e9; + snprintf(s, sizeof(s), + "%s wake in %f sec\n", + info_lead, remain); + _thread_sys_write(fd, s, strlen(s)); + } + break; + case PS_SELECT_WAIT: + case PS_POLL_WAIT: + { + int i; + + for (i = 0; i < pthread->data.poll_data->nfds; i++) + snprintf(s, sizeof(s), "%s%d:%s%s", + i ? " " : "", + pthread->data.poll_data->fds[i].fd, + pthread->data.poll_data->fds[i].events & + POLLIN ? "r" : "", + pthread->data.poll_data->fds[i].events & + POLLOUT ? "w" : "" + ); + snprintf(s, sizeof(s), "\n"); + } + break; + default: + /* Nothing to do here. */ + break; + } +} + +void +_thread_dump_info(void) +{ + char s[512]; + int fd; + int i; + pthread_t pthread; + pq_list_t * pq_list; + + /* Open the controlling tty: */ + fd = _thread_sys_open(_PATH_TTY, O_WRONLY | O_APPEND); + if (fd < 0) + return; + + /* Display a list of active threads: */ + snprintf(s, sizeof s, " %8s%c%-11s %2s %7s %-8s %s\n", + "id", ' ', "state", "pr", "flags", "name", "location"); + _thread_sys_write(fd, s, strlen(s)); + + writestring(fd, "active:\n"); + TAILQ_FOREACH(pthread, &_thread_list, tle) + _thread_dump_entry(pthread, fd); + + writestring(fd, "ready:\n"); + TAILQ_FOREACH (pq_list, &_readyq.pq_queue, pl_link) + TAILQ_FOREACH(pthread, &pq_list->pl_head, pqe) + _thread_dump_entry(pthread, fd); + + writestring(fd, "waiting:\n"); + TAILQ_FOREACH (pthread, &_waitingq, pqe) + _thread_dump_entry(pthread, fd); + + writestring(fd, "workq:\n"); + TAILQ_FOREACH (pthread, &_workq, qe) + _thread_dump_entry(pthread, fd); + + writestring(fd, "dead:\n"); + TAILQ_FOREACH(pthread, &_dead_list, dle) + _thread_dump_entry(pthread, fd); + + /* Output a header for file descriptors: */ + snprintf(s, sizeof(s), "file descriptor table, size %d\n", + _thread_dtablesize); + _thread_sys_write(fd, s, strlen(s)); + + snprintf(s, sizeof s, + " %3s %8s %4s %21s %8s %4s %21s\n", + "fd", "rdowner", "rcnt", "rdcode", + "wrowner", "wcnt", "wrcode"); + _thread_sys_write(fd, s, strlen(s)); + + /* Enter a loop to report file descriptor lock usage: */ + for (i = 0; i < _thread_dtablesize; i++) { + /* + * Check if memory is allocated for this file + * descriptor: + */ + char rcode[22], wcode[22]; + + if (_thread_fd_table[i] != NULL) { + + /* Find the reader's last file:line: */ + if (_thread_fd_table[i]->r_owner) + snprintf(rcode, sizeof rcode, "%s:%d", + truncname(_thread_fd_table[i]->r_fname, 16), + _thread_fd_table[i]->r_lineno); + else + rcode[0] = '\0'; + + /* Find the writer's last file:line: */ + if (_thread_fd_table[i]->w_owner) + snprintf(wcode, sizeof wcode, "%s:%d", + truncname(_thread_fd_table[i]->w_fname, 16), + _thread_fd_table[i]->w_lineno); + else + wcode[0] = '\0'; + + /* Report the file descriptor lock status: */ + snprintf(s, sizeof(s), + " %3d %8p %4d %21s %8p %4d %21s\n", + i, + _thread_fd_table[i]->r_owner, + _thread_fd_table[i]->r_lockcount, + rcode, + _thread_fd_table[i]->w_owner, + _thread_fd_table[i]->w_lockcount, + wcode + ); + _thread_sys_write(fd, s, strlen(s)); + } + } + + /* Close the dump file: */ + _thread_sys_close(fd); + return; +} + +/* Set the thread name for debug: */ +void +pthread_set_name_np(pthread_t thread, char *name) +{ + /* Check if the caller has specified a valid thread: */ + if (thread != NULL && thread->magic == PTHREAD_MAGIC) { + if (thread->name != NULL) + free(thread->name); + thread->name = strdup(name); + } + return; +} +#endif diff --git a/lib/libpthread/uthread/uthread_info.c b/lib/libpthread/uthread/uthread_info.c index 870a283701d..dac30c7e6c4 100644 --- a/lib/libpthread/uthread/uthread_info.c +++ b/lib/libpthread/uthread/uthread_info.c @@ -1,3 +1,4 @@ +/* $OpenBSD: uthread_info.c,v 1.9 1999/11/25 06:57:04 d Exp $ */ /* * Copyright (c) 1995-1998 John Birrell <jb@cimlogic.com.au> * All rights reserved. @@ -20,7 +21,7 @@ * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) @@ -29,20 +30,17 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $OpenBSD: uthread_info.c,v 1.8 1999/05/26 00:18:24 d Exp $ + * $FreeBSD: uthread_info.c,v 1.14 1999/09/29 15:18:38 marcel Exp $ */ #include <stdio.h> #include <fcntl.h> #include <string.h> #include <unistd.h> -#include <stdlib.h> -#include <stddef.h> #ifdef _THREAD_SAFE #include <pthread.h> +#include <errno.h> #include "pthread_private.h" -extern int _thread_sig_statistics[]; - struct s_thread_info { enum pthread_state state; char *name; @@ -50,45 +48,29 @@ struct s_thread_info { /* Static variables: */ static const struct s_thread_info thread_info[] = { - {PS_RUNNING , "running"}, - {PS_SIGTHREAD , "sigthread"}, - {PS_MUTEX_WAIT , "mutex_wait"}, - {PS_COND_WAIT , "cond_wait"}, - {PS_FDLR_WAIT , "fdlr_wait"}, - {PS_FDLW_WAIT , "fdlw_wait"}, - {PS_FDR_WAIT , "fdr_wait"}, - {PS_FDW_WAIT , "fdw_wait"}, - {PS_FILE_WAIT , "file_wait"}, - {PS_SELECT_WAIT , "select_wait"}, - {PS_SLEEP_WAIT , "sleep_wait"}, - {PS_WAIT_WAIT , "wait_wait"}, - {PS_SIGSUSPEND , "sigsuspend"}, - {PS_SIGWAIT , "sigwait"}, - {PS_SPINBLOCK , "spinblock"}, - {PS_JOIN , "join"}, - {PS_SUSPENDED , "suspended"}, - {PS_DEAD , "dead"}, - {PS_DEADLOCK , "deadlock"}, - {PS_STATE_MAX , "xxx"} + {PS_RUNNING , "Running"}, + {PS_SIGTHREAD , "Waiting on signal thread"}, + {PS_MUTEX_WAIT , "Waiting on a mutex"}, + {PS_COND_WAIT , "Waiting on a condition variable"}, + {PS_FDLR_WAIT , "Waiting for a file read lock"}, + {PS_FDLW_WAIT , "Waiting for a file write lock"}, + {PS_FDR_WAIT , "Waiting for read"}, + {PS_FDW_WAIT , "Waiting for write"}, + {PS_FILE_WAIT , "Waiting for FILE lock"}, + {PS_POLL_WAIT , "Waiting on poll"}, + {PS_SELECT_WAIT , "Waiting on select"}, + {PS_SLEEP_WAIT , "Sleeping"}, + {PS_WAIT_WAIT , "Waiting process"}, + {PS_SIGSUSPEND , "Suspended, waiting for a signal"}, + {PS_SIGWAIT , "Waiting for a signal"}, + {PS_SPINBLOCK , "Waiting for a spinlock"}, + {PS_JOIN , "Waiting to join"}, + {PS_SUSPENDED , "Suspended"}, + {PS_DEAD , "Dead"}, + {PS_DEADLOCK , "Deadlocked"}, + {PS_STATE_MAX , "Not a real state!"} }; -const static char info_lead[] = " -"; - -/* Determine a filename for display purposes: */ -static const char * -truncname(const char *name, int maxlen) -{ - int len; - - if (name == NULL) - name = "(null)"; - len = strlen(name); - if (len > maxlen) - return name + len - maxlen; - else - return name; -} - void _thread_dump_info(void) { @@ -97,237 +79,224 @@ _thread_dump_info(void) int i; int j; pthread_t pthread; - const char *state; - - /* Open either the controlling tty or the dump file */ + char tmpfile[128]; + pq_list_t *pq_list; - fd = _thread_sys_open(_PATH_TTY, O_WRONLY | O_APPEND); - if (fd < 0) - fd = _thread_sys_open(INFO_DUMP_FILE, - O_WRONLY | O_APPEND | O_CREAT, 0666); - if (fd < 0) + for (i = 0; i < 100000; i++) { + snprintf(tmpfile, sizeof(tmpfile), "/tmp/uthread.dump.%u.%i", + getpid(), i); + /* Open the dump file for append and create it if necessary: */ + if ((fd = _thread_sys_open(tmpfile, O_RDWR | O_CREAT | O_EXCL, + 0666)) < 0) { + /* Can't open the dump file. */ + if (errno == EEXIST) + continue; + /* + * We only need to continue in case of + * EEXIT error. Most other error + * codes means that we will fail all + * the times. + */ + return; + } else { + break; + } + } + if (i==100000) { + /* all 100000 possibilities are in use :( */ return; - - /* Display a list of active threads */ - - snprintf(s, sizeof s, -#ifdef _THREAD_RUSAGE - " %8s%c%-11s %2s %5s %-8s %5s %5s %s\n", -#else - " %8s%c%-11s %2s %5s %-8s %s\n", -#endif - "id", ' ', "state", "pr", "flag", "name", -#ifdef _THREAD_RUSAGE - "utime", "stime", -#endif - "location"); - _thread_sys_write(fd, s, strlen(s)); - - for (pthread = _thread_link_list; pthread != NULL; - pthread = pthread->nxt) - { - char location[30]; - - /* Find last known file:line checkpoint: */ - if (pthread->fname && pthread->state != PS_RUNNING) - snprintf(location, sizeof location, "%s:%d", - truncname(pthread->fname, 21), pthread->lineno); - else - location[0] = '\0'; - - /* Find the state: */ - for (j = 0; j < (sizeof(thread_info) / - sizeof(struct s_thread_info)) - 1; j++) - if (thread_info[j].state == pthread->state) - break; - state = thread_info[j].name; - - /* Output a record for the current thread: */ - s[0] = 0; - snprintf(s, sizeof(s), -#ifdef _THREAD_RUSAGE - " %8p%c%-11s %2d %c%c%c%c%c %-8.8s %5.2f %5.2f %s\n", -#else - " %8p%c%-11s %2d %c%c%c%c%c %-8.8s %s\n", -#endif - (void *)pthread, - (pthread == _thread_run) ? '*' : ' ', - state, - pthread->base_priority, - (pthread->flags & PTHREAD_EXITING) ? 'E' : - (pthread->flags & PTHREAD_CANCELLING) ? 'C' : - (pthread->flags & PTHREAD_AT_CANCEL_POINT) ? 'c' : ' ', - (pthread->attr.flags & PTHREAD_DETACHED) ? 'D' : ' ', - (pthread->attr.flags & PTHREAD_SCOPE_SYSTEM) ? 'S' : ' ', - (pthread->attr.flags & PTHREAD_INHERIT_SCHED) ? 'I' : ' ', - (pthread->attr.flags & PTHREAD_NOFLOAT) ? 'F' : ' ', - (pthread->name == NULL) ? "" : pthread->name, -#ifdef _THREAD_RUSAGE - pthread->ru_utime.tv_sec + - (double)pthread->ru_utime.tv_usec / 1000000.0, - pthread->ru_stime.tv_sec + - (double)pthread->ru_stime.tv_usec / 1000000.0, -#endif - location - ); + } else { + /* Output a header for active threads: */ + strcpy(s, "\n\n=============\nACTIVE THREADS\n\n"); _thread_sys_write(fd, s, strlen(s)); - /* Process according to thread state: */ - switch (pthread->state) { - /* File descriptor read lock wait: */ - case PS_FDLR_WAIT: - case PS_FDLW_WAIT: - case PS_FDR_WAIT: - case PS_FDW_WAIT: - /* Write the lock details: */ - snprintf(s, sizeof(s), "%s fd %d [%s:%d]\n", - info_lead, - pthread->data.fd.fd, - truncname(pthread->data.fd.fname, 32), - pthread->data.fd.branch); - _thread_sys_write(fd, s, strlen(s)); - s[0] = 0; - snprintf(s, sizeof(s), "%s owner %pr/%pw\n", - info_lead, - _thread_fd_table[pthread->data.fd.fd]->r_owner, - _thread_fd_table[pthread->data.fd.fd]->w_owner); - _thread_sys_write(fd, s, strlen(s)); - break; - case PS_SIGWAIT: - snprintf(s, sizeof(s), "%s sigmask 0x%08lx\n", - info_lead, - (unsigned long)pthread->sigmask); - _thread_sys_write(fd, s, strlen(s)); - break; - case PS_MUTEX_WAIT: - snprintf(s, sizeof(s), - "%s mutex %p\n", - info_lead, - pthread->data.mutex); + /* Enter a loop to report each thread in the global list: */ + TAILQ_FOREACH(pthread, &_thread_list, tle) { + /* Find the state: */ + for (j = 0; j < (sizeof(thread_info) / + sizeof(struct s_thread_info)) - 1; j++) + if (thread_info[j].state == pthread->state) + break; + /* Output a record for the current thread: */ + snprintf(s, sizeof(s), + "--------------------\nThread %p (%s) prio %3d state %s [%s:%d]\n", + pthread, (pthread->name == NULL) ? + "":pthread->name, pthread->base_priority, + thread_info[j].name, + pthread->fname,pthread->lineno); _thread_sys_write(fd, s, strlen(s)); - if (pthread->data.mutex) { - snprintf(s, sizeof(s), - "%s owner %p\n", - info_lead, - NULL /* (*pthread->data.mutex)->m_owner*/); + + /* Check if this is the running thread: */ + if (pthread == _thread_run) { + /* Output a record for the running thread: */ + strcpy(s, "This is the running thread\n"); _thread_sys_write(fd, s, strlen(s)); } - break; - case PS_COND_WAIT: - snprintf(s, sizeof(s), - "%s cond %p\n", - info_lead, - pthread->data.cond); - _thread_sys_write(fd, s, strlen(s)); - break; - case PS_JOIN: - if (pthread->queue) { - struct pthread *t; - - /* Locate the thread through its queue: */ - t = (struct pthread*)(( - (char *)pthread->queue) - - offsetof(struct pthread, join_queue)); - snprintf(s, sizeof(s), - "%s thread %p\n", info_lead, t); + /* Check if this is the initial thread: */ + if (pthread == _thread_initial) { + /* Output a record for the initial thread: */ + strcpy(s, "This is the initial thread\n"); _thread_sys_write(fd, s, strlen(s)); } - break; - case PS_SLEEP_WAIT: - { - struct timeval tv; - struct timespec current_time; - struct timespec remaining_time; - double remain; - - gettimeofday(&tv, NULL); - TIMEVAL_TO_TIMESPEC(&tv, ¤t_time); - timespecsub(&pthread->wakeup_time, - ¤t_time, &remaining_time); - remain = remaining_time.tv_sec - + (double)remaining_time.tv_nsec / 1e9; - snprintf(s, sizeof(s), - "%s wake in %f sec\n", - info_lead, remain); + /* Process according to thread state: */ + switch (pthread->state) { + /* File descriptor read lock wait: */ + case PS_FDLR_WAIT: + case PS_FDLW_WAIT: + case PS_FDR_WAIT: + case PS_FDW_WAIT: + /* Write the lock details: */ + snprintf(s, sizeof(s), "fd %d[%s:%d]", + pthread->data.fd.fd, + pthread->data.fd.fname, + pthread->data.fd.branch); + _thread_sys_write(fd, s, strlen(s)); + snprintf(s, sizeof(s), "owner %pr/%pw\n", + _thread_fd_table[pthread->data.fd.fd]->r_owner, + _thread_fd_table[pthread->data.fd.fd]->w_owner); _thread_sys_write(fd, s, strlen(s)); + break; + case PS_SIGWAIT: + snprintf(s, sizeof(s), "sigmask (hi)"); + _thread_sys_write(fd, s, strlen(s)); + for (i = _SIG_WORDS - 1; i >= 0; i--) { + snprintf(s, sizeof(s), "%08x\n", + pthread->sigmask.__bits[i]); + _thread_sys_write(fd, s, strlen(s)); + } + snprintf(s, sizeof(s), "(lo)\n"); + _thread_sys_write(fd, s, strlen(s)); + break; + + /* + * Trap other states that are not explicitly + * coded to dump information: + */ + default: + /* Nothing to do here. */ + break; } - break; - case PS_SELECT_WAIT: - /* XXX information in pthread->data.select_data */ - break; - default: - /* Nothing to do here. */ - break; } - } - - /* Output a header for file descriptors: */ - snprintf(s, sizeof(s), "file descriptor table, size %d\n", - _thread_dtablesize); - _thread_sys_write(fd, s, strlen(s)); - snprintf(s, sizeof s, - " %3s %8s %4s %21s %8s %4s %21s\n", - "fd", "rdowner", "rcnt", "rdcode", - "wrowner", "wcnt", "wrcode"); - _thread_sys_write(fd, s, strlen(s)); + /* Output a header for ready threads: */ + strcpy(s, "\n\n=============\nREADY THREADS\n\n"); + _thread_sys_write(fd, s, strlen(s)); - /* Enter a loop to report file descriptor lock usage: */ - for (i = 0; i < _thread_dtablesize; i++) { - /* - * Check if memory is allocated for this file - * descriptor: - */ - char rcode[22], wcode[22]; + /* Enter a loop to report each thread in the ready queue: */ + TAILQ_FOREACH (pq_list, &_readyq.pq_queue, pl_link) { + TAILQ_FOREACH(pthread, &pq_list->pl_head, pqe) { + /* Find the state: */ + for (j = 0; j < (sizeof(thread_info) / + sizeof(struct s_thread_info)) - 1; j++) + if (thread_info[j].state == pthread->state) + break; + /* Output a record for the current thread: */ + snprintf(s, sizeof(s), + "--------------------\nThread %p (%s) prio %3d state %s [%s:%d]\n", + pthread, (pthread->name == NULL) ? + "":pthread->name, pthread->base_priority, + thread_info[j].name, + pthread->fname,pthread->lineno); + _thread_sys_write(fd, s, strlen(s)); + } + } - if (_thread_fd_table[i] != NULL) { + /* Output a header for waiting threads: */ + strcpy(s, "\n\n=============\nWAITING THREADS\n\n"); + _thread_sys_write(fd, s, strlen(s)); - /* Find the reader's last file:line: */ - if (_thread_fd_table[i]->r_owner) - snprintf(rcode, sizeof rcode, "%s:%d", - truncname(_thread_fd_table[i]->r_fname, 16), - _thread_fd_table[i]->r_lineno); - else - rcode[0] = '\0'; + /* Enter a loop to report each thread in the waiting queue: */ + TAILQ_FOREACH (pthread, &_waitingq, pqe) { + /* Find the state: */ + for (j = 0; j < (sizeof(thread_info) / + sizeof(struct s_thread_info)) - 1; j++) + if (thread_info[j].state == pthread->state) + break; + /* Output a record for the current thread: */ + snprintf(s, sizeof(s), + "--------------------\nThread %p (%s) prio %3d state %s [%s:%d]\n", + pthread, (pthread->name == NULL) ? + "":pthread->name, pthread->base_priority, + thread_info[j].name, + pthread->fname,pthread->lineno); + _thread_sys_write(fd, s, strlen(s)); + } - /* Find the writer's last file:line: */ - if (_thread_fd_table[i]->w_owner) - snprintf(wcode, sizeof wcode, "%s:%d", - truncname(_thread_fd_table[i]->w_fname, 16), - _thread_fd_table[i]->w_lineno); - else - wcode[0] = '\0'; + /* Output a header for threads in the work queue: */ + strcpy(s, "\n\n=============\nTHREADS IN WORKQ\n\n"); + _thread_sys_write(fd, s, strlen(s)); - /* Report the file descriptor lock status: */ + /* Enter a loop to report each thread in the waiting queue: */ + TAILQ_FOREACH (pthread, &_workq, qe) { + /* Find the state: */ + for (j = 0; j < (sizeof(thread_info) / + sizeof(struct s_thread_info)) - 1; j++) + if (thread_info[j].state == pthread->state) + break; + /* Output a record for the current thread: */ snprintf(s, sizeof(s), - " %3d %8p %4d %21s %8p %4d %21s\n", - i, - _thread_fd_table[i]->r_owner, - _thread_fd_table[i]->r_lockcount, - rcode, - _thread_fd_table[i]->w_owner, - _thread_fd_table[i]->w_lockcount, - wcode - ); + "--------------------\nThread %p (%s) prio %3d state %s [%s:%d]\n", + pthread, (pthread->name == NULL) ? + "":pthread->name, pthread->base_priority, + thread_info[j].name, + pthread->fname,pthread->lineno); _thread_sys_write(fd, s, strlen(s)); } - } - /* Show signal counter statistics: */ - snprintf(s, sizeof s, "sig:"); - for (i = 0; i < NSIG; i++) { - char buf[16] = " xx:xxxxx"; - if (_thread_sig_statistics[i]) { - snprintf(buf, sizeof buf, " %d:%d", i, - _thread_sig_statistics[i]); - strlcat(s, buf, sizeof s); + /* Check if there are no dead threads: */ + if (TAILQ_FIRST(&_dead_list) == NULL) { + /* Output a record: */ + strcpy(s, "\n\nTHERE ARE NO DEAD THREADS\n"); + _thread_sys_write(fd, s, strlen(s)); + } else { + /* Output a header for dead threads: */ + strcpy(s, "\n\nDEAD THREADS\n\n"); + _thread_sys_write(fd, s, strlen(s)); + + /* + * Enter a loop to report each thread in the global + * dead thread list: + */ + TAILQ_FOREACH(pthread, &_dead_list, dle) { + /* Output a record for the current thread: */ + snprintf(s, sizeof(s), + "Thread %p prio %3d [%s:%d]\n", + pthread, pthread->base_priority, + pthread->fname,pthread->lineno); + _thread_sys_write(fd, s, strlen(s)); + } } - } - strlcat(s, "\n", sizeof s); - _thread_sys_write(fd, s, strlen(s)); - /* Close the dump file: */ - _thread_sys_close(fd); + /* Output a header for file descriptors: */ + snprintf(s, sizeof(s), "\n\n=============\nFILE DESCRIPTOR TABLE (table size %d)\n\n",_thread_dtablesize); + _thread_sys_write(fd, s, strlen(s)); + + /* Enter a loop to report file descriptor lock usage: */ + for (i = 0; i < _thread_dtablesize; i++) { + /* + * Check if memory is allocated for this file + * descriptor: + */ + if (_thread_fd_table[i] != NULL) { + /* Report the file descriptor lock status: */ + snprintf(s, sizeof(s), + "fd[%3d] read owner %p count %d [%s:%d]\n write owner %p count %d [%s:%d]\n", + i, + _thread_fd_table[i]->r_owner, + _thread_fd_table[i]->r_lockcount, + _thread_fd_table[i]->r_fname, + _thread_fd_table[i]->r_lineno, + _thread_fd_table[i]->w_owner, + _thread_fd_table[i]->w_lockcount, + _thread_fd_table[i]->w_fname, + _thread_fd_table[i]->w_lineno); + _thread_sys_write(fd, s, strlen(s)); + } + } + + /* Close the dump file: */ + _thread_sys_close(fd); + } return; } @@ -336,11 +305,8 @@ void pthread_set_name_np(pthread_t thread, char *name) { /* Check if the caller has specified a valid thread: */ - if (thread != NULL && thread->magic == PTHREAD_MAGIC) { - if (thread->name != NULL) - free(thread->name); + if (thread != NULL && thread->magic == PTHREAD_MAGIC) thread->name = strdup(name); - } return; } #endif diff --git a/lib/libpthread/uthread/uthread_info_openbsd.c b/lib/libpthread/uthread/uthread_info_openbsd.c new file mode 100644 index 00000000000..5f90bdcea20 --- /dev/null +++ b/lib/libpthread/uthread/uthread_info_openbsd.c @@ -0,0 +1,364 @@ +/* + * Copyright (c) 1995-1998 John Birrell <jb@cimlogic.com.au> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by John Birrell. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $OpenBSD: uthread_info_openbsd.c,v 1.1 1999/11/25 06:57:05 d Exp $ + */ +#include <stdio.h> +#include <fcntl.h> +#include <string.h> +#include <unistd.h> +#include <stdlib.h> +#include <stddef.h> +#include <paths.h> +#include <sys/poll.h> +#ifdef _THREAD_SAFE +#include <pthread.h> +#include "pthread_private.h" + +struct s_thread_info { + enum pthread_state state; + char *name; +}; + +/* Static variables: */ +static const struct s_thread_info thread_info[] = { + {PS_RUNNING , "running"}, + {PS_SIGTHREAD , "sigthread"}, + {PS_MUTEX_WAIT , "mutex_wait"}, + {PS_COND_WAIT , "cond_wait"}, + {PS_FDLR_WAIT , "fdlr_wait"}, + {PS_FDLW_WAIT , "fdlw_wait"}, + {PS_FDR_WAIT , "fdr_wait"}, + {PS_FDW_WAIT , "fdw_wait"}, + {PS_FILE_WAIT , "file_wait"}, + {PS_POLL_WAIT , "poll_wait"}, + {PS_SELECT_WAIT , "select_wait"}, + {PS_SLEEP_WAIT , "sleep_wait"}, + {PS_WAIT_WAIT , "wait_wait"}, + {PS_SIGSUSPEND , "sigsuspend"}, + {PS_SIGWAIT , "sigwait"}, + {PS_SPINBLOCK , "spinblock"}, + {PS_JOIN , "join"}, + {PS_SUSPENDED , "suspended"}, + {PS_DEAD , "dead"}, + {PS_DEADLOCK , "deadlock"}, + {(enum pthread_state)0, "<invalid>"}, +}; + +#define writestring(fd, s) _thread_sys_write(fd, s, (sizeof s) - 1) + +const static char info_lead[] = " -"; + +/* Determine a filename for display purposes: */ +static const char * +truncname(const char *name, int maxlen) +{ + int len; + + if (name == NULL) + name = "(null)"; + len = strlen(name); + if (len > maxlen) + return name + len - maxlen; + else + return name; +} + +static void +_thread_dump_entry(pthread, fd) + pthread_t pthread; + int fd; +{ + pthread_t t; + const char *state; + char s[512]; + char location[30]; + int j; + + /* Find last known file:line checkpoint: */ + if (pthread->fname && pthread->state != PS_RUNNING) + snprintf(location, sizeof location, "%s:%d", + truncname(pthread->fname, 21), pthread->lineno); + else + location[0] = '\0'; + + /* Find the state: */ + for (j = 0; j < (sizeof(thread_info) / + sizeof(struct s_thread_info)) - 1; j++) + if (thread_info[j].state == pthread->state) + break; + state = thread_info[j].name; + + /* Output a record for the current thread: */ + s[0] = 0; + snprintf(s, sizeof(s), + " %8p%c%-11s %2d %c%c%c%c%c%c%c %-8.8s %s\n", + (void *)pthread, + (pthread == _thread_run) ? '*' : ' ', + state, + pthread->active_priority, + (pthread->flags & PTHREAD_FLAGS_PRIVATE) ? 'p' : '-', + (pthread->flags & PTHREAD_EXITING) ? 'e' : + (pthread->flags & PTHREAD_FLAGS_CANCELED) ? 'C' : + (pthread->flags & PTHREAD_FLAGS_CANCELPT) ? 'c' : '-', + (pthread->flags & PTHREAD_FLAGS_TRACE) ? 't' : '-', + (pthread->attr.flags & PTHREAD_DETACHED) ? 'D' : '-', + (pthread->attr.flags & PTHREAD_SCOPE_SYSTEM) ? 'S' : '-', + (pthread->attr.flags & PTHREAD_INHERIT_SCHED) ? 'I' : '-', + (pthread->attr.flags & PTHREAD_NOFLOAT) ? 'F' : '-', + (pthread->name == NULL) ? "" : pthread->name, + location + ); + _thread_sys_write(fd, s, strlen(s)); + + /* Process according to thread state: */ + switch (pthread->state) { + /* File descriptor read lock wait: */ + case PS_FDLR_WAIT: + case PS_FDLW_WAIT: + case PS_FDR_WAIT: + case PS_FDW_WAIT: + /* Write the lock details: */ + snprintf(s, sizeof(s), "%s fd %d [%s:%d]\n", + info_lead, + pthread->data.fd.fd, + truncname(pthread->data.fd.fname, 32), + pthread->data.fd.branch); + _thread_sys_write(fd, s, strlen(s)); + s[0] = 0; + snprintf(s, sizeof(s), "%s owner %pr/%pw\n", + info_lead, + _thread_fd_table[pthread->data.fd.fd]->r_owner, + _thread_fd_table[pthread->data.fd.fd]->w_owner); + _thread_sys_write(fd, s, strlen(s)); + break; + case PS_SIGWAIT: + snprintf(s, sizeof(s), "%s sigmask 0x%08lx\n", + info_lead, + (unsigned long)pthread->sigmask); + _thread_sys_write(fd, s, strlen(s)); + break; + case PS_MUTEX_WAIT: + snprintf(s, sizeof(s), + "%s mutex %p\n", + info_lead, + pthread->data.mutex); + _thread_sys_write(fd, s, strlen(s)); + if (pthread->data.mutex) { + snprintf(s, sizeof(s), + "%s owner %p\n", + info_lead, + NULL /* (*pthread->data.mutex)->m_owner*/); + _thread_sys_write(fd, s, strlen(s)); + } + break; + case PS_COND_WAIT: + snprintf(s, sizeof(s), + "%s cond %p\n", + info_lead, + pthread->data.cond); + _thread_sys_write(fd, s, strlen(s)); + break; + case PS_JOIN: + { + struct pthread *t, **last; + pthread_entry_t *e; + + /* Find the end of the list: */ + for (e = &pthread->qe; e->tqe_next != NULL; + e = &e->tqe_next->qe) + ; + last = &e->tqe_next; + /* Walk backwards to the head: */ + for (e = &pthread->qe; + ((_thread_list_t *)e)->tqh_last != last; + e = (pthread_entry_t *)e->tqe_prev) + ; + /* Convert the head address into a thread address: */ + t = (pthread_t)((caddr_t)e - + offsetof(struct pthread, join_queue)); + snprintf(s, sizeof(s), + "%s thread %p\n", info_lead, t); + _thread_sys_write(fd, s, strlen(s)); + } + break; + case PS_SLEEP_WAIT: + { + struct timeval tv; + struct timespec current_time; + struct timespec remaining_time; + double remain; + + gettimeofday(&tv, NULL); + TIMEVAL_TO_TIMESPEC(&tv, ¤t_time); + timespecsub(&pthread->wakeup_time, + ¤t_time, &remaining_time); + remain = remaining_time.tv_sec + + (double)remaining_time.tv_nsec / 1e9; + snprintf(s, sizeof(s), + "%s wake in %f sec\n", + info_lead, remain); + _thread_sys_write(fd, s, strlen(s)); + } + break; + case PS_SELECT_WAIT: + case PS_POLL_WAIT: + { + int i; + + for (i = 0; i < pthread->data.poll_data->nfds; i++) + snprintf(s, sizeof(s), "%s%d:%s%s", + i ? " " : "", + pthread->data.poll_data->fds[i].fd, + pthread->data.poll_data->fds[i].events & + POLLIN ? "r" : "", + pthread->data.poll_data->fds[i].events & + POLLOUT ? "w" : "" + ); + snprintf(s, sizeof(s), "\n"); + } + break; + default: + /* Nothing to do here. */ + break; + } +} + +void +_thread_dump_info(void) +{ + char s[512]; + int fd; + int i; + pthread_t pthread; + pq_list_t * pq_list; + + /* Open the controlling tty: */ + fd = _thread_sys_open(_PATH_TTY, O_WRONLY | O_APPEND); + if (fd < 0) + return; + + /* Display a list of active threads: */ + snprintf(s, sizeof s, " %8s%c%-11s %2s %7s %-8s %s\n", + "id", ' ', "state", "pr", "flags", "name", "location"); + _thread_sys_write(fd, s, strlen(s)); + + writestring(fd, "active:\n"); + TAILQ_FOREACH(pthread, &_thread_list, tle) + _thread_dump_entry(pthread, fd); + + writestring(fd, "ready:\n"); + TAILQ_FOREACH (pq_list, &_readyq.pq_queue, pl_link) + TAILQ_FOREACH(pthread, &pq_list->pl_head, pqe) + _thread_dump_entry(pthread, fd); + + writestring(fd, "waiting:\n"); + TAILQ_FOREACH (pthread, &_waitingq, pqe) + _thread_dump_entry(pthread, fd); + + writestring(fd, "workq:\n"); + TAILQ_FOREACH (pthread, &_workq, qe) + _thread_dump_entry(pthread, fd); + + writestring(fd, "dead:\n"); + TAILQ_FOREACH(pthread, &_dead_list, dle) + _thread_dump_entry(pthread, fd); + + /* Output a header for file descriptors: */ + snprintf(s, sizeof(s), "file descriptor table, size %d\n", + _thread_dtablesize); + _thread_sys_write(fd, s, strlen(s)); + + snprintf(s, sizeof s, + " %3s %8s %4s %21s %8s %4s %21s\n", + "fd", "rdowner", "rcnt", "rdcode", + "wrowner", "wcnt", "wrcode"); + _thread_sys_write(fd, s, strlen(s)); + + /* Enter a loop to report file descriptor lock usage: */ + for (i = 0; i < _thread_dtablesize; i++) { + /* + * Check if memory is allocated for this file + * descriptor: + */ + char rcode[22], wcode[22]; + + if (_thread_fd_table[i] != NULL) { + + /* Find the reader's last file:line: */ + if (_thread_fd_table[i]->r_owner) + snprintf(rcode, sizeof rcode, "%s:%d", + truncname(_thread_fd_table[i]->r_fname, 16), + _thread_fd_table[i]->r_lineno); + else + rcode[0] = '\0'; + + /* Find the writer's last file:line: */ + if (_thread_fd_table[i]->w_owner) + snprintf(wcode, sizeof wcode, "%s:%d", + truncname(_thread_fd_table[i]->w_fname, 16), + _thread_fd_table[i]->w_lineno); + else + wcode[0] = '\0'; + + /* Report the file descriptor lock status: */ + snprintf(s, sizeof(s), + " %3d %8p %4d %21s %8p %4d %21s\n", + i, + _thread_fd_table[i]->r_owner, + _thread_fd_table[i]->r_lockcount, + rcode, + _thread_fd_table[i]->w_owner, + _thread_fd_table[i]->w_lockcount, + wcode + ); + _thread_sys_write(fd, s, strlen(s)); + } + } + + /* Close the dump file: */ + _thread_sys_close(fd); + return; +} + +/* Set the thread name for debug: */ +void +pthread_set_name_np(pthread_t thread, char *name) +{ + /* Check if the caller has specified a valid thread: */ + if (thread != NULL && thread->magic == PTHREAD_MAGIC) { + if (thread->name != NULL) + free(thread->name); + thread->name = strdup(name); + } + return; +} +#endif |