Source code

Revision control

Copy as Markdown

Other Tools

/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "mozilla/ProcInfo.h"
#include "mozilla/Sprintf.h"
#include "mozilla/Logging.h"
#include "mozilla/ScopeExit.h"
#include "mozilla/ipc/GeckoChildProcessHost.h"
#include "nsMemoryReporterManager.h"
#include "nsWhitespaceTokenizer.h"
#include <cerrno>
#include <cstdio>
#include <cstring>
#include <fcntl.h>
#include <procfs.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <unistd.h>
// Maximal length on /proc filename
// "/proc/999999/lwp/999999/lwpsinfo"
// "/proc/999999/psinfo"
#define FNMAX_PROCFS "/proc/999999/lwp/999999/lwpsinfo"
namespace mozilla {
int GetCycleTimeFrequencyMHz() { return 0; }
nsresult GetCpuTimeSinceProcessStartInMs(uint64_t* aResult) {
timespec t;
if (clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &t) == 0) {
uint64_t cpuTime =
uint64_t(t.tv_sec) * 1'000'000'000u + uint64_t(t.tv_nsec);
*aResult = cpuTime / PR_NSEC_PER_MSEC;
return NS_OK;
}
return NS_ERROR_FAILURE;
}
nsresult GetGpuTimeSinceProcessStartInMs(uint64_t* aResult) {
return NS_ERROR_NOT_IMPLEMENTED;
}
ProcInfoPromise::ResolveOrRejectValue GetProcInfoSync(
nsTArray<ProcInfoRequest>&& aRequests) {
ProcInfoPromise::ResolveOrRejectValue result;
HashMap<base::ProcessId, ProcInfo> gathered;
if (!gathered.reserve(aRequests.Length())) {
result.SetReject(NS_ERROR_OUT_OF_MEMORY);
return result;
}
for (const auto& request : aRequests) {
ProcInfo info;
int fd;
char filename[sizeof(FNMAX_PROCFS)];
psinfo_t psinfo;
snprintf(filename, sizeof(FNMAX_PROCFS), "/proc/%d/psinfo", request.pid);
if ((fd = open(filename, O_RDONLY)) == -1) {
result.SetReject(NS_ERROR_FAILURE);
return result;
}
if (read(fd, &psinfo, sizeof(psinfo_t)) != sizeof(psinfo_t)) {
close(fd);
result.SetReject(NS_ERROR_FAILURE);
return result;
}
close(fd);
info.cpuTime =
psinfo.pr_time.tv_sec * 1'000'000'000u + psinfo.pr_time.tv_nsec;
info.memory = psinfo.pr_rssize * 1024;
// Extra info
info.pid = request.pid;
info.childId = request.childId;
info.type = request.processType;
info.origin = request.origin;
info.windows = std::move(request.windowInfo);
info.utilityActors = std::move(request.utilityInfo);
// Let's look at the threads
for (int lwp = 1, lwp_max = psinfo.pr_nlwp; lwp <= lwp_max; lwp++) {
lwpsinfo_t lwpsinfo;
snprintf(filename, sizeof(FNMAX_PROCFS), "/proc/%d/lwp/%d/lwpsinfo",
request.pid, lwp);
if ((fd = open(filename, O_RDONLY)) == -1) {
// Some LWPs might no longer exist. That just means that there are
// probably others with bigger LWP id. But we need to limit the search
// because of possible race condition.
if (lwp_max < 2 * psinfo.pr_nlwp) lwp_max++;
continue;
}
if (read(fd, &lwpsinfo, sizeof(lwpsinfo_t)) != sizeof(lwpsinfo_t)) {
close(fd);
continue;
}
close(fd);
ThreadInfo threadInfo;
threadInfo.tid = lwpsinfo.pr_lwpid;
threadInfo.cpuTime =
lwpsinfo.pr_time.tv_sec * 1'000'000'000u + lwpsinfo.pr_time.tv_nsec;
threadInfo.name.AssignASCII(lwpsinfo.pr_name, strlen(lwpsinfo.pr_name));
info.threads.AppendElement(threadInfo);
}
if (!gathered.put(request.pid, std::move(info))) {
result.SetReject(NS_ERROR_OUT_OF_MEMORY);
return result;
}
}
// ... and we're done!
result.SetResolve(std::move(gathered));
return result;
}
} // namespace mozilla