gator: Version 5.20

Signed-off-by: Jon Medhurst <tixy@linaro.org>
diff --git a/tools/gator/daemon/FtraceSource.cpp b/tools/gator/daemon/FtraceSource.cpp
new file mode 100644
index 0000000..5216333
--- /dev/null
+++ b/tools/gator/daemon/FtraceSource.cpp
@@ -0,0 +1,158 @@
+/**
+ * Copyright (C) ARM Limited 2010-2014. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include "FtraceSource.h"
+
+#include <fcntl.h>
+#include <signal.h>
+#include <sys/prctl.h>
+#include <sys/syscall.h>
+#include <unistd.h>
+
+#include "DriverSource.h"
+#include "Logging.h"
+#include "SessionData.h"
+
+static void handler(int signum)
+{
+	(void)signum;
+};
+
+FtraceSource::FtraceSource(sem_t *senderSem) : mFtraceFh(NULL), mBuffer(0, FRAME_BLOCK_COUNTER, 128*1024, senderSem), mTid(-1), mTracingOn(0) {
+}
+
+FtraceSource::~FtraceSource() {
+}
+
+bool FtraceSource::prepare() {
+	{
+		struct sigaction act;
+		act.sa_handler = handler;
+		act.sa_flags = (int)SA_RESETHAND;
+		if (sigaction(SIGUSR1, &act, NULL) != 0) {
+			logg->logError(__FILE__, __LINE__, "sigaction failed: %s\n", strerror(errno));
+			handleException();
+		}
+	}
+
+	if (DriverSource::readIntDriver("/sys/kernel/debug/tracing/tracing_on", &mTracingOn)) {
+		logg->logError(__FILE__, __LINE__, "Unable to read if ftrace is enabled");
+		handleException();
+	}
+
+	if (DriverSource::writeDriver("/sys/kernel/debug/tracing/tracing_on", "0") != 0) {
+		logg->logError(__FILE__, __LINE__, "Unable to turn ftrace off before truncating the buffer");
+		handleException();
+	}
+
+	{
+		int fd;
+		fd = open("/sys/kernel/debug/tracing/trace", O_WRONLY | O_TRUNC | O_CLOEXEC, 0666);
+		if (fd < 0) {
+			logg->logError(__FILE__, __LINE__, "Unable truncate ftrace buffer: %s", strerror(errno));
+			handleException();
+		}
+		close(fd);
+	}
+
+	if (DriverSource::writeDriver("/sys/kernel/debug/tracing/trace_clock", "perf") != 0) {
+		logg->logError(__FILE__, __LINE__, "Unable to switch ftrace to the perf clock, please ensure you are running Linux 3.10 or later");
+		handleException();
+	}
+
+	mFtraceFh = fopen_cloexec("/sys/kernel/debug/tracing/trace_pipe", "rb");
+	if (mFtraceFh == NULL) {
+		logg->logError(__FILE__, __LINE__, "Unable to open trace_pipe");
+		handleException();
+	}
+
+	return true;
+}
+
+void FtraceSource::run() {
+	prctl(PR_SET_NAME, (unsigned long)&"gatord-ftrace", 0, 0, 0);
+	mTid = syscall(__NR_gettid);
+
+	if (DriverSource::writeDriver("/sys/kernel/debug/tracing/tracing_on", "1") != 0) {
+		logg->logError(__FILE__, __LINE__, "Unable to turn ftrace on");
+		handleException();
+	}
+
+	while (gSessionData->mSessionIsActive) {
+		char buf[1<<12];
+
+		if (fgets(buf, sizeof(buf), mFtraceFh) == NULL) {
+			if (errno == EINTR) {
+				// Interrupted by interrupt - likely user request to terminate
+				break;
+			}
+			logg->logError(__FILE__, __LINE__, "Unable read trace data: %s", strerror(errno));
+			handleException();
+		}
+
+		const uint64_t currTime = getTime();
+
+		char *const colon = strstr(buf, ": ");
+		if (colon == NULL) {
+			logg->logError(__FILE__, __LINE__, "Unable find colon: %s", buf);
+			handleException();
+		}
+		*colon = '\0';
+
+		char *const space = strrchr(buf, ' ');
+		if (space == NULL) {
+			logg->logError(__FILE__, __LINE__, "Unable find space: %s", buf);
+			handleException();
+		}
+		*colon = ':';
+
+		int64_t *data = NULL;
+		int count = gSessionData->ftraceDriver.read(colon + 2, &data);
+		if (count > 0) {
+			errno = 0;
+			const long long time = strtod(space, NULL) * 1000000000;
+			if (errno != 0) {
+				logg->logError(__FILE__, __LINE__, "Unable to parse time: %s", strerror(errno));
+				handleException();
+			}
+			mBuffer.event64(-1, time);
+
+			for (int i = 0; i < count; ++i) {
+				mBuffer.event64(data[2*i + 0], data[2*i + 1]);
+			}
+
+			mBuffer.check(currTime);
+		}
+
+	}
+
+	mBuffer.setDone();
+
+	DriverSource::writeDriver("/sys/kernel/debug/tracing/tracing_on", mTracingOn);
+	fclose(mFtraceFh);
+	DriverSource::writeDriver("/sys/kernel/debug/tracing/trace_clock", "local");
+}
+
+void FtraceSource::interrupt() {
+	// Closing the underlying file handle does not result in the read on the ftrace file handle to return, so send a signal to the thread
+	syscall(__NR_tgkill, getpid(), mTid, SIGUSR1);
+}
+
+bool FtraceSource::isDone() {
+	return mBuffer.isDone();
+}
+
+void FtraceSource::write(Sender *sender) {
+	// Don't send ftrace data until the summary packet is sent so that monotonic delta is available
+	if (!gSessionData->mSentSummary) {
+		return;
+	}
+	if (!mBuffer.isDone()) {
+		mBuffer.write(sender);
+	}
+}