Issue #21 - Remove Telemetry plumbing and fix build.

Note this won't give working applications. Requires FE changes and
additional js module changes (next part).
This commit is contained in:
Moonchild 2021-10-29 11:02:27 +00:00 committed by roytam1
commit 8d800b1cb0
205 changed files with 45 additions and 40519 deletions

View file

@ -1,5 +1,4 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
* vim: sw=2 ts=2 et lcs=trail\:.,tab\:>~ :
* 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/. */
@ -44,7 +43,6 @@
#include "mozilla/Services.h"
#include "mozilla/UniquePtr.h"
#include "mozilla/Unused.h"
#include "mozilla/Telemetry.h"
// Normally, the number of milliseconds that AsyncShutdown waits until
// it decides to crash is specified as a preference. We use the
@ -156,143 +154,6 @@ RunWatchdog(void* arg)
}
}
////////////////////////////////////////////
//
// Writer thread
//
// This nspr thread is in charge of writing to disk statistics produced by the
// watchdog thread and collected by the main thread. Note that we use a nspr
// thread rather than usual XPCOM I/O simply because we outlive XPCOM and its
// threads.
//
// Utility class, used by UniquePtr<> to close nspr files.
class PR_CloseDelete
{
public:
constexpr PR_CloseDelete() {}
PR_CloseDelete(const PR_CloseDelete& aOther)
{}
void operator()(PRFileDesc* aPtr) const
{
PR_Close(aPtr);
}
};
//
// Communication between the main thread and the writer thread.
//
// Main thread:
//
// * Whenever a shutdown step has been completed, the main thread
// obtains the number of ticks from the watchdog threads, builds
// a string representing all the data gathered so far, places
// this string in `gWriteData`, and wakes up the writer thread
// using `gWriteReady`. If `gWriteData` already contained a non-null
// pointer, this means that the writer thread is lagging behind the
// main thread, and the main thread cleans up the memory.
//
// Writer thread:
//
// * When awake, the writer thread swaps `gWriteData` to nullptr. If
// `gWriteData` contained data to write, the . If so, the writer
// thread writes the data to a file named "ShutdownDuration.json.tmp",
// then moves that file to "ShutdownDuration.json" and cleans up the
// data. If `gWriteData` contains a nullptr, the writer goes to sleep
// until it is awkened using `gWriteReady`.
//
//
// The data written by the writer thread will be read by another
// module upon the next restart and fed to Telemetry.
//
Atomic<nsCString*> gWriteData(nullptr);
PRMonitor* gWriteReady = nullptr;
void RunWriter(void* arg)
{
PR_SetCurrentThreadName("Shutdown Statistics Writer");
MOZ_LSAN_INTENTIONALLY_LEAK_OBJECT(arg);
// Shutdown will generally complete before we have a chance to
// deallocate. This is not a leak.
// Setup destinationPath and tmpFilePath
nsCString destinationPath(static_cast<char*>(arg));
nsAutoCString tmpFilePath;
tmpFilePath.Append(destinationPath);
tmpFilePath.AppendLiteral(".tmp");
// Cleanup any file leftover from a previous run
Unused << PR_Delete(tmpFilePath.get());
Unused << PR_Delete(destinationPath.get());
while (true) {
//
// Check whether we have received data from the main thread.
//
// We perform the check before waiting on `gWriteReady` as we may
// have received data while we were busy writing.
//
// Also note that gWriteData may have been modified several times
// since we last checked. That's ok, we are not losing any important
// data (since we keep adding data), and we are not leaking memory
// (since the main thread deallocates any data that hasn't been
// consumed by the writer thread).
//
UniquePtr<nsCString> data(gWriteData.exchange(nullptr));
if (!data) {
// Data is not available yet.
// Wait until the main thread provides it.
PR_EnterMonitor(gWriteReady);
PR_Wait(gWriteReady, PR_INTERVAL_NO_TIMEOUT);
PR_ExitMonitor(gWriteReady);
continue;
}
MOZ_LSAN_INTENTIONALLY_LEAK_OBJECT(data.get());
// Shutdown may complete before we have a chance to deallocate.
// This is not a leak.
//
// Write to a temporary file
//
// In case of any error, we simply give up. Since the data is
// hardly critical, we don't want to spend too much effort
// salvaging it.
//
UniquePtr<PRFileDesc, PR_CloseDelete>
tmpFileDesc(PR_Open(tmpFilePath.get(),
PR_WRONLY | PR_TRUNCATE | PR_CREATE_FILE,
00600));
// Shutdown may complete before we have a chance to close the file.
// This is not a leak.
MOZ_LSAN_INTENTIONALLY_LEAK_OBJECT(tmpFileDesc.get());
if (tmpFileDesc == nullptr) {
break;
}
if (PR_Write(tmpFileDesc.get(), data->get(), data->Length()) == -1) {
break;
}
tmpFileDesc.reset();
//
// Rename on top of destination file.
//
// This is not sufficient to guarantee that the destination file
// will be written correctly, but, again, we don't care enough
// about the data to make more efforts.
//
if (PR_Rename(tmpFilePath.get(), destinationPath.get()) != PR_SUCCESS) {
break;
}
}
}
/**
* A step during shutdown.
*
@ -347,18 +208,12 @@ nsTerminator::SelfInit()
return NS_OK;
}
// Actually launch these threads. This takes place at the first sign of shutdown.
// Actually launch the thread. This takes place at the first sign of shutdown.
void
nsTerminator::Start()
{
MOZ_ASSERT(!mInitialized);
StartWatchdog();
#if !defined(DEBUG)
// Only allow nsTerminator to write on non-debug builds so we don't get leak warnings on
// shutdown for intentional leaks (see bug 1242084). This will be enabled again by bug
// 1255484 when 1255478 lands.
StartWriter();
#endif // !defined(DEBUG)
mInitialized = true;
}
@ -397,43 +252,6 @@ nsTerminator::StartWatchdog()
MOZ_ASSERT(watchdogThread);
}
// Prepare, allocate and start the writer thread. By design, it will never
// finish, nor be deallocated. In case of error, we degrade
// gracefully to not writing Telemetry data.
void
nsTerminator::StartWriter()
{
if (!Telemetry::CanRecordExtended()) {
return;
}
nsCOMPtr<nsIFile> profLD;
nsresult rv = NS_GetSpecialDirectory(NS_APP_USER_PROFILE_LOCAL_50_DIR,
getter_AddRefs(profLD));
if (NS_FAILED(rv)) {
return;
}
rv = profLD->Append(NS_LITERAL_STRING("ShutdownDuration.json"));
if (NS_FAILED(rv)) {
return;
}
nsAutoString path;
rv = profLD->GetPath(path);
if (NS_FAILED(rv)) {
return;
}
gWriteReady = PR_NewMonitor();
MOZ_LSAN_INTENTIONALLY_LEAK_OBJECT(gWriteReady); // We will never deallocate this object
PRThread* writerThread = CreateSystemThread(RunWriter,
ToNewUTF8String(path));
if (!writerThread) {
return;
}
}
NS_IMETHODIMP
nsTerminator::Observe(nsISupports *, const char *aTopic, const char16_t *)
{
@ -451,13 +269,6 @@ nsTerminator::Observe(nsISupports *, const char *aTopic, const char16_t *)
}
UpdateHeartbeat(aTopic);
#if !defined(DEBUG)
// Only allow nsTerminator to write on non-debug builds so we don't get leak warnings on
// shutdown for intentional leaks (see bug 1242084). This will be enabled again by bug
// 1255484 when 1255478 lands.
UpdateTelemetry();
#endif // !defined(DEBUG)
UpdateCrashReport(aTopic);
// Perform a little cleanup
nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
@ -489,61 +300,4 @@ nsTerminator::UpdateHeartbeat(const char* aTopic)
mCurrentStep = nextStep;
}
void
nsTerminator::UpdateTelemetry()
{
if (!Telemetry::CanRecordExtended() || !gWriteReady) {
return;
}
//
// We need Telemetry data on the effective duration of each step,
// to be able to tune the time-to-crash of each of both the
// Terminator and AsyncShutdown. However, at this stage, it is too
// late to record such data into Telemetry, so we write it to disk
// and read it upon the next startup.
//
// Build JSON.
UniquePtr<nsCString> telemetryData(new nsCString());
telemetryData->AppendLiteral("{");
size_t fields = 0;
for (size_t i = 0; i < ArrayLength(sShutdownSteps); ++i) {
if (sShutdownSteps[i].mTicks < 0) {
// Ignore this field.
continue;
}
if (fields++ > 0) {
telemetryData->Append(", ");
}
telemetryData->AppendLiteral("\"");
telemetryData->Append(sShutdownSteps[i].mTopic);
telemetryData->AppendLiteral("\": ");
telemetryData->AppendInt(sShutdownSteps[i].mTicks);
}
telemetryData->AppendLiteral("}");
if (fields == 0) {
// Nothing to write
return;
}
//
// Send data to the worker thread.
//
delete gWriteData.exchange(telemetryData.release()); // Clear any data that hasn't been written yet
// In case the worker thread was sleeping, wake it up.
PR_EnterMonitor(gWriteReady);
PR_Notify(gWriteReady);
PR_ExitMonitor(gWriteReady);
}
void
nsTerminator::UpdateCrashReport(const char* aTopic)
{
/*** STUB ***/
}
} // namespace mozilla