|
1 |
| -// todo copyright stuff |
2 |
| -// as I rewrote all the implem |
| 1 | +// Copyright (C) Datadog 2025 |
| 2 | +// Implementation of thread filter management |
3 | 3 |
|
4 | 4 | #include "threadFilter.h"
|
5 |
| -#include <mutex> |
6 |
| -#include <thread> |
7 |
| -#include <cstdlib> |
8 |
| -#include <cstring> |
9 |
| - |
10 |
| -static std::mutex slot_mutex; |
11 | 5 |
|
| 6 | +#include <cstdlib> |
| 7 | +#include <thread> |
12 | 8 |
|
13 |
| -ThreadFilter::ThreadFilter() : _next_index(0), _enabled(false) { |
14 |
| - std::lock_guard<std::mutex> lock(slot_mutex); |
15 |
| - _slots.resize(128); // preallocate some slots |
16 |
| - // Initialize all slots to -1 |
17 |
| - for (auto& slot : _slots) { |
18 |
| - slot.value.store(-1, std::memory_order_relaxed); |
19 |
| - } |
| 9 | +ThreadFilter::ThreadFilter() |
| 10 | + : _next_index(0), _enabled(false) { |
| 11 | + std::unique_lock<std::mutex> lock(_slot_mutex); |
| 12 | + _slots.emplace_back(); // Allocate first chunk |
| 13 | + clear(); |
20 | 14 | }
|
21 | 15 |
|
22 | 16 | ThreadFilter::~ThreadFilter() {
|
23 |
| - std::lock_guard<std::mutex> lock(slot_mutex); |
| 17 | + std::unique_lock<std::mutex> lock(_slot_mutex); |
24 | 18 | _slots.clear();
|
25 |
| - _free_list.clear(); // todo: implement this, not needed for benchmark |
26 | 19 | }
|
27 | 20 |
|
28 | 21 | ThreadFilter::SlotID ThreadFilter::registerThread() {
|
29 |
| - int index = _next_index.fetch_add(1, std::memory_order_relaxed); |
30 |
| - if (index < static_cast<int>(_slots.size())) { |
31 |
| - return index; |
| 22 | + SlotID index = _next_index.fetch_add(1, std::memory_order_relaxed); |
| 23 | + if (index >= kMaxThreads) { |
| 24 | + return -1; |
32 | 25 | }
|
33 |
| - // Lock required to safely grow the vector |
| 26 | + const int outer_idx = index >> kChunkShift; |
34 | 27 | {
|
35 |
| - std::lock_guard<std::mutex> lock(slot_mutex); |
36 |
| - size_t current_size = _slots.size(); |
37 |
| - if (static_cast<size_t>(index) >= current_size) { |
38 |
| - _slots.resize(current_size * 2); |
39 |
| - // Initialize new slots |
40 |
| - for (size_t i = current_size; i < current_size * 2; ++i) { |
41 |
| - _slots[i].value.store(-1, std::memory_order_relaxed); |
42 |
| - } |
| 28 | + if (outer_idx < static_cast<int>(_slots.size())) { |
| 29 | + return index; |
| 30 | + } |
| 31 | + } |
| 32 | + |
| 33 | + { |
| 34 | + std::unique_lock<std::mutex> write_lock(_slot_mutex); |
| 35 | + while (outer_idx >= static_cast<int>(_slots.size())) { |
| 36 | + _slots.emplace_back(); |
43 | 37 | }
|
44 | 38 | }
|
| 39 | + |
45 | 40 | return index;
|
46 | 41 | }
|
47 | 42 |
|
48 | 43 | void ThreadFilter::clear() {
|
49 |
| - std::lock_guard<std::mutex> lock(slot_mutex); |
50 |
| - for (auto& slot : _slots) { |
51 |
| - slot.value.store(-1, std::memory_order_relaxed); |
| 44 | + for (auto& chunk : _slots) { |
| 45 | + for (auto& slot : chunk) { |
| 46 | + slot.value.store(-1, std::memory_order_relaxed); |
| 47 | + } |
| 48 | + } |
| 49 | +} |
| 50 | + |
| 51 | +bool ThreadFilter::accept(SlotID slot_id) const { |
| 52 | + if (!_enabled) { |
| 53 | + return true; |
52 | 54 | }
|
| 55 | + if (slot_id < 0) return false; |
| 56 | + int outer_idx = slot_id >> kChunkShift; |
| 57 | + int inner_idx = slot_id & kChunkMask; |
| 58 | + if (outer_idx >= static_cast<int>(_slots.size())) return false; |
| 59 | + return _slots[outer_idx][inner_idx].value.load(std::memory_order_acquire) != -1; |
53 | 60 | }
|
54 | 61 |
|
55 |
| -bool ThreadFilter::accept(int slot_id) const { |
56 |
| - if (!_enabled) return true; |
57 |
| - return slot_id >= 0 && slot_id < static_cast<int>(_slots.size()) && _slots[slot_id].value.load(std::memory_order_acquire) != -1; |
| 62 | +void ThreadFilter::add(int tid, SlotID slot_id) { |
| 63 | + int outer_idx = slot_id >> kChunkShift; |
| 64 | + int inner_idx = slot_id & kChunkMask; |
| 65 | + _slots[outer_idx][inner_idx].value.store(tid, std::memory_order_relaxed); |
58 | 66 | }
|
59 | 67 |
|
60 |
| -void ThreadFilter::add(int tid, int slot_id) { |
61 |
| - _slots[slot_id].value.store(tid, std::memory_order_relaxed); |
| 68 | +void ThreadFilter::remove(SlotID slot_id) { |
| 69 | + int outer_idx = slot_id >> kChunkShift; |
| 70 | + int inner_idx = slot_id & kChunkMask; |
| 71 | + _slots[outer_idx][inner_idx].value.store(-1, std::memory_order_relaxed); |
62 | 72 | }
|
63 | 73 |
|
64 |
| -void ThreadFilter::remove(int slot_id) { |
65 |
| - _slots[slot_id].value.store(-1, std::memory_order_relaxed); |
| 74 | +void ThreadFilter::unregisterThread(SlotID slot_id) { |
| 75 | + if (slot_id < 0) return; |
| 76 | + int outer_idx = slot_id >> kChunkShift; |
| 77 | + int inner_idx = slot_id & kChunkMask; |
| 78 | + _slots[outer_idx][inner_idx].value.store(-1, std::memory_order_relaxed); |
66 | 79 | }
|
67 | 80 |
|
68 | 81 | void ThreadFilter::collect(std::vector<int>& tids) const {
|
69 | 82 | tids.clear();
|
70 |
| - std::lock_guard<std::mutex> lock(slot_mutex); |
71 |
| - for (const auto& slot : _slots) { |
72 |
| - int slot_tid = slot.value.load(std::memory_order_acquire); |
73 |
| - if (slot_tid != -1) { |
74 |
| - tids.push_back(slot_tid); |
| 83 | + // std::unique_lock<std::mutex> lock(_slot_mutex); |
| 84 | + for (const auto& chunk : _slots) { |
| 85 | + for (const auto& slot : chunk) { |
| 86 | + int slot_tid = slot.value.load(std::memory_order_acquire); |
| 87 | + if (slot_tid != -1) { |
| 88 | + tids.push_back(slot_tid); |
| 89 | + } |
75 | 90 | }
|
76 | 91 | }
|
77 | 92 | }
|
78 | 93 |
|
79 | 94 | void ThreadFilter::init(const char* filter) {
|
80 |
| - if (filter == nullptr) { |
| 95 | + if (!filter) { |
81 | 96 | return;
|
82 | 97 | }
|
83 |
| - // char* end; |
84 |
| - // // todo understand this strange init |
85 |
| - // do { |
86 |
| - // int id = strtol(filter, &end, 0); |
87 |
| - // if (id <= 0) { |
88 |
| - // break; |
89 |
| - // } |
90 |
| - |
91 |
| - // if (*end == '-') { |
92 |
| - // int to = strtol(end + 1, &end, 0); |
93 |
| - // while (id <= to) { |
94 |
| - // add(id++); |
95 |
| - // } |
96 |
| - // } else { |
97 |
| - // add(id); |
98 |
| - // } |
99 |
| - // filter = end + 1; |
100 |
| - // } while (*end); |
| 98 | + // TODO: Implement parsing of filter string if needed |
101 | 99 | _enabled = true;
|
102 | 100 | }
|
103 | 101 |
|
104 | 102 | bool ThreadFilter::enabled() const {
|
105 | 103 | return _enabled;
|
106 | 104 | }
|
107 |
| - |
108 |
| -// Implementation of unregisterThread - releases a slot by its ID |
109 |
| -void ThreadFilter::unregisterThread(SlotID slot_id) { |
110 |
| - if (slot_id >= 0 && slot_id < static_cast<int>(_slots.size())) { |
111 |
| - // Reset this slot to be available again |
112 |
| - _slots[slot_id].value.store(-1, std::memory_order_relaxed); |
113 |
| - } |
114 |
| -} |
0 commit comments