summaryrefslogtreecommitdiff
path: root/sim/queue.h
blob: 890beb64b189c5680a1adeeb80f42322140ba218 (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
82
83
84
85
86
87
#pragma once

#include <cstdint>
#include <iterator> // IWYU pragma: keep
#include <map>
#include <set>

#include "sim/sim.h"
#include "util/assert.h"

namespace sim {

    template<typename Element> struct Queue {
        Scheduler &scheduler;

        Schedulable *reader = nullptr;
        std::set<Schedulable *> writers;

        unsigned int min_latency;

        std::multimap<std::uint64_t, Element> waiting;

        Queue(Scheduler &scheduler, unsigned int min_latency)
            : scheduler(scheduler)
            , min_latency(min_latency)
        { }

        void add_reader(Schedulable *x)
        {
            ASSERT(&x->scheduler == &scheduler, "Reader associated with incorrect Scheduler");
            ASSERT(!reader, "Already have a reader");
            reader = x;
            if (min_latency == 0) {
                for (const auto &w : writers)
                    scheduler.constrain(w, reader);
            }
        }

        void add_writer(Schedulable *x)
        {
            ASSERT(&x->scheduler == &scheduler, "Writer associated with incorrect Scheduler");
            writers.emplace(x);
            if (min_latency == 0 && reader)
                scheduler.constrain(x, reader);
        }

        void write(Element &&x)
        {
            write(std::move(x), min_latency);
        }

        void write(Element &&x, unsigned int latency)
        {
            ASSERT(latency >= min_latency, "Latency too low");
            ASSERT(!scheduler.current_schedulable || writers.count(scheduler.current_schedulable), "Write lacks permission");
            waiting.emplace(scheduler.now + min_latency, std::move(x));
        }

        unsigned int available()
        {
            ASSERT(!scheduler.current_schedulable || reader == scheduler.current_schedulable, "Read lacks permission");
            unsigned int c = 0;
            for (auto x = waiting.begin(); x != waiting.end() && x->first <= scheduler.now; ++x)
                ++c;
            return c;
        }

        Element &peek(unsigned int i=0)
        {
            ASSERT(i < available(), "Peek past available elements");
            auto x = waiting.begin();
            std::advance(x, i);
            return x->second;
        }

        Element read(unsigned int i=0)
        {
            ASSERT(i < available(), "Read past available elements");
            auto x = waiting.begin();
            std::advance(x, i);
            Element e{std::move(x->second)};
            waiting.erase(x);
            return e;
        }
    };

}