1
1
// uvco (c) 2023 Lewin Bormann. See LICENSE for specific terms.
2
2
3
+ #include < array>
3
4
#include < fmt/core.h>
4
5
#include < uv.h>
5
6
@@ -14,37 +15,6 @@ namespace uvco {
14
15
15
16
namespace {
16
17
17
- using BloomFilter = std::size_t ;
18
-
19
- size_t splitmix64 (size_t x) {
20
- size_t z = (x + 0x9e3779b97f4a7c15 );
21
- z = (z ^ (z >> 30 )) * 0xbf58476d1ce4e5b9 ;
22
- z = (z ^ (z >> 27 )) * 0x94d049bb133111eb ;
23
- return z ^ (z >> 31 );
24
- }
25
-
26
- bool haveSeenOrAdd (BloomFilter &filter, std::coroutine_handle<> handle) {
27
- static_assert (sizeof (BloomFilter) == 8 , " BloomFilter is not 64 bits" );
28
- const size_t hash = splitmix64 ((size_t )handle.address ());
29
- const unsigned index1 = hash % 64 ;
30
- const unsigned index2 = (hash >> 6U ) % 64 ;
31
- const unsigned index3 = (hash >> 12U ) % 64 ;
32
- const unsigned index4 = (hash >> 18U ) % 64 ;
33
- const unsigned index5 = (hash >> 24U ) % 64 ;
34
-
35
- // More than the first 32 bits appear to not gain much.
36
- const size_t bloomIndex = (1U << index1) | (1U << index2) | (1U << index3) |
37
- (1U << index4) | (1U << index5);
38
-
39
- if ((filter & bloomIndex) == bloomIndex) {
40
- // Potentially a false positive.
41
- return true ;
42
- }
43
- // Definitely not seen before.
44
- filter |= bloomIndex;
45
- return false ;
46
- }
47
-
48
18
unsigned findFirstIndexOf (std::span<const std::coroutine_handle<>> handles,
49
19
std::coroutine_handle<> handle) {
50
20
return std::ranges::find_if (
@@ -61,39 +31,35 @@ void Scheduler::runAll() {
61
31
unsigned turns = 0 ;
62
32
63
33
while (!resumableActive_.empty () && turns < maxTurnsBeforeReturning) {
64
- BloomFilter seenHandles = 0 ;
65
34
resumableRunning_.swap (resumableActive_);
66
35
for (unsigned i = 0 ; i < resumableRunning_.size (); ++i) {
67
36
auto &coro = resumableRunning_[i];
68
-
69
37
// Defend against resuming the same coroutine twice in the same loop pass.
70
38
// This happens when SelectSet selects two coroutines which return at the
71
39
// same time. Resuming the same handle twice is not good, very bad, and
72
40
// will usually at least cause a heap use-after-free.
73
41
74
- // Explicitly written in an explicit way :)
75
- if (!haveSeenOrAdd (seenHandles, coro)) [[likely]] {
76
- coro.resume ();
77
- } else if (findFirstIndexOf (resumableRunning_, coro) == i) {
42
+ // Check if this coroutine handle has already been resumed. This has
43
+ // quadratic complexity, but appears to be faster than e.g. a Bloom
44
+ // filter, because it takes fewer calculations and is a nice linear search
45
+ // over a usually short vector.
46
+ if (findFirstIndexOf (resumableRunning_, coro) == i) {
78
47
// This is only true if the coroutine is a false positive in the bloom
79
48
// filter, and has not been run before. The linear search is slow (but
80
49
// not too slow), and only happens in the case of a false positive.
81
50
coro.resume ();
82
- } else {
83
- // This is most likely a SelectSet being awaited, with two coroutines
84
- // being ready at the same time.
85
51
}
86
52
}
87
53
resumableRunning_.clear ();
88
54
++turns;
89
55
}
90
56
}
91
57
92
- void Scheduler::close () { BOOST_ASSERT (resumableActive_.empty ()); }
58
+ void Scheduler::close () { BOOST_ASSERT (! resumableActive_.empty ()); }
93
59
94
60
void Scheduler::enqueue (std::coroutine_handle<> handle) {
95
61
// Use of moved-out Scheduler?
96
- BOOST_ASSERT (resumableActive_.capacity () != 0 );
62
+ BOOST_ASSERT (resumableActive_.capacity () > 0 );
97
63
98
64
if (run_mode_ == RunMode::Immediate) {
99
65
handle.resume ();
@@ -108,9 +74,8 @@ void Scheduler::setUpLoop(uv_loop_t *loop) { uv_loop_set_data(loop, this); }
108
74
Scheduler::~Scheduler () = default ;
109
75
110
76
Scheduler::Scheduler (RunMode mode) : run_mode_{mode} {
111
- static constexpr size_t resumableBufferSize = 16 ;
112
- resumableActive_.reserve (resumableBufferSize);
113
- resumableRunning_.reserve (resumableBufferSize);
77
+ resumableActive_.reserve (16 );
78
+ resumableRunning_.reserve (16 );
114
79
}
115
80
116
81
} // namespace uvco
0 commit comments