* Locate a thread by number and return with proc lock held. * * thread exit establishes proc -> tidhash lock ordering, but lookup * takes tidhash first and needs to return locked proc. * * The problem is worked around by relying on type-safety of both * structures and doing the work in 2 steps: * - tidhash-locked lookup which saves both thread and proc pointers * - proc-locked verification
| 1614 | * - proc-locked verification that the found thread still matches |
| 1615 | */ |
| 1616 | static bool |
| 1617 | tdfind_hash(lwpid_t tid, pid_t pid, struct proc **pp, struct thread **tdp) |
| 1618 | { |
| 1619 | #define RUN_THRESH 16 |
| 1620 | struct proc *p; |
| 1621 | struct thread *td; |
| 1622 | int run; |
| 1623 | bool locked; |
| 1624 | |
| 1625 | run = 0; |
| 1626 | rw_rlock(TIDHASHLOCK(tid)); |
| 1627 | locked = true; |
| 1628 | LIST_FOREACH(td, TIDHASH(tid), td_hash) { |
| 1629 | if (td->td_tid != tid) { |
| 1630 | run++; |
| 1631 | continue; |
| 1632 | } |
| 1633 | p = td->td_proc; |
| 1634 | if (pid != -1 && p->p_pid != pid) { |
| 1635 | td = NULL; |
| 1636 | break; |
| 1637 | } |
| 1638 | if (run > RUN_THRESH) { |
| 1639 | if (rw_try_upgrade(TIDHASHLOCK(tid))) { |
| 1640 | LIST_REMOVE(td, td_hash); |
| 1641 | LIST_INSERT_HEAD(TIDHASH(td->td_tid), |
| 1642 | td, td_hash); |
| 1643 | rw_wunlock(TIDHASHLOCK(tid)); |
| 1644 | locked = false; |
| 1645 | break; |
| 1646 | } |
| 1647 | } |
| 1648 | break; |
| 1649 | } |
| 1650 | if (locked) |
| 1651 | rw_runlock(TIDHASHLOCK(tid)); |
| 1652 | if (td == NULL) |
| 1653 | return (false); |
| 1654 | *pp = p; |
| 1655 | *tdp = td; |
| 1656 | return (true); |
| 1657 | } |
| 1658 | |
| 1659 | struct thread * |
| 1660 | tdfind(lwpid_t tid, pid_t pid) |