| 1314 | } |
| 1315 | |
| 1316 | int thread_yield_to(thread* th) { |
| 1317 | if (unlikely(th == nullptr)) { // yield to any thread |
| 1318 | return thread_yield(); |
| 1319 | } |
| 1320 | RunQ rq; |
| 1321 | if (unlikely(th == rq.current)) { // yield to current should just update time |
| 1322 | if_update_now(); |
| 1323 | return 0; |
| 1324 | } else if (unlikely(th->vcpu != rq.current->vcpu)) { |
| 1325 | LOG_ERROR_RETURN(EINVAL, -1, "target thread ` must be run by the same vcpu as CURRENT!", th); |
| 1326 | } else if (unlikely(th->state == states::STANDBY)) { |
| 1327 | while (th->state == states::STANDBY) |
| 1328 | resume_threads(th->get_vcpu(), rq); |
| 1329 | assert(th->state == states::READY); |
| 1330 | } else if (unlikely(th->state != states::READY)) { |
| 1331 | LOG_ERROR_RETURN(EINVAL, -1, "target thread ` must be READY!", th); |
| 1332 | } else if (unlikely(rq.current->next() == th)) { |
| 1333 | return thread_yield(); |
| 1334 | } |
| 1335 | |
| 1336 | auto sw = AtomicRunQ(rq).try_goto(th); |
| 1337 | if_update_now(); |
| 1338 | rq.current->error_number = 0; |
| 1339 | switch_context(sw.from, sw.to); |
| 1340 | return rq.current->error_number; |
| 1341 | } |
| 1342 | |
| 1343 | __attribute__((always_inline)) inline |
| 1344 | Switch prepare_usleep(Timeout timeout, thread_list* waitq, RunQ rq = {}) |