Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/lib/libpthread_dbg Add td_thr_suspend() and td_thr_resume(), ...



details:   https://anonhg.NetBSD.org/src/rev/35206c36eb4b
branches:  trunk
changeset: 567145:35206c36eb4b
user:      nathanw <nathanw%NetBSD.org@localhost>
date:      Wed Jun 02 21:13:42 2004 +0000

description:
Add td_thr_suspend() and td_thr_resume(), to suspend and resume
threads from the context of a debugger.

diffstat:

 lib/libpthread_dbg/pthread_dbg.c     |  310 ++++++++++++++++++++++++++++++++++-
 lib/libpthread_dbg/pthread_dbg.h     |    8 +-
 lib/libpthread_dbg/pthread_dbg_int.h |    3 +
 3 files changed, 318 insertions(+), 3 deletions(-)

diffs (truncated from 370 to 300 lines):

diff -r f4b02e6237fd -r 35206c36eb4b lib/libpthread_dbg/pthread_dbg.c
--- a/lib/libpthread_dbg/pthread_dbg.c  Wed Jun 02 21:11:15 2004 +0000
+++ b/lib/libpthread_dbg/pthread_dbg.c  Wed Jun 02 21:13:42 2004 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: pthread_dbg.c,v 1.16 2004/02/21 20:48:11 cl Exp $      */
+/*     $NetBSD: pthread_dbg.c,v 1.17 2004/06/02 21:13:42 nathanw Exp $ */
 
 /*-
  * Copyright (c) 2002 Wasabi Systems, Inc.
@@ -36,7 +36,7 @@
  */
 
 #include <sys/cdefs.h>
-__RCSID("$NetBSD: pthread_dbg.c,v 1.16 2004/02/21 20:48:11 cl Exp $");
+__RCSID("$NetBSD: pthread_dbg.c,v 1.17 2004/06/02 21:13:42 nathanw Exp $");
 
 #include <stddef.h>
 #include <stdlib.h>
@@ -92,6 +92,30 @@
        }
        proc->allqaddr = addr;
 
+       val = LOOKUP(proc, "pthread__runqueue", &addr);
+       if (val != 0) {
+               if (val == TD_ERR_NOSYM)
+                       val = TD_ERR_NOLIB;
+               goto error;
+       }
+       proc->runqaddr = addr;
+
+       val = LOOKUP(proc, "pthread__idlequeue", &addr);
+       if (val != 0) {
+               if (val == TD_ERR_NOSYM)
+                       val = TD_ERR_NOLIB;
+               goto error;
+       }
+       proc->idleqaddr = addr;
+
+       val = LOOKUP(proc, "pthread__suspqueue", &addr);
+       if (val != 0) {
+               if (val == TD_ERR_NOSYM)
+                       val = TD_ERR_NOLIB;
+               goto error;
+       }
+       proc->suspqaddr = addr;
+
        val = LOOKUP(proc, "pthread__maxlwps", &addr);
        if (val != 0) {
                if (val == TD_ERR_NOSYM)
@@ -953,6 +977,288 @@
 
 }
 
+#define DPTQ_REMOVE(head, elm, field) do {                             \
+       int _val;                                                       \
+       PTQ_ENTRY(__pthread_st) _qent;                                  \
+                                                                       \
+        _val = READ(thread->proc,                                      \
+           (elm) + offsetof(struct __pthread_st, field),               \
+           &_qent, sizeof(_qent));                                     \
+        if (_val != 0)                                                         \
+               return _val;                                            \
+       if (_qent.ptqe_next != NULL) {                                  \
+               _val = WRITE(thread->proc,                              \
+                   (caddr_t)(void *)_qent.ptqe_next +                  \
+                   offsetof(struct __pthread_st, field.ptqe_prev),     \
+                   &_qent.ptqe_prev, sizeof(_qent.ptqe_prev));         \
+               if (_val != 0)                                          \
+                       return _val;                                    \
+       } else {                                                        \
+               _val = WRITE(thread->proc, (head) +                     \
+                   offsetof(struct pthread_queue_t, ptqh_last),        \
+                   &_qent.ptqe_prev, sizeof(_qent.ptqe_prev));         \
+               if (_val != 0)                                          \
+                       return _val;                                    \
+       }                                                               \
+       _val = WRITE(thread->proc, (caddr_t)(void *)_qent.ptqe_prev,    \
+           &_qent.ptqe_next, sizeof(_qent.ptqe_next));                 \
+       if (_val != 0)                                                  \
+               return _val;                                            \
+} while (/*CONSTCOND*/0)
+
+#define DPTQ_INSERT_TAIL(head, elm, field) do {                                \
+       int _val;                                                       \
+       struct pthread_queue_t _qhead;                                  \
+       PTQ_ENTRY(__pthread_st) _qent;                                  \
+                                                                       \
+       /* if ((head)->ptqh_last == NULL)                       */      \
+       /*   (head)->ptqh_last = &(head)->ptqh_first;           */      \
+       _val = READ(thread->proc, (head), &_qhead, sizeof(_qhead));     \
+                                                                       \
+       if (_val != 0)                                                  \
+               return _val;                                            \
+       if (_qhead.ptqh_last == NULL)                                   \
+               _qhead.ptqh_last = (void *)(head);                      \
+                                                                       \
+       /* (elm)->field.ptqe_prev = (head)->ptqh_last;          */      \
+       _qent.ptqe_prev = _qhead.ptqh_last;                             \
+                                                                       \
+       /* *(head)->ptqh_last = (elm);                          */      \
+       _qent.ptqe_next = (void *)elm;                                  \
+       _val = WRITE(thread->proc, (caddr_t)(void *)_qhead.ptqh_last,   \
+           &_qent.ptqe_next, sizeof(_qent.ptqe_next));                 \
+       if (_val != 0)                                                  \
+               return _val;                                            \
+                                                                       \
+       /* (elm)->field.ptqe_next = NULL; */                            \
+       _qent.ptqe_next = NULL;                                         \
+                                                                       \
+       /* (head)->ptqh_last = &(elm)->field.ptqe_next;         */      \
+       _qhead.ptqh_last = (void *) ((elm) +                            \
+           offsetof(struct __pthread_st, field.ptqe_next));            \
+                                                                       \
+       _val = WRITE(thread->proc, (elm) +                              \
+           offsetof(struct __pthread_st, field),                       \
+           &_qent, sizeof(_qent));                                     \
+       if (_val != 0)                                                  \
+               return _val;                                            \
+       _val = WRITE(thread->proc,                                      \
+           (head) + offsetof(struct pthread_queue_t, ptqh_last),       \
+           &_qhead.ptqh_last, sizeof(_qhead.ptqh_last));               \
+       if (_val != 0)                                                  \
+               return _val;                                            \
+} while (/*CONSTCOND*/0)
+
+               
+/* Suspend a thread from running */
+int
+td_thr_suspend(td_thread_t *thread)
+{
+       int tmp, tmp1, val;
+       caddr_t addr, sp, nthread, qaddr;
+       struct reg r;
+       struct fpreg fr;
+       ucontext_t uc;
+       struct pthread_queue_t qhead;
+
+       /* validate the thread */
+       val = READ(thread->proc, thread->addr, &tmp, sizeof(tmp));
+       if (val != 0)
+               return val;
+       if (tmp != PT_MAGIC)
+               return TD_ERR_BADTHREAD;
+
+       val = READ(thread->proc, 
+           thread->addr + offsetof(struct __pthread_st, pt_type), 
+           &tmp, sizeof(tmp));
+       if (val != 0)
+               return val;
+       if (tmp != PT_THREAD_NORMAL)
+               return TD_ERR_BADTHREAD;
+
+       /* find the thread's current state */
+       if ((val = READ(thread->proc, 
+           thread->addr + offsetof(struct __pthread_st, pt_blockgen), 
+           &tmp, sizeof(tmp))) != 0)
+               return val;
+       if ((val = READ(thread->proc, 
+           thread->addr + offsetof(struct __pthread_st, pt_unblockgen), 
+           &tmp1, sizeof(tmp1))) != 0)
+               return val;
+       if (tmp != tmp1)
+               tmp = _PT_STATE_BLOCKED_SYS;
+       else if ((val = READ(thread->proc, 
+                     thread->addr + offsetof(struct __pthread_st, pt_state), 
+                     &tmp, sizeof(tmp))) != 0)
+               return val;
+
+       switch (tmp) {
+       case PT_STATE_RUNNING:
+               /* grab the current thread's state and stash it */
+               val = GETREGS(thread->proc, 0, thread->lwp, &r);
+               if (val != 0)
+                       return val;
+               val = GETREGS(thread->proc, 1, thread->lwp, &fr);
+               if (val != 0)
+                       return val;
+               _INITCONTEXT_U(&uc);
+               PTHREAD_REG_TO_UCONTEXT(&uc, &r);
+               PTHREAD_FPREG_TO_UCONTEXT(&uc, &fr);
+               sp = (caddr_t)pthread__uc_sp(&uc);
+               sp -= sizeof(uc);
+#ifdef _UC_UCONTEXT_ALIGN
+               sp = (caddr_t) ((unsigned long)sp & _UC_UCONTEXT_ALIGN);
+#endif
+               val = WRITE(thread->proc, sp, &uc, sizeof(uc));
+               if (val != 0)
+                       return val;
+               val = WRITE(thread->proc,
+                   thread->addr + offsetof(struct __pthread_st, pt_uc),
+                   &sp, sizeof(sp));
+               
+               /* get a thread from the runq or idleq and put it on the cpu */
+               qaddr = thread->proc->runqaddr;
+               val = READ(thread->proc, qaddr, &qhead, sizeof(qhead));
+               if (val != 0)
+                       return val;
+               if (qhead.ptqh_first == NULL) {
+                       qaddr = thread->proc->idleqaddr;
+                       val = READ(thread->proc, qaddr, &qhead, sizeof(qhead));
+                       if (val != 0)
+                               return val;
+                       if (qhead.ptqh_first == NULL) {
+                               /* Well, crap. This isn't supposed to happen */
+                               return TD_ERR_ERR;
+                       }
+               }
+
+               nthread = (caddr_t)(void *)qhead.ptqh_first;
+               DPTQ_REMOVE(qaddr, nthread, pt_runq);
+               val = READ(thread->proc,
+                   nthread + offsetof(struct __pthread_st, pt_trapuc),
+                   &addr, sizeof(addr));
+               if (val != 0)
+                       return val;
+               if (addr == 0) {
+                       val = READ(thread->proc,
+                           nthread + offsetof(struct __pthread_st, pt_uc),
+                           &addr, sizeof(addr));
+                       if (val != 0)
+                               return val;
+               }
+               val = READ(thread->proc, addr, &uc, sizeof(uc));
+               if (val != 0)
+                       return val;
+               PTHREAD_UCONTEXT_TO_REG(&r, &uc);
+               PTHREAD_UCONTEXT_TO_FPREG(&fr, &uc);
+               val = SETREGS(thread->proc, 0, thread->lwp, &r);
+               if (val != 0)
+                       return val;
+               val = SETREGS(thread->proc, 1, thread->lwp, &fr);
+               if (val != 0)
+                       return val;
+
+               /* XXX update thread->lwp or nthread's lwp? */
+               break;
+       case PT_STATE_RUNNABLE:
+               /* remove from runq */
+               DPTQ_REMOVE(thread->proc->runqaddr, thread->addr, pt_runq);
+               break;
+       case PT_STATE_BLOCKED_QUEUE:
+               /* remove from the particular sleepq */
+               val = READ(thread->proc, thread->addr +
+                   offsetof(struct __pthread_st, pt_sleepq),
+                   &addr, sizeof(addr));
+               DPTQ_REMOVE(addr, thread->addr, pt_sleep);
+               break;
+       case _PT_STATE_BLOCKED_SYS:
+               /* set flag so unblock upcall will suspend */
+               val = READ(thread->proc, thread->addr +
+                   offsetof(struct __pthread_st, pt_flags),
+                   &tmp, sizeof(tmp));
+               if (val != 0)
+                       return val;
+               tmp |= PT_FLAG_SUSPENDED;
+               val = WRITE(thread->proc, thread->addr +
+                   offsetof(struct __pthread_st, pt_flags),
+                   &tmp, sizeof(tmp));
+               /* all done, don't want to actually go on the queue yet. */
+               return 0;
+       case PT_STATE_SUSPENDED: 
+               /* don't do anything */
+               return 0;
+       case PT_STATE_ZOMBIE:
+       case PT_STATE_DEAD:
+               /* suspending these isn't meaningful */
+               return TD_ERR_BADTHREAD;
+       default:
+               return TD_ERR_ERR;
+       }
+
+       DPTQ_INSERT_TAIL(thread->proc->suspqaddr, thread->addr, pt_runq);
+       tmp = PT_STATE_SUSPENDED;
+       val = WRITE(thread->proc, thread->addr +
+           offsetof(struct __pthread_st, pt_state),
+           &tmp, sizeof(tmp));
+       if (val != 0)
+               return val;
+                   
+       return 0;
+}
+
+/* Restore a suspended thread to its previous state */
+int
+td_thr_resume(td_thread_t *thread)
+{
+       int tmp, tmp1, val;
+
+       /* validate the thread */
+       val = READ(thread->proc, thread->addr, &tmp, sizeof(tmp));
+       if (val != 0)
+               return val;
+       if (tmp != PT_MAGIC)
+               return TD_ERR_BADTHREAD;
+
+       /* clear flag */
+       val = READ(thread->proc, thread->addr +
+           offsetof(struct __pthread_st, pt_flags),
+           &tmp, sizeof(tmp));
+       if (val != 0)



Home | Main Index | Thread Index | Old Index