forked from OSchip/llvm-project
[lldb] [MainLoop] Support "pending callbacks", to be called once
Support adding a "pending callback" to the main loop, that will be called once after all the pending events are processed. This can be e.g. to defer destroying the process instance until its exit is fully processed, as suggested in D127500. Sponsored by: The FreeBSD Foundation Differential Revision: https://reviews.llvm.org/D128253
This commit is contained in:
parent
9f499d9d73
commit
5b04eb23ae
|
@ -14,6 +14,7 @@
|
|||
#include "llvm/ADT/DenseMap.h"
|
||||
#include <csignal>
|
||||
#include <list>
|
||||
#include <vector>
|
||||
|
||||
#if !HAVE_PPOLL && !HAVE_SYS_EVENT_H && !defined(__ANDROID__)
|
||||
#define SIGNAL_POLLING_UNSUPPORTED 1
|
||||
|
@ -59,6 +60,11 @@ public:
|
|||
SignalHandleUP RegisterSignal(int signo, const Callback &callback,
|
||||
Status &error);
|
||||
|
||||
// Add a pending callback that will be executed once after all the pending
|
||||
// events are processed. The callback will be executed even if termination
|
||||
// was requested.
|
||||
void AddPendingCallback(const Callback &callback) override;
|
||||
|
||||
Status Run() override;
|
||||
|
||||
// This should only be performed from a callback. Do not attempt to terminate
|
||||
|
@ -104,6 +110,7 @@ private:
|
|||
|
||||
llvm::DenseMap<IOObject::WaitableHandle, Callback> m_read_fds;
|
||||
llvm::DenseMap<int, SignalInfo> m_signals;
|
||||
std::vector<Callback> m_pending_callbacks;
|
||||
#if HAVE_SYS_EVENT_H
|
||||
int m_kqueue;
|
||||
#endif
|
||||
|
|
|
@ -46,6 +46,13 @@ public:
|
|||
llvm_unreachable("Not implemented");
|
||||
}
|
||||
|
||||
// Add a pending callback that will be executed once after all the pending
|
||||
// events are processed. The callback will be executed even if termination
|
||||
// was requested.
|
||||
virtual void AddPendingCallback(const Callback &callback) {
|
||||
llvm_unreachable("Not implemented");
|
||||
}
|
||||
|
||||
// Waits for registered events and invoke the proper callbacks. Returns when
|
||||
// all callbacks deregister themselves or when someone requests termination.
|
||||
virtual Status Run() { llvm_unreachable("Not implemented"); }
|
||||
|
|
|
@ -347,6 +347,10 @@ MainLoop::RegisterSignal(int signo, const Callback &callback, Status &error) {
|
|||
#endif
|
||||
}
|
||||
|
||||
void MainLoop::AddPendingCallback(const Callback &callback) {
|
||||
m_pending_callbacks.push_back(callback);
|
||||
}
|
||||
|
||||
void MainLoop::UnregisterReadObject(IOObject::WaitableHandle handle) {
|
||||
bool erased = m_read_fds.erase(handle);
|
||||
UNUSED_IF_ASSERT_DISABLED(erased);
|
||||
|
@ -401,6 +405,10 @@ Status MainLoop::Run() {
|
|||
return error;
|
||||
|
||||
impl.ProcessEvents();
|
||||
|
||||
for (const Callback &callback : m_pending_callbacks)
|
||||
callback(*this);
|
||||
m_pending_callbacks.clear();
|
||||
}
|
||||
return Status();
|
||||
}
|
||||
|
|
|
@ -98,6 +98,56 @@ TEST_F(MainLoopTest, TerminatesImmediately) {
|
|||
ASSERT_EQ(1u, callback_count);
|
||||
}
|
||||
|
||||
TEST_F(MainLoopTest, PendingCallback) {
|
||||
char X = 'X';
|
||||
size_t len = sizeof(X);
|
||||
ASSERT_TRUE(socketpair[0]->Write(&X, len).Success());
|
||||
|
||||
MainLoop loop;
|
||||
Status error;
|
||||
auto handle = loop.RegisterReadObject(
|
||||
socketpair[1],
|
||||
[&](MainLoopBase &loop) {
|
||||
// Both callbacks should be called before the loop terminates.
|
||||
loop.AddPendingCallback(make_callback());
|
||||
loop.AddPendingCallback(make_callback());
|
||||
loop.RequestTermination();
|
||||
},
|
||||
error);
|
||||
ASSERT_TRUE(error.Success());
|
||||
ASSERT_TRUE(handle);
|
||||
ASSERT_TRUE(loop.Run().Success());
|
||||
ASSERT_EQ(2u, callback_count);
|
||||
}
|
||||
|
||||
TEST_F(MainLoopTest, PendingCallbackCalledOnlyOnce) {
|
||||
char X = 'X';
|
||||
size_t len = sizeof(X);
|
||||
ASSERT_TRUE(socketpair[0]->Write(&X, len).Success());
|
||||
|
||||
MainLoop loop;
|
||||
Status error;
|
||||
auto handle = loop.RegisterReadObject(
|
||||
socketpair[1],
|
||||
[&](MainLoopBase &loop) {
|
||||
// Add one pending callback on the first iteration.
|
||||
if (callback_count == 0) {
|
||||
loop.AddPendingCallback([&](MainLoopBase &loop) {
|
||||
callback_count++;
|
||||
});
|
||||
}
|
||||
// Terminate the loop on second iteration.
|
||||
if (callback_count++ >= 1)
|
||||
loop.RequestTermination();
|
||||
},
|
||||
error);
|
||||
ASSERT_TRUE(error.Success());
|
||||
ASSERT_TRUE(handle);
|
||||
ASSERT_TRUE(loop.Run().Success());
|
||||
// 2 iterations of read callback + 1 call of pending callback.
|
||||
ASSERT_EQ(3u, callback_count);
|
||||
}
|
||||
|
||||
#ifdef LLVM_ON_UNIX
|
||||
TEST_F(MainLoopTest, DetectsEOF) {
|
||||
|
||||
|
|
Loading…
Reference in New Issue