summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/libc_r/uthread/uthread_info.c474
-rw-r--r--lib/libc_r/uthread/uthread_info_openbsd.c364
-rw-r--r--lib/libpthread/uthread/uthread_info.c474
-rw-r--r--lib/libpthread/uthread/uthread_info_openbsd.c364
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, &current_time);
- timespecsub(&pthread->wakeup_time,
- &current_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, &current_time);
+ timespecsub(&pthread->wakeup_time,
+ &current_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, &current_time);
- timespecsub(&pthread->wakeup_time,
- &current_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, &current_time);
+ timespecsub(&pthread->wakeup_time,
+ &current_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