Bug 1756164: part 2) Document the order of the external clipboard formats and remove...
[gecko.git] / tools / code-coverage / CodeCoverageHandler.cpp
blobfbe7494c6b1f3722c227de37890590dd75c6e1ef
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
4 * You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #include <stdio.h>
7 #ifdef XP_WIN
8 # include <process.h>
9 # define getpid _getpid
10 #else
11 # include <signal.h>
12 # include <unistd.h>
13 #endif
14 #include "js/experimental/CodeCoverage.h"
15 #include "mozilla/Atomics.h"
16 #include "mozilla/dom/ScriptSettings.h" // for AutoJSAPI
17 #include "mozilla/CodeCoverageHandler.h"
18 #include "mozilla/ClearOnShutdown.h"
19 #include "mozilla/DebugOnly.h"
20 #include "nsAppRunner.h"
21 #include "nsIFile.h"
22 #include "nsIOutputStream.h"
23 #include "nsNetUtil.h"
24 #include "nsPrintfCString.h"
25 #include "prtime.h"
27 using namespace mozilla;
29 // The __gcov_flush function writes the coverage counters to gcda files and then
30 // resets them to zero. It is defined at
31 // https://github.com/gcc-mirror/gcc/blob/aad93da1a579b9ae23ede6b9cf8523360f0a08b4/libgcc/libgcov-interface.c.
32 // __gcov_flush is protected by a mutex in GCC, but not in LLVM, so we are using
33 // a CrossProcessMutex to protect it.
35 extern "C" void __gcov_flush();
36 extern "C" void __gcov_dump();
37 extern "C" void __gcov_reset();
39 StaticAutoPtr<CodeCoverageHandler> CodeCoverageHandler::instance;
41 void CodeCoverageHandler::FlushCounters(const bool initialized) {
42 static Atomic<bool> hasBeenInitialized(false);
43 if (!hasBeenInitialized) {
44 hasBeenInitialized = initialized;
45 return;
48 printf_stderr("[CodeCoverage] Requested flush for %d.\n", getpid());
50 CrossProcessMutexAutoLock lock(*CodeCoverageHandler::Get()->GetMutex());
52 #if defined(__clang__) && __clang_major__ >= 12
53 __gcov_dump();
54 __gcov_reset();
55 #else
56 __gcov_flush();
57 #endif
59 printf_stderr("[CodeCoverage] flush completed.\n");
61 const char* outDir = getenv("JS_CODE_COVERAGE_OUTPUT_DIR");
62 if (!outDir || *outDir == 0) {
63 return;
66 dom::AutoJSAPI jsapi;
67 jsapi.Init();
68 size_t length;
69 JS::UniqueChars result = js::GetCodeCoverageSummaryAll(jsapi.cx(), &length);
70 if (!result) {
71 return;
74 nsCOMPtr<nsIFile> file;
76 nsresult rv = NS_NewNativeLocalFile(nsDependentCString(outDir), false,
77 getter_AddRefs(file));
78 MOZ_ASSERT(NS_SUCCEEDED(rv));
80 rv = file->AppendNative(
81 nsPrintfCString("%lu-%d.info", PR_Now() / PR_USEC_PER_MSEC, getpid()));
83 rv = file->CreateUnique(nsIFile::NORMAL_FILE_TYPE, 0666);
84 MOZ_ASSERT(NS_SUCCEEDED(rv));
86 nsCOMPtr<nsIOutputStream> outputStream;
87 rv = NS_NewLocalFileOutputStream(getter_AddRefs(outputStream), file);
88 MOZ_ASSERT(NS_SUCCEEDED(rv));
90 char* data = result.get();
91 while (length) {
92 uint32_t n = 0;
93 rv = outputStream->Write(data, length, &n);
94 MOZ_ASSERT(NS_SUCCEEDED(rv));
95 data += n;
96 length -= n;
99 rv = outputStream->Close();
100 MOZ_ASSERT(NS_SUCCEEDED(rv));
102 printf_stderr("[CodeCoverage] JS flush completed.\n");
105 void CodeCoverageHandler::FlushCountersSignalHandler(int) { FlushCounters(); }
107 void CodeCoverageHandler::SetSignalHandlers() {
108 #ifndef XP_WIN
109 printf_stderr("[CodeCoverage] Setting handlers for process %d.\n", getpid());
111 struct sigaction dump_sa;
112 dump_sa.sa_handler = CodeCoverageHandler::FlushCountersSignalHandler;
113 dump_sa.sa_flags = SA_RESTART;
114 sigemptyset(&dump_sa.sa_mask);
115 DebugOnly<int> r1 = sigaction(SIGUSR1, &dump_sa, nullptr);
116 MOZ_ASSERT(r1 == 0, "Failed to install GCOV SIGUSR1 handler");
117 #endif
120 CodeCoverageHandler::CodeCoverageHandler() : mGcovLock("GcovLock") {
121 SetSignalHandlers();
124 CodeCoverageHandler::CodeCoverageHandler(CrossProcessMutexHandle aHandle)
125 : mGcovLock(std::move(aHandle)) {
126 SetSignalHandlers();
129 void CodeCoverageHandler::Init() {
130 MOZ_ASSERT(!instance);
131 MOZ_ASSERT(XRE_IsParentProcess());
132 instance = new CodeCoverageHandler();
133 ClearOnShutdown(&instance);
135 // Don't really flush but just make FlushCounters usable.
136 FlushCounters(true);
139 void CodeCoverageHandler::Init(CrossProcessMutexHandle aHandle) {
140 MOZ_ASSERT(!instance);
141 MOZ_ASSERT(!XRE_IsParentProcess());
142 instance = new CodeCoverageHandler(std::move(aHandle));
143 ClearOnShutdown(&instance);
145 // Don't really flush but just make FlushCounters usable.
146 FlushCounters(true);
149 CodeCoverageHandler* CodeCoverageHandler::Get() {
150 MOZ_ASSERT(instance);
151 return instance;
154 CrossProcessMutex* CodeCoverageHandler::GetMutex() { return &mGcovLock; }
156 CrossProcessMutexHandle CodeCoverageHandler::GetMutexHandle() {
157 return mGcovLock.CloneHandle();