1#include "internal.h"
2#include <thread/apc.h>
3
4/* file implements `thread_migrate`.
5 *
6 * NOTE: when we acquire two `struct scheduler` locks,
7 * we ALWAYS ALWAYS acquire the lock for the LOWER
8 * memory address first, same for unlock,
9 * and we ALWAYS acquire thread
10 * locks AFTER any scheduler locks! */
11
12void thread_post_migrate(struct thread *t, cpu_id_t old_cpu, cpu_id_t new_cpu) {
13 /* assert that both scheduler/runqueue locks are held,
14 * migrate relevant things */
15 SPINLOCK_ASSERT_HELD(&global.schedulers[old_cpu]->lock);
16 SPINLOCK_ASSERT_HELD(&global.schedulers[new_cpu]->lock);
17 climb_post_migrate_hook(t, old_cpu, new_cpu);
18 wroost_post_migrate_hook(t, from: old_cpu, to: new_cpu);
19}
20
21void thread_migrate(struct thread *t, size_t dest_core) TSA_NO_ANALYSIS {
22 /* first acquire both the lock of the thread's scheduler
23 * and the destination core's scheduler */
24
25 enum irql sirql, dirql, tirql;
26
27 struct scheduler *to_force_resched = NULL;
28 struct scheduler *src;
29 struct scheduler *dst = global.schedulers[dest_core];
30
31 thread_lock_thread_and_rq(t, other_rq: dst, out_thread_rq: &src, irq_first: &sirql, irq_second: &dirql);
32
33 if (src == dst) {
34 thread_unlock_thread_and_rq(thread_rq: src, other_rq: dst, irq_first: sirql, irq_second: dirql);
35 return;
36 }
37
38 bool ok;
39 tirql = thread_acquire(t, success: &ok);
40 if (!ok) {
41 goto end;
42 }
43
44 /* bro cannot be migrated */
45 if (!scheduler_can_take_thread(core: dest_core, target: t)) {
46 goto out;
47 }
48
49 /* finally, we can do something here. */
50 if (thread_get_state(t) == THREAD_STATE_RUNNING ||
51 !(thread_get_flags(t) & THREAD_FLAG_YIELDED)) {
52 thread_set_migration_target(t, new: dest_core);
53 to_force_resched = dst;
54 } else if (thread_get_state(t) == THREAD_STATE_READY) {
55 scheduler_remove_thread_locked(sched: src, t);
56 scheduler_add_thread_locked(sched: dst, thread: t);
57 to_force_resched = dst;
58 }
59
60 thread_set_runqueue(t, s: dst);
61
62out:
63
64 thread_release(t, irql: tirql);
65
66end:
67 thread_unlock_thread_and_rq(thread_rq: src, other_rq: dst, irq_first: sirql, irq_second: dirql);
68
69 if (to_force_resched)
70 scheduler_force_resched(sched: to_force_resched);
71}
72