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
diff --git a/cmds/lshal/Lshal.cpp b/cmds/lshal/Lshal.cpp
index ce058c8..6fd9b21 100644
--- a/cmds/lshal/Lshal.cpp
+++ b/cmds/lshal/Lshal.cpp
@@ -469,9 +469,17 @@
     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 001c3d6..ca477bf 100644
--- a/cmds/lshal/Timeout.h
+++ b/cmds/lshal/Timeout.h
@@ -29,7 +29,8 @@
 
 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 @@
         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;
 }