diff options
| author | 2017-02-21 14:59:00 -0800 | |
|---|---|---|
| committer | 2017-02-21 15:28:41 -0800 | |
| commit | a57dffb151145529e71b22a8d7f985bc1de105f4 (patch) | |
| tree | 73b4a3411b300e0d176d3440673c811efb61cd75 | |
| parent | 52a60e08fb3c636b073a9b6a27672bbd3061e5b8 (diff) | |
lshal: Fix timeout causes unexpected exits.
with thread::detach the background thread keeps running even after
the thread object is destroyed; the background thread will access
caller's stack memory, causing segfault. Change it to a thread join
to avoid the issue. To avoid waiting too long on the child thread,
send a SIGINT if timeout (child thread's signal handler will then
call pthread_exit() to terminate the thread).
Since we are using pthread_* functions, change usage of std::thread
to pthread_t for consistency.
Test: lshal
Test: run lshal with IPC_CALL_TIMEOUT set to zero will no longer
cause SIGSEGV and SIGABRT (test 10 times)
Bug: 35623669
Change-Id: I4eef8ffd8ff399793648e861ca4c1a2bdcc7ec50
| -rw-r--r-- | cmds/lshal/Lshal.cpp | 8 | ||||
| -rw-r--r-- | cmds/lshal/Timeout.h | 32 |
2 files changed, 32 insertions, 8 deletions
diff --git a/cmds/lshal/Lshal.cpp b/cmds/lshal/Lshal.cpp index ce058c8a47..6fd9b21368 100644 --- a/cmds/lshal/Lshal.cpp +++ b/cmds/lshal/Lshal.cpp @@ -469,9 +469,17 @@ int Lshal::main(int argc, char **argv) { return status; } +void signalHandler(int sig) { + if (sig == SIGINT) { + int retVal; + pthread_exit(&retVal); + } +} + } // namespace lshal } // namespace android int main(int argc, char **argv) { + signal(SIGINT, ::android::lshal::signalHandler); return ::android::lshal::Lshal{}.main(argc, argv); } diff --git a/cmds/lshal/Timeout.h b/cmds/lshal/Timeout.h index 001c3d6790..ca477bf615 100644 --- a/cmds/lshal/Timeout.h +++ b/cmds/lshal/Timeout.h @@ -29,7 +29,8 @@ static constexpr std::chrono::milliseconds IPC_CALL_WAIT{500}; class BackgroundTaskState { public: - BackgroundTaskState(){} + BackgroundTaskState(std::function<void(void)> &&func) + : mFunc(std::forward<decltype(func)>(func)) {} void notify() { std::unique_lock<std::mutex> lock(mMutex); mFinished = true; @@ -42,22 +43,37 @@ public: mCondVar.wait_until(lock, end, [this](){ return this->mFinished; }); return mFinished; } + void operator()() { + mFunc(); + } private: std::mutex mMutex; std::condition_variable mCondVar; bool mFinished = false; + std::function<void(void)> mFunc; }; +void *callAndNotify(void *data) { + BackgroundTaskState &state = *static_cast<BackgroundTaskState *>(data); + state(); + state.notify(); + return NULL; +} + template<class R, class P> -bool timeout(std::chrono::duration<R, P> delay, const std::function<void(void)> &func) { +bool timeout(std::chrono::duration<R, P> delay, std::function<void(void)> &&func) { auto now = std::chrono::system_clock::now(); - BackgroundTaskState state{}; - std::thread t([&state, &func] { - func(); - state.notify(); - }); - t.detach(); + BackgroundTaskState state{std::forward<decltype(func)>(func)}; + pthread_t thread; + if (pthread_create(&thread, NULL, callAndNotify, &state)) { + std::cerr << "FATAL: could not create background thread." << std::endl; + return false; + } bool success = state.wait(now + delay); + if (!success) { + pthread_kill(thread, SIGINT); + } + pthread_join(thread, NULL); return success; } |