src/
Coverage:
low: ≥ 0%
medium: ≥ 75.0%
high: ≥ 90.0%
Lines:
44 / 44
100.0%
Branches:
28 / 30
93.3%
Functions:
7 / 7
100.0%

ProtoSlots.cpp
Line Branch Exec Source
1 #include "ProtoSlots.h"
2
3 22 proto_slot_t *claimSlot(proto_slot_t *slots, uint8_t count, uint32_t clientId, bool withSchema) {
4
2/2
✓ Branch 0 taken 37 times.
✓ Branch 1 taken 1 time.
38 for(uint8_t i = 0; i < count; i++) {
5 37 uint32_t expected = 0;
6
2/2
✓ Branch 1 taken 16 times.
✓ Branch 2 taken 21 times.
74 if(!slots[i].clientId.compare_exchange_strong(expected, clientId)) continue;
7 21 slots[i].withSchema = withSchema;
8 21 slots[i].feeds = 0;
9 21 return &slots[i];
10 }
11 1 return nullptr;
12 }
13 20 void startSync(proto_slot_t &slot) { slot.wants.fetch_or(WANTS_SYNC); }
14 1 proto_slot_t *slotOf(proto_slot_t *slots, uint8_t count, uint32_t clientId) {
15
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 1 time.
6 for(uint8_t i = 0; i < count; i++)
16
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
10 if(slots[i].clientId.load() == clientId) return &slots[i];
17 1 return nullptr;
18 }
19 69 void freeSlot(proto_slot_t &slot) {
20 // Cleared before the slot is free, so the next client starts clean.
21 69 slot.wants = 0;
22 69 slot.feeds = 0;
23 69 slot.clientId = 0;
24 69 }
25
26 24 uint32_t takeWants(proto_slot_t &slot, uint32_t seenId) {
27 24 const uint32_t wants = slot.wants.exchange(0);
28
2/2
✓ Branch 1 taken 23 times.
✓ Branch 2 taken 1 time.
48 if(slot.clientId.load() == seenId) return wants;
29 // The client left and another took the slot after loop() read it: what was
30 // taken may be the new client's, so it goes back for the next pass. A bit
31 // the old client left behind does no harm, as the new one wants a sync.
32
1/2
✓ Branch 0 taken 1 time.
✗ Branch 1 not taken.
1 if(wants) slot.wants.fetch_or(wants);
33 1 return 0;
34 }
35 23 sync_step_t nextSyncStep(proto_slot_t &slot, uint32_t now) {
36 23 const uint32_t id = slot.clientId.load();
37
2/2
✓ Branch 0 taken 14 times.
✓ Branch 1 taken 9 times.
23 if(id != slot.loopId) {
38 // A client left or another took the slot.
39 14 slot.loopId = id;
40 14 slot.cur = sync_cursor_t();
41 14 slot.awaitingNext = false;
42 }
43
2/2
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 22 times.
23 if(!id) return sync_step_t::none;
44 22 const uint32_t wants = takeWants(slot, id);
45
2/2
✓ Branch 0 taken 14 times.
✓ Branch 1 taken 8 times.
22 if(wants & (WANTS_SYNC | WANTS_SYNC_AGAIN)) {
46 // A client that just connected may skip the schema; one that asks again
47 // never gets it.
48
4/4
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 1 time.
✓ Branch 3 taken 12 times.
✓ Branch 4 taken 1 time.
14 slot.cur = beginSync((wants & WANTS_SYNC) && slot.withSchema.load());
49 14 return sync_step_t::send;
50 }
51
4/4
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 1 time.
✓ Branch 3 taken 1 time.
8 if((wants & WANTS_NEXT) && slot.awaitingNext) return sync_step_t::send;
52
4/4
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 1 time.
✓ Branch 3 taken 2 times.
7 if(slot.awaitingNext && now - slot.sentAt > PROTO_SYNC_TIMEOUT_MS) {
53 1 slot.awaitingNext = false;
54 1 slot.cur = sync_cursor_t();
55 1 return sync_step_t::timedOut;
56 }
57 6 return sync_step_t::none;
58 }
59 7 void syncFrameSent(proto_slot_t &slot, uint32_t now) {
60 7 slot.awaitingNext = slot.cur.active();
61 7 slot.sentAt = now;
62 7 }
63