rtc::Event::Wait(kForever): Print stack trace when we deadlock

After being stuck "forever" (3 seconds) waiting for an event to
trigger, log the stack trace of the current thread to aid debugging of
the deadlock.

Bug: webrtc:10308
Change-Id: I04852f191027294d7e7a7f5e63de4c6c7fdd6326
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/128342
Commit-Queue: Karl Wiberg <kwiberg@webrtc.org>
Reviewed-by: Magnus Jedvert <magjed@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#27263}
diff --git a/rtc_base/event.cc b/rtc_base/event.cc
index 71dca49..4b8e9ff 100644
--- a/rtc_base/event.cc
+++ b/rtc_base/event.cc
@@ -13,6 +13,7 @@
 #if defined(WEBRTC_WIN)
 #include <windows.h>
 #elif defined(WEBRTC_POSIX)
+#include <errno.h>
 #include <pthread.h>
 #include <sys/time.h>
 #include <time.h>
@@ -22,6 +23,7 @@
 
 #include "rtc_base/checks.h"
 #include "rtc_base/synchronization/yield_policy.h"
+#include "rtc_base/system/warn_current_thread_is_deadlocked.h"
 
 namespace rtc {
 
@@ -103,45 +105,65 @@
   pthread_mutex_unlock(&event_mutex_);
 }
 
-bool Event::Wait(int milliseconds) {
-  ScopedYieldPolicy::YieldExecution();
+namespace {
 
-  int error = 0;
+timespec GetTimespec(const int milliseconds_from_now) {
+  timespec ts;
 
-  struct timespec ts;
-  if (milliseconds != kForever) {
+  // Get the current time.
 #if USE_CLOCK_GETTIME
-    clock_gettime(CLOCK_MONOTONIC, &ts);
+  clock_gettime(CLOCK_MONOTONIC, &ts);
 #else
-    struct timeval tv;
-    gettimeofday(&tv, nullptr);
-    ts.tv_sec = tv.tv_sec;
-    ts.tv_nsec = tv.tv_usec * 1000;
+  timeval tv;
+  gettimeofday(&tv, nullptr);
+  ts.tv_sec = tv.tv_sec;
+  ts.tv_nsec = tv.tv_usec * 1000;
 #endif
 
-    ts.tv_sec += (milliseconds / 1000);
-    ts.tv_nsec += (milliseconds % 1000) * 1000000;
+  // Add the specified number of milliseconds to it.
+  ts.tv_sec += (milliseconds_from_now / 1000);
+  ts.tv_nsec += (milliseconds_from_now % 1000) * 1000000;
 
-    // Handle overflow.
-    if (ts.tv_nsec >= 1000000000) {
-      ts.tv_sec++;
-      ts.tv_nsec -= 1000000000;
-    }
+  // Normalize.
+  if (ts.tv_nsec >= 1000000000) {
+    ts.tv_sec++;
+    ts.tv_nsec -= 1000000000;
   }
 
+  return ts;
+}
+
+}  // namespace
+
+bool Event::Wait(const int milliseconds) {
+  // Set a timeout for the given number of milliseconds, or 3000 ms if the
+  // caller asked for kForever.
+  const timespec ts =
+      GetTimespec(milliseconds == kForever ? 3000 : milliseconds);
+
+  ScopedYieldPolicy::YieldExecution();
   pthread_mutex_lock(&event_mutex_);
-  if (milliseconds != kForever) {
-    while (!event_status_ && error == 0) {
+
+  // Wait for the event to trigger or the timeout to expire, whichever comes
+  // first.
+  int error = 0;
+  while (!event_status_ && error == 0) {
 #if USE_PTHREAD_COND_TIMEDWAIT_MONOTONIC_NP
-      error =
-          pthread_cond_timedwait_monotonic_np(&event_cond_, &event_mutex_, &ts);
+    error =
+        pthread_cond_timedwait_monotonic_np(&event_cond_, &event_mutex_, &ts);
 #else
-      error = pthread_cond_timedwait(&event_cond_, &event_mutex_, &ts);
+    error = pthread_cond_timedwait(&event_cond_, &event_mutex_, &ts);
 #endif
-    }
-  } else {
-    while (!event_status_ && error == 0)
+  }
+
+  if (milliseconds == kForever && error == ETIMEDOUT) {
+    // Our 3000 ms timeout expired, but the caller asked us to wait forever, so
+    // do that.
+    webrtc::WarnThatTheCurrentThreadIsProbablyDeadlocked();
+    error = 0;
+    while (!event_status_ && error == 0) {
       error = pthread_cond_wait(&event_cond_, &event_mutex_);
+    }
   }
 
   // NOTE(liulk): Exactly one thread will auto-reset this event. All