| 105 | #endif |
| 106 | |
| 107 | int |
| 108 | stack_save_td(struct stack *st, struct thread *td) |
| 109 | { |
| 110 | int cpuid, error; |
| 111 | bool done; |
| 112 | |
| 113 | THREAD_LOCK_ASSERT(td, MA_OWNED); |
| 114 | KASSERT(!TD_IS_SWAPPED(td), |
| 115 | ("stack_save_td: thread %p is swapped", td)); |
| 116 | if (TD_IS_RUNNING(td) && td != curthread) |
| 117 | PROC_LOCK_ASSERT(td->td_proc, MA_OWNED); |
| 118 | |
| 119 | if (td == curthread) { |
| 120 | stack_save(st); |
| 121 | return (0); |
| 122 | } |
| 123 | |
| 124 | for (done = false, error = 0; !done;) { |
| 125 | if (!TD_IS_RUNNING(td)) { |
| 126 | /* |
| 127 | * The thread will not start running so long as we hold |
| 128 | * its lock. |
| 129 | */ |
| 130 | stack_capture(td, st, PCB_FP(td->td_pcb)); |
| 131 | error = 0; |
| 132 | break; |
| 133 | } |
| 134 | |
| 135 | #ifdef SMP |
| 136 | thread_unlock(td); |
| 137 | cpuid = atomic_load_int(&td->td_oncpu); |
| 138 | if (cpuid == NOCPU) { |
| 139 | cpu_spinwait(); |
| 140 | } else { |
| 141 | mtx_lock(&intr_lock); |
| 142 | stack_intr_td = NULL; |
| 143 | stack_intr_stack = st; |
| 144 | ipi_cpu(cpuid, IPI_TRACE); |
| 145 | while (atomic_load_acq_ptr((void *)&stack_intr_td) == |
| 146 | (uintptr_t)NULL) |
| 147 | cpu_spinwait(); |
| 148 | if (stack_intr_td == td) { |
| 149 | done = true; |
| 150 | error = st->depth > 0 ? 0 : EBUSY; |
| 151 | } |
| 152 | stack_intr_td = NULL; |
| 153 | mtx_unlock(&intr_lock); |
| 154 | } |
| 155 | thread_lock(td); |
| 156 | #else |
| 157 | (void)cpuid; |
| 158 | KASSERT(0, ("%s: multiple running threads", __func__)); |
| 159 | #endif |
| 160 | } |
| 161 | |
| 162 | return (error); |
| 163 | } |
| 164 |
nothing calls this directly
no test coverage detected