Tue, 06 Jan 2015 21:39:09 +0100
Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.
michael@0 | 1 | // Copyright (c) 2006-2011 The Chromium Authors. All rights reserved. |
michael@0 | 2 | // |
michael@0 | 3 | // Redistribution and use in source and binary forms, with or without |
michael@0 | 4 | // modification, are permitted provided that the following conditions |
michael@0 | 5 | // are met: |
michael@0 | 6 | // * Redistributions of source code must retain the above copyright |
michael@0 | 7 | // notice, this list of conditions and the following disclaimer. |
michael@0 | 8 | // * Redistributions in binary form must reproduce the above copyright |
michael@0 | 9 | // notice, this list of conditions and the following disclaimer in |
michael@0 | 10 | // the documentation and/or other materials provided with the |
michael@0 | 11 | // distribution. |
michael@0 | 12 | // * Neither the name of Google, Inc. nor the names of its contributors |
michael@0 | 13 | // may be used to endorse or promote products derived from this |
michael@0 | 14 | // software without specific prior written permission. |
michael@0 | 15 | // |
michael@0 | 16 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
michael@0 | 17 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
michael@0 | 18 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS |
michael@0 | 19 | // FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE |
michael@0 | 20 | // COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, |
michael@0 | 21 | // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, |
michael@0 | 22 | // BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS |
michael@0 | 23 | // OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED |
michael@0 | 24 | // AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, |
michael@0 | 25 | // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT |
michael@0 | 26 | // OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
michael@0 | 27 | // SUCH DAMAGE. |
michael@0 | 28 | |
michael@0 | 29 | #ifndef TOOLS_PLATFORM_H_ |
michael@0 | 30 | #define TOOLS_PLATFORM_H_ |
michael@0 | 31 | |
michael@0 | 32 | #ifdef ANDROID |
michael@0 | 33 | #include <android/log.h> |
michael@0 | 34 | #else |
michael@0 | 35 | #define __android_log_print(a, ...) |
michael@0 | 36 | #endif |
michael@0 | 37 | |
michael@0 | 38 | #ifdef XP_UNIX |
michael@0 | 39 | #include <pthread.h> |
michael@0 | 40 | #endif |
michael@0 | 41 | |
michael@0 | 42 | #include <stdint.h> |
michael@0 | 43 | #include <math.h> |
michael@0 | 44 | #include "mozilla/unused.h" |
michael@0 | 45 | #include "mozilla/TimeStamp.h" |
michael@0 | 46 | #include "mozilla/Mutex.h" |
michael@0 | 47 | #include "MainThreadUtils.h" |
michael@0 | 48 | #include "PlatformMacros.h" |
michael@0 | 49 | #include "v8-support.h" |
michael@0 | 50 | #include <vector> |
michael@0 | 51 | |
michael@0 | 52 | #ifdef XP_WIN |
michael@0 | 53 | #include <windows.h> |
michael@0 | 54 | #endif |
michael@0 | 55 | |
michael@0 | 56 | #define ASSERT(a) MOZ_ASSERT(a) |
michael@0 | 57 | |
michael@0 | 58 | bool moz_profiler_verbose(); |
michael@0 | 59 | |
michael@0 | 60 | #ifdef ANDROID |
michael@0 | 61 | # if defined(__arm__) || defined(__thumb__) |
michael@0 | 62 | # define ENABLE_SPS_LEAF_DATA |
michael@0 | 63 | # define ENABLE_ARM_LR_SAVING |
michael@0 | 64 | # endif |
michael@0 | 65 | # define LOG(text) \ |
michael@0 | 66 | do { if (moz_profiler_verbose()) \ |
michael@0 | 67 | __android_log_write(ANDROID_LOG_ERROR, "Profiler", text); \ |
michael@0 | 68 | } while (0) |
michael@0 | 69 | # define LOGF(format, ...) \ |
michael@0 | 70 | do { if (moz_profiler_verbose()) \ |
michael@0 | 71 | __android_log_print(ANDROID_LOG_ERROR, "Profiler", format, \ |
michael@0 | 72 | __VA_ARGS__); \ |
michael@0 | 73 | } while (0) |
michael@0 | 74 | |
michael@0 | 75 | #else |
michael@0 | 76 | # define LOG(text) \ |
michael@0 | 77 | do { if (moz_profiler_verbose()) fprintf(stderr, "Profiler: %s\n", text); \ |
michael@0 | 78 | } while (0) |
michael@0 | 79 | # define LOGF(format, ...) \ |
michael@0 | 80 | do { if (moz_profiler_verbose()) fprintf(stderr, "Profiler: " format \ |
michael@0 | 81 | "\n", __VA_ARGS__); \ |
michael@0 | 82 | } while (0) |
michael@0 | 83 | |
michael@0 | 84 | #endif |
michael@0 | 85 | |
michael@0 | 86 | #if defined(XP_MACOSX) || defined(XP_WIN) || defined(XP_LINUX) |
michael@0 | 87 | #define ENABLE_SPS_LEAF_DATA |
michael@0 | 88 | #endif |
michael@0 | 89 | |
michael@0 | 90 | extern mozilla::TimeStamp sStartTime; |
michael@0 | 91 | |
michael@0 | 92 | typedef uint8_t* Address; |
michael@0 | 93 | |
michael@0 | 94 | // ---------------------------------------------------------------------------- |
michael@0 | 95 | // Mutex |
michael@0 | 96 | // |
michael@0 | 97 | // Mutexes are used for serializing access to non-reentrant sections of code. |
michael@0 | 98 | // The implementations of mutex should allow for nested/recursive locking. |
michael@0 | 99 | |
michael@0 | 100 | class Mutex { |
michael@0 | 101 | public: |
michael@0 | 102 | virtual ~Mutex() {} |
michael@0 | 103 | |
michael@0 | 104 | // Locks the given mutex. If the mutex is currently unlocked, it becomes |
michael@0 | 105 | // locked and owned by the calling thread, and immediately. If the mutex |
michael@0 | 106 | // is already locked by another thread, suspends the calling thread until |
michael@0 | 107 | // the mutex is unlocked. |
michael@0 | 108 | virtual int Lock() = 0; |
michael@0 | 109 | |
michael@0 | 110 | // Unlocks the given mutex. The mutex is assumed to be locked and owned by |
michael@0 | 111 | // the calling thread on entrance. |
michael@0 | 112 | virtual int Unlock() = 0; |
michael@0 | 113 | |
michael@0 | 114 | // Tries to lock the given mutex. Returns whether the mutex was |
michael@0 | 115 | // successfully locked. |
michael@0 | 116 | virtual bool TryLock() = 0; |
michael@0 | 117 | }; |
michael@0 | 118 | |
michael@0 | 119 | // ---------------------------------------------------------------------------- |
michael@0 | 120 | // OS |
michael@0 | 121 | // |
michael@0 | 122 | // This class has static methods for the different platform specific |
michael@0 | 123 | // functions. Add methods here to cope with differences between the |
michael@0 | 124 | // supported platforms. |
michael@0 | 125 | |
michael@0 | 126 | class OS { |
michael@0 | 127 | public: |
michael@0 | 128 | |
michael@0 | 129 | // Sleep for a number of milliseconds. |
michael@0 | 130 | static void Sleep(const int milliseconds); |
michael@0 | 131 | |
michael@0 | 132 | // Sleep for a number of microseconds. |
michael@0 | 133 | static void SleepMicro(const int microseconds); |
michael@0 | 134 | |
michael@0 | 135 | // Called on startup to initialize platform specific things |
michael@0 | 136 | static void Startup(); |
michael@0 | 137 | |
michael@0 | 138 | private: |
michael@0 | 139 | static const int msPerSecond = 1000; |
michael@0 | 140 | |
michael@0 | 141 | }; |
michael@0 | 142 | |
michael@0 | 143 | |
michael@0 | 144 | |
michael@0 | 145 | |
michael@0 | 146 | // ---------------------------------------------------------------------------- |
michael@0 | 147 | // Thread |
michael@0 | 148 | // |
michael@0 | 149 | // Thread objects are used for creating and running threads. When the start() |
michael@0 | 150 | // method is called the new thread starts running the run() method in the new |
michael@0 | 151 | // thread. The Thread object should not be deallocated before the thread has |
michael@0 | 152 | // terminated. |
michael@0 | 153 | |
michael@0 | 154 | class Thread { |
michael@0 | 155 | public: |
michael@0 | 156 | // Create new thread. |
michael@0 | 157 | explicit Thread(const char* name); |
michael@0 | 158 | virtual ~Thread(); |
michael@0 | 159 | |
michael@0 | 160 | // Start new thread by calling the Run() method in the new thread. |
michael@0 | 161 | void Start(); |
michael@0 | 162 | |
michael@0 | 163 | void Join(); |
michael@0 | 164 | |
michael@0 | 165 | inline const char* name() const { |
michael@0 | 166 | return name_; |
michael@0 | 167 | } |
michael@0 | 168 | |
michael@0 | 169 | // Abstract method for run handler. |
michael@0 | 170 | virtual void Run() = 0; |
michael@0 | 171 | |
michael@0 | 172 | // The thread name length is limited to 16 based on Linux's implementation of |
michael@0 | 173 | // prctl(). |
michael@0 | 174 | static const int kMaxThreadNameLength = 16; |
michael@0 | 175 | |
michael@0 | 176 | #ifdef XP_WIN |
michael@0 | 177 | HANDLE thread_; |
michael@0 | 178 | typedef DWORD tid_t; |
michael@0 | 179 | tid_t thread_id_; |
michael@0 | 180 | #else |
michael@0 | 181 | typedef ::pid_t tid_t; |
michael@0 | 182 | #endif |
michael@0 | 183 | #if defined(XP_MACOSX) |
michael@0 | 184 | pthread_t thread_; |
michael@0 | 185 | #endif |
michael@0 | 186 | |
michael@0 | 187 | static tid_t GetCurrentId(); |
michael@0 | 188 | |
michael@0 | 189 | private: |
michael@0 | 190 | void set_name(const char *name); |
michael@0 | 191 | |
michael@0 | 192 | char name_[kMaxThreadNameLength]; |
michael@0 | 193 | int stack_size_; |
michael@0 | 194 | |
michael@0 | 195 | DISALLOW_COPY_AND_ASSIGN(Thread); |
michael@0 | 196 | }; |
michael@0 | 197 | |
michael@0 | 198 | // ---------------------------------------------------------------------------- |
michael@0 | 199 | // HAVE_NATIVE_UNWIND |
michael@0 | 200 | // |
michael@0 | 201 | // Pseudo backtraces are available on all platforms. Native |
michael@0 | 202 | // backtraces are available only on selected platforms. Breakpad is |
michael@0 | 203 | // the only supported native unwinder. HAVE_NATIVE_UNWIND is set at |
michael@0 | 204 | // build time to indicate whether native unwinding is possible on this |
michael@0 | 205 | // platform. The actual unwind mode currently in use is stored in |
michael@0 | 206 | // sUnwindMode. |
michael@0 | 207 | |
michael@0 | 208 | #undef HAVE_NATIVE_UNWIND |
michael@0 | 209 | #if defined(MOZ_PROFILING) \ |
michael@0 | 210 | && (defined(SPS_PLAT_amd64_linux) || defined(SPS_PLAT_arm_android) \ |
michael@0 | 211 | || defined(SPS_PLAT_x86_linux) \ |
michael@0 | 212 | || defined(SPS_OS_windows) \ |
michael@0 | 213 | || defined(SPS_OS_darwin)) |
michael@0 | 214 | # define HAVE_NATIVE_UNWIND |
michael@0 | 215 | #endif |
michael@0 | 216 | |
michael@0 | 217 | /* Some values extracted at startup from environment variables, that |
michael@0 | 218 | control the behaviour of the breakpad unwinder. */ |
michael@0 | 219 | extern const char* PROFILER_MODE; |
michael@0 | 220 | extern const char* PROFILER_INTERVAL; |
michael@0 | 221 | extern const char* PROFILER_ENTRIES; |
michael@0 | 222 | extern const char* PROFILER_STACK; |
michael@0 | 223 | extern const char* PROFILER_FEATURES; |
michael@0 | 224 | |
michael@0 | 225 | void read_profiler_env_vars(); |
michael@0 | 226 | void profiler_usage(); |
michael@0 | 227 | |
michael@0 | 228 | // Helper methods to expose modifying profiler behavior |
michael@0 | 229 | bool set_profiler_mode(const char*); |
michael@0 | 230 | bool set_profiler_interval(const char*); |
michael@0 | 231 | bool set_profiler_entries(const char*); |
michael@0 | 232 | bool set_profiler_scan(const char*); |
michael@0 | 233 | bool is_native_unwinding_avail(); |
michael@0 | 234 | |
michael@0 | 235 | typedef enum { UnwINVALID, UnwNATIVE, UnwPSEUDO, UnwCOMBINED } UnwMode; |
michael@0 | 236 | extern UnwMode sUnwindMode; /* what mode? */ |
michael@0 | 237 | extern int sUnwindInterval; /* in milliseconds */ |
michael@0 | 238 | extern int sUnwindStackScan; /* max # of dubious frames allowed */ |
michael@0 | 239 | |
michael@0 | 240 | extern int sProfileEntries; /* how many entries do we store? */ |
michael@0 | 241 | |
michael@0 | 242 | void set_tls_stack_top(void* stackTop); |
michael@0 | 243 | |
michael@0 | 244 | // ---------------------------------------------------------------------------- |
michael@0 | 245 | // Sampler |
michael@0 | 246 | // |
michael@0 | 247 | // A sampler periodically samples the state of the VM and optionally |
michael@0 | 248 | // (if used for profiling) the program counter and stack pointer for |
michael@0 | 249 | // the thread that created it. |
michael@0 | 250 | |
michael@0 | 251 | class PseudoStack; |
michael@0 | 252 | class ThreadProfile; |
michael@0 | 253 | |
michael@0 | 254 | // TickSample captures the information collected for each sample. |
michael@0 | 255 | class TickSample { |
michael@0 | 256 | public: |
michael@0 | 257 | TickSample() |
michael@0 | 258 | : |
michael@0 | 259 | pc(NULL), |
michael@0 | 260 | sp(NULL), |
michael@0 | 261 | fp(NULL), |
michael@0 | 262 | #ifdef ENABLE_ARM_LR_SAVING |
michael@0 | 263 | lr(NULL), |
michael@0 | 264 | #endif |
michael@0 | 265 | context(NULL), |
michael@0 | 266 | isSamplingCurrentThread(false) {} |
michael@0 | 267 | |
michael@0 | 268 | void PopulateContext(void* aContext); |
michael@0 | 269 | |
michael@0 | 270 | Address pc; // Instruction pointer. |
michael@0 | 271 | Address sp; // Stack pointer. |
michael@0 | 272 | Address fp; // Frame pointer. |
michael@0 | 273 | #ifdef ENABLE_ARM_LR_SAVING |
michael@0 | 274 | Address lr; // ARM link register |
michael@0 | 275 | #endif |
michael@0 | 276 | void* context; // The context from the signal handler, if available. On |
michael@0 | 277 | // Win32 this may contain the windows thread context. |
michael@0 | 278 | bool isSamplingCurrentThread; |
michael@0 | 279 | ThreadProfile* threadProfile; |
michael@0 | 280 | mozilla::TimeStamp timestamp; |
michael@0 | 281 | }; |
michael@0 | 282 | |
michael@0 | 283 | class ThreadInfo; |
michael@0 | 284 | class PlatformData; |
michael@0 | 285 | class TableTicker; |
michael@0 | 286 | class SyncProfile; |
michael@0 | 287 | class Sampler { |
michael@0 | 288 | public: |
michael@0 | 289 | // Initialize sampler. |
michael@0 | 290 | explicit Sampler(double interval, bool profiling, int entrySize); |
michael@0 | 291 | virtual ~Sampler(); |
michael@0 | 292 | |
michael@0 | 293 | double interval() const { return interval_; } |
michael@0 | 294 | |
michael@0 | 295 | // This method is called for each sampling period with the current |
michael@0 | 296 | // program counter. |
michael@0 | 297 | virtual void Tick(TickSample* sample) = 0; |
michael@0 | 298 | |
michael@0 | 299 | // Immediately captures the calling thread's call stack and returns it. |
michael@0 | 300 | virtual SyncProfile* GetBacktrace() = 0; |
michael@0 | 301 | |
michael@0 | 302 | // Request a save from a signal handler |
michael@0 | 303 | virtual void RequestSave() = 0; |
michael@0 | 304 | // Process any outstanding request outside a signal handler. |
michael@0 | 305 | virtual void HandleSaveRequest() = 0; |
michael@0 | 306 | |
michael@0 | 307 | // Start and stop sampler. |
michael@0 | 308 | void Start(); |
michael@0 | 309 | void Stop(); |
michael@0 | 310 | |
michael@0 | 311 | // Is the sampler used for profiling? |
michael@0 | 312 | bool IsProfiling() const { return profiling_; } |
michael@0 | 313 | |
michael@0 | 314 | // Whether the sampler is running (that is, consumes resources). |
michael@0 | 315 | bool IsActive() const { return active_; } |
michael@0 | 316 | |
michael@0 | 317 | // Low overhead way to stop the sampler from ticking |
michael@0 | 318 | bool IsPaused() const { return paused_; } |
michael@0 | 319 | void SetPaused(bool value) { NoBarrier_Store(&paused_, value); } |
michael@0 | 320 | |
michael@0 | 321 | virtual bool ProfileThreads() const = 0; |
michael@0 | 322 | |
michael@0 | 323 | int EntrySize() { return entrySize_; } |
michael@0 | 324 | |
michael@0 | 325 | // We can't new/delete the type safely without defining it |
michael@0 | 326 | // (-Wdelete-incomplete). Use these Alloc/Free functions instead. |
michael@0 | 327 | static PlatformData* AllocPlatformData(int aThreadId); |
michael@0 | 328 | static void FreePlatformData(PlatformData*); |
michael@0 | 329 | |
michael@0 | 330 | // If we move the backtracing code into the platform files we won't |
michael@0 | 331 | // need to have these hacks |
michael@0 | 332 | #ifdef XP_WIN |
michael@0 | 333 | // xxxehsan sucky hack :( |
michael@0 | 334 | static uintptr_t GetThreadHandle(PlatformData*); |
michael@0 | 335 | #endif |
michael@0 | 336 | #ifdef XP_MACOSX |
michael@0 | 337 | static pthread_t GetProfiledThread(PlatformData*); |
michael@0 | 338 | #endif |
michael@0 | 339 | |
michael@0 | 340 | static std::vector<ThreadInfo*> GetRegisteredThreads() { |
michael@0 | 341 | return *sRegisteredThreads; |
michael@0 | 342 | } |
michael@0 | 343 | |
michael@0 | 344 | static bool RegisterCurrentThread(const char* aName, |
michael@0 | 345 | PseudoStack* aPseudoStack, |
michael@0 | 346 | bool aIsMainThread, void* stackTop); |
michael@0 | 347 | static void UnregisterCurrentThread(); |
michael@0 | 348 | |
michael@0 | 349 | static void Startup(); |
michael@0 | 350 | // Should only be called on shutdown |
michael@0 | 351 | static void Shutdown(); |
michael@0 | 352 | |
michael@0 | 353 | static TableTicker* GetActiveSampler() { return sActiveSampler; } |
michael@0 | 354 | static void SetActiveSampler(TableTicker* sampler) { sActiveSampler = sampler; } |
michael@0 | 355 | |
michael@0 | 356 | static mozilla::Mutex* sRegisteredThreadsMutex; |
michael@0 | 357 | |
michael@0 | 358 | static bool CanNotifyObservers() { |
michael@0 | 359 | #if defined(SPS_OS_android) && !defined(MOZ_WIDGET_GONK) |
michael@0 | 360 | // Android ANR reporter uses the profiler off the main thread |
michael@0 | 361 | return NS_IsMainThread(); |
michael@0 | 362 | #else |
michael@0 | 363 | MOZ_ASSERT(NS_IsMainThread()); |
michael@0 | 364 | return true; |
michael@0 | 365 | #endif |
michael@0 | 366 | } |
michael@0 | 367 | |
michael@0 | 368 | protected: |
michael@0 | 369 | static std::vector<ThreadInfo*>* sRegisteredThreads; |
michael@0 | 370 | static TableTicker* sActiveSampler; |
michael@0 | 371 | |
michael@0 | 372 | private: |
michael@0 | 373 | void SetActive(bool value) { NoBarrier_Store(&active_, value); } |
michael@0 | 374 | |
michael@0 | 375 | const double interval_; |
michael@0 | 376 | const bool profiling_; |
michael@0 | 377 | Atomic32 paused_; |
michael@0 | 378 | Atomic32 active_; |
michael@0 | 379 | const int entrySize_; |
michael@0 | 380 | |
michael@0 | 381 | // Refactor me! |
michael@0 | 382 | #if defined(SPS_OS_linux) || defined(SPS_OS_android) |
michael@0 | 383 | bool signal_handler_installed_; |
michael@0 | 384 | struct sigaction old_sigprof_signal_handler_; |
michael@0 | 385 | struct sigaction old_sigsave_signal_handler_; |
michael@0 | 386 | bool signal_sender_launched_; |
michael@0 | 387 | pthread_t signal_sender_thread_; |
michael@0 | 388 | #endif |
michael@0 | 389 | }; |
michael@0 | 390 | |
michael@0 | 391 | class ThreadInfo { |
michael@0 | 392 | public: |
michael@0 | 393 | ThreadInfo(const char* aName, int aThreadId, bool aIsMainThread, PseudoStack* aPseudoStack, void* aStackTop) |
michael@0 | 394 | : mName(strdup(aName)) |
michael@0 | 395 | , mThreadId(aThreadId) |
michael@0 | 396 | , mIsMainThread(aIsMainThread) |
michael@0 | 397 | , mPseudoStack(aPseudoStack) |
michael@0 | 398 | , mPlatformData(Sampler::AllocPlatformData(aThreadId)) |
michael@0 | 399 | , mProfile(NULL) |
michael@0 | 400 | , mStackTop(aStackTop) {} |
michael@0 | 401 | |
michael@0 | 402 | virtual ~ThreadInfo(); |
michael@0 | 403 | |
michael@0 | 404 | const char* Name() const { return mName; } |
michael@0 | 405 | int ThreadId() const { return mThreadId; } |
michael@0 | 406 | |
michael@0 | 407 | bool IsMainThread() const { return mIsMainThread; } |
michael@0 | 408 | PseudoStack* Stack() const { return mPseudoStack; } |
michael@0 | 409 | |
michael@0 | 410 | void SetProfile(ThreadProfile* aProfile) { mProfile = aProfile; } |
michael@0 | 411 | ThreadProfile* Profile() const { return mProfile; } |
michael@0 | 412 | |
michael@0 | 413 | PlatformData* GetPlatformData() const { return mPlatformData; } |
michael@0 | 414 | void* StackTop() const { return mStackTop; } |
michael@0 | 415 | private: |
michael@0 | 416 | char* mName; |
michael@0 | 417 | int mThreadId; |
michael@0 | 418 | const bool mIsMainThread; |
michael@0 | 419 | PseudoStack* mPseudoStack; |
michael@0 | 420 | PlatformData* mPlatformData; |
michael@0 | 421 | ThreadProfile* mProfile; |
michael@0 | 422 | void* const mStackTop; |
michael@0 | 423 | }; |
michael@0 | 424 | |
michael@0 | 425 | #endif /* ndef TOOLS_PLATFORM_H_ */ |