Exercise both native owners throughout concurrent radio rebinding
This commit is contained in:
1 parent
6063d3eb2c
commit
d9abb1f025
1 file changed
+28
-8
@@ -53,7 +53,12 @@ extern "C" void __wrap_u_free_impl(void* pointer, const char* source) {
|
||||
extern "C" void __real_radio_call_trampoline(void*);
|
||||
extern "C" void __wrap_radio_call_trampoline(void* arg) {
|
||||
auto* request = static_cast<radio_call_request*>(arg);
|
||||
bindingValid &= request->inst == executingCore; observed.append(*request);
|
||||
if (request->inst != executingCore) {
|
||||
bindingValid = false;
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_RADIO, "Radio command binding mismatch id=%llu request_inst=%p executing_core=%p",
|
||||
(unsigned long long)request->id, static_cast<void*>(request->inst), static_cast<void*>(executingCore));
|
||||
}
|
||||
observed.append(*request);
|
||||
__real_radio_call_trampoline(arg);
|
||||
}
|
||||
// Настоящий mixer остаётся включённым; null backend устраняет зависимость от аппаратных устройств.
|
||||
@@ -199,18 +204,33 @@ private slots:
|
||||
#ifdef UTUN_TEST_RADIO_HOOKS
|
||||
watching = true;
|
||||
#endif
|
||||
std::thread producer([] {
|
||||
for (uint64_t id = 1; id <= 96; ++id) gui_bridge_radio_call(GUI_RADIO_CALL_CANCEL, id, 0, 0);
|
||||
std::atomic<unsigned> turn{0}, submitted{0};
|
||||
std::thread producer([&] {
|
||||
for (unsigned id = 1; id <= 96; ++id) {
|
||||
while (turn < id) std::this_thread::yield();
|
||||
gui_bridge_radio_call(GUI_RADIO_CALL_CANCEL, id, 0, 0); submitted = id;
|
||||
}
|
||||
});
|
||||
for (unsigned i = 0; i < 64; ++i) {
|
||||
gui_bridge_set_inst(nullptr); auto& core = i % 2 ? first : second; core.attach(); core.poll();
|
||||
bool controlsAccepted = true;
|
||||
for (unsigned i = 1; i <= 96; ++i) {
|
||||
turn = i;
|
||||
gui_bridge_set_inst(nullptr); auto& core = i % 2 ? first : second; core.attach();
|
||||
while (submitted < i) std::this_thread::yield();
|
||||
first.poll(); second.poll();
|
||||
// Контроль исполняется у каждого владельца даже при отклонении/отмене конкурирующей команды.
|
||||
controlsAccepted &= gui_bridge_radio_call(GUI_RADIO_CALL_CANCEL, 1000 + i, 0, 0) == 0; core.poll();
|
||||
}
|
||||
producer.join(); gui_bridge_set_inst(nullptr); first.attach();
|
||||
QCOMPARE(gui_bridge_radio_call(GUI_RADIO_CALL_START, 1000, 7654321, 42), 0); first.poll();
|
||||
QVERIFY(bindingValid); QCOMPARE(pending(first.ua), 0u); QCOMPARE(pending(second.ua), 0u);
|
||||
QCOMPARE(gui_bridge_radio_call(GUI_RADIO_CALL_START, 2000, 7654321, 42), 0); first.poll();
|
||||
QVERIFY(controlsAccepted); QVERIFY(bindingValid); QCOMPARE(pending(first.ua), 0u); QCOMPARE(pending(second.ua), 0u);
|
||||
QCOMPARE(first.results, 1u); QCOMPARE(second.results, 0u); QVERIFY(first.resultValid);
|
||||
#ifdef UTUN_TEST_RADIO_HOOKS
|
||||
QVERIFY(!observed.isEmpty()); QCOMPARE(observed.back().inst, first.inst); QCOMPARE(observed.back().id, uint64_t(1000));
|
||||
size_t firstCount = 0, secondCount = 0;
|
||||
for (const auto& request : observed) { firstCount += request.inst == first.inst; secondCount += request.inst == second.inst; }
|
||||
QVERIFY(firstCount >= 49); QVERIFY(secondCount >= 48);
|
||||
QCOMPARE(observed.back().inst, first.inst); QCOMPARE(observed.back().id, uint64_t(2000));
|
||||
DEBUG_INFO(DEBUG_CATEGORY_RADIO, "Radio binding verified: first_executed=%zu second_executed=%zu binding_valid=%d",
|
||||
firstCount, secondCount, bindingValid);
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
Reference in new issue
Block a user