mirror of
https://github.com/intel/llvm.git
synced 2026-01-13 19:08:21 +08:00
Make LLDB skip server-client roundtrip for signals that don't require any actions
If QPassSignals packaet is supported by lldb-server, lldb-client will utilize it and ask the server to ignore signals that don't require stops or notifications. Such signals will be immediately re-injected into inferior to continue normal execution. Differential Revision: https://reviews.llvm.org/D30520 llvm-svn: 297231
This commit is contained in:
@@ -2607,7 +2607,7 @@ public:
|
||||
bool RunPreResumeActions();
|
||||
|
||||
void ClearPreResumeActions();
|
||||
|
||||
|
||||
void ClearPreResumeAction(PreResumeActionCallback callback, void *baton);
|
||||
|
||||
ProcessRunLock &GetRunLock();
|
||||
@@ -3145,6 +3145,8 @@ protected:
|
||||
|
||||
Error StopForDestroyOrDetach(lldb::EventSP &exit_event_sp);
|
||||
|
||||
virtual Error UpdateAutomaticSignalFiltering();
|
||||
|
||||
bool StateChangedIsExternallyHijacked();
|
||||
|
||||
void LoadOperatingSystemPlugin(bool flush);
|
||||
|
||||
@@ -14,11 +14,13 @@
|
||||
// C++ Includes
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
// Other libraries and framework includes
|
||||
// Project includes
|
||||
#include "lldb/Utility/ConstString.h"
|
||||
#include "lldb/lldb-private.h"
|
||||
#include "llvm/ADT/Optional.h"
|
||||
|
||||
namespace lldb_private {
|
||||
|
||||
@@ -88,6 +90,19 @@ public:
|
||||
|
||||
void RemoveSignal(int signo);
|
||||
|
||||
// Returns a current version of the data stored in this class.
|
||||
// Version gets incremented each time Set... method is called.
|
||||
uint64_t GetVersion() const;
|
||||
|
||||
// Returns a vector of signals that meet criteria provided in arguments.
|
||||
// Each should_[suppress|stop|notify] flag can be
|
||||
// None - no filtering by this flag
|
||||
// true - only signals that have it set to true are returned
|
||||
// false - only signals that have it set to true are returned
|
||||
std::vector<int32_t> GetFilteredSignals(llvm::Optional<bool> should_suppress,
|
||||
llvm::Optional<bool> should_stop,
|
||||
llvm::Optional<bool> should_notify);
|
||||
|
||||
protected:
|
||||
//------------------------------------------------------------------
|
||||
// Classes that inherit from UnixSignals can see and modify these
|
||||
@@ -111,6 +126,12 @@ protected:
|
||||
|
||||
collection m_signals;
|
||||
|
||||
// This version gets incremented every time something is changing in
|
||||
// this class, including when we call AddSignal from the constructor.
|
||||
// So after the object is constructed m_version is going to be > 0
|
||||
// if it has at least one signal registered in it.
|
||||
uint64_t m_version = 0;
|
||||
|
||||
// GDBRemote signals need to be copyable.
|
||||
UnixSignals(const UnixSignals &rhs);
|
||||
|
||||
|
||||
@@ -87,6 +87,7 @@ GDBRemoteCommunicationClient::GDBRemoteCommunicationClient()
|
||||
m_supports_jThreadExtendedInfo(eLazyBoolCalculate),
|
||||
m_supports_jLoadedDynamicLibrariesInfos(eLazyBoolCalculate),
|
||||
m_supports_jGetSharedCacheInfo(eLazyBoolCalculate),
|
||||
m_supports_QPassSignals(eLazyBoolCalculate),
|
||||
m_supports_qProcessInfoPID(true), m_supports_qfProcessInfo(true),
|
||||
m_supports_qUserName(true), m_supports_qGroupName(true),
|
||||
m_supports_qThreadStopInfo(true), m_supports_z0(true),
|
||||
@@ -150,6 +151,13 @@ bool GDBRemoteCommunicationClient::GetEchoSupported() {
|
||||
return m_supports_qEcho == eLazyBoolYes;
|
||||
}
|
||||
|
||||
bool GDBRemoteCommunicationClient::GetQPassSignalsSupported() {
|
||||
if (m_supports_QPassSignals == eLazyBoolCalculate) {
|
||||
GetRemoteQSupported();
|
||||
}
|
||||
return m_supports_QPassSignals == eLazyBoolYes;
|
||||
}
|
||||
|
||||
bool GDBRemoteCommunicationClient::GetAugmentedLibrariesSVR4ReadSupported() {
|
||||
if (m_supports_augmented_libraries_svr4_read == eLazyBoolCalculate) {
|
||||
GetRemoteQSupported();
|
||||
@@ -419,6 +427,11 @@ void GDBRemoteCommunicationClient::GetRemoteQSupported() {
|
||||
else
|
||||
m_supports_qEcho = eLazyBoolNo;
|
||||
|
||||
if (::strstr(response_cstr, "QPassSignals+"))
|
||||
m_supports_QPassSignals = eLazyBoolYes;
|
||||
else
|
||||
m_supports_QPassSignals = eLazyBoolNo;
|
||||
|
||||
const char *packet_size_str = ::strstr(response_cstr, "PacketSize=");
|
||||
if (packet_size_str) {
|
||||
StringExtractorGDBRemote packet_response(packet_size_str +
|
||||
@@ -3570,6 +3583,26 @@ GDBRemoteCommunicationClient::GetSupportedStructuredDataPlugins() {
|
||||
: nullptr;
|
||||
}
|
||||
|
||||
Error GDBRemoteCommunicationClient::SendSignalsToIgnore(
|
||||
llvm::ArrayRef<int32_t> signals) {
|
||||
// Format packet:
|
||||
// QPassSignals:<hex_sig1>;<hex_sig2>...;<hex_sigN>
|
||||
auto range = llvm::make_range(signals.begin(), signals.end());
|
||||
std::string packet = formatv("QPassSignals:{0:$[;]@(x-2)}", range).str();
|
||||
|
||||
StringExtractorGDBRemote response;
|
||||
auto send_status = SendPacketAndWaitForResponse(packet, response, false);
|
||||
|
||||
if (send_status != GDBRemoteCommunication::PacketResult::Success)
|
||||
return Error("Sending QPassSignals packet failed");
|
||||
|
||||
if (response.IsOKResponse()) {
|
||||
return Error();
|
||||
} else {
|
||||
return Error("Unknown error happened during sending QPassSignals packet.");
|
||||
}
|
||||
}
|
||||
|
||||
Error GDBRemoteCommunicationClient::ConfigureRemoteStructuredData(
|
||||
const ConstString &type_name, const StructuredData::ObjectSP &config_sp) {
|
||||
Error error;
|
||||
|
||||
@@ -347,6 +347,8 @@ public:
|
||||
|
||||
bool GetEchoSupported();
|
||||
|
||||
bool GetQPassSignalsSupported();
|
||||
|
||||
bool GetAugmentedLibrariesSVR4ReadSupported();
|
||||
|
||||
bool GetQXferFeaturesReadSupported();
|
||||
@@ -450,6 +452,9 @@ public:
|
||||
|
||||
void ServeSymbolLookups(lldb_private::Process *process);
|
||||
|
||||
// Sends QPassSignals packet to the server with given signals to ignore.
|
||||
Error SendSignalsToIgnore(llvm::ArrayRef<int32_t> signals);
|
||||
|
||||
//------------------------------------------------------------------
|
||||
/// Return the feature set supported by the gdb-remote server.
|
||||
///
|
||||
@@ -527,6 +532,7 @@ protected:
|
||||
LazyBool m_supports_jThreadExtendedInfo;
|
||||
LazyBool m_supports_jLoadedDynamicLibrariesInfos;
|
||||
LazyBool m_supports_jGetSharedCacheInfo;
|
||||
LazyBool m_supports_QPassSignals;
|
||||
|
||||
bool m_supports_qProcessInfoPID : 1, m_supports_qfProcessInfo : 1,
|
||||
m_supports_qUserName : 1, m_supports_qGroupName : 1,
|
||||
|
||||
@@ -80,8 +80,8 @@
|
||||
#include "lldb/Host/Host.h"
|
||||
|
||||
#include "llvm/ADT/StringSwitch.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include "llvm/Support/Threading.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
|
||||
#define DEBUGSERVER_BASENAME "debugserver"
|
||||
using namespace lldb;
|
||||
@@ -3739,6 +3739,43 @@ bool ProcessGDBRemote::NewThreadNotifyBreakpointHit(
|
||||
return false;
|
||||
}
|
||||
|
||||
Error ProcessGDBRemote::UpdateAutomaticSignalFiltering() {
|
||||
Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS));
|
||||
LLDB_LOG(log, "Check if need to update ignored signals");
|
||||
|
||||
// QPassSignals package is not supported by the server,
|
||||
// there is no way we can ignore any signals on server side.
|
||||
if (!m_gdb_comm.GetQPassSignalsSupported())
|
||||
return Error();
|
||||
|
||||
// No signals, nothing to send.
|
||||
if (m_unix_signals_sp == nullptr)
|
||||
return Error();
|
||||
|
||||
// Signals' version hasn't changed, no need to send anything.
|
||||
uint64_t new_signals_version = m_unix_signals_sp->GetVersion();
|
||||
if (new_signals_version == m_last_signals_version) {
|
||||
LLDB_LOG(log, "Signals' version hasn't changed. version={0}",
|
||||
m_last_signals_version);
|
||||
return Error();
|
||||
}
|
||||
|
||||
auto signals_to_ignore =
|
||||
m_unix_signals_sp->GetFilteredSignals(false, false, false);
|
||||
Error error = m_gdb_comm.SendSignalsToIgnore(signals_to_ignore);
|
||||
|
||||
LLDB_LOG(log,
|
||||
"Signals' version changed. old version={0}, new version={1}, "
|
||||
"signals ignored={2}, update result={3}",
|
||||
m_last_signals_version, new_signals_version,
|
||||
signals_to_ignore.size(), error);
|
||||
|
||||
if (error.Success())
|
||||
m_last_signals_version = new_signals_version;
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
bool ProcessGDBRemote::StartNoticingNewThreads() {
|
||||
Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP));
|
||||
if (m_thread_create_bp_sp) {
|
||||
|
||||
@@ -397,12 +397,15 @@ protected:
|
||||
lldb::addr_t base_addr,
|
||||
bool value_is_offset);
|
||||
|
||||
Error UpdateAutomaticSignalFiltering() override;
|
||||
|
||||
private:
|
||||
//------------------------------------------------------------------
|
||||
// For ProcessGDBRemote only
|
||||
//------------------------------------------------------------------
|
||||
std::string m_partial_profile_data;
|
||||
std::map<uint64_t, uint32_t> m_thread_id_to_used_usec_map;
|
||||
uint64_t m_last_signals_version = 0;
|
||||
|
||||
static bool NewThreadNotifyBreakpointHit(void *baton,
|
||||
StoppointCallbackContext *context,
|
||||
|
||||
@@ -2778,6 +2778,10 @@ Error Process::Launch(ProcessLaunchInfo &launch_info) {
|
||||
if (!m_os_ap)
|
||||
LoadOperatingSystemPlugin(false);
|
||||
|
||||
// We successfully launched the process and stopped,
|
||||
// now it the right time to set up signal filters before resuming.
|
||||
UpdateAutomaticSignalFiltering();
|
||||
|
||||
// Note, the stop event was consumed above, but not handled. This
|
||||
// was done
|
||||
// to give DidLaunch a chance to run. The target is either stopped
|
||||
@@ -3257,6 +3261,10 @@ Error Process::PrivateResume() {
|
||||
m_mod_id.GetStopID(), StateAsCString(m_public_state.GetValue()),
|
||||
StateAsCString(m_private_state.GetValue()));
|
||||
|
||||
// If signals handing status changed we might want to update
|
||||
// our signal filters before resuming.
|
||||
UpdateAutomaticSignalFiltering();
|
||||
|
||||
Error error(WillResume());
|
||||
// Tell the process it is about to resume before the thread list
|
||||
if (error.Success()) {
|
||||
@@ -6219,3 +6227,9 @@ bool Process::RouteAsyncStructuredData(
|
||||
find_it->second->HandleArrivalOfStructuredData(*this, type_name, object_sp);
|
||||
return true;
|
||||
}
|
||||
|
||||
Error Process::UpdateAutomaticSignalFiltering() {
|
||||
// Default implementation does nothign.
|
||||
// No automatic signal filtering to speak of.
|
||||
return Error();
|
||||
}
|
||||
|
||||
@@ -123,12 +123,14 @@ void UnixSignals::AddSignal(int signo, const char *name, bool default_suppress,
|
||||
Signal new_signal(name, default_suppress, default_stop, default_notify,
|
||||
description, alias);
|
||||
m_signals.insert(std::make_pair(signo, new_signal));
|
||||
++m_version;
|
||||
}
|
||||
|
||||
void UnixSignals::RemoveSignal(int signo) {
|
||||
collection::iterator pos = m_signals.find(signo);
|
||||
if (pos != m_signals.end())
|
||||
m_signals.erase(pos);
|
||||
++m_version;
|
||||
}
|
||||
|
||||
const char *UnixSignals::GetSignalAsCString(int signo) const {
|
||||
@@ -217,6 +219,7 @@ bool UnixSignals::SetShouldSuppress(int signo, bool value) {
|
||||
collection::iterator pos = m_signals.find(signo);
|
||||
if (pos != m_signals.end()) {
|
||||
pos->second.m_suppress = value;
|
||||
++m_version;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@@ -240,6 +243,7 @@ bool UnixSignals::SetShouldStop(int signo, bool value) {
|
||||
collection::iterator pos = m_signals.find(signo);
|
||||
if (pos != m_signals.end()) {
|
||||
pos->second.m_stop = value;
|
||||
++m_version;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@@ -263,6 +267,7 @@ bool UnixSignals::SetShouldNotify(int signo, bool value) {
|
||||
collection::iterator pos = m_signals.find(signo);
|
||||
if (pos != m_signals.end()) {
|
||||
pos->second.m_notify = value;
|
||||
++m_version;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@@ -284,3 +289,37 @@ int32_t UnixSignals::GetSignalAtIndex(int32_t index) const {
|
||||
std::advance(it, index);
|
||||
return it->first;
|
||||
}
|
||||
|
||||
uint64_t UnixSignals::GetVersion() const { return m_version; }
|
||||
|
||||
std::vector<int32_t>
|
||||
UnixSignals::GetFilteredSignals(llvm::Optional<bool> should_suppress,
|
||||
llvm::Optional<bool> should_stop,
|
||||
llvm::Optional<bool> should_notify) {
|
||||
std::vector<int32_t> result;
|
||||
for (int32_t signo = GetFirstSignalNumber();
|
||||
signo != LLDB_INVALID_SIGNAL_NUMBER;
|
||||
signo = GetNextSignalNumber(signo)) {
|
||||
|
||||
bool signal_suppress = false;
|
||||
bool signal_stop = false;
|
||||
bool signal_notify = false;
|
||||
GetSignalInfo(signo, signal_suppress, signal_stop, signal_notify);
|
||||
|
||||
// If any of filtering conditions are not met,
|
||||
// we move on to the next signal.
|
||||
if (should_suppress.hasValue() &&
|
||||
signal_suppress != should_suppress.getValue())
|
||||
continue;
|
||||
|
||||
if (should_stop.hasValue() && signal_stop != should_stop.getValue())
|
||||
continue;
|
||||
|
||||
if (should_notify.hasValue() && signal_notify != should_notify.getValue())
|
||||
continue;
|
||||
|
||||
result.push_back(signo);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -63,6 +63,7 @@ add_subdirectory(ObjectFile)
|
||||
add_subdirectory(Platform)
|
||||
add_subdirectory(Process)
|
||||
add_subdirectory(ScriptInterpreter)
|
||||
add_subdirectory(Signals)
|
||||
add_subdirectory(Symbol)
|
||||
add_subdirectory(SymbolFile)
|
||||
add_subdirectory(Target)
|
||||
|
||||
@@ -307,3 +307,27 @@ TEST_F(GDBRemoteCommunicationClientTest, TestPacketSpeedJSON) {
|
||||
<< ss.GetString();
|
||||
ASSERT_EQ(10, num_packets);
|
||||
}
|
||||
|
||||
TEST_F(GDBRemoteCommunicationClientTest, SendSignalsToIgnore) {
|
||||
TestClient client;
|
||||
MockServer server;
|
||||
Connect(client, server);
|
||||
if (HasFailure())
|
||||
return;
|
||||
|
||||
const lldb::tid_t tid = 0x47;
|
||||
const uint32_t reg_num = 4;
|
||||
std::future<Error> result = std::async(std::launch::async, [&] {
|
||||
return client.SendSignalsToIgnore({2, 3, 5, 7, 0xB, 0xD, 0x11});
|
||||
});
|
||||
|
||||
HandlePacket(server, "QPassSignals:02;03;05;07;0b;0d;11", "OK");
|
||||
EXPECT_TRUE(result.get().Success());
|
||||
|
||||
result = std::async(std::launch::async, [&] {
|
||||
return client.SendSignalsToIgnore(std::vector<int32_t>());
|
||||
});
|
||||
|
||||
HandlePacket(server, "QPassSignals:", "OK");
|
||||
EXPECT_TRUE(result.get().Success());
|
||||
}
|
||||
|
||||
6
lldb/unittests/Signals/CMakeLists.txt
Normal file
6
lldb/unittests/Signals/CMakeLists.txt
Normal file
@@ -0,0 +1,6 @@
|
||||
add_lldb_unittest(SignalsTests
|
||||
UnixSignalsTest.cpp
|
||||
|
||||
LINK_LIBS
|
||||
lldbTarget
|
||||
)
|
||||
140
lldb/unittests/Signals/UnixSignalsTest.cpp
Normal file
140
lldb/unittests/Signals/UnixSignalsTest.cpp
Normal file
@@ -0,0 +1,140 @@
|
||||
//===-- UnixSignalsTest.cpp -------------------------------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
#include <string>
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
#include "lldb/Target/UnixSignals.h"
|
||||
#include "llvm/Support/FormatVariadic.h"
|
||||
|
||||
using namespace lldb;
|
||||
using namespace lldb_private;
|
||||
using llvm::None;
|
||||
|
||||
class TestSignals : public UnixSignals {
|
||||
public:
|
||||
TestSignals() {
|
||||
m_signals.clear();
|
||||
AddSignal(2, "SIG2", false, true, true, "DESC2");
|
||||
AddSignal(4, "SIG4", true, false, true, "DESC4");
|
||||
AddSignal(8, "SIG8", true, true, true, "DESC8");
|
||||
AddSignal(16, "SIG16", true, false, false, "DESC16");
|
||||
}
|
||||
};
|
||||
|
||||
void ExpectEqArrays(llvm::ArrayRef<int32_t> expected,
|
||||
llvm::ArrayRef<int32_t> observed, const char *file,
|
||||
int line) {
|
||||
std::string location = llvm::formatv("{0}:{1}", file, line);
|
||||
ASSERT_EQ(expected.size(), observed.size()) << location;
|
||||
|
||||
for (size_t i = 0; i < observed.size(); ++i) {
|
||||
ASSERT_EQ(expected[i], observed[i])
|
||||
<< "array index: " << i << "location:" << location;
|
||||
}
|
||||
}
|
||||
|
||||
#define EXPECT_EQ_ARRAYS(expected, observed) \
|
||||
ExpectEqArrays((expected), (observed), __FILE__, __LINE__);
|
||||
|
||||
TEST(UnixSignalsTest, Iteration) {
|
||||
TestSignals signals;
|
||||
|
||||
EXPECT_EQ(4, signals.GetNumSignals());
|
||||
EXPECT_EQ(2, signals.GetFirstSignalNumber());
|
||||
EXPECT_EQ(4, signals.GetNextSignalNumber(2));
|
||||
EXPECT_EQ(8, signals.GetNextSignalNumber(4));
|
||||
EXPECT_EQ(16, signals.GetNextSignalNumber(8));
|
||||
EXPECT_EQ(LLDB_INVALID_SIGNAL_NUMBER, signals.GetNextSignalNumber(16));
|
||||
}
|
||||
|
||||
TEST(UnixSignalsTest, GetInfo) {
|
||||
TestSignals signals;
|
||||
|
||||
bool should_suppress = false, should_stop = false, should_notify = false;
|
||||
int32_t signo = 4;
|
||||
std::string name =
|
||||
signals.GetSignalInfo(signo, should_suppress, should_stop, should_notify);
|
||||
EXPECT_EQ("SIG4", name);
|
||||
EXPECT_EQ(true, should_suppress);
|
||||
EXPECT_EQ(false, should_stop);
|
||||
EXPECT_EQ(true, should_notify);
|
||||
|
||||
EXPECT_EQ(true, signals.GetShouldSuppress(signo));
|
||||
EXPECT_EQ(false, signals.GetShouldStop(signo));
|
||||
EXPECT_EQ(true, signals.GetShouldNotify(signo));
|
||||
EXPECT_EQ(name, signals.GetSignalAsCString(signo));
|
||||
}
|
||||
|
||||
TEST(UnixSignalsTest, VersionChange) {
|
||||
TestSignals signals;
|
||||
|
||||
int32_t signo = 8;
|
||||
uint64_t ver = signals.GetVersion();
|
||||
EXPECT_GT(ver, 0ull);
|
||||
EXPECT_EQ(true, signals.GetShouldSuppress(signo));
|
||||
EXPECT_EQ(true, signals.GetShouldStop(signo));
|
||||
EXPECT_EQ(true, signals.GetShouldNotify(signo));
|
||||
|
||||
EXPECT_EQ(signals.GetVersion(), ver);
|
||||
|
||||
signals.SetShouldSuppress(signo, false);
|
||||
EXPECT_LT(ver, signals.GetVersion());
|
||||
ver = signals.GetVersion();
|
||||
|
||||
signals.SetShouldStop(signo, true);
|
||||
EXPECT_LT(ver, signals.GetVersion());
|
||||
ver = signals.GetVersion();
|
||||
|
||||
signals.SetShouldNotify(signo, false);
|
||||
EXPECT_LT(ver, signals.GetVersion());
|
||||
ver = signals.GetVersion();
|
||||
|
||||
EXPECT_EQ(false, signals.GetShouldSuppress(signo));
|
||||
EXPECT_EQ(true, signals.GetShouldStop(signo));
|
||||
EXPECT_EQ(false, signals.GetShouldNotify(signo));
|
||||
|
||||
EXPECT_EQ(ver, signals.GetVersion());
|
||||
}
|
||||
|
||||
TEST(UnixSignalsTest, GetFilteredSignals) {
|
||||
TestSignals signals;
|
||||
|
||||
auto all_signals = signals.GetFilteredSignals(None, None, None);
|
||||
std::vector<int32_t> expected = {2, 4, 8, 16};
|
||||
EXPECT_EQ_ARRAYS(expected, all_signals);
|
||||
|
||||
auto supressed = signals.GetFilteredSignals(true, None, None);
|
||||
expected = {4, 8, 16};
|
||||
EXPECT_EQ_ARRAYS(expected, supressed);
|
||||
|
||||
auto not_supressed = signals.GetFilteredSignals(false, None, None);
|
||||
expected = {2};
|
||||
EXPECT_EQ_ARRAYS(expected, not_supressed);
|
||||
|
||||
auto stopped = signals.GetFilteredSignals(None, true, None);
|
||||
expected = {2, 8};
|
||||
EXPECT_EQ_ARRAYS(expected, stopped);
|
||||
|
||||
auto not_stopped = signals.GetFilteredSignals(None, false, None);
|
||||
expected = {4, 16};
|
||||
EXPECT_EQ_ARRAYS(expected, not_stopped);
|
||||
|
||||
auto notified = signals.GetFilteredSignals(None, None, true);
|
||||
expected = {2, 4, 8};
|
||||
EXPECT_EQ_ARRAYS(expected, notified);
|
||||
|
||||
auto not_notified = signals.GetFilteredSignals(None, None, false);
|
||||
expected = {16};
|
||||
EXPECT_EQ_ARRAYS(expected, not_notified);
|
||||
|
||||
auto signal4 = signals.GetFilteredSignals(true, false, true);
|
||||
expected = {4};
|
||||
EXPECT_EQ_ARRAYS(expected, signal4);
|
||||
}
|
||||
Reference in New Issue
Block a user