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

Annotation of src/lib/libpthread_dbg/pthread_dbg.c, Revision 1.2

1.2     ! thorpej     1: /*     $NetBSD: pthread_dbg.c,v 1.1.2.10 2003/01/07 00:54:29 nathanw Exp $     */
        !             2:
        !             3: /*-
        !             4:  * Copyright (c) 2002 Wasabi Systems, Inc.
        !             5:  * All rights reserved.
        !             6:  *
        !             7:  * Written by Nathan J. Williams for Wasabi Systems, Inc.
        !             8:  *
        !             9:  * Redistribution and use in source and binary forms, with or without
        !            10:  * modification, are permitted provided that the following conditions
        !            11:  * are met:
        !            12:  * 1. Redistributions of source code must retain the above copyright
        !            13:  *    notice, this list of conditions and the following disclaimer.
        !            14:  * 2. Redistributions in binary form must reproduce the above copyright
        !            15:  *    notice, this list of conditions and the following disclaimer in the
        !            16:  *    documentation and/or other materials provided with the distribution.
        !            17:  * 3. All advertising materials mentioning features or use of this software
        !            18:  *    must display the following acknowledgement:
        !            19:  *      This product includes software developed for the NetBSD Project by
        !            20:  *      Wasabi Systems, Inc.
        !            21:  * 4. The name of Wasabi Systems, Inc. may not be used to endorse
        !            22:  *    or promote products derived from this software without specific
        !            23:  *    prior written permission.
        !            24:  *
        !            25:  * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
        !            26:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
        !            27:  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
        !            28:  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL WASABI SYSTEMS, INC
        !            29:  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
        !            30:  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
        !            31:  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
        !            32:  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
        !            33:  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
        !            34:  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
        !            35:  * POSSIBILITY OF SUCH DAMAGE.
        !            36:  */
        !            37:
        !            38: #include <stddef.h>
        !            39: #include <stdlib.h>
        !            40: #include <string.h>
        !            41: #include <errno.h>
        !            42: #include <sys/types.h>
        !            43: #include <unistd.h>
        !            44:
        !            45: #include <pthread.h>
        !            46: #include <pthread_int.h>
        !            47: #include <pthread_dbg.h>
        !            48: #include <pthread_dbg_int.h>
        !            49: #include <machine/reg.h>
        !            50:
        !            51: static int td__getthread(td_proc_t *proc, caddr_t addr, td_thread_t **threadp);
        !            52: static int td__getsync(td_proc_t *proc, caddr_t addr, td_sync_t **syncp);
        !            53:
        !            54: int
        !            55: td_open(struct td_proc_callbacks_t *cb, void *arg, td_proc_t **procp)
        !            56: {
        !            57:        td_proc_t *proc;
        !            58:        caddr_t dbgaddr;
        !            59:        int dbg;
        !            60:        int val;
        !            61:
        !            62:        proc = malloc(sizeof(*proc));
        !            63:        if (proc == NULL)
        !            64:                return TD_ERR_NOMEM;
        !            65:
        !            66:        proc->cb = cb;
        !            67:        proc->arg = arg;
        !            68:
        !            69:        val = LOOKUP(proc, "pthread__dbg", &dbgaddr);
        !            70:        if (val != 0) {
        !            71:                if (val == TD_ERR_NOSYM)
        !            72:                        val = TD_ERR_NOLIB;
        !            73:                goto error;
        !            74:        }
        !            75:
        !            76:        val = READ(proc, dbgaddr, &dbg, sizeof(int));
        !            77:        if (val != 0)
        !            78:                goto error;
        !            79:
        !            80:        if (dbg != 0) {
        !            81:                /* Another instance of libpthread_dbg is already attached. */
        !            82:                val = TD_ERR_INUSE;
        !            83:                goto error;
        !            84:        }
        !            85:
        !            86:        dbg = getpid();
        !            87:        /*
        !            88:         * If this fails it probably means we're debugging a core file and
        !            89:         * can't write to it.
        !            90:         * If it's something else we'll lose the next time we hit WRITE,
        !            91:         * but not before, and that's OK.
        !            92:         */
        !            93:        WRITE(proc, dbgaddr, &dbg, sizeof(int));
        !            94:
        !            95:        proc->allqueue = 0;
        !            96:        PTQ_INIT(&proc->threads);
        !            97:        PTQ_INIT(&proc->syncs);
        !            98:
        !            99:        *procp = proc;
        !           100:
        !           101:        return 0;
        !           102:
        !           103:  error:
        !           104:        free(proc);
        !           105:        return val;
        !           106: }
        !           107:
        !           108: int
        !           109: td_close(td_proc_t *proc)
        !           110: {
        !           111:        caddr_t dbgaddr;
        !           112:        int dbg;
        !           113:        int val;
        !           114:        td_thread_t *t, *next;
        !           115:        td_sync_t *s, *nexts;
        !           116:
        !           117:        val = LOOKUP(proc, "pthread__dbg", &dbgaddr);
        !           118:        if (val != 0)
        !           119:                return val;
        !           120:
        !           121:        dbg = 0;
        !           122:        /*
        !           123:         * Error returns from this write are mot really a problem;
        !           124:         * the process doesn't exist any more.
        !           125:         */
        !           126:        WRITE(proc, dbgaddr, &dbg, sizeof(int));
        !           127:
        !           128:        /* Deallocate the list of thread structures */
        !           129:        for (t = PTQ_FIRST(&proc->threads); t; t = next) {
        !           130:                next = PTQ_NEXT(t, list);
        !           131:                PTQ_REMOVE(&proc->threads, t, list);
        !           132:                free(t);
        !           133:        }
        !           134:        /* Deallocate the list of sync objects */
        !           135:        for (s = PTQ_FIRST(&proc->syncs); s; s = nexts) {
        !           136:                nexts = PTQ_NEXT(s, list);
        !           137:                PTQ_REMOVE(&proc->syncs, s, list);
        !           138:                free(s);
        !           139:        }
        !           140:        free(proc);
        !           141:        return 0;
        !           142: }
        !           143:
        !           144:
        !           145: int
        !           146: td_thr_iter(td_proc_t *proc, int (*call)(td_thread_t *, void *), void *callarg)
        !           147: {
        !           148:        int val;
        !           149:        caddr_t allqaddr, next;
        !           150:        struct pthread_queue_t allq;
        !           151:        td_thread_t *thread;
        !           152:
        !           153:        if (proc->allqueue == 0) {
        !           154:                val = LOOKUP(proc, "pthread__allqueue", &allqaddr);
        !           155:                if (val != 0)
        !           156:                        return val;
        !           157:                proc->allqueue = allqaddr;
        !           158:        } else {
        !           159:                allqaddr = proc->allqueue;
        !           160:        }
        !           161:
        !           162:        val = READ(proc, allqaddr, &allq, sizeof(allq));
        !           163:        if (val != 0)
        !           164:                return val;
        !           165:
        !           166:        next = (caddr_t) allq.ptqh_first;
        !           167:        while (next != 0) {
        !           168:                val = td__getthread(proc, next, &thread);
        !           169:                if (val != 0)
        !           170:                        return val;
        !           171:                val = (*call)(thread, callarg);
        !           172:                if (val != 0)
        !           173:                        return 0;
        !           174:
        !           175:                val = READ(proc,
        !           176:                    next + offsetof(struct pthread_st, pt_allq.ptqe_next),
        !           177:                    &next, sizeof(next));
        !           178:                if (val != 0)
        !           179:                        return val;
        !           180:        }
        !           181:        return 0;
        !           182: }
        !           183:
        !           184: int
        !           185: td_thr_info(td_thread_t *thread, td_thread_info_t *info)
        !           186: {
        !           187:        int val, tmp;
        !           188:        struct pthread_queue_t queue;
        !           189:
        !           190:        val = READ(thread->proc, thread->addr, &tmp, sizeof(tmp));
        !           191:        if (val != 0)
        !           192:                return val;
        !           193:
        !           194:        if (tmp != PT_MAGIC)
        !           195:                return TD_ERR_BADTHREAD;
        !           196:
        !           197:        info->thread_addr = thread->addr;
        !           198:        if ((val = READ(thread->proc,
        !           199:            thread->addr + offsetof(struct pthread_st, pt_state),
        !           200:            &tmp, sizeof(int))) != 0)
        !           201:                return val;
        !           202:        switch (tmp) {
        !           203:        case PT_STATE_RUNNING:
        !           204:                info->thread_state = TD_STATE_RUNNING;
        !           205:                break;
        !           206:        case PT_STATE_RUNNABLE:
        !           207:                info->thread_state = TD_STATE_RUNNABLE;
        !           208:                break;
        !           209:        case PT_STATE_BLOCKED_SYS:
        !           210:                info->thread_state = TD_STATE_BLOCKED;
        !           211:                break;
        !           212:        case PT_STATE_BLOCKED_QUEUE:
        !           213:                info->thread_state = TD_STATE_SLEEPING;
        !           214:                break;
        !           215:        case PT_STATE_ZOMBIE:
        !           216:                info->thread_state = TD_STATE_ZOMBIE;
        !           217:                break;
        !           218:        default:
        !           219:                info->thread_state = TD_STATE_UNKNOWN;
        !           220:        }
        !           221:
        !           222:        if ((val = READ(thread->proc,
        !           223:            thread->addr + offsetof(struct pthread_st, pt_type),
        !           224:            &tmp, sizeof(int))) != 0)
        !           225:                return val;
        !           226:        switch (tmp) {
        !           227:        case PT_THREAD_NORMAL:
        !           228:                info->thread_type = TD_TYPE_USER;
        !           229:                break;
        !           230:        case PT_THREAD_UPCALL:
        !           231:        case PT_THREAD_IDLE:
        !           232:                info->thread_type = TD_TYPE_SYSTEM;
        !           233:                break;
        !           234:        default:
        !           235:                info->thread_type = TD_TYPE_UNKNOWN;
        !           236:        }
        !           237:
        !           238:        if ((val = READ(thread->proc,
        !           239:            thread->addr + offsetof(struct pthread_st, pt_stack),
        !           240:            &info->thread_stack, sizeof(stack_t))) != 0)
        !           241:                return val;
        !           242:
        !           243:        if ((val = READ(thread->proc,
        !           244:            thread->addr + offsetof(struct pthread_st, pt_joiners),
        !           245:            &queue, sizeof(struct pthread_queue_t))) != 0)
        !           246:                return val;
        !           247:
        !           248:        if (PTQ_EMPTY(&queue))
        !           249:                info->thread_hasjoiners = 0;
        !           250:        else
        !           251:                info->thread_hasjoiners = 1;
        !           252:
        !           253:        if ((val = READ(thread->proc,
        !           254:            thread->addr + offsetof(struct pthread_st, pt_errno),
        !           255:            &info->thread_errno, sizeof(info->thread_errno))) != 0)
        !           256:                return val;
        !           257:
        !           258:        if ((val = READ(thread->proc,
        !           259:            thread->addr + offsetof(struct pthread_st, pt_num),
        !           260:            &info->thread_id, sizeof(info->thread_errno))) != 0)
        !           261:                return val;
        !           262:
        !           263:        if ((val = READ(thread->proc,
        !           264:            thread->addr + offsetof(struct pthread_st, pt_sigmask),
        !           265:            &info->thread_sigmask, sizeof(info->thread_sigmask))) != 0)
        !           266:                return val;
        !           267:
        !           268:        if ((val = READ(thread->proc,
        !           269:            thread->addr + offsetof(struct pthread_st, pt_siglist),
        !           270:            &info->thread_sigpending, sizeof(info->thread_sigpending))) != 0)
        !           271:                return val;
        !           272:
        !           273:        return 0;
        !           274: }
        !           275:
        !           276: int
        !           277: td_thr_getregs(td_thread_t *thread, int regset, void *buf)
        !           278: {
        !           279:        int tmp, val;
        !           280:        caddr_t addr;
        !           281:        ucontext_t uc;
        !           282:
        !           283:        val = READ(thread->proc,
        !           284:            thread->addr + offsetof(struct pthread_st, pt_state),
        !           285:            &tmp, sizeof(int));
        !           286:        if (val != 0)
        !           287:                return val;
        !           288:
        !           289:        switch (tmp) {
        !           290:        case PT_STATE_RUNNING:
        !           291:                /*
        !           292:                 * The register state of the thread is live in the
        !           293:                 * inferior process's register state.
        !           294:                 */
        !           295:                val = GETREGS(thread->proc, regset, thread->lwp, buf);
        !           296:                if (val != 0)
        !           297:                        return val;
        !           298:                break;
        !           299:        case PT_STATE_RUNNABLE:
        !           300:        case PT_STATE_BLOCKED_SYS:
        !           301:        case PT_STATE_BLOCKED_QUEUE:
        !           302:                /*
        !           303:                 * The register state of the thread is in the ucontext_t
        !           304:                 * of the thread structure.
        !           305:                 */
        !           306:                val = READ(thread->proc,
        !           307:                    thread->addr + offsetof(struct pthread_st, pt_uc),
        !           308:                    &addr, sizeof(addr));
        !           309:                if (val != 0)
        !           310:                        return val;
        !           311:                val = READ(thread->proc,
        !           312:                    addr, &uc, sizeof(uc));
        !           313:                if (val != 0)
        !           314:                        return val;
        !           315:
        !           316:                switch (regset) {
        !           317:                case 0:
        !           318:                        PTHREAD_UCONTEXT_TO_REG((struct reg *)buf, &uc);
        !           319:                        break;
        !           320:                case 1:
        !           321:                        PTHREAD_UCONTEXT_TO_FPREG((struct fpreg *)buf, &uc);
        !           322:                        break;
        !           323:                case 2:
        !           324:                        return TD_ERR_INVAL;
        !           325:                }
        !           326:                break;
        !           327:        case PT_STATE_ZOMBIE:
        !           328:        default:
        !           329:                return TD_ERR_BADTHREAD;
        !           330:        }
        !           331:
        !           332:        return 0;
        !           333: }
        !           334:
        !           335: int
        !           336: td_thr_setregs(td_thread_t *thread, int regset, void *buf)
        !           337: {
        !           338:
        !           339:        int tmp, val;
        !           340:        caddr_t addr;
        !           341:        ucontext_t uc;
        !           342:
        !           343:        val = READ(thread->proc,
        !           344:            thread->addr + offsetof(struct pthread_st, pt_state),
        !           345:            &tmp, sizeof(int));
        !           346:        if (val != 0)
        !           347:                return val;
        !           348:
        !           349:        switch (tmp) {
        !           350:        case PT_STATE_RUNNING:
        !           351:                /*
        !           352:                 * The register state of the thread is live in the
        !           353:                 * inferior process's register state.
        !           354:                 */
        !           355:                val = SETREGS(thread->proc, regset, thread->lwp, buf);
        !           356:                if (val != 0)
        !           357:                        return val;
        !           358:                break;
        !           359:        case PT_STATE_RUNNABLE:
        !           360:        case PT_STATE_BLOCKED_SYS:
        !           361:        case PT_STATE_BLOCKED_QUEUE:
        !           362:                /*
        !           363:                 * The register state of the thread is in the ucontext_t
        !           364:                 * of the thread structure.
        !           365:                 *
        !           366:                 * Fetch the uc first, since there is state in it
        !           367:                 * besides the registers that should be preserved.
        !           368:                 */
        !           369:                val = READ(thread->proc,
        !           370:                    thread->addr + offsetof(struct pthread_st, pt_uc),
        !           371:                    &addr, sizeof(addr));
        !           372:                if (val != 0)
        !           373:                        return val;
        !           374:                val = READ(thread->proc,
        !           375:                    addr, &uc, sizeof(uc));
        !           376:                if (val != 0)
        !           377:                        return val;
        !           378:
        !           379:                switch (regset) {
        !           380:                case 0:
        !           381:                        PTHREAD_REG_TO_UCONTEXT(&uc, (struct reg *)buf);
        !           382:                        break;
        !           383:                case 1:
        !           384:                        PTHREAD_FPREG_TO_UCONTEXT(&uc, (struct fpreg *)buf);
        !           385:                        break;
        !           386:                case 2:
        !           387:                        return TD_ERR_INVAL;
        !           388:                }
        !           389:
        !           390:                val = WRITE(thread->proc,
        !           391:                    addr, &uc, sizeof(uc));
        !           392:                if (val != 0)
        !           393:                        return val;
        !           394:
        !           395:                break;
        !           396:        case PT_STATE_ZOMBIE:
        !           397:        default:
        !           398:                return TD_ERR_BADTHREAD;
        !           399:        }
        !           400:
        !           401:        return 0;
        !           402: }
        !           403:
        !           404: int
        !           405: td_thr_join_iter(td_thread_t *thread, int (*call)(td_thread_t *, void *),
        !           406:     void *arg)
        !           407: {
        !           408:        int val;
        !           409:        caddr_t next;
        !           410:        td_thread_t *thread2;
        !           411:        struct pthread_queue_t queue;
        !           412:
        !           413:        if ((val = READ(thread->proc,
        !           414:            thread->addr + offsetof(struct pthread_st, pt_joiners),
        !           415:            &queue, sizeof(struct pthread_queue_t))) != 0)
        !           416:                return val;
        !           417:
        !           418:        next = (caddr_t) queue.ptqh_first;
        !           419:        while (next != 0) {
        !           420:                val = td__getthread(thread->proc, next, &thread2);
        !           421:                if (val != 0)
        !           422:                        return val;
        !           423:                val = (*call)(thread, arg);
        !           424:                if (val != 0)
        !           425:                        return 0;
        !           426:
        !           427:                val = READ(thread->proc,
        !           428:                    next + offsetof(struct pthread_st, pt_sleep.ptqe_next),
        !           429:                    &next, sizeof(next));
        !           430:                if (val != 0)
        !           431:                        return val;
        !           432:        }
        !           433:
        !           434:        return 0;
        !           435: }
        !           436:
        !           437: int
        !           438: td_sync_info(td_sync_t *s, td_sync_info_t *info)
        !           439: {
        !           440:        int val, magic, n;
        !           441:        struct pthread_queue_t queue;
        !           442:        pthread_spin_t slock;
        !           443:        pthread_t taddr;
        !           444:
        !           445:        val = READ(s->proc, s->addr, &magic, sizeof(magic));
        !           446:        if (val != 0)
        !           447:                return val;
        !           448:
        !           449:        info->sync_type = TD_SYNC_UNKNOWN;
        !           450:        info->sync_size = 0;
        !           451:        info->sync_haswaiters = 0;
        !           452:        switch (magic) {
        !           453:        case _PT_MUTEX_MAGIC:
        !           454:                info->sync_type = TD_SYNC_MUTEX;
        !           455:                info->sync_size = sizeof(struct pthread_mutex_st);
        !           456:                if ((val = READ(s->proc,
        !           457:                    s->addr + offsetof(struct pthread_mutex_st, ptm_blocked),
        !           458:                    &queue, sizeof(struct pthread_queue_t))) != 0)
        !           459:                return val;
        !           460:
        !           461:                if (!PTQ_EMPTY(&queue))
        !           462:                        info->sync_haswaiters = 1;
        !           463:                /*
        !           464:                 * The cast to (void *) is to explicitly throw away the
        !           465:                 * volatile qualifier on pthread_spin_t,
        !           466:                 * from __cpu_simple_lock_t.
        !           467:                 */
        !           468:                if ((val = READ(s->proc,
        !           469:                    s->addr + offsetof(struct pthread_mutex_st, ptm_lock),
        !           470:                    (void *)&slock, sizeof(struct pthread_spinlock_st))) != 0)
        !           471:                        return val;
        !           472:                if (slock == __SIMPLELOCK_LOCKED) {
        !           473:                        info->sync_data.mutex.locked = 1;
        !           474:                        if ((val = READ(s->proc,
        !           475:                            s->addr + offsetof(struct pthread_mutex_st,
        !           476:                                ptm_owner),
        !           477:                            &taddr, sizeof(pthread_t))) != 0)
        !           478:                                return val;
        !           479:                        taddr = pthread__id(taddr);
        !           480:                        td__getthread(s->proc, (caddr_t)taddr,
        !           481:                            &info->sync_data.mutex.owner);
        !           482:                } else
        !           483:                        info->sync_data.mutex.locked = 0;
        !           484:                break;
        !           485:        case _PT_COND_MAGIC:
        !           486:                info->sync_type = TD_SYNC_COND;
        !           487:                info->sync_size = sizeof(struct pthread_cond_st);
        !           488:                if ((val = READ(s->proc,
        !           489:                    s->addr + offsetof(struct pthread_cond_st, ptc_waiters),
        !           490:                    &queue, sizeof(struct pthread_queue_t))) != 0)
        !           491:                        return val;
        !           492:                if (!PTQ_EMPTY(&queue))
        !           493:                        info->sync_haswaiters = 1;
        !           494:                break;
        !           495:        case _PT_SPINLOCK_MAGIC:
        !           496:                info->sync_type = TD_SYNC_SPIN;
        !           497:                info->sync_size = sizeof(struct pthread_spinlock_st);
        !           498:                if ((val = READ(s->proc,
        !           499:                    s->addr + offsetof(struct pthread_spinlock_st, pts_spin),
        !           500:                    (void *)&slock, sizeof(struct pthread_spinlock_st))) != 0)
        !           501:                        return val;
        !           502:                if (slock == __SIMPLELOCK_LOCKED)
        !           503:                        info->sync_data.spin.locked = 1;
        !           504:                break;
        !           505:        case PT_MAGIC:
        !           506:                info->sync_type = TD_SYNC_JOIN;
        !           507:                info->sync_size = sizeof(struct pthread_st);
        !           508:                td__getthread(s->proc, s->addr,
        !           509:                    &info->sync_data.join.thread);
        !           510:                if ((val = READ(s->proc,
        !           511:                    s->addr + offsetof(struct pthread_st, pt_joiners),
        !           512:                    &queue, sizeof(struct pthread_queue_t))) != 0)
        !           513:                        return val;
        !           514:
        !           515:                if (!PTQ_EMPTY(&queue))
        !           516:                        info->sync_haswaiters = 1;
        !           517:                break;
        !           518:        case _PT_RWLOCK_MAGIC:
        !           519:                info->sync_type = TD_SYNC_RWLOCK;
        !           520:                info->sync_size = sizeof(struct pthread_rwlock_st);
        !           521:                if ((val = READ(s->proc,
        !           522:                    s->addr + offsetof(struct pthread_rwlock_st, ptr_rblocked),
        !           523:                    &queue, sizeof(struct pthread_queue_t))) != 0)
        !           524:                        return val;
        !           525:                if (!PTQ_EMPTY(&queue))
        !           526:                        info->sync_haswaiters = 1;
        !           527:
        !           528:                if ((val = READ(s->proc,
        !           529:                    s->addr + offsetof(struct pthread_rwlock_st, ptr_wblocked),
        !           530:                    &queue, sizeof(struct pthread_queue_t))) != 0)
        !           531:                        return val;
        !           532:                if (!PTQ_EMPTY(&queue))
        !           533:                        info->sync_haswaiters = 1;
        !           534:
        !           535:
        !           536:                info->sync_data.rwlock.locked = 0;
        !           537:                if ((val = READ(s->proc,
        !           538:                    s->addr + offsetof(struct pthread_rwlock_st, ptr_nreaders),
        !           539:                    &n, sizeof(int))) != 0)
        !           540:                        return val;
        !           541:                info->sync_data.rwlock.readlocks = n;
        !           542:                if (n > 0)
        !           543:                        info->sync_data.rwlock.locked = 1;
        !           544:
        !           545:                if ((val = READ(s->proc,
        !           546:                    s->addr + offsetof(struct pthread_rwlock_st, ptr_writer),
        !           547:                    &taddr, sizeof(pthread_t))) != 0)
        !           548:                        return val;
        !           549:                if (taddr != 0) {
        !           550:                        info->sync_data.rwlock.locked = 1;
        !           551:                        td__getthread(s->proc, (caddr_t)taddr,
        !           552:                            &info->sync_data.rwlock.writeowner);
        !           553:                }
        !           554:        default:
        !           555:                return (0);
        !           556:        }
        !           557:
        !           558:        info->sync_addr = s->addr;
        !           559:
        !           560:        return 0;
        !           561: }
        !           562:
        !           563:
        !           564: int
        !           565: td_sync_waiters_iter(td_sync_t *s, int (*call)(td_thread_t *, void *),
        !           566:     void *arg)
        !           567: {
        !           568:        int val, magic;
        !           569:        caddr_t next;
        !           570:        struct pthread_queue_t queue;
        !           571:        td_thread_t *thread;
        !           572:
        !           573:        val = READ(s->proc, s->addr, &magic, sizeof(magic));
        !           574:        if (val != 0)
        !           575:                return val;
        !           576:
        !           577:        switch (magic) {
        !           578:        case _PT_MUTEX_MAGIC:
        !           579:                if ((val = READ(s->proc,
        !           580:                    s->addr + offsetof(struct pthread_mutex_st, ptm_blocked),
        !           581:                    &queue, sizeof(struct pthread_queue_t))) != 0)
        !           582:                        return val;
        !           583:                break;
        !           584:        case _PT_COND_MAGIC:
        !           585:                if ((val = READ(s->proc,
        !           586:                    s->addr + offsetof(struct pthread_cond_st, ptc_waiters),
        !           587:                    &queue, sizeof(struct pthread_queue_t))) != 0)
        !           588:                        return val;
        !           589:                break;
        !           590:        case PT_MAGIC:
        !           591:                /* Redundant with join_iter, but what the hell... */
        !           592:                if ((val = READ(s->proc,
        !           593:                    s->addr + offsetof(struct pthread_st, pt_joiners),
        !           594:                    &queue, sizeof(struct pthread_queue_t))) != 0)
        !           595:                        return val;
        !           596:                break;
        !           597:        default:
        !           598:                return (0);
        !           599:        }
        !           600:
        !           601:        next = (caddr_t) queue.ptqh_first;
        !           602:        while (next != 0) {
        !           603:                val = td__getthread(s->proc, next, &thread);
        !           604:                if (val != 0)
        !           605:                        return val;
        !           606:                val = (*call)(thread, arg);
        !           607:                if (val != 0)
        !           608:                        return 0;
        !           609:
        !           610:                val = READ(s->proc,
        !           611:                    next + offsetof(struct pthread_st, pt_sleep.ptqe_next),
        !           612:                    &next, sizeof(next));
        !           613:                if (val != 0)
        !           614:                        return val;
        !           615:        }
        !           616:        return 0;
        !           617: }
        !           618:
        !           619:
        !           620: int
        !           621: td_map_addr2sync(td_proc_t *proc, caddr_t addr, td_sync_t **syncp)
        !           622: {
        !           623:        int magic, val;
        !           624:
        !           625:        val = READ(proc, addr, &magic, sizeof(magic));
        !           626:        if (val != 0)
        !           627:                return val;
        !           628:
        !           629:        if ((magic != _PT_MUTEX_MAGIC) &&
        !           630:            (magic != _PT_COND_MAGIC) &&
        !           631:            (magic != _PT_SPINLOCK_MAGIC))
        !           632:                return TD_ERR_NOOBJ;
        !           633:
        !           634:        val = td__getsync(proc, addr, syncp);
        !           635:        if (val != 0)
        !           636:                return val;
        !           637:
        !           638:        return 0;
        !           639: }
        !           640:
        !           641:
        !           642: int
        !           643: td_map_pth2thr(td_proc_t *proc, pthread_t thread, td_thread_t **threadp)
        !           644: {
        !           645:        int magic, val;
        !           646:
        !           647:        val = READ(proc, (caddr_t)thread, &magic, sizeof(magic));
        !           648:        if (val != 0)
        !           649:                return val;
        !           650:
        !           651:        if (magic != PT_MAGIC)
        !           652:                return TD_ERR_NOOBJ;
        !           653:
        !           654:        val = td__getthread(proc, (caddr_t)thread, threadp);
        !           655:        if (val != 0)
        !           656:                return val;
        !           657:
        !           658:        return 0;
        !           659: }
        !           660:
        !           661: int
        !           662: td_map_id2thr(td_proc_t *proc, int threadid, td_thread_t **threadp)
        !           663: {
        !           664:        int val, num;
        !           665:        caddr_t allqaddr, next;
        !           666:        struct pthread_queue_t allq;
        !           667:        td_thread_t *thread;
        !           668:
        !           669:
        !           670:        if (proc->allqueue == 0) {
        !           671:                val = LOOKUP(proc, "pthread__allqueue", &allqaddr);
        !           672:                if (val != 0)
        !           673:                        return val;
        !           674:                proc->allqueue = allqaddr;
        !           675:        } else {
        !           676:                allqaddr = proc->allqueue;
        !           677:        }
        !           678:
        !           679:        val = READ(proc, allqaddr, &allq, sizeof(allq));
        !           680:        if (val != 0)
        !           681:                return val;
        !           682:
        !           683:        next = (caddr_t) allq.ptqh_first;
        !           684:        while (next != 0) {
        !           685:                val = READ(proc,
        !           686:                    next + offsetof(struct pthread_st, pt_num),
        !           687:                    &num, sizeof(num));
        !           688:
        !           689:                if (num == threadid)
        !           690:                        break;
        !           691:
        !           692:                val = READ(proc,
        !           693:                    next + offsetof(struct pthread_st, pt_allq.ptqe_next),
        !           694:                    &next, sizeof(next));
        !           695:                if (val != 0)
        !           696:                        return val;
        !           697:        }
        !           698:
        !           699:        if (next == 0) {
        !           700:                /* A matching thread was not found. */
        !           701:                return TD_ERR_NOOBJ;
        !           702:        }
        !           703:
        !           704:        val = td__getthread(proc, next, &thread);
        !           705:        if (val != 0)
        !           706:                return val;
        !           707:        *threadp = thread;
        !           708:
        !           709:        return 0;
        !           710: }
        !           711:
        !           712: /* Return the thread handle of the thread running on the given LWP */
        !           713: int
        !           714: td_map_lwp2thr(td_proc_t *proc, int lwp, td_thread_t **threadp)
        !           715: {
        !           716:        int val, magic;
        !           717:        struct reg gregs;
        !           718:        ucontext_t uc;
        !           719:        caddr_t th;
        !           720:
        !           721:        val = GETREGS(proc, 0, lwp, &gregs);
        !           722:        if (val != 0)
        !           723:                return val;
        !           724:
        !           725:        PTHREAD_REG_TO_UCONTEXT(&uc, &gregs);
        !           726:
        !           727:        th = (caddr_t) pthread__id(pthread__uc_sp(&uc));
        !           728:
        !           729:        val = READ(proc, th, &magic, sizeof(magic));
        !           730:        if (val != 0)
        !           731:                return val;
        !           732:
        !           733:        if (magic != PT_MAGIC)
        !           734:                return TD_ERR_NOOBJ;
        !           735:
        !           736:        val = td__getthread(proc, th, threadp);
        !           737:        if (val != 0)
        !           738:                return val;
        !           739:
        !           740:        (*threadp)->lwp = lwp;
        !           741:
        !           742:        return 0;
        !           743: }
        !           744:
        !           745: int
        !           746: td_map_lwps(td_proc_t *proc)
        !           747: {
        !           748:        int i, val, nlwps;
        !           749:        caddr_t addr;
        !           750:        td_thread_t *thread;
        !           751:
        !           752:        val = LOOKUP(proc, "pthread__maxlwps", &addr);
        !           753:        if (val != 0)
        !           754:                return val;
        !           755:
        !           756:        val = READ(proc, addr, &nlwps, sizeof(int));
        !           757:        if (val != 0)
        !           758:                return val;
        !           759:
        !           760:        for (i = 1; i <= nlwps; i++) {
        !           761:                /*
        !           762:                 * Errors are deliberately ignored for the call to
        !           763:                 * td_map_lwp2thr(); it is entirely likely that not
        !           764:                 * all LWPs in the range 1..nlwps exist, and that's
        !           765:                 * not a problem.
        !           766:                 */
        !           767:                td_map_lwp2thr(proc, i, &thread);
        !           768:        }
        !           769:        return 0;
        !           770: }
        !           771:
        !           772: int
        !           773: td_tsd_iter(td_proc_t *proc,
        !           774:     int (*call)(pthread_key_t, void (*)(void *), void *), void *arg)
        !           775: {
        !           776:        caddr_t desaddr, allocaddr;
        !           777:        int val;
        !           778:        int i, allocated;
        !           779:        void (*destructor)(void *);
        !           780:
        !           781:        val = LOOKUP(proc, "pthread__tsd_alloc", &allocaddr);
        !           782:        if (val != 0)
        !           783:                return val;
        !           784:        val = LOOKUP(proc, "pthread__tsd_destructors", &desaddr);
        !           785:        if (val != 0)
        !           786:                return val;
        !           787:
        !           788:        for (i = 0; i < PTHREAD_KEYS_MAX; i++) {
        !           789:                val = READ(proc, allocaddr + i * sizeof(int),
        !           790:                    &allocated, sizeof(int));
        !           791:                if (val != 0)
        !           792:                        return val;
        !           793:
        !           794:                if (allocated) {
        !           795:                        val = READ(proc,  desaddr + i * sizeof(destructor),
        !           796:                            &destructor, sizeof(destructor));
        !           797:                        if (val != 0)
        !           798:                                return val;
        !           799:
        !           800:                        val = (call)(i, destructor, arg);
        !           801:                        if (val != 0)
        !           802:                                return val;
        !           803:                }
        !           804:        }
        !           805:
        !           806:        return 0;
        !           807: }
        !           808:
        !           809: /* Get the synchronization object that the thread is sleeping on */
        !           810: int
        !           811: td_thr_sleepinfo(td_thread_t *thread, td_sync_t **s)
        !           812: {
        !           813:        int val;
        !           814:        caddr_t addr;
        !           815:
        !           816:        if ((val = READ(thread->proc,
        !           817:            thread->addr + offsetof(struct pthread_st, pt_sleepobj),
        !           818:            &addr, sizeof(caddr_t))) != 0)
        !           819:                return val;
        !           820:
        !           821:        td__getsync(thread->proc, addr, s);
        !           822:
        !           823:        return 0;
        !           824:
        !           825: }
        !           826:
        !           827:
        !           828:
        !           829: static int
        !           830: td__getthread(td_proc_t *proc, caddr_t addr, td_thread_t **threadp)
        !           831: {
        !           832:        td_thread_t *thread;
        !           833:
        !           834:        /*
        !           835:         * Check if we've allocated a descriptor for this thread.
        !           836:         * Sadly, this makes iterating over a set of threads O(N^2)
        !           837:         * in the number of threads. More sophisticated data structures
        !           838:         * can wait.
        !           839:                 */
        !           840:        PTQ_FOREACH(thread, &proc->threads, list) {
        !           841:                if (thread->addr == addr)
        !           842:                        break;
        !           843:        }
        !           844:        if (thread == NULL) {
        !           845:                thread = malloc(sizeof(*thread));
        !           846:                if (thread == NULL)
        !           847:                        return TD_ERR_NOMEM;
        !           848:                thread->proc = proc;
        !           849:                thread->addr = addr;
        !           850:                thread->lwp  = 0;
        !           851:                PTQ_INSERT_HEAD(&proc->threads, thread, list);
        !           852:        }
        !           853:
        !           854:        *threadp = thread;
        !           855:        return 0;
        !           856: }
        !           857:
        !           858:
        !           859: static int
        !           860: td__getsync(td_proc_t *proc, caddr_t addr, td_sync_t **syncp)
        !           861: {
        !           862:        td_sync_t *s;
        !           863:
        !           864:        /* Check if we've allocated a descriptor for this object. */
        !           865:        PTQ_FOREACH(s, &proc->syncs, list) {
        !           866:                if (s->addr == addr)
        !           867:                        break;
        !           868:        }
        !           869:        /* Allocate a fresh one */
        !           870:        if (s == NULL) {
        !           871:                s = malloc(sizeof(*s));
        !           872:                if (s == NULL)
        !           873:                        return TD_ERR_NOMEM;
        !           874:                s->proc = proc;
        !           875:                s->addr = addr;
        !           876:                PTQ_INSERT_HEAD(&proc->syncs, s, list);
        !           877:        }
        !           878:
        !           879:        *syncp = s;
        !           880:        return 0;
        !           881: }
        !           882:
        !           883:
        !           884: int
        !           885: td_thr_tsd(td_thread_t *thread, pthread_key_t key, void **value)
        !           886: {
        !           887:        int val;
        !           888:
        !           889:        val = READ(thread->proc, thread->addr +
        !           890:            offsetof(struct pthread_st, pt_specific) +
        !           891:            key * sizeof(void *), &value, sizeof(void *));
        !           892:
        !           893:        return val;
        !           894: }
        !           895:

CVSweb <webmaster@jp.NetBSD.org>