Merge "Disable features that fail in Chromium builds"
diff --git a/include/perfetto/base/time.h b/include/perfetto/base/time.h
index f41f245..d1895c1 100644
--- a/include/perfetto/base/time.h
+++ b/include/perfetto/base/time.h
@@ -46,6 +46,8 @@
   return TimeNanos(ts.tv_sec * 1000000000LL + ts.tv_nsec);
 }
 
+void SleepMicroseconds(unsigned interval_us);
+
 #if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
 
 TimeNanos GetWallTimeNs();
diff --git a/src/base/time.cc b/src/base/time.cc
index c371eb6..8e22d59 100644
--- a/src/base/time.cc
+++ b/src/base/time.cc
@@ -19,10 +19,15 @@
 
 #if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
 #include <Windows.h>
+#else
+#include <unistd.h>
+#endif
 
 namespace perfetto {
 namespace base {
 
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
+
 TimeNanos GetWallTimeNs() {
   LARGE_INTEGER freq;
   ::QueryPerformanceFrequency(&freq);
@@ -44,7 +49,21 @@
   return TimeNanos((kernel_time + user_time) * 100);
 }
 
-}  // namespace base
-}  // namespace perfetto
+void SleepMicroseconds(unsigned interval_us) {
+  // The Windows Sleep function takes a millisecond count. Round up so that
+  // short sleeps don't turn into a busy wait. Note that the sleep granularity
+  // on Windows can dynamically vary from 1 ms to ~16 ms, so don't count on this
+  // being a short sleep.
+  ::Sleep(static_cast<DWORD>((interval_us + 999) / 1000));
+}
+
+#else  // PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
+
+void SleepMicroseconds(unsigned interval_us) {
+  ::usleep(static_cast<useconds_t>(interval_us));
+}
 
 #endif  // PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
+
+}  // namespace base
+}  // namespace perfetto
diff --git a/src/ftrace_reader/cpu_reader.cc b/src/ftrace_reader/cpu_reader.cc
index fa173f3..936cf54 100644
--- a/src/ftrace_reader/cpu_reader.cc
+++ b/src/ftrace_reader/cpu_reader.cc
@@ -173,7 +173,7 @@
 
   worker_thread_ =
       std::thread(std::bind(&RunWorkerThread, cpu_, *trace_fd_,
-                            *staging_write_fd_, on_data_available));
+                            *staging_write_fd_, on_data_available, &exiting_));
 }
 
 CpuReader::~CpuReader() {
@@ -183,17 +183,18 @@
   // trace fd (which prevents another splice from starting), raise SIGPIPE and
   // wait for the worker to exit (i.e., to guarantee no splice is in progress)
   // and only then close the staging pipe.
+  exiting_ = true;
   trace_fd_.reset();
   pthread_kill(worker_thread_.native_handle(), SIGPIPE);
   worker_thread_.join();
 }
 
 // static
-void CpuReader::RunWorkerThread(
-    size_t cpu,
-    int trace_fd,
-    int staging_write_fd,
-    const std::function<void()>& on_data_available) {
+void CpuReader::RunWorkerThread(size_t cpu,
+                                int trace_fd,
+                                int staging_write_fd,
+                                const std::function<void()>& on_data_available,
+                                std::atomic<bool>* exiting) {
 #if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) || \
     PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
   // This thread is responsible for moving data from the trace pipe into the
@@ -220,11 +221,12 @@
       // The kernel ftrace code has its own splice() implementation that can
       // occasionally fail with transient errors not reported in man 2 splice.
       // Just try again if we see these.
-      if (errno == ENOMEM || errno == EBUSY) {
+      if (errno == ENOMEM || errno == EBUSY || (errno == EINTR && !*exiting)) {
         PERFETTO_DPLOG("Transient splice failure -- retrying");
         usleep(100 * 1000);
         continue;
       }
+      PERFETTO_DPLOG("Stopping CPUReader loop for CPU %zd.", cpu);
       PERFETTO_DCHECK(errno == EPIPE || errno == EINTR || errno == EBADF);
       break;  // ~CpuReader is waiting to join this thread.
     }
diff --git a/src/ftrace_reader/cpu_reader.h b/src/ftrace_reader/cpu_reader.h
index 563758c..ce9a014 100644
--- a/src/ftrace_reader/cpu_reader.h
+++ b/src/ftrace_reader/cpu_reader.h
@@ -21,6 +21,7 @@
 #include <string.h>
 
 #include <array>
+#include <atomic>
 #include <memory>
 #include <set>
 #include <thread>
@@ -202,7 +203,8 @@
   static void RunWorkerThread(size_t cpu,
                               int trace_fd,
                               int staging_write_fd,
-                              const std::function<void()>& on_data_available);
+                              const std::function<void()>& on_data_available,
+                              std::atomic<bool>* exiting);
 
   uint8_t* GetBuffer();
   CpuReader(const CpuReader&) = delete;
@@ -215,6 +217,7 @@
   base::ScopedFile staging_write_fd_;
   base::PageAllocator::UniquePtr buffer_;
   std::thread worker_thread_;
+  std::atomic<bool> exiting_{false};
   PERFETTO_THREAD_CHECKER(thread_checker_)
 };
 
diff --git a/src/tracing/core/service_impl.cc b/src/tracing/core/service_impl.cc
index 028c0d4..b67eb56 100644
--- a/src/tracing/core/service_impl.cc
+++ b/src/tracing/core/service_impl.cc
@@ -16,12 +16,17 @@
 
 #include "src/tracing/core/service_impl.h"
 
+#include "perfetto/base/build_config.h"
+
 #include <errno.h>
 #include <inttypes.h>
 #include <limits.h>
 #include <string.h>
+
+#if !PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
 #include <sys/uio.h>
 #include <unistd.h>
+#endif
 
 #include <algorithm>
 
@@ -64,6 +69,33 @@
 // These apply only if enable_extra_guardrails is true.
 constexpr uint64_t kMaxTracingDurationMillis = 24 * kMillisPerHour;
 constexpr uint64_t kMaxTracingBufferSizeKb = 32 * 1024;
+
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
+struct iovec {
+  void  *iov_base; // Address
+  size_t iov_len;  // Block size
+};
+
+// Simple implementation of writev. Note that this does not give the atomicity
+// guarantees of a real writev, but we don't depend on these (we aren't writing
+// to the same file from another thread).
+ssize_t writev(int fd, const struct iovec *iov, int iovcnt) {
+  ssize_t total_size = 0;
+  for (int i = 0; i < iovcnt; ++i) {
+    ssize_t current_size = write(fd, iov[i].iov_base, iov[i].iov_len);
+    if (current_size != static_cast<ssize_t>(iov[i].iov_len))
+      return -1;
+    total_size += current_size;
+  }
+  return total_size;
+}
+
+#define IOV_MAX 1024  // Linux compatible limit.
+
+// uid checking is a NOP on Windows.
+uid_t getuid() { return 0; }
+uid_t geteuid() { return 0; }
+#endif  // PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
 }  // namespace
 
 // These constants instead are defined in the header because are used by tests.
@@ -1009,7 +1041,7 @@
   protos::TrustedPacket packet;
   protos::ClockSnapshot* clock_snapshot = packet.mutable_clock_snapshot();
 
-#if !PERFETTO_BUILDFLAG(PERFETTO_OS_MACOSX)
+#if !PERFETTO_BUILDFLAG(PERFETTO_OS_MACOSX) && !PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
   struct {
     clockid_t id;
     protos::ClockSnapshot::Clock::Type type;
diff --git a/src/tracing/core/shared_memory_abi.cc b/src/tracing/core/shared_memory_abi.cc
index 11ef1a1..c2ac74e 100644
--- a/src/tracing/core/shared_memory_abi.cc
+++ b/src/tracing/core/shared_memory_abi.cc
@@ -15,7 +15,12 @@
  */
 #include "perfetto/tracing/core/shared_memory_abi.h"
 
+#include "perfetto/base/build_config.h"
+#include "perfetto/base/time.h"
+
+#if !PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
 #include <sys/mman.h>
+#endif
 
 #include "perfetto/base/utils.h"
 #include "perfetto/tracing/core/basic_types.h"
@@ -30,7 +35,7 @@
   if (attempt < kRetryAttempts / 2) {
     std::this_thread::yield();
   } else {
-    usleep((useconds_t(attempt) / 10) * 1000);
+    base::SleepMicroseconds((unsigned(attempt) / 10) * 1000);
   }
 }
 
@@ -299,6 +304,7 @@
 void SharedMemoryABI::ReleaseAllChunksAsFree(size_t page_idx) {
   PageHeader* phdr = page_header(page_idx);
   phdr->layout.store(0, std::memory_order_release);
+#if !PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
   uint8_t* page_start = start_ + page_idx * page_size_;
   // TODO(fmayer): On Linux/Android this should be MADV_REMOVE if we use
   // memfd_create() and tmpfs supports hole punching (need to consult kernel
@@ -306,6 +312,7 @@
   int ret = madvise(reinterpret_cast<uint8_t*>(page_start), page_size_,
                     MADV_DONTNEED);
   PERFETTO_DCHECK(ret == 0);
+#endif
 }
 
 SharedMemoryABI::Chunk::Chunk() = default;
diff --git a/src/tracing/core/shared_memory_arbiter_impl.cc b/src/tracing/core/shared_memory_arbiter_impl.cc
index f0960f8..1618b41 100644
--- a/src/tracing/core/shared_memory_arbiter_impl.cc
+++ b/src/tracing/core/shared_memory_arbiter_impl.cc
@@ -18,6 +18,7 @@
 
 #include "perfetto/base/logging.h"
 #include "perfetto/base/task_runner.h"
+#include "perfetto/base/time.h"
 #include "perfetto/tracing/core/commit_data_request.h"
 #include "perfetto/tracing/core/shared_memory.h"
 #include "src/tracing/core/null_trace_writer.h"
@@ -62,8 +63,8 @@
     size_t size_hint) {
   PERFETTO_DCHECK(size_hint == 0);  // Not implemented yet.
   int stall_count = 0;
-  useconds_t stall_interval_us = 0;
-  static const useconds_t kMaxStallIntervalUs = 100000;
+  unsigned stall_interval_us = 0;
+  static const unsigned kMaxStallIntervalUs = 100000;
   static const int kLogAfterNStalls = 3;
 
   for (;;) {
@@ -123,7 +124,7 @@
       // SMB.
       FlushPendingCommitDataRequests();
     }
-    usleep(stall_interval_us);
+    base::SleepMicroseconds(stall_interval_us);
     stall_interval_us =
         std::min(kMaxStallIntervalUs, (stall_interval_us + 1) * 8);
   }
diff --git a/src/tracing/core/trace_buffer.cc b/src/tracing/core/trace_buffer.cc
index 605be74..1e80012 100644
--- a/src/tracing/core/trace_buffer.cc
+++ b/src/tracing/core/trace_buffer.cc
@@ -16,7 +16,6 @@
 
 #include "src/tracing/core/trace_buffer.h"
 
-#include <sys/mman.h>
 #include <limits>
 
 #include "perfetto/base/logging.h"
diff --git a/test/configs/BUILD.gn b/test/configs/BUILD.gn
index 01e149e..1505529 100644
--- a/test/configs/BUILD.gn
+++ b/test/configs/BUILD.gn
@@ -26,6 +26,7 @@
     sources = [
       "atrace.cfg",
       "ftrace.cfg",
+      "ftrace_largebuffer.cfg",
       "long_trace.cfg",
       "processes.cfg",
       "summary.cfg",
diff --git a/test/configs/ftrace_largebuffer.cfg b/test/configs/ftrace_largebuffer.cfg
new file mode 100644
index 0000000..03c212e
--- /dev/null
+++ b/test/configs/ftrace_largebuffer.cfg
@@ -0,0 +1,38 @@
+buffers {
+  size_kb: 16000
+  fill_policy: RING_BUFFER
+}
+
+data_sources {
+  config {
+    name: "linux.ftrace"
+    target_buffer: 0
+    ftrace_config {
+      buffer_size_kb: 2048 # 4 (page size) * 128
+      drain_period_ms: 200
+      ftrace_events: "sched_wakeup"
+      ftrace_events: "sched_wakeup_new"
+      ftrace_events: "sched_switch"
+      ftrace_events: "sched_blocked_reason"
+      ftrace_events: "cpu_idle"
+      ftrace_events: "cpu_frequency"
+      ftrace_events: "cpu_frequency_limits"
+      ftrace_events: "suspend_resume"
+      ftrace_events: "clock_set_rate"
+      ftrace_events: "workqueue_activate_work"
+      ftrace_events: "workqueue_execute_end"
+      ftrace_events: "workqueue_execute_start"
+      ftrace_events: "workqueue_queue_work"
+    }
+  }
+}
+
+producers {
+  producer_name: "perfetto.traced_probes"
+  shm_size_kb: 4096
+  page_size_kb: 4
+}
+
+duration_ms: 7200000
+write_into_file: true
+max_file_size_bytes: 4000000000
diff --git a/tools/trace_to_text/main.cc b/tools/trace_to_text/main.cc
index 5f45af4..a0488c3 100644
--- a/tools/trace_to_text/main.cc
+++ b/tools/trace_to_text/main.cc
@@ -587,15 +587,15 @@
   if (compact_output) {
     sprintf(line, "ftrace duration,%" PRIu64 "\n", ftrace_duration);
   } else {
-    sprintf(line, "Ftrace Duration: %" PRIu64 "ms\n", ftrace_duration);
+    sprintf(line, "Ftrace duration: %" PRIu64 "ms\n", ftrace_duration);
   }
   *output << std::string(line);
 
   uint64_t boottime_duration = (boottime_end - boottime_start) / (1000 * 1000);
   if (compact_output) {
-    sprintf(line, "total duration,%" PRIu64 "\n", boottime_duration);
+    sprintf(line, "boottime duration,%" PRIu64 "\n", boottime_duration);
   } else {
-    sprintf(line, "Total Duration: %" PRIu64 "ms\n", boottime_duration);
+    sprintf(line, "Boottime duration: %" PRIu64 "ms\n", boottime_duration);
   }
   *output << std::string(line);