| 171 | } |
| 172 | |
| 173 | error_code sys_ppu_thread_join(ppu_thread &ppu, u32 thread_id, |
| 174 | vm::ptr<u64> vptr) { |
| 175 | lv2_obj::prepare_for_sleep(ppu); |
| 176 | |
| 177 | sys_ppu_thread.trace("sys_ppu_thread_join(thread_id=0x%x, vptr=*0x%x)", |
| 178 | thread_id, vptr); |
| 179 | |
| 180 | if (thread_id == ppu.id) { |
| 181 | return CELL_EDEADLK; |
| 182 | } |
| 183 | |
| 184 | auto thread = idm::get<named_thread<ppu_thread>>( |
| 185 | thread_id, |
| 186 | [&, notify = lv2_obj::notify_all_t()](ppu_thread &thread) -> CellError { |
| 187 | CellError result = |
| 188 | thread.joiner.atomic_op([&](ppu_join_status &value) -> CellError { |
| 189 | switch (value) { |
| 190 | case ppu_join_status::joinable: |
| 191 | value = ppu_join_status{ppu.id}; |
| 192 | return {}; |
| 193 | case ppu_join_status::zombie: |
| 194 | value = ppu_join_status::exited; |
| 195 | return CELL_EAGAIN; |
| 196 | case ppu_join_status::exited: |
| 197 | return CELL_ESRCH; |
| 198 | case ppu_join_status::detached: |
| 199 | default: |
| 200 | return CELL_EINVAL; |
| 201 | } |
| 202 | }); |
| 203 | |
| 204 | if (!result) { |
| 205 | lv2_obj::prepare_for_sleep(ppu); |
| 206 | lv2_obj::sleep(ppu); |
| 207 | } |
| 208 | |
| 209 | notify.cleanup(); |
| 210 | return result; |
| 211 | }); |
| 212 | |
| 213 | if (!thread) { |
| 214 | return CELL_ESRCH; |
| 215 | } |
| 216 | |
| 217 | if (thread.ret && thread.ret != CELL_EAGAIN) { |
| 218 | return thread.ret; |
| 219 | } |
| 220 | |
| 221 | if (thread.ret == CELL_EAGAIN) { |
| 222 | // Notify thread if waiting for a joiner |
| 223 | thread->joiner.notify_one(); |
| 224 | } |
| 225 | |
| 226 | // Wait for cleanup |
| 227 | (*thread.ptr)(); |
| 228 | |
| 229 | if (thread->joiner != ppu_join_status::exited) { |
| 230 | // Thread aborted, log it later |
no test coverage detected