[BACK]Return to pthread_dbg.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / lib / libpthread_dbg

Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.

Diff for /src/lib/libpthread_dbg/Attic/pthread_dbg.c between version 1.1 and 1.1.2.9

version 1.1, 2002/07/31 23:05:18 version 1.1.2.9, 2002/12/10 15:33:48
Line 0 
Line 1 
   /*      $NetBSD$        */
   
   /*-
    * Copyright (c) 2002 Wasabi Systems, Inc.
    * All rights reserved.
    *
    * Written by Nathan J. Williams for Wasabi Systems, Inc.
    *
    * 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 for the NetBSD Project by
    *      Wasabi Systems, Inc.
    * 4. The name of Wasabi Systems, Inc. may not be used to endorse
    *    or promote products derived from this software without specific
    *    prior written permission.
    *
    * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``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 WASABI SYSTEMS, INC
    * 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.
    */
   
   #include <stddef.h>
   #include <stdlib.h>
   #include <string.h>
   #include <errno.h>
   #include <sys/types.h>
   #include <unistd.h>
   
   #include <pthread.h>
   #include <pthread_int.h>
   #include <pthread_dbg.h>
   #include <pthread_dbg_int.h>
   #include <machine/reg.h>
   
   static int td__getthread(td_proc_t *proc, caddr_t addr, td_thread_t **threadp);
   static int td__getsync(td_proc_t *proc, caddr_t addr, td_sync_t **syncp);
   
   int
   td_open(struct td_proc_callbacks_t *cb, void *arg, td_proc_t **procp)
   {
           td_proc_t *proc;
           caddr_t dbgaddr;
           int dbg;
           int val;
   
           proc = malloc(sizeof(*proc));
           if (proc == NULL)
                   return TD_ERR_NOMEM;
   
           proc->cb = cb;
           proc->arg = arg;
   
           val = LOOKUP(proc, "pthread__dbg", &dbgaddr);
           if (val != 0) {
                   if (val == TD_ERR_NOSYM)
                           val = TD_ERR_NOLIB;
                   goto error;
           }
   
           val = READ(proc, dbgaddr, &dbg, sizeof(int));
           if (val != 0)
                   goto error;
   
           if (dbg != 0) {
                   /* Another instance of libpthread_dbg is already attached. */
                   val = TD_ERR_INUSE;
                   goto error;
           }
   
           dbg = getpid();
           /*
            * If this fails it probably means we're debugging a core file and
            * can't write to it.
            * If it's something else we'll lose the next time we hit WRITE,
            * but not before, and that's OK.
            */
           WRITE(proc, dbgaddr, &dbg, sizeof(int));
   
           proc->allqueue = 0;
           PTQ_INIT(&proc->threads);
           PTQ_INIT(&proc->syncs);
   
           *procp = proc;
   
           return 0;
   
    error:
           free(proc);
           return val;
   }
   
   int
   td_close(td_proc_t *proc)
   {
           caddr_t dbgaddr;
           int dbg;
           int val;
           td_thread_t *t, *next;
           td_sync_t *s, *nexts;
   
           val = LOOKUP(proc, "pthread__dbg", &dbgaddr);
           if (val != 0)
                   return val;
   
           dbg = 0;
           /*
            * Error returns from this write are mot really a problem;
            * the process doesn't exist any more.
            */
           WRITE(proc, dbgaddr, &dbg, sizeof(int));
   
           /* Deallocate the list of thread structures */
           for (t = PTQ_FIRST(&proc->threads); t; t = next) {
                   next = PTQ_NEXT(t, list);
                   PTQ_REMOVE(&proc->threads, t, list);
                   free(t);
           }
           /* Deallocate the list of sync objects */
           for (s = PTQ_FIRST(&proc->syncs); s; s = nexts) {
                   nexts = PTQ_NEXT(s, list);
                   PTQ_REMOVE(&proc->syncs, s, list);
                   free(s);
           }
           free(proc);
           return 0;
   }
   
   
   int
   td_thr_iter(td_proc_t *proc, int (*call)(td_thread_t *, void *), void *callarg)
   {
           int val;
           caddr_t allqaddr, next;
           struct pthread_queue_t allq;
           td_thread_t *thread;
   
           if (proc->allqueue == 0) {
                   val = LOOKUP(proc, "allqueue", &allqaddr);
                   if (val != 0)
                           return val;
                   proc->allqueue = allqaddr;
           } else {
                   allqaddr = proc->allqueue;
           }
   
           val = READ(proc, allqaddr, &allq, sizeof(allq));
           if (val != 0)
                   return val;
   
           next = (caddr_t) allq.ptqh_first;
           while (next != 0) {
                   val = td__getthread(proc, next, &thread);
                   if (val != 0)
                           return val;
                   val = (*call)(thread, callarg);
                   if (val != 0)
                           return 0;
   
                   val = READ(proc,
                       next + offsetof(struct pthread_st, pt_allq.ptqe_next),
                       &next, sizeof(next));
                   if (val != 0)
                           return val;
           }
           return 0;
   }
   
   int
   td_thr_info(td_thread_t *thread, td_thread_info_t *info)
   {
           int val, tmp;
           struct pthread_queue_t queue;
   
           val = READ(thread->proc, thread->addr, &tmp, sizeof(tmp));
           if (val != 0)
                   return val;
   
           if (tmp != PT_MAGIC)
                   return TD_ERR_BADTHREAD;
   
           info->thread_addr = thread->addr;
           if ((val = READ(thread->proc,
               thread->addr + offsetof(struct pthread_st, pt_state),
               &tmp, sizeof(int))) != 0)
                   return val;
           switch (tmp) {
           case PT_STATE_RUNNING:
                   info->thread_state = TD_STATE_RUNNING;
                   break;
           case PT_STATE_RUNNABLE:
                   info->thread_state = TD_STATE_RUNNABLE;
                   break;
           case PT_STATE_BLOCKED_SYS:
                   info->thread_state = TD_STATE_BLOCKED;
                   break;
           case PT_STATE_BLOCKED_QUEUE:
                   info->thread_state = TD_STATE_SLEEPING;
                   break;
           case PT_STATE_ZOMBIE:
                   info->thread_state = TD_STATE_ZOMBIE;
                   break;
           default:
                   info->thread_state = TD_STATE_UNKNOWN;
           }
   
           if ((val = READ(thread->proc,
               thread->addr + offsetof(struct pthread_st, pt_type),
               &tmp, sizeof(int))) != 0)
                   return val;
           switch (tmp) {
           case PT_THREAD_NORMAL:
                   info->thread_type = TD_TYPE_USER;
                   break;
           case PT_THREAD_UPCALL:
           case PT_THREAD_IDLE:
                   info->thread_type = TD_TYPE_SYSTEM;
                   break;
           default:
                   info->thread_type = TD_TYPE_UNKNOWN;
           }
   
           if ((val = READ(thread->proc,
               thread->addr + offsetof(struct pthread_st, pt_stack),
               &info->thread_stack, sizeof(stack_t))) != 0)
                   return val;
   
           if ((val = READ(thread->proc,
               thread->addr + offsetof(struct pthread_st, pt_joiners),
               &queue, sizeof(struct pthread_queue_t))) != 0)
                   return val;
   
           if (PTQ_EMPTY(&queue))
                   info->thread_hasjoiners = 0;
           else
                   info->thread_hasjoiners = 1;
   
           if ((val = READ(thread->proc,
               thread->addr + offsetof(struct pthread_st, pt_errno),
               &info->thread_errno, sizeof(info->thread_errno))) != 0)
                   return val;
   
           if ((val = READ(thread->proc,
               thread->addr + offsetof(struct pthread_st, pt_num),
               &info->thread_id, sizeof(info->thread_errno))) != 0)
                   return val;
   
           if ((val = READ(thread->proc,
               thread->addr + offsetof(struct pthread_st, pt_sigmask),
               &info->thread_sigmask, sizeof(info->thread_sigmask))) != 0)
                   return val;
   
           if ((val = READ(thread->proc,
               thread->addr + offsetof(struct pthread_st, pt_siglist),
               &info->thread_sigpending, sizeof(info->thread_sigpending))) != 0)
                   return val;
   
           return 0;
   }
   
   int
   td_thr_getregs(td_thread_t *thread, int regset, void *buf)
   {
           int tmp, val;
           caddr_t addr;
           ucontext_t uc;
   
           val = READ(thread->proc,
               thread->addr + offsetof(struct pthread_st, pt_state),
               &tmp, sizeof(int));
           if (val != 0)
                   return val;
   
           switch (tmp) {
           case PT_STATE_RUNNING:
                   /*
                    * The register state of the thread is live in the
                    * inferior process's register state.
                    */
                   val = GETREGS(thread->proc, regset, thread->lwp, buf);
                   if (val != 0)
                           return val;
                   break;
           case PT_STATE_RUNNABLE:
           case PT_STATE_BLOCKED_SYS:
           case PT_STATE_BLOCKED_QUEUE:
                   /*
                    * The register state of the thread is in the ucontext_t
                    * of the thread structure.
                    */
                   val = READ(thread->proc,
                       thread->addr + 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;
   
                   switch (regset) {
                   case 0:
                           PTHREAD_UCONTEXT_TO_REG((struct reg *)buf, &uc);
                           break;
                   case 1:
                           PTHREAD_UCONTEXT_TO_FPREG((struct fpreg *)buf, &uc);
                           break;
                   case 2:
                           return TD_ERR_INVAL;
                   }
                   break;
           case PT_STATE_ZOMBIE:
           default:
                   return TD_ERR_BADTHREAD;
           }
   
           return 0;
   }
   
   int
   td_thr_setregs(td_thread_t *thread, int regset, void *buf)
   {
   
           int tmp, val;
           caddr_t addr;
           ucontext_t uc;
   
           val = READ(thread->proc,
               thread->addr + offsetof(struct pthread_st, pt_state),
               &tmp, sizeof(int));
           if (val != 0)
                   return val;
   
           switch (tmp) {
           case PT_STATE_RUNNING:
                   /*
                    * The register state of the thread is live in the
                    * inferior process's register state.
                    */
                   val = SETREGS(thread->proc, regset, thread->lwp, buf);
                   if (val != 0)
                           return val;
                   break;
           case PT_STATE_RUNNABLE:
           case PT_STATE_BLOCKED_SYS:
           case PT_STATE_BLOCKED_QUEUE:
                   /*
                    * The register state of the thread is in the ucontext_t
                    * of the thread structure.
                    *
                    * Fetch the uc first, since there is state in it
                    * besides the registers that should be preserved.
                    */
                   val = READ(thread->proc,
                       thread->addr + 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;
   
                   switch (regset) {
                   case 0:
                           PTHREAD_REG_TO_UCONTEXT(&uc, (struct reg *)buf);
                           break;
                   case 1:
                           PTHREAD_FPREG_TO_UCONTEXT(&uc, (struct fpreg *)buf);
                           break;
                   case 2:
                           return TD_ERR_INVAL;
                   }
   
                   val = WRITE(thread->proc,
                       addr, &uc, sizeof(uc));
                   if (val != 0)
                           return val;
   
                   break;
           case PT_STATE_ZOMBIE:
           default:
                   return TD_ERR_BADTHREAD;
           }
   
           return 0;
   }
   
   int
   td_thr_join_iter(td_thread_t *thread, int (*call)(td_thread_t *, void *),
       void *arg)
   {
           int val;
           caddr_t next;
           td_thread_t *thread2;
           struct pthread_queue_t queue;
   
           if ((val = READ(thread->proc,
               thread->addr + offsetof(struct pthread_st, pt_joiners),
               &queue, sizeof(struct pthread_queue_t))) != 0)
                   return val;
   
           next = (caddr_t) queue.ptqh_first;
           while (next != 0) {
                   val = td__getthread(thread->proc, next, &thread2);
                   if (val != 0)
                           return val;
                   val = (*call)(thread, arg);
                   if (val != 0)
                           return 0;
   
                   val = READ(thread->proc,
                       next + offsetof(struct pthread_st, pt_sleep.ptqe_next),
                       &next, sizeof(next));
                   if (val != 0)
                           return val;
           }
   
           return 0;
   }
   
   int
   td_sync_info(td_sync_t *s, td_sync_info_t *info)
   {
           int val, magic, n;
           struct pthread_queue_t queue;
           pthread_spin_t slock;
           pthread_t taddr;
   
           val = READ(s->proc, s->addr, &magic, sizeof(magic));
           if (val != 0)
                   return val;
   
           info->sync_type = TD_SYNC_UNKNOWN;
           info->sync_size = 0;
           info->sync_haswaiters = 0;
           switch (magic) {
           case _PT_MUTEX_MAGIC:
                   info->sync_type = TD_SYNC_MUTEX;
                   info->sync_size = sizeof(struct pthread_mutex_st);
                   if ((val = READ(s->proc,
                       s->addr + offsetof(struct pthread_mutex_st, ptm_blocked),
                       &queue, sizeof(struct pthread_queue_t))) != 0)
                   return val;
   
                   if (!PTQ_EMPTY(&queue))
                           info->sync_haswaiters = 1;
                   /*
                    * The cast to (void *) is to explicitly throw away the
                    * volatile qualifier on pthread_spin_t,
                    * from __cpu_simple_lock_t.
                    */
                   if ((val = READ(s->proc,
                       s->addr + offsetof(struct pthread_mutex_st, ptm_lock),
                       (void *)&slock, sizeof(struct pthread_spinlock_st))) != 0)
                           return val;
                   if (slock == __SIMPLELOCK_LOCKED) {
                           info->sync_data.mutex.locked = 1;
                           if ((val = READ(s->proc,
                               s->addr + offsetof(struct pthread_mutex_st,
                                   ptm_owner),
                               &taddr, sizeof(pthread_t))) != 0)
                                   return val;
                           taddr = pthread__id(taddr);
                           td__getthread(s->proc, (caddr_t)taddr,
                               &info->sync_data.mutex.owner);
                   } else
                           info->sync_data.mutex.locked = 0;
                   break;
           case _PT_COND_MAGIC:
                   info->sync_type = TD_SYNC_COND;
                   info->sync_size = sizeof(struct pthread_cond_st);
                   if ((val = READ(s->proc,
                       s->addr + offsetof(struct pthread_cond_st, ptc_waiters),
                       &queue, sizeof(struct pthread_queue_t))) != 0)
                           return val;
                   if (!PTQ_EMPTY(&queue))
                           info->sync_haswaiters = 1;
                   break;
           case _PT_SPINLOCK_MAGIC:
                   info->sync_type = TD_SYNC_SPIN;
                   info->sync_size = sizeof(struct pthread_spinlock_st);
                   if ((val = READ(s->proc,
                       s->addr + offsetof(struct pthread_spinlock_st, pts_spin),
                       (void *)&slock, sizeof(struct pthread_spinlock_st))) != 0)
                           return val;
                   if (slock == __SIMPLELOCK_LOCKED)
                           info->sync_data.spin.locked = 1;
                   break;
           case PT_MAGIC:
                   info->sync_type = TD_SYNC_JOIN;
                   info->sync_size = sizeof(struct pthread_st);
                   td__getthread(s->proc, s->addr,
                       &info->sync_data.join.thread);
                   if ((val = READ(s->proc,
                       s->addr + offsetof(struct pthread_st, pt_joiners),
                       &queue, sizeof(struct pthread_queue_t))) != 0)
                           return val;
   
                   if (!PTQ_EMPTY(&queue))
                           info->sync_haswaiters = 1;
                   break;
           case _PT_RWLOCK_MAGIC:
                   info->sync_type = TD_SYNC_RWLOCK;
                   info->sync_size = sizeof(struct pthread_rwlock_st);
                   if ((val = READ(s->proc,
                       s->addr + offsetof(struct pthread_rwlock_st, ptr_rblocked),
                       &queue, sizeof(struct pthread_queue_t))) != 0)
                           return val;
                   if (!PTQ_EMPTY(&queue))
                           info->sync_haswaiters = 1;
   
                   if ((val = READ(s->proc,
                       s->addr + offsetof(struct pthread_rwlock_st, ptr_wblocked),
                       &queue, sizeof(struct pthread_queue_t))) != 0)
                           return val;
                   if (!PTQ_EMPTY(&queue))
                           info->sync_haswaiters = 1;
   
   
                   info->sync_data.rwlock.locked = 0;
                   if ((val = READ(s->proc,
                       s->addr + offsetof(struct pthread_rwlock_st, ptr_nreaders),
                       &n, sizeof(int))) != 0)
                           return val;
                   info->sync_data.rwlock.readlocks = n;
                   if (n > 0)
                           info->sync_data.rwlock.locked = 1;
   
                   if ((val = READ(s->proc,
                       s->addr + offsetof(struct pthread_rwlock_st, ptr_writer),
                       &taddr, sizeof(pthread_t))) != 0)
                           return val;
                   if (taddr != 0) {
                           info->sync_data.rwlock.locked = 1;
                           td__getthread(s->proc, (caddr_t)taddr,
                               &info->sync_data.rwlock.writeowner);
                   }
           default:
                   return (0);
           }
   
           info->sync_addr = s->addr;
   
           return 0;
   }
   
   
   int
   td_sync_waiters_iter(td_sync_t *s, int (*call)(td_thread_t *, void *),
       void *arg)
   {
           int val, magic;
           caddr_t next;
           struct pthread_queue_t queue;
           td_thread_t *thread;
   
           val = READ(s->proc, s->addr, &magic, sizeof(magic));
           if (val != 0)
                   return val;
   
           switch (magic) {
           case _PT_MUTEX_MAGIC:
                   if ((val = READ(s->proc,
                       s->addr + offsetof(struct pthread_mutex_st, ptm_blocked),
                       &queue, sizeof(struct pthread_queue_t))) != 0)
                           return val;
                   break;
           case _PT_COND_MAGIC:
                   if ((val = READ(s->proc,
                       s->addr + offsetof(struct pthread_cond_st, ptc_waiters),
                       &queue, sizeof(struct pthread_queue_t))) != 0)
                           return val;
                   break;
           case PT_MAGIC:
                   /* Redundant with join_iter, but what the hell... */
                   if ((val = READ(s->proc,
                       s->addr + offsetof(struct pthread_st, pt_joiners),
                       &queue, sizeof(struct pthread_queue_t))) != 0)
                           return val;
                   break;
           default:
                   return (0);
           }
   
           next = (caddr_t) queue.ptqh_first;
           while (next != 0) {
                   val = td__getthread(s->proc, next, &thread);
                   if (val != 0)
                           return val;
                   val = (*call)(thread, arg);
                   if (val != 0)
                           return 0;
   
                   val = READ(s->proc,
                       next + offsetof(struct pthread_st, pt_sleep.ptqe_next),
                       &next, sizeof(next));
                   if (val != 0)
                           return val;
           }
           return 0;
   }
   
   
   int
   td_map_addr2sync(td_proc_t *proc, caddr_t addr, td_sync_t **syncp)
   {
           int magic, val;
   
           val = READ(proc, addr, &magic, sizeof(magic));
           if (val != 0)
                   return val;
   
           if ((magic != _PT_MUTEX_MAGIC) &&
               (magic != _PT_COND_MAGIC) &&
               (magic != _PT_SPINLOCK_MAGIC))
                   return TD_ERR_NOOBJ;
   
           val = td__getsync(proc, addr, syncp);
           if (val != 0)
                   return val;
   
           return 0;
   }
   
   
   int
   td_map_pth2thr(td_proc_t *proc, pthread_t thread, td_thread_t **threadp)
   {
           int magic, val;
   
           val = READ(proc, (caddr_t)thread, &magic, sizeof(magic));
           if (val != 0)
                   return val;
   
           if (magic != PT_MAGIC)
                   return TD_ERR_NOOBJ;
   
           val = td__getthread(proc, (caddr_t)thread, threadp);
           if (val != 0)
                   return val;
   
           return 0;
   }
   
   int
   td_map_id2thr(td_proc_t *proc, int threadid, td_thread_t **threadp)
   {
           int val, num;
           caddr_t allqaddr, next;
           struct pthread_queue_t allq;
           td_thread_t *thread;
   
   
           if (proc->allqueue == 0) {
                   val = LOOKUP(proc, "allqueue", &allqaddr);
                   if (val != 0)
                           return val;
                   proc->allqueue = allqaddr;
           } else {
                   allqaddr = proc->allqueue;
           }
   
           val = READ(proc, allqaddr, &allq, sizeof(allq));
           if (val != 0)
                   return val;
   
           next = (caddr_t) allq.ptqh_first;
           while (next != 0) {
                   val = READ(proc,
                       next + offsetof(struct pthread_st, pt_num),
                       &num, sizeof(num));
   
                   if (num == threadid)
                           break;
   
                   val = READ(proc,
                       next + offsetof(struct pthread_st, pt_allq.ptqe_next),
                       &next, sizeof(next));
                   if (val != 0)
                           return val;
           }
   
           if (next == 0) {
                   /* A matching thread was not found. */
                   return TD_ERR_NOOBJ;
           }
   
           val = td__getthread(proc, next, &thread);
           if (val != 0)
                   return val;
           *threadp = thread;
   
           return 0;
   }
   
   /* Return the thread handle of the thread running on the given LWP */
   int
   td_map_lwp2thr(td_proc_t *proc, int lwp, td_thread_t **threadp)
   {
           int val, magic;
           struct reg gregs;
           ucontext_t uc;
           caddr_t th;
   
           val = GETREGS(proc, 0, lwp, &gregs);
           if (val != 0)
                   return val;
   
           PTHREAD_REG_TO_UCONTEXT(&uc, &gregs);
   
           th = (caddr_t) pthread__id(pthread__uc_sp(&uc));
   
           val = READ(proc, th, &magic, sizeof(magic));
           if (val != 0)
                   return val;
   
           if (magic != PT_MAGIC)
                   return TD_ERR_NOOBJ;
   
           val = td__getthread(proc, th, threadp);
           if (val != 0)
                   return val;
   
           (*threadp)->lwp = lwp;
   
           return 0;
   }
   
   int
   td_map_lwps(td_proc_t *proc)
   {
           int i, val, nlwps;
           caddr_t addr;
           td_thread_t *thread;
   
           val = LOOKUP(proc, "pthread__maxlwps", &addr);
           if (val != 0)
                   return val;
   
           val = READ(proc, addr, &nlwps, sizeof(int));
           if (val != 0)
                   return val;
   
           for (i = 1; i <= nlwps; i++) {
                   /*
                    * Errors are deliberately ignored for the call to
                    * td_map_lwp2thr(); it is entirely likely that not
                    * all LWPs in the range 1..nlwps exist, and that's
                    * not a problem.
                    */
                   td_map_lwp2thr(proc, i, &thread);
           }
           return 0;
   }
   
   int
   td_tsd_iter(td_proc_t *proc,
       int (*call)(pthread_key_t, void (*)(void *), void *), void *arg)
   {
           caddr_t desaddr, allocaddr;
           int val;
           int i, allocated;
           void (*destructor)(void *);
   
           val = LOOKUP(proc, "pthread__tsd_alloc", &allocaddr);
           if (val != 0)
                   return val;
           val = LOOKUP(proc, "pthread__tsd_destructors", &desaddr);
           if (val != 0)
                   return val;
   
           for (i = 0; i < PTHREAD_KEYS_MAX; i++) {
                   val = READ(proc, allocaddr + i * sizeof(int),
                       &allocated, sizeof(int));
                   if (val != 0)
                           return val;
   
                   if (allocated) {
                           val = READ(proc,  desaddr + i * sizeof(destructor),
                               &destructor, sizeof(destructor));
                           if (val != 0)
                                   return val;
   
                           val = (call)(i, destructor, arg);
                           if (val != 0)
                                   return val;
                   }
           }
   
           return 0;
   }
   
   /* Get the synchronization object that the thread is sleeping on */
   int
   td_thr_sleepinfo(td_thread_t *thread, td_sync_t **s)
   {
           int val;
           caddr_t addr;
   
           if ((val = READ(thread->proc,
               thread->addr + offsetof(struct pthread_st, pt_sleepobj),
               &addr, sizeof(caddr_t))) != 0)
                   return val;
   
           td__getsync(thread->proc, addr, s);
   
           return 0;
   
   }
   
   
   
   static int
   td__getthread(td_proc_t *proc, caddr_t addr, td_thread_t **threadp)
   {
           td_thread_t *thread;
   
           /*
            * Check if we've allocated a descriptor for this thread.
            * Sadly, this makes iterating over a set of threads O(N^2)
            * in the number of threads. More sophisticated data structures
            * can wait.
            */
           PTQ_FOREACH(thread, &proc->threads, list) {
                   if (thread->addr == addr)
                           break;
           }
           if (thread == NULL) {
                   thread = malloc(sizeof(*thread));
                   if (thread == NULL)
                           return TD_ERR_NOMEM;
                   thread->proc = proc;
                   thread->addr = addr;
                   thread->lwp  = 0;
                   PTQ_INSERT_HEAD(&proc->threads, thread, list);
           }
   
           *threadp = thread;
           return 0;
   }
   
   
   static int
   td__getsync(td_proc_t *proc, caddr_t addr, td_sync_t **syncp)
   {
           td_sync_t *s;
   
           /* Check if we've allocated a descriptor for this object. */
           PTQ_FOREACH(s, &proc->syncs, list) {
                   if (s->addr == addr)
                           break;
           }
           /* Allocate a fresh one */
           if (s == NULL) {
                   s = malloc(sizeof(*s));
                   if (s == NULL)
                           return TD_ERR_NOMEM;
                   s->proc = proc;
                   s->addr = addr;
                   PTQ_INSERT_HEAD(&proc->syncs, s, list);
           }
   
           *syncp = s;
           return 0;
   }
   
   
   int
   td_thr_tsd(td_thread_t *thread, pthread_key_t key, void **value)
   {
           int val;
   
           val = READ(thread->proc, thread->addr +
               offsetof(struct pthread_st, pt_specific) +
               key * sizeof(void *), &value, sizeof(void *));
   
           return val;
   }
   

Legend:
Removed from v.1.1  
changed lines
  Added in v.1.1.2.9

CVSweb <webmaster@jp.NetBSD.org>