liyujie
2025-08-28 d9927380ed7c8366f762049be9f3fee225860833
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
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
// Copyright 2018 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
 
// Can't compile this for Zircon userspace yet since libstdc++ isn't available.
#ifndef FIT_NO_STD_FOR_ZIRCON_USERSPACE
 
#include <lib/fit/scheduler.h>
 
#include <map>
#include <queue>
#include <utility>
 
namespace fit {
namespace subtle {
 
scheduler::scheduler() = default;
 
scheduler::~scheduler() = default;
 
void scheduler::schedule_task(pending_task task) {
    assert(task);
    runnable_tasks_.push(std::move(task));
}
 
suspended_task::ticket scheduler::obtain_ticket(uint32_t initial_refs) {
    suspended_task::ticket ticket = next_ticket_++;
    tickets_.emplace(ticket, ticket_record(initial_refs));
    return ticket;
}
 
void scheduler::finalize_ticket(suspended_task::ticket ticket,
                                pending_task* task) {
    auto it = tickets_.find(ticket);
    assert(it != tickets_.end());
    assert(!it->second.task);
    assert(it->second.ref_count > 0);
    assert(task);
 
    it->second.ref_count--;
    if (!*task) {
        // task already finished
    } else if (it->second.was_resumed) {
        // task immediately became runnable
        runnable_tasks_.push(std::move(*task));
    } else if (it->second.ref_count > 0) {
        // task remains suspended
        it->second.task = std::move(*task);
        suspended_task_count_++;
    } // else, task was abandoned and caller retains ownership of it
    if (it->second.ref_count == 0) {
        tickets_.erase(it);
    }
}
 
void scheduler::duplicate_ticket(suspended_task::ticket ticket) {
    auto it = tickets_.find(ticket);
    assert(it != tickets_.end());
    assert(it->second.ref_count > 0);
 
    it->second.ref_count++;
    assert(it->second.ref_count != 0); // did we really make 4 billion refs?!
}
 
pending_task scheduler::release_ticket(suspended_task::ticket ticket) {
    auto it = tickets_.find(ticket);
    assert(it != tickets_.end());
    assert(it->second.ref_count > 0);
 
    it->second.ref_count--;
    if (it->second.ref_count == 0) {
        pending_task task = std::move(it->second.task);
        if (task) {
            assert(suspended_task_count_ > 0);
            suspended_task_count_--;
        }
        tickets_.erase(it);
        return task;
    }
    return pending_task();
}
 
bool scheduler::resume_task_with_ticket(suspended_task::ticket ticket) {
    auto it = tickets_.find(ticket);
    assert(it != tickets_.end());
    assert(it->second.ref_count > 0);
 
    bool did_resume = false;
    it->second.ref_count--;
    if (!it->second.was_resumed) {
        it->second.was_resumed = true;
        if (it->second.task) {
            did_resume = true;
            assert(suspended_task_count_ > 0);
            suspended_task_count_--;
            runnable_tasks_.push(std::move(it->second.task));
        }
    }
    if (it->second.ref_count == 0) {
        tickets_.erase(it);
    }
    return did_resume;
}
 
void scheduler::take_runnable_tasks(task_queue* tasks) {
    assert(tasks && tasks->empty());
    runnable_tasks_.swap(*tasks);
}
 
void scheduler::take_all_tasks(task_queue* tasks) {
    assert(tasks && tasks->empty());
 
    runnable_tasks_.swap(*tasks);
    if (suspended_task_count_ > 0) {
        for (auto& item : tickets_) {
            if (item.second.task) {
                assert(suspended_task_count_ > 0);
                suspended_task_count_--;
                tasks->push(std::move(item.second.task));
            }
        }
    }
}
 
} // namespace subtle
} // namespace fit
 
#endif // FIT_NO_STD_FOR_ZIRCON_USERSPACE