summaryrefslogtreecommitdiffstats
path: root/src/core/hle/kernel/k_thread_queue.h
blob: c52eba24993b40f4f3dddcfd148a8325d6f15b1f (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
// Copyright 2021 yuzu Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.

#pragma once

#include "core/hle/kernel/k_thread.h"

namespace Kernel {

class KThreadQueue {
public:
    explicit KThreadQueue(KernelCore& kernel) : kernel{kernel} {}

    bool IsEmpty() const {
        return wait_list.empty();
    }

    KThread::WaiterList::iterator begin() {
        return wait_list.begin();
    }
    KThread::WaiterList::iterator end() {
        return wait_list.end();
    }

    bool SleepThread(KThread* t) {
        KScopedSchedulerLock sl{kernel};

        // If the thread needs terminating, don't enqueue it.
        if (t->IsTerminationRequested()) {
            return false;
        }

        // Set the thread's queue and mark it as waiting.
        t->SetSleepingQueue(this);
        t->SetState(ThreadState::Waiting);

        // Add the thread to the queue.
        wait_list.push_back(*t);

        return true;
    }

    void WakeupThread(KThread* t) {
        KScopedSchedulerLock sl{kernel};

        // Remove the thread from the queue.
        wait_list.erase(wait_list.iterator_to(*t));

        // Mark the thread as no longer sleeping.
        t->SetState(ThreadState::Runnable);
        t->SetSleepingQueue(nullptr);
    }

    KThread* WakeupFrontThread() {
        KScopedSchedulerLock sl{kernel};

        if (wait_list.empty()) {
            return nullptr;
        } else {
            // Remove the thread from the queue.
            auto it = wait_list.begin();
            KThread* thread = std::addressof(*it);
            wait_list.erase(it);

            ASSERT(thread->GetState() == ThreadState::Waiting);

            // Mark the thread as no longer sleeping.
            thread->SetState(ThreadState::Runnable);
            thread->SetSleepingQueue(nullptr);

            return thread;
        }
    }

private:
    KernelCore& kernel;
    KThread::WaiterList wait_list{};
};

} // namespace Kernel